Overview
Card linking allows users to connect their custodial internal wallets to their payment cards. Once linked, card transactions automatically deduct funds from the connected wallets, enabling seamless cryptocurrency spending for everyday purchases.
How It Works
When a card transaction occurs:
Platform checks the highest priority linked wallet
If balance is sufficient, funds are deducted
If insufficient, platform moves to next priority wallet
Process continues until transaction succeeds or all wallets exhausted
Linking Wallets
Link an internal wallet to a user’s card:
curl -X POST "https://api.example.com/v1/wallet/internal/card_linked" \
-H "x-client-key: YOUR_PUBLIC_KEY" \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addressId": "7c1839ee-918e-4787-b74f-deeb48ead58b"
}'
Getting the addressId
The addressId is returned when you retrieve internal wallets:
curl -X GET "https://api.example.com/v1/wallet/internal" \
-H "x-client-key: YOUR_PUBLIC_KEY" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
[
{
"id" : "098aeb90-e7f7-4f81-bc2e-4963330122c5" ,
"balance" : "150.50" ,
"currency" : "usdc" ,
"address" : "0x0a4b21fa733e9aeaddbf070302a85c559de13c4d" ,
"addressId" : "7c1839ee-918e-4787-b74f-deeb48ead58b" , // Use this value
"type" : "INTERNAL"
}
]
Each user can link up to 5 wallets to their card. Attempting to link more than 5 wallets returns a validation error.
Viewing Linked Wallets
Get all wallets currently linked to the user’s card:
curl -X GET "https://api.example.com/v1/wallet/internal/card_linked" \
-H "x-client-key: YOUR_PUBLIC_KEY" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
Response Fields
Field Description idLinked wallet identifier addressBlockchain address of the wallet currencyCurrency held in the wallet networkBlockchain network priorityPayment priority (lower numbers charged first)
Unlinking Wallets
Remove a wallet from card linking:
curl -X DELETE "https://api.example.com/v1/wallet/internal/card_linked" \
-H "x-client-key: YOUR_PUBLIC_KEY" \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addressId": "7c1839ee-918e-4787-b74f-deeb48ead58b"
}'
Unlinking a wallet does not affect the wallet itself or its balance. The wallet remains accessible for deposits and withdrawals.
Priority Management
Priority determines which wallet is charged first for card transactions. Lower priority numbers have higher precedence (priority 1 is charged before priority 2).
Viewing Current Priority
curl -X GET "https://api.example.com/v1/wallet/internal/card_linked" \
-H "x-client-key: YOUR_PUBLIC_KEY" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
Updating Priority
Change the priority order of linked wallets:
curl -X PUT "https://api.example.com/v1/wallet/internal/card_linked/priority" \
-H "x-client-key: YOUR_PUBLIC_KEY" \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"wallets": [
{
"addressId": "7c1839ee-918e-4787-b74f-deeb48ead58b",
"priority": 1
},
{
"addressId": "8d9e0f1g-2h3i-4j5k-6l7m-8n9o0p1q2r3s",
"priority": 2
},
{
"addressId": "9e0f1g2h-3i4j-5k6l-7m8n-9o0p1q2r3s4t",
"priority": 3
}
]
}'
You must provide ALL linked wallets when updating priority. The API replaces the entire priority configuration with the provided list.
Priority Rules
Ascending Order : Priority 1 is checked first, then 2, then 3, etc.
Sequential Processing : Platform checks each wallet in order until transaction succeeds
Balance-Based : If a wallet has insufficient balance, platform moves to next priority
No Gaps : Priority numbers should be sequential (1, 2, 3) without gaps
Common Use Cases
Link wallets with different currencies (USDC, USDT, SOL) and set priority based on which currency you prefer to spend first. Example:
Priority 1: USDC on Linea (lowest fees)
Priority 2: USDT on Ethereum (backup)
Priority 3: SOL on Solana (last resort)
Prioritize wallets on networks with lower transaction fees. For example, set Linea wallets to priority 1 (lower fees) and Ethereum wallets to priority 2 (higher fees). Example:
Priority 1: USDC on Linea ($0.01 avg fee)
Priority 2: USDC on Ethereum ($2-5 avg fee)
Set priority based on wallet balances. Use wallets with smaller balances first to consolidate funds, or use larger balance wallets first to keep smaller amounts as reserves. Example (Spend Small First):
Priority 1: Wallet with $50 balance
Priority 2: Wallet with $500 balance
If certain wallets offer cashback or rewards, prioritize those wallets to maximize benefits. Example:
Priority 1: Wallet with 2% cashback
Priority 2: Wallet with 1% cashback
Priority 3: Standard wallet
Implementation Examples
Complete Linking Flow
async function linkWalletToCard ( userToken , currency ) {
// 1. Get available internal wallets
const walletsResponse = await fetch (
'https://api.example.com/v1/wallet/internal' ,
{
headers: {
'x-client-key' : 'YOUR_PUBLIC_KEY' ,
'Authorization' : `Bearer ${ userToken } `
}
}
);
const wallets = await walletsResponse . json ();
// 2. Find wallet with specified currency
const wallet = wallets . find ( w => w . currency === currency );
if ( ! wallet ) {
throw new Error ( `No ${ currency } wallet found` );
}
// 3. Link wallet to card
const linkResponse = await fetch (
'https://api.example.com/v1/wallet/internal/card_linked' ,
{
method: 'POST' ,
headers: {
'x-client-key' : 'YOUR_PUBLIC_KEY' ,
'Authorization' : `Bearer ${ userToken } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
addressId: wallet . addressId
})
}
);
return await linkResponse . json ();
}
// Usage
await linkWalletToCard ( userToken , 'usdc' );
Priority Management UI
import { useState , useEffect } from 'react' ;
function WalletPriorityManager ({ userToken }) {
const [ linkedWallets , setLinkedWallets ] = useState ([]);
const [ loading , setLoading ] = useState ( false );
useEffect (() => {
fetchLinkedWallets ();
}, []);
const fetchLinkedWallets = async () => {
const response = await fetch (
'https://api.example.com/v1/wallet/internal/card_linked' ,
{
headers: {
'x-client-key' : 'YOUR_PUBLIC_KEY' ,
'Authorization' : `Bearer ${ userToken } `
}
}
);
const wallets = await response . json ();
setLinkedWallets ( wallets . sort (( a , b ) => a . priority - b . priority ));
};
const updatePriority = async ( walletId , newPriority ) => {
setLoading ( true );
const updatedWallets = linkedWallets . map ( w =>
w . id === walletId ? { ... w , priority: newPriority } : w
);
// Reorder and reassign priorities
const sorted = updatedWallets
. sort (( a , b ) => a . priority - b . priority )
. map (( w , index ) => ({ ... w , priority: index + 1 }));
const payload = {
wallets: sorted . map ( w => ({
addressId: w . address ,
priority: w . priority
}))
};
await fetch (
'https://api.example.com/v1/wallet/internal/card_linked/priority' ,
{
method: 'PUT' ,
headers: {
'x-client-key' : 'YOUR_PUBLIC_KEY' ,
'Authorization' : `Bearer ${ userToken } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ( payload )
}
);
await fetchLinkedWallets ();
setLoading ( false );
};
return (
< div className = "priority-manager" >
< h3 > Linked Wallets (Payment Priority) </ h3 >
< p > Lower numbers are charged first </ p >
{ linkedWallets . map ( wallet => (
< div key = { wallet . id } className = "wallet-row" >
< span className = "priority" > # { wallet . priority } </ span >
< div className = "wallet-info" >
< strong > { wallet . currency . toUpperCase () } </ strong >
< span > { wallet . network } </ span >
< code > { wallet . address . slice ( 0 , 10 ) } ... </ code >
</ div >
< div className = "priority-controls" >
< button
onClick = { () => updatePriority ( wallet . id , wallet . priority - 1 ) }
disabled = { wallet . priority === 1 || loading }
>
↑
</ button >
< button
onClick = { () => updatePriority ( wallet . id , wallet . priority + 1 ) }
disabled = { wallet . priority === linkedWallets . length || loading }
>
↓
</ button >
</ div >
</ div >
)) }
</ div >
);
}
Transaction Flow Example
Here’s what happens when a user makes a $100 purchase with multiple linked wallets:
Linked Wallets:
Priority 1: USDC on Linea (balance: $50)
Priority 2: USDT on Ethereum (balance: $75)
Priority 3: USDC on Solana (balance: $200)
Transaction Flow:
Check Priority 1
Platform checks USDC Linea wallet. Balance: 50. I n s u f f i c i e n t f o r 50. Insufficient for 50. I n s u ff i c i e n t f or 100 purchase.
Check Priority 2
Platform checks USDT Ethereum wallet. Balance: 75. I n s u f f i c i e n t f o r 75. Insufficient for 75. I n s u ff i c i e n t f or 100 purchase.
Check Priority 3
Platform checks USDC Solana wallet. Balance: 200. S u f f i c i e n t ! D e d u c t 200. Sufficient! Deduct 200. S u ff i c i e n t ! De d u c t 100.
Complete Transaction
Card transaction approved. User’s Solana wallet balance now $100.
The platform checks wallets sequentially until finding one with sufficient balance. Only one wallet is charged per transaction.
Error Handling
Maximum Linked Wallets Exceeded
{
"error" : "Maximum linked wallets" ,
"code" : "WALLET_MAX_LINKED" ,
"message" : "User has reached the maximum number of linked wallets (5)"
}
Solution: Unlink an existing wallet before linking a new one.
Wallet Already Linked
{
"error" : "Wallet already linked" ,
"code" : "WALLET_ALREADY_LINKED" ,
"message" : "This wallet is already linked to the card"
}
Solution: No action needed. Wallet is already available for card payments.
Invalid Address ID
{
"error" : "Invalid address ID" ,
"code" : "WALLET_INVALID_ADDRESS_ID" ,
"message" : "The specified addressId does not exist or does not belong to this user"
}
Solution: Verify the addressId from GET /v1/wallet/internal response and ensure it belongs to the authenticated user.
Insufficient Balance (During Transaction)
{
"error" : "Insufficient balance" ,
"code" : "WALLET_INSUFFICIENT_BALANCE" ,
"message" : "All linked wallets have insufficient balance for this transaction"
}
Solution: Prompt user to fund one of their linked wallets or add a new wallet with sufficient balance.
Best Practices
Set Logical Priority Prioritize wallets based on fees, balances, or user preferences. Lower-fee networks should typically have higher priority.
Display Balance Status Show wallet balances in your UI so users understand which wallet will be charged and whether they have sufficient funds.
Allow Easy Reordering Provide drag-and-drop or button controls to let users easily adjust wallet priority.
Show Network Fees Display typical network fees for each wallet to help users make informed priority decisions.
Notify on Insufficient Balance Alert users when their primary wallet has low balance and suggest funding it or adjusting priority.
Limit Linked Wallets Consider encouraging users to link only 2-3 wallets to keep the experience simple and manageable.
Next Steps