Custodial On-Chain Card Issuing Integration guide

For apps that have custody of user funds, this guide provides an end-to-end reference linking all necessary guides and API documentation. It includes detailed curl commands for each API call required to set up a partner, onboard users, and create and test a card, with card spending pre-funded through deposits to an on-chain contract.

Before You Get Started

Verify your asset is supported

Before you begin integrating ensure your chain and token combination is supported. See Supported Chains and Supported Tokens.

Select Funding Protocol

See the Funding Protocols guide to find which protocol would best suit your use case.

Select KYC Mode

Partner Conducted KYC is the recommended KYC mode for custodial apps that have already verified their users. If users have not already been verified then Immersve Conducted KYC can be used.

Provision application resources

Set up your partner account

Contact support to get your: API Key, Partner Account ID, and Card Program ID.

Register a Funding Channel

You will need a funding channel per token and chain. See: Creating a Funding Channel.

Setup Environment

The following variables are referenced from the example bash scripts throughout this guide.

Terminal window
card_issuer_api_key="<your_card_issuer_api_key>"
card_issuer_api_secret="<your_card_issuer_api_secret>"
partner_account_id="<your_partner_account_id>"
card_program_id="<your_card_program_id>"
funding_channel_id="<your_funding_channel_id>"

Per cardholder setup

Create a cardholder account

Provision each cardholder with an account and save their ID. In the custodial case it is assumed that you have gained permission to act on the cardholders behalf. All cardholder resources on our platform will be fully owned by your app. Each request on a cardholder resource must specify the cardholder by referencing the cardholder ID in the headers as specified in the Authentication Guide.

Terminal window
cardholder_account_id=$(curl \
-X POST "https://test.immersve.com/api/accounts" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
--data '{
"parentAccountId": "'${partner_account_id}'",
"type": "cardholder",
"name": "<e.g. Cardholder Account of Joe>"
}' | jq -r .id)

Prove ownership of web3 address

In order to prove ownership of the respective EOA (Externally owned account), sign a challenge message using the EOA's private key. Use an address that you control and would like to use to fund a user's card(s). To learn more about web3 message signing, checkout Etherscan, Eth Signer and Ethers.js.

Terminal window
wallet_address="<wallet_address>"
response=$(curl -X POST "https://test.immersve.com/api/challenges" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "x-account-id: ${cardholder_account_id}" \
--data '{
"purpose": "claim-web3-address",
"network": "<network name e.g polygon-amoy>",
"address": "'${wallet_address}'"
}')
challenge_id=$(echo $response | jq -r '.id')
message=$(echo $response | jq -r '.message')
echo "Message:${message}"

Register Cardholder Funding Source

Creating a Funding Source for a cardholder enables Immersve to attribute transactions from a funding address to individual cardholders. The "signature" parameter is the signature of the signed message from the previous step. For more context and information on card funding and executing deposits and withdrawals see the Card Funding guide.

Terminal window
signature="<signature hash of cardholder signing the challenge message with their wallet>"
funding_source_id=$(curl -X POST "https://test.immersve.com/api/funding-sources" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}" \
--data '{
"accountId": "'${cardholder_account_id}'",
"fundingAddress": "'${wallet_address}'",
"fundingChannelId": "'${funding_channel_id}'",
"signature": "'${signature}'",
"challengeId": "'${challenge_id}'"
}' | jq -r '.id')

Request a Card

For a more complete guide on card creation see Issue a Virtual Card.

Create a card

Post the funding source ID and your provided card program ID to the card orders endpoint and record the returned card ID.

Terminal window
card_id=$(curl -X POST "https://test.immersve.com/api/cards" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}" \
--data '{
"cardProgramId": "'${card_program_id}'",
"fundingSourceId": "'${funding_source_id}'"
}' | jq -r .cardId)

Get card details

Call Get Card Details to see card status and ensure it is active.

Terminal window
curl -X GET "https://test.immersve.com/api/cards/${card_id}" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}"

Get sensitive card details

Card sensitive details are obtained by generating a unique time-limited token. The response contains a callback URL which can be used to obtain the sensitive card details. See Fetching Secure Card Information for more details.

Terminal window
curl -X POST "https://test.immersve.com/api/cards/${card_id}/pan-token" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}"

Get KYC and Contact Details Prerequisites

The spending prerequisites endpoint can be used to check whether the KYC and contact details requirements for a cardholder have been satisfied.

Terminal window
curl -X POST "https://test.immersve.com/api/spending-prerequisites" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}" \
--data '{
"cardProgramId": "'${card_program_id}'",
"fundingSourceId": "'${funding_source_id}'",
"spendableAmount": 100,
"spendableCurrency": "USD",
"kycType": "partner-conducted",
"kycRegion":"NZ"
}'

Supply Contact Details

Immersve requires users contact details (phone number and email) for the following reasons, this should be explained to customers:

  • Adding cards to Apple/Google Pay wallets (X-Pay)
  • Performing 3DS validation for online transactions

If a user doesn't provide contact details, they risk online transactions being rejected and might not be able to add cards to X-Pay wallets.

Before you share contact details with Immersve you must collect user consent via a checkbox. This can be done at the same time as KYC information sharing.

Terminal window
curl -X PATCH "https://test.immersve.com/api/accounts/${cardholder_account_id}/contact-details" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}" \
--data '{
"email": {
"emailAddress": "joe@cardholder.email",
},
"phone": {
"phoneNumber": "+64123456789",
}
}'

Partner Conducted KYC

See: Partner Conducted KYC.

Deposit Funds

Before spending with a card, funds must be deposited to a funding source connected to the card. Use the Get spending prerequisites endpoint to get the correct Smart Contract write transaction for the specified amount, chain, and token.

For more information on executing deposits and withdrawals see the Card Funding guide.

Terminal window
curl -X POST "https://test.immersve.com/api/spending-prerequisites" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}" \
--data '{
"cardProgramId": "'${card_program_id}'",
"fundingSourceId": "'${funding_source_id}'",
"spendableAmount": 100,
"spendableCurrency": "USD"
}'

Check Card Balance

Verify that the balance is reflected on the Funding Source.

Terminal window
curl -X GET "https://test.immersve.com/api/accounts/${cardholder_account_id}/funding-sources" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}"

Perform a Test Card Payment

Perform a card payment using the Immersve Payment Simulator. Call the simulator endpoint with the sensitive card details.

Terminal window
curl -X POST "https://test.immersve.com/api/simulator/authorize" \
-H "X-Api-Key: ${card_issuer_api_key}" \
-H "X-Api-Secret: ${card_issuer_api_secret}" \
-H "X-Account-Id: ${cardholder_account_id}"
--data '{
"transactionType": "purchase",
"transactionAmount": "10",
"cardPan": "1234567812345678",
"cardExpiry": "202510",
"cardCvv": "123"
}'