Skip to main content

Issuing Management API

danger

This part have released for public.

The Issuing management API is about how to create and manage your cards through OpenAPI.

Cards are divided into B2B cards and B2C cards, suitable for different business needs:


Cards API

The Cards API is a core interface for card management systems, which is used to manage card statuses and edit card limits, among other operations such as updating cardholder information.

info

The cards need to be purchased in one batch through the business team. After the purchase is completed, a document containing all card information will be delivered to you. Therefore, there is no need to create cards via the online API.

  • Lock Card: If you want to temporarily deactivate the card, then please change the card status to Locked via the card lock API, the Locked status of the card will not allow any transactions.
  • Unlock Card: If the temporary deactivation is expected to be terminated, then the card can be brought back into normal use via the Unlock Card API.
  • Termination Card: If it is decided that the card is no longer to be used, the card is terminated via the Card Termination API.
info

which is used to terminate the card. Unlike the Lock Card API, terminating a card is permanent and unrecoverable.

Card Limit

In addition to specifying the limit policy when creating the card, it can be modified through the Edit Card Limit Configure API. We support 4 different rules at the same time, if you want to disable a rule, set the amount to 0.

  • Transaction: Maximum limit per transaction.
  • Daily: Aggregate limit within a single natural day.
  • Monthly: Aggregate limit within a single natural month.
  • Lifetime: Aggregate limit within whole lifetime.

Physical card activation

When the bulk card purchase is completed, the virtual cards will be activated immediately and ready for direct use. However, physical cards require a PIN code setup to initiate the activation process.

  • Generate keys using the ECDSA algorithm
  • Send a POST request to the Exchange Key API to exchange keys
  • Calculate and obtain the secretKey using the returned key
  • Encrypt the password with the secretKey and send a POST request to the Set Pin And Card Active API

Get Full Card Number

The full card number is extremely sensitive information and also requires ECDSA encrypted transmission in requests.

ECDSA Sample Code - Golang

This process implements a secure workflow for physical card activation and PIN code setup, leveraging Elliptic Curve Cryptography (ECC) (ECDSA for key generation, ECDH for key exchange), SHA-256 for key derivation, and JWE (JSON Web Encryption) for PIN encryption. The core goal is to ensure the secure transmission of the PIN code during the card activation process by avoiding plaintext transmission and using ephemeral key exchange.

  • Generate ECDSA Key Pair: Generate an Elliptic Curve Digital Signature Algorithm (ECDSA) key pair using the NIST P-256 (secp256r1) curve, a widely adopted 256-bit elliptic curve standard for balancing security and performance. The key pair consists of a private key (a large random integer) and a public key (a point on the curve represented by X/Y coordinates). Additionally, generate a unique Key ID (Kid) to identify this key pair.
  • Exchange Keys via the Exchange Key API: Send a POST request to the /svc/card_issuer/api/v1/pci_session endpoint (Exchange Key API) with the ECDSA public key (X/Y coordinates in hex string format) and Kid. The server responds with its ephemeral public key (EphemPubKey) in JWK (JSON Web Key) format, which is also based on the P-256 curve.
  • Derive SecretKey via ECDH and SHA-256: ECDH Key Exchange: Use the client's ECDSA private key and the server's ephemeral public key to compute a shared secret via the Elliptic Curve Diffie-Hellman (ECDH) algorithm. Both parties (client and server) can independently compute the same shared secret without transmitting it directly.Key Derivation Function (KDF): Combine the shared secret with context data (e.g., Kid) and apply the SHA-256 hash function to derive a fixed-length (32-byte) symmetric key (secretKey). This step enhances key uniqueness and security by incorporating additional context.
  • Encrypt PIN with SecretKey and Call Set Pin And Card Active API: Encrypt the PIN code using the derived secretKey with the JWE (JSON Web Encryption) standard in DIRECT encryption mode (a lightweight symmetric encryption mode for short data). Send a POST request to the /api/v1/pci_pin_with_session endpoint with the JWE-encrypted data to complete PIN setup and physical card activation.
// Global constants and dependencies
CONST P256_CURVE = NIST P-256 (secp256r1)
CONST KEY_SIZE = 32 // 256 bits for SHA-256 derived key
CONST EXCHANGE_KEY_API = "/svc/card_issuer/api/v1/pci_session"
CONST SET_PIN_ACTIVE_API = "/api/v1/pci_pin_with_session"

// Step 1: Generate ECDSA key pair and Kid
FUNCTION generateECDSAKeyPair():
// Generate ECDSA private key using cryptographically secure random number generator
privateKey = ECDSA.GenerateKey(P256_CURVE, CryptRandom.Reader)
// Extract public key (X/Y coordinates) from the private key
publicKey = privateKey.PublicKey
// Encode X/Y coordinates to hex strings for API transmission
pubKeyX = Hex.Encode(publicKey.X.Bytes())
pubKeyY = Hex.Encode(publicKey.Y.Bytes())
// Generate unique Key ID (Kid) for the key pair
kid = UUID.Generate()
RETURN privateKey, pubKeyX, pubKeyY, kid

// Step 2: Call Exchange Key API to get server's ephemeral public key
FUNCTION exchangeKeys(pubKeyX, pubKeyY, kid):
// Build request payload (JWK format for ECC key)
requestPayload = {
"kty": "EC",
"crv": "P-256",
"kid": kid,
"x": pubKeyX,
"y": pubKeyY
}
// Send POST request to Exchange Key API
response = HTTP.Post(EXCHANGE_KEY_API, requestPayload)
// Parse response to extract server's ephemeral public key (JWK)
serverEphemPubKey = response.jwk
RETURN serverEphemPubKey

// Step 3: Derive secretKey using ECDH and SHA-256 KDF
FUNCTION deriveSecretKey(clientPrivateKey, serverEphemPubKey, kid):
// Decode server's X/Y hex strings to big integers
sdkX = Hex.Decode(serverEphemPubKey.x)
sdkY = Hex.Decode(serverEphemPubKey.y)
x = BigInt.FromBytes(sdkX)
y = BigInt.FromBytes(sdkY)

// Validate if the server's public key is on the P-256 curve (security check)
IF NOT P256_CURVE.IsOnCurve(x, y):
THROW Error("Server public key is not on P-256 curve")

// Construct server's ECDSA public key object
serverPublicKey = ECDSA.PublicKey(Curve = P256_CURVE, X = x, Y = y)

// Compute ECDH shared secret
clientECDHKey = clientPrivateKey.ECDH()
serverECDHKey = serverPublicKey.ECDH()
sharedSecret = clientECDHKey.ECDH(serverECDHKey)

// Build combined data for KDF: alg + apuData + apvData + kid + sharedSecret
combinedData = Concat(EmptyBytes, EmptyBytes, kid.Bytes(), sharedSecret)

// Apply SHA-256 hash and truncate to key size
derivedKey = SHA256.Hash(combinedData)
secretKey = derivedKey[:KEY_SIZE]

RETURN secretKey

// Step 4: Encrypt PIN with secretKey via JWE and call activation API
FUNCTION encryptPINAndActivate(secretKey, kid, pinCode):
// Build payload with PIN code
pinData = {
"password": pinCode
}
pinDataBytes = JSON.Marshal(pinData)

// Build JWE protected headers (include Kid for key identification)
jweHeaders = JWE.NewHeaders()
jweHeaders.Set("kid", kid)

// Encrypt PIN data using JWE DIRECT mode with secretKey
jweBlock = JWE.Encrypt(
plaintext = pinDataBytes,
key = secretKey,
algorithm = JWA.DIRECT,
headers = jweHeaders
)

// Send POST request to Set Pin And Card Active API
activationResponse = HTTP.Post(SET_PIN_ACTIVE_API, jweBlock)

RETURN activationResponse

// Main workflow
FUNCTION main(pinCode):
// Step 1: Generate ECDSA key pair
privateKey, pubKeyX, pubKeyY, kid = generateECDSAKeyPair()

// Step 2: Exchange keys with server
serverEphemPubKey = exchangeKeys(pubKeyX, pubKeyY, kid)

// Step 3: Derive secretKey
secretKey = deriveSecretKey(privateKey, serverEphemPubKey, kid)

// Step 4: Encrypt PIN and activate card
activationResult = encryptPINAndActivate(secretKey, kid, pinCode)

PRINT "Card activation result: ", activationResult

POST
Create Card
>
PUT
Edit Card Limit Configure
>
GET
Get Account Balance
>
GET
Get Card Limit Logs
>
PUT
Card Lock
>
PUT
Card Unlock
>
PUT
Card Termination
>
GET
Get Card
>
GET
Get Card List
>
GET
Get Card Transaction List
>
GET
Exchange Key
>
GET
Get Full Card Number
>
GET
Set Card Pin And Active
>

Users API

If you need to use B2C Cards, you must use the User API to associate them with your users, and pass in the p_user_id when creating the cards. You must ensure that the submitted eKYC information is accurate.

  • Link Card: After a user is created, the Link Card API can be used to assign one card to the user from the unassigned B2C card pool, with a limit of one card per user.
POST
Create User
>
PUT
Edit User
>
GET
Get User
>
GET
Get Account Balance
>
POST
Link Card
>

Wallet API

The Wallet API enables you to create recharge addresses for mainstream blockchains for each user.

POST
Create Wallet
>
GET
Get Wallet
>
GET
Get Wallet List
>
GET
Get Wallet Transaction List
>
GET
Get Wallet Topup Fee Rule
>
POST
Set Wallet Topup Fee Rule
>

Platform Transfer API

The Platform Transfer API enables you to transfer account balances between your users.

Create platform transfer

When initiating a transfer request from User A (sender_party) to User B (receiver_party), the following conditions must be met: The eKYC information is consistent with that submitted during registration. User A has a sufficient balance in the corresponding currency. The status of User A or User B is Active.

The Platform Transfer is completed instantly, with no waiting required.

POST
Create Platform Transfer
>
GET
Get Platform Transfer Transaction List
>

Balance API

Both Business Wallets and B2C User Wallets may have wallets in different currencies based on actual circumstances, and the Balance API will return balance information for each currency.

The Balance API is an interface used to query the balance of your corporate account or B2C User account. Once the funds in an account change, the data returned by the Balance API will update in real time immediately.

If you pass the p_user_id parameter, the API will query the balance of the B2C User account; otherwise, it will query the balance of the corporate account.

GET
Get Account Balance
>

Process 3DS Verification

When a card is used for an online transaction, 3DS verification may be triggered. We support sending the verification code to your server via webhook, and you can then send it to your users in any way you like. We will send the webhook in the following format.

{
"p_business_id": "********",
"card_reference_id": "33cc2ca1-b4bf-4516-9962-31c67a885eeb",
"verification_id": "03e69dd9-a70c-4b0f-b084-c0ee077772fb",
"business_name": "******",
"card_num": "356772******8213"
"transaction_currency": "HKD",
"transaction_amount": "-101",
"merchant_id": "666666660057123",
"merchant_country": "HK",
"merchant_city": "",
"merchant_name": "Bindo Simulator Test",
"p_created_at": "2025-03-04T03:32:11.051702Z"
"otp_code": "123456" // 验证码
}
FieldComment
p_business_idyour wonder side merchant id
card_reference_idthe card identifier
verification_idthe verification identifier
business_namename of the p_business_id
card_numdesensitized card number information
transaction_currencythe transaction currency
transaction amountthe transaction amount
merchant_idthe transaction merchant id
merchant_citythe transaction merchant city
merchant_namethe transaction merchant name
otp_codeOTP code of the verification, 6 digits

Realtime Webhook

If you would like to receive real-time notifications of transactions via webhook, please contact us to configure the webhook url.

For each transaction we will send the following transaction notification:

Actions

ActionDescription
AuthorizationWhen new transaction authorized
ReversedWhen transaction void from acquirer side
SettledSettled an authorized transaction

Request Body

{
"action": "Authorization",
"card_transaction": {
"id": "33cc2ca1-b4bf-4516-9962-31c67a885eeb",
"p_business_id": "***************",
"card": "03e69dd9-a70c-4b0f-b084-c0ee077772fb",
"status": "Declined",
"type": "Sales",
"transaction_currency": "HKD",
"transaction_amount": "-101",
"local_currency": "HKD",
"local_amount": "-101",
"final_local_amount": "-101",
"billing_currency" : "HKD",
"billing_amount" : "-106"
"calculated_fee": "5",
"merchant_id": "666666660057123",
"merchant_country": "HK",
"merchant_city": "",
"merchant_name": "Bindo Simulator Test",
"p_created_at": "2025-03-04T03:32:11.051702Z"
}
}
FieldComment
idthe transaction id
p_business_idyour wonder side merchant id
cardthe wonder card id
typetransaction type
transaction_currencythe transaction currency
transaction amountthe transaction amount
local currencybilling currency
local amountbilling_amount
calculated_feetotal transaction fee of local_currency
billing_currencyequal to local_currency
billing_amounttotal billing_amount, includes calculated_fee
merchant_idthe transaction merchant id
merchant_citythe transaction merchant city
merchant_namethe transaction merchant name