En resumen
La API de Withdraw de Blockradar le permite enviar activos stablecoin desde sus billeteras a direcciones blockchain externas. Soporta retiros individuales, retiros por lotes hacia múltiples destinatarios, y proporciona estimación de comisiones antes de la ejecución.
Requisitos previos
Antes de utilizar la API de Withdraw, asegúrese de contar con:
Billetera creada
Cree una billetera mediante la API Create Wallet o desde el dashboard. Necesitará el walletId para las operaciones de retiro.
ID de activo
Obtenga el assetId del token que desea retirar desde Assets en el dashboard o mediante la API Get Assets .
Saldo suficiente
Asegúrese de que su billetera tenga suficiente saldo del activo a retirar, además del token nativo (ETH, BNB, MATIC, etc.) para cubrir las comisiones de red.
Cómo funciona
La API de Withdraw envía activos stablecoin desde su billetera de Blockradar a cualquier dirección blockchain externa:
Retiro individual Envíe activos a una dirección de destinatario con una sola llamada API.
Retiro por lotes Envíe activos a múltiples destinatarios en una sola llamada API, reduciendo la sobrecarga y simplificando los pagos masivos.
Estimación de comisiones Calcule las comisiones de red antes de la ejecución para garantizar saldo suficiente y mostrar los costos a los usuarios.
Modo Sign-Only Firme transacciones sin transmitirlas para casos de uso avanzados como firma offline o envío personalizado.
Master Wallet vs Child Address
La API de Withdraw está disponible en dos niveles:
Master Wallet Retire directamente desde su master wallet. Ideal para operaciones de tesorería y gestión centralizada de fondos.
Child Address Retire desde child addresses individuales. Perfecto para operaciones específicas de usuario y gestión segregada de fondos.
Endpoints
Operación Master Wallet Child Address Withdraw POST /v1/wallets/{walletId}/withdrawPOST /v1/wallets/{walletId}/addresses/{addressId}/withdrawComisión de red POST /v1/wallets/{walletId}/withdraw/network-feePOST /v1/wallets/{walletId}/addresses/{addressId}/withdraw/network-feeSign-Only POST /v1/wallets/{walletId}/withdraw/signPOST /v1/wallets/{walletId}/addresses/{addressId}/withdraw/sign
Retiro individual
Envíe activos a una sola dirección de destinatario.
Parámetros de la solicitud
Parámetro Tipo Requerido Descripción assetIdstring Sí* El UUID del activo a retirar. Requerido si no se proporciona el array assets. addressstring Sí* La dirección de destino. Requerido si no se proporciona el array assets. amountstring Sí* El monto del retiro. Debe ser mayor que 0. Requerido si no se proporciona el array assets. referencestring No Su ID interno de seguimiento para el retiro. notestring No Un mensaje breve o nota interna. No visible en la blockchain. metadataobject No Pares clave-valor personalizados para detalles adicionales de la transacción.
Los parámetros marcados con * son requeridos para retiros individuales pero no son necesarios si está utilizando el array assets para retiros por lotes.
Ejemplo de retiro individual
curl --request POST \
--url https://api.blockradar.co/v1/wallets/{walletId}/withdraw \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '{
"assetId": "asset-uuid-here",
"address": "0xRecipientAddress...",
"amount": "100",
"reference": "payout-12345",
"note": "Monthly payout",
"metadata": {
"userId": "user_abc123",
"payoutType": "salary"
}
}'
const withdrawal = await fetch (
`https://api.blockradar.co/v1/wallets/ ${ walletId } /withdraw` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assetId: 'asset-uuid-here' ,
address: '0xRecipientAddress...' ,
amount: '100' ,
reference: 'payout-12345' ,
note: 'Monthly payout' ,
metadata: {
userId: 'user_abc123' ,
payoutType: 'salary'
}
})
}
). then ( r => r . json ());
console . log ( 'Withdrawal initiated:' , withdrawal . data );
Respuesta del retiro individual
{
"message" : "Withdrawal initiated successfully" ,
"statusCode" : 200 ,
"data" : {
"id" : "tx-uuid-123" ,
"hash" : "0xabc123..." ,
"status" : "PENDING" ,
"amount" : "100" ,
"recipientAddress" : "0xRecipientAddress..." ,
"reference" : "payout-12345" ,
"note" : "Monthly payout" ,
"metadata" : {
"userId" : "user_abc123" ,
"payoutType" : "salary"
},
"createdAt" : "2024-01-15T10:30:00Z"
}
}
Retiros por lotes
Envíe activos a múltiples destinatarios en una sola llamada API. Los retiros por lotes se ejecutan secuencialmente, y cada retiro se procesa como una transacción blockchain independiente.
Cuándo usar retiros por lotes
Pagos masivos : Pague a múltiples empleados, proveedores o socios a la vez
Distribuciones : Envíe activos a múltiples direcciones
Transferencias multi-destinatario : Envíe diferentes montos a diferentes direcciones
Eficiencia operativa : Reduzca las llamadas API y simplifique la lógica de pagos
Parámetros de la solicitud por lotes
Para retiros por lotes, utilice el array assets en lugar de parámetros individuales:
Parámetro Tipo Requerido Descripción assetsarray Sí Array de objetos de retiro (máximo 20 por lote)
Cada elemento del array assets:
Campo Tipo Requerido Descripción idstring Sí El UUID del activo a retirar addressstring Sí La dirección de destino amountstring Sí El monto del retiro. Debe ser mayor que 0. referencestring No Nota de referencia opcional para este retiro notestring No Un mensaje breve o nota interna. No visible en la blockchain. metadataobject No Pares clave-valor personalizados para detalles adicionales de la transacción.
Ejemplo de retiro por lotes
curl --request POST \
--url https://api.blockradar.co/v1/wallets/{walletId}/withdraw \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '{
"assets": [
{
"id": "asset-uuid-usdc",
"address": "0xRecipient1...",
"amount": "100",
"reference": "payout-001",
"note": "January salary"
},
{
"id": "asset-uuid-usdc",
"address": "0xRecipient2...",
"amount": "150",
"reference": "payout-002",
"note": "January salary"
},
{
"id": "asset-uuid-usdt",
"address": "0xRecipient3...",
"amount": "200",
"reference": "payout-003",
"note": "Vendor payment"
}
]
}'
const batchWithdrawal = await fetch (
`https://api.blockradar.co/v1/wallets/ ${ walletId } /withdraw` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assets: [
{
id: 'asset-uuid-usdc' ,
address: '0xRecipient1...' ,
amount: '100' ,
reference: 'payout-001' ,
note: 'January salary'
},
{
id: 'asset-uuid-usdc' ,
address: '0xRecipient2...' ,
amount: '150' ,
reference: 'payout-002' ,
note: 'January salary'
},
{
id: 'asset-uuid-usdt' ,
address: '0xRecipient3...' ,
amount: '200' ,
reference: 'payout-003' ,
note: 'Vendor payment'
}
]
})
}
). then ( r => r . json ());
console . log ( 'Batch withdrawal result:' , batchWithdrawal . data );
Respuesta del retiro por lotes
{
"message" : "Batch withdrawal initiated successfully" ,
"statusCode" : 200 ,
"data" : {
"success" : [
{
"index" : 0 ,
"id" : "tx-uuid-1" ,
"hash" : "0xabc..." ,
"status" : "PENDING" ,
"amount" : "100" ,
"recipientAddress" : "0xRecipient1..." ,
"reference" : "payout-001"
},
{
"index" : 1 ,
"id" : "tx-uuid-2" ,
"hash" : "0xdef..." ,
"status" : "PENDING" ,
"amount" : "150" ,
"recipientAddress" : "0xRecipient2..." ,
"reference" : "payout-002"
},
{
"index" : 2 ,
"id" : "tx-uuid-3" ,
"hash" : "0xghi..." ,
"status" : "PENDING" ,
"amount" : "200" ,
"recipientAddress" : "0xRecipient3..." ,
"reference" : "payout-003"
}
],
"errors" : []
}
}
Manejo de fallos parciales
Los retiros por lotes admiten éxito parcial. Si algunos retiros fallan, los demás se ejecutarán igualmente:
const result = await batchWithdrawal . json ();
// Process successful withdrawals
result . data . success . forEach ( tx => {
console . log ( `✓ ${ tx . reference } : ${ tx . hash } ` );
});
// Handle failed withdrawals
result . data . errors . forEach ( error => {
console . error ( `✗ Index ${ error . index } : ${ error . error } ` );
// Retry logic or error reporting here
});
Reglas de retiro por lotes
Regla Valor Tamaño máximo del lote 20 retiros por solicitud Tamaño mínimo del lote 1 retiro Orden de ejecución Secuencial Manejo de errores Éxito parcial (los fallos no detienen los retiros posteriores)
Estimación de comisiones de red
Estime siempre las comisiones antes de ejecutar retiros para asegurar saldo suficiente del token nativo y mostrar costos precisos a los usuarios.
Estimación de comisión individual
curl --request POST \
--url https://api.blockradar.co/v1/wallets/{walletId}/withdraw/network-fee \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '{
"assetId": "asset-uuid-here",
"address": "0xRecipientAddress...",
"amount": "100"
}'
const fee = await fetch (
`https://api.blockradar.co/v1/wallets/ ${ walletId } /withdraw/network-fee` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assetId: 'asset-uuid-here' ,
address: '0xRecipientAddress...' ,
amount: '100'
})
}
). then ( r => r . json ());
console . log ( 'Network fee:' , fee . data . networkFee );
console . log ( 'Fee in USD:' , fee . data . networkFeeInUSD );
Respuesta de comisión individual
{
"message" : "Network fee fetched successfully" ,
"statusCode" : 200 ,
"data" : {
"networkFee" : "0.00001247904" ,
"networkFeeInUSD" : "0.01" ,
"transactionFee" : "0" ,
"nativeBalance" : "0.5" ,
"nativeBalanceInUSD" : "450.00" ,
"estimatedArrivalTime" : 30
}
}
Estimación de comisiones por lotes
Estime comisiones para múltiples retiros a la vez:
curl --request POST \
--url https://api.blockradar.co/v1/wallets/{walletId}/withdraw/network-fee \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '{
"assets": [
{
"id": "asset-uuid-1",
"address": "0xRecipient1...",
"amount": "100"
},
{
"id": "asset-uuid-2",
"address": "0xRecipient2...",
"amount": "50"
}
]
}'
const batchFee = await fetch (
`https://api.blockradar.co/v1/wallets/ ${ walletId } /withdraw/network-fee` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assets: [
{
id: 'asset-uuid-1' ,
address: '0xRecipient1...' ,
amount: '100'
},
{
id: 'asset-uuid-2' ,
address: '0xRecipient2...' ,
amount: '50'
}
]
})
}
). then ( r => r . json ());
console . log ( 'Total network fee:' , batchFee . data . totalNetworkFee );
console . log ( 'Total fee in USD:' , batchFee . data . totalNetworkFeeInUSD );
Respuesta de comisión por lotes
{
"message" : "Network fee fetched successfully" ,
"statusCode" : 200 ,
"data" : {
"fees" : [
{
"index" : 0 ,
"assetId" : "asset-uuid-1" ,
"address" : "0xRecipient1..." ,
"amount" : "100" ,
"networkFee" : "0.00001247904" ,
"transactionFee" : "0" ,
"estimatedArrivalTime" : 30
},
{
"index" : 1 ,
"assetId" : "asset-uuid-2" ,
"address" : "0xRecipient2..." ,
"amount" : "50" ,
"networkFee" : "0.00000504" ,
"transactionFee" : "0" ,
"estimatedArrivalTime" : 30
}
],
"totalNetworkFee" : "0.00001751904" ,
"totalNetworkFeeInUSD" : "0.02" ,
"totalTransactionFee" : "0" ,
"nativeBalance" : "0.073690520542044578" ,
"nativeBalanceInUSD" : "66.54" ,
"estimatedArrivalTime" : 60 ,
"errors" : []
}
}
Campos de la respuesta de comisión
Campo Descripción networkFeeComisión de gas en unidades de token nativo (retiro individual) networkFeeInUSDComisión de gas convertida a USD (retiro individual) feesArray de estimaciones individuales de comisión (retiro por lotes) totalNetworkFeeSuma de todas las comisiones de red (retiro por lotes) totalNetworkFeeInUSDComisión total de red en USD (retiro por lotes) transactionFeeComisión de transacción de la plataforma (si aplica) nativeBalanceSaldo actual del token nativo nativeBalanceInUSDSaldo del token nativo en USD estimatedArrivalTimeTiempo de confirmación esperado en segundos errorsArray de cualquier estimación fallida (retiro por lotes)
Modo Sign-Only
Firme transacciones sin transmitirlas a la blockchain. Útil para:
Firma offline : Prepare transacciones para envío posterior
Flujos multi-firma : Recolecte firmas antes del envío
Inspección de transacciones : Revise detalles de la transacción antes de transmitirla
Ejemplo de Sign-Only
curl --request POST \
--url https://api.blockradar.co/v1/wallets/{walletId}/withdraw/sign \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '{
"assetId": "asset-uuid-here",
"address": "0xRecipientAddress...",
"amount": "100"
}'
const signedTx = await fetch (
`https://api.blockradar.co/v1/wallets/ ${ walletId } /withdraw/sign` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assetId: 'asset-uuid-here' ,
address: '0xRecipientAddress...' ,
amount: '100'
})
}
). then ( r => r . json ());
console . log ( 'Signed transaction:' , signedTx . data . signedTransaction );
Respuesta de Sign-Only
{
"message" : "Transaction signed successfully" ,
"statusCode" : 200 ,
"data" : {
"id" : "tx-uuid-123" ,
"signedTransaction" : "0xf86c..." ,
"status" : "SIGNED" ,
"amount" : "100" ,
"recipientAddress" : "0xRecipientAddress..." ,
"createdAt" : "2024-01-15T10:30:00Z"
}
}
Retiros desde Child Address
Retire desde child addresses individuales en lugar de la master wallet:
curl --request POST \
--url https://api.blockradar.co/v1/wallets/{walletId}/addresses/{addressId}/withdraw \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '{
"assetId": "asset-uuid-here",
"address": "0xRecipientAddress...",
"amount": "50",
"reference": "user-withdrawal-123"
}'
const childWithdrawal = await fetch (
`https://api.blockradar.co/v1/wallets/ ${ walletId } /addresses/ ${ addressId } /withdraw` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assetId: 'asset-uuid-here' ,
address: '0xRecipientAddress...' ,
amount: '50' ,
reference: 'user-withdrawal-123'
})
}
). then ( r => r . json ());
console . log ( 'Child address withdrawal:' , childWithdrawal . data );
Los retiros desde child address también admiten operaciones por lotes utilizando el array assets, siguiendo el mismo formato que los retiros por lotes desde master wallet.
Eventos de Webhook
Monitoree la finalización de los retiros mediante webhooks:
Evento Descripción withdraw.successRetiro completado y confirmado en la blockchain withdraw.failedEl retiro no pudo ejecutarse withdraw.cancelledEl retiro fue cancelado antes de completarse
Payload del Webhook
{
"event" : "withdraw.success" ,
"data" : {
"id" : "081d6315-159f-4c38-b02a-c4708836c5bd" ,
"reference" : "payout-12345" ,
"senderAddress" : "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a" ,
"recipientAddress" : "0x2455eC6700092991Ce0782365A89d5Cd89c8Fa22" ,
"amount" : "100" ,
"amountPaid" : "100" ,
"fee" : null ,
"currency" : "USD" ,
"blockNumber" : 6928833 ,
"hash" : "0x5fcb7dd11cbb5a6d64da08cf7e0d63c1a1e7b9d1b89e3e8d1c6a5f4b3a2c1d0e" ,
"status" : "SUCCESS" ,
"type" : "WITHDRAW" ,
"note" : "Monthly payout" ,
"asset" : {
"id" : "asset-uuid" ,
"name" : "USD Coin" ,
"symbol" : "USDC" ,
"decimals" : 6
},
"wallet" : {
"id" : "wallet-uuid" ,
"name" : "Main Treasury"
},
"blockchain" : {
"id" : "blockchain-uuid" ,
"name" : "ethereum" ,
"network" : "mainnet"
},
"metadata" : {
"userId" : "user_abc123" ,
"payoutType" : "salary"
},
"createdAt" : "2024-01-15T10:30:00Z" ,
"updatedAt" : "2024-01-15T10:31:00Z"
}
}
Ejemplo de flujo completo
A continuación se muestra una implementación completa del flujo: estimación de comisión → confirmación del usuario → retiro:
async function processWithdrawal ( walletId , assetId , recipientAddress , amount ) {
const apiKey = process . env . BLOCKRADAR_API_KEY ;
const baseUrl = 'https://api.blockradar.co/v1' ;
// Step 1: Estimate network fee
const feeResponse = await fetch (
` ${ baseUrl } /wallets/ ${ walletId } /withdraw/network-fee` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assetId ,
address: recipientAddress ,
amount
})
}
). then ( r => r . json ());
// Step 2: Check if we have enough native balance for gas
const fee = feeResponse . data ;
if ( parseFloat ( fee . nativeBalance ) < parseFloat ( fee . networkFee )) {
throw new Error ( `Insufficient gas: need ${ fee . networkFee } , have ${ fee . nativeBalance } ` );
}
// Step 3: Display fee to user (in your UI)
console . log ( `Network fee: ${ fee . networkFee } (≈$ ${ fee . networkFeeInUSD } )` );
console . log ( `Estimated time: ${ fee . estimatedArrivalTime } s` );
// Step 4: Execute withdrawal (after user confirmation)
const withdrawal = await fetch (
` ${ baseUrl } /wallets/ ${ walletId } /withdraw` ,
{
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'x-api-key' : apiKey
},
body: JSON . stringify ({
assetId ,
address: recipientAddress ,
amount ,
reference: `withdraw- ${ Date . now () } `
})
}
). then ( r => r . json ());
console . log ( 'Withdrawal initiated:' , withdrawal . data . id );
console . log ( 'Transaction hash:' , withdrawal . data . hash );
// Step 5: Listen for webhook to confirm completion
return withdrawal . data ;
}
// Usage
processWithdrawal (
'wallet-uuid' ,
'asset-uuid-usdc' ,
'0xRecipientAddress...' ,
'100'
);
Respuestas de error
{
"message" : "Insufficient balance for withdrawal" ,
"statusCode" : 400 ,
"error" : "INSUFFICIENT_BALANCE" ,
"data" : {
"required" : "100" ,
"available" : "50.25" ,
"asset" : "USDC"
}
}
{
"message" : "Insufficient native token balance for gas" ,
"statusCode" : 400 ,
"error" : "INSUFFICIENT_GAS" ,
"data" : {
"required" : "0.005" ,
"available" : "0.001" ,
"token" : "ETH"
}
}
{
"message" : "Invalid recipient address" ,
"statusCode" : 400 ,
"error" : "INVALID_ADDRESS" ,
"data" : {
"address" : "invalid_address_here"
}
}
{
"message" : "Asset not found" ,
"statusCode" : 404 ,
"error" : "ASSET_NOT_FOUND" ,
"data" : {
"assetId" : "invalid-asset-uuid"
}
}
{
"message" : "Amount must be greater than 0" ,
"statusCode" : 400 ,
"error" : "INVALID_AMOUNT" ,
"data" : {
"amount" : "0"
}
}
{
"message" : "Batch size exceeds maximum limit" ,
"statusCode" : 400 ,
"error" : "BATCH_SIZE_EXCEEDED" ,
"data" : {
"maximum" : 20 ,
"provided" : 25
}
}
Mejores prácticas
Seguridad
Valide direcciones : Verifique siempre las direcciones de los destinatarios antes de iniciar retiros
Use referencias : Rastree los retiros con IDs de referencia únicos para conciliación
Implemente webhooks : Escuche los eventos withdraw.success y withdraw.failed para confirmar el estado
Verifique AML : Blockradar detecta automáticamente las direcciones; revise cualquier transacción marcada
Gestión de comisiones
Estime antes de la ejecución : Llame siempre al endpoint network-fee antes de los retiros
Monitoree el saldo nativo : Asegure suficiente ETH/BNB/MATIC para las comisiones de gas
Use lotes para mayor eficiencia : Agrupe múltiples retiros para reducir las llamadas API y la sobrecarga operativa
Manejo de errores
Maneje fallos parciales : En retiros por lotes, revise tanto los arrays success como errors
Implemente reintentos : Use backoff exponencial para fallos transitorios
Registre todas las transacciones : Almacene IDs y hashes de transacciones para depuración y conciliación
Rendimiento
Use tamaños de lote adecuados : Lotes más grandes reducen las llamadas API pero aumentan el tiempo de cada solicitud
Almacene los IDs de activos en caché : Guarde los IDs de activos localmente para evitar consultas repetidas
Implemente limitación de tasa : Respete los límites de tasa de la API para evitar throttling
Referencia API
Endpoints de Master Wallet
Endpoint Descripción Withdraw Ejecutar retiro individual o por lotes Network Fee Estimar comisiones de retiro Sign-Only Firmar sin transmitir
Endpoints de Child Address
Endpoint Descripción Withdraw Ejecutar retiro individual o por lotes Network Fee Estimar comisiones de retiro Sign-Only Firmar sin transmitir
Soporte
La API de Withdraw proporciona una interfaz flexible para enviar activos stablecoin a direcciones externas. Comience con retiros individuales y estimación de comisiones, e incorpore operaciones por lotes para pagos masivos a medida que sus necesidades crezcan.