Overview
Withdraw funds from a custodial (internal) wallet to an external blockchain address. Specify the source wallet, destination address, amount, and currency. Withdrawals are processed on-chain and may require network confirmations.
Use Cases:
Send funds to personal external wallet
Transfer to exchanges or other platforms
Withdraw to whitelisted addresses
Move funds between platforms
Prerequisites:
Source internal wallet must have sufficient balance
For some platforms, destination address may need to be whitelisted
User must have appropriate verification status
Authentication
Your public API client key
Bearer token for authentication
Query Parameters
Route to US backend environment
Request Body
Amount to withdraw (decimal string)
Destination blockchain address (Note: field name has typo in API)
Memo/destination tag for recipient address (required for XRP, Stellar, etc.)
Source wallet address (obtained from address field in GET /v1/wallet/internal)
Source wallet memo (obtained from addressMemo field in GET /v1/wallet/internal)
Currency code (e.g., “xrp”, “usdc”, “sol”)
Response
Whether withdrawal was initiated successfully
200 - Success
400 - Bad Request
401 - Authentication Error
422 - Validation Error
500 - Internal Server Error
Code Examples
curl -X POST "https://dev.api.baanx.com/v1/wallet/internal/withdraw" \
-H "x-client-key: YOUR_CLIENT_KEY" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": "10.5",
"recipientAddrss": "rNxp4h8apvRis6mJf9Sh8C6iRxfrDWN7AA",
"recipientMemo": "12345",
"sourceAddress": "rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY",
"sourceMemo": "78",
"currency": "xrp"
}'
Complete Withdrawal Flow
Get Internal Wallets
Retrieve available internal wallets const wallets = await fetch ( '/v1/wallet/internal' )
. then ( r => r . json ());
const xrpWallet = wallets . find ( w => w . currency === 'xrp' );
Validate Balance
Ensure sufficient balance for withdrawal const balance = parseFloat ( xrpWallet . balance );
const withdrawAmount = 10.5 ;
if ( balance < withdrawAmount ) {
throw new Error ( 'Insufficient balance' );
}
Prepare Withdrawal Data
Collect all required information const withdrawalData = {
amount: withdrawAmount . toString (),
recipientAddrss: 'rNxp4h8apvRis6mJf9Sh8C6iRxfrDWN7AA' ,
recipientMemo: '12345' ,
sourceAddress: xrpWallet . address ,
sourceMemo: xrpWallet . addressMemo ,
currency: xrpWallet . currency
};
Initiate Withdrawal
Execute the withdrawal request const response = await fetch ( '/v1/wallet/internal/withdraw' , {
method: 'POST' ,
body: JSON . stringify ( withdrawalData )
});
const result = await response . json ();
if ( result . success ) {
console . log ( 'Withdrawal initiated!' );
}
Monitor Completion
Check wallet history for confirmation setTimeout ( async () => {
const history = await fetch (
`/v1/wallet/history?walletId= ${ xrpWallet . id } &walletType=INTERNAL&walletCurrency= ${ xrpWallet . currency } `
). then ( r => r . json ());
const withdrawal = history . find ( tx =>
tx . sign === 'debit' &&
tx . amount === withdrawAmount . toString ()
);
if ( withdrawal ) {
console . log ( 'Withdrawal confirmed!' );
}
}, 5000 );
Important Notes
Field Name Typo : The recipient address field is named recipientAddrss (missing an ‘e’). This is a known API quirk that must be used exactly as shown.
Source Address Fields : The sourceAddress corresponds to the address field and sourceMemo corresponds to the addressMemo field from the GET /v1/wallet/internal response.
Memo Requirements : For XRP, Stellar, and other memo-based networks, always include recipient memo if withdrawing to an exchange or custodial service. Missing memos can result in lost funds.
Error Handling
Common Errors
Insufficient Balance
{
"message" : "Insufficient balance for withdrawal"
}
Solution: Check balance before withdrawal and account for network fees.
Invalid Address Format
{
"message" : "Invalid recipient address format"
}
Solution: Validate address format for the specific blockchain before submitting.
Missing Memo
{
"message" : "Recipient memo required for this network"
}
Solution: Include recipientMemo for XRP, Stellar, and similar networks.
Withdrawal Not Allowed
{
"message" : "Withdrawals temporarily disabled"
}
Solution: Check platform status or contact support. May be due to maintenance or security holds.
Address Validation
Validate addresses before withdrawal to prevent errors:
Address Validation
Python Address Validation
function validateAddress ( address , currency ) {
const patterns = {
xrp: / ^ r [ 1-9A-HJ-NP-Za-km-z ] {25,34} $ / ,
eth: / ^ 0x [ a-fA-F0-9 ] {40} $ / ,
solana: / ^ [ 1-9A-HJ-NP-Za-km-z ] {32,44} $ /
};
const pattern = patterns [ currency . toLowerCase ()];
if ( ! pattern ) {
throw new Error ( `Validation pattern not found for ${ currency } ` );
}
if ( ! pattern . test ( address )) {
throw new Error ( `Invalid ${ currency . toUpperCase () } address format` );
}
return true ;
}
try {
validateAddress ( 'rNxp4h8apvRis6mJf9Sh8C6iRxfrDWN7AA' , 'xrp' );
console . log ( 'Address is valid' );
} catch ( error ) {
console . error ( error . message );
}
Edge Cases
Minimum Withdrawal Amounts
Networks may have minimum withdrawal thresholds:
const minimums = {
xrp: 10 ,
usdc: 1 ,
eth: 0.01
};
if ( parseFloat ( amount ) < minimums [ currency ]) {
throw new Error ( `Minimum withdrawal is ${ minimums [ currency ] } ${ currency . toUpperCase () } ` );
}
Network Fees
Withdrawal amounts should account for network fees:
const balance = parseFloat ( wallet . balance );
const estimatedFee = 0.1 ;
const maxWithdrawal = balance - estimatedFee ;
console . log ( `Maximum withdrawal: ${ maxWithdrawal } ${ wallet . currency . toUpperCase () } ` );
Whitelist Requirements
Some configurations require whitelisted addresses:
const whitelistedAddresses = await fetch (
`/v1/wallet/whitelist?currency= ${ currency } `
). then ( r => r . json ());
const isWhitelisted = whitelistedAddresses . some (
w => w . walletAddress === recipientAddress
);
if ( ! isWhitelisted ) {
console . warn ( 'Address not whitelisted. Withdrawal may fail.' );
}