Saltar al contenido principal
En resumen
La API de Retiros de Blockradar te permite enviar stablecoins desde tus billeteras a direcciones blockchain externas. Soporta retiros individuales, retiros por lotes a múltiples destinatarios y proporciona estimación de comisiones antes de la ejecución.
Interfaz de Retiros de Blockradar

Requisitos Previos

Antes de usar la API de Retiros, asegúrate de tener:
1

Clave API

Obtén tu clave API desde el Panel de Blockradar. Navega a Configuración → Claves API para generar una.
2

Billetera Creada

Crea una billetera a través de la API Crear Billetera o el panel. Necesitarás el walletId para las operaciones de retiro.
3

ID del Activo

Obtén el assetId del token que deseas retirar desde Activos en el panel o a través de la API Obtener Activos.
4

Saldo Suficiente

Asegúrate de que tu billetera tenga suficiente saldo del activo para retirar, además de moneda nativa (ETH, BNB, MATIC, etc.) para cubrir las comisiones de red.

Cómo Funciona

La API de Retiros envía stablecoins desde tu billetera Blockradar a cualquier dirección blockchain externa:

Retiro Individual

Envía activos a una dirección de destinatario con una sola llamada API.

Retiro por Lotes

Envía activos a múltiples destinatarios en una sola llamada API, reduciendo la sobrecarga y simplificando los pagos masivos.

Estimación de Comisiones

Calcula las comisiones de red antes de la ejecución para garantizar saldo suficiente y mostrar costos a los usuarios.

Modo Solo Firma

Firma transacciones sin transmitirlas para casos de uso avanzados como firma offline o envío personalizado.

Billetera Principal vs Dirección Hija

La API de Retiros está disponible en dos niveles:

Billetera Principal

Retira directamente desde tu billetera principal. Ideal para operaciones de tesorería y gestión centralizada de fondos.

Dirección Hija

Retira desde direcciones hijas individuales. Perfecto para operaciones específicas de usuarios y gestión segregada de fondos.

Endpoints

OperaciónBilletera PrincipalDirección Hija
RetirarPOST /v1/wallets/{walletId}/withdrawPOST /v1/wallets/{walletId}/addresses/{addressId}/withdraw
Comisión de RedPOST /v1/wallets/{walletId}/withdraw/network-feePOST /v1/wallets/{walletId}/addresses/{addressId}/withdraw/network-fee
Solo FirmaPOST /v1/wallets/{walletId}/withdraw/signPOST /v1/wallets/{walletId}/addresses/{addressId}/withdraw/sign

Retiro Individual

Envía activos a una única dirección de destinatario.

Parámetros de la Solicitud

ParámetroTipoRequeridoDescripción
assetIdstringSí*El UUID del activo a retirar. Requerido si no se proporciona el array assets.
addressstringSí*La dirección de la billetera de destino. Requerido si no se proporciona el array assets.
amountstringSí*El monto del retiro. Debe ser mayor que 0. Requerido si no se proporciona el array assets.
referencestringNoTu ID de seguimiento interno para el retiro.
notestringNoUn mensaje corto o nota interna. No visible en la blockchain.
metadataobjectNoPares 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ás usando 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-aqui",
    "address": "0xDireccionDestinatario...",
    "amount": "100",
    "reference": "pago-12345",
    "note": "Pago mensual",
    "metadata": {
      "userId": "user_abc123",
      "payoutType": "salario"
    }
  }'

Respuesta de Retiro Individual

{
  "message": "Retiro iniciado exitosamente",
  "statusCode": 200,
  "data": {
    "id": "tx-uuid-123",
    "hash": "0xabc123...",
    "status": "PENDING",
    "amount": "100",
    "recipientAddress": "0xDireccionDestinatario...",
    "reference": "pago-12345",
    "note": "Pago mensual",
    "metadata": {
      "userId": "user_abc123",
      "payoutType": "salario"
    },
    "createdAt": "2024-01-15T10:30:00Z"
  }
}

Retiros por Lotes

Envía 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 separada.

Cuándo Usar Retiros por Lotes

  • Pagos masivos: Paga a múltiples empleados, proveedores o socios a la vez
  • Distribuciones: Envía activos a múltiples direcciones
  • Transferencias multi-destinatario: Envía diferentes montos a diferentes direcciones
  • Eficiencia operacional: Reduce las llamadas API y simplifica la lógica de pagos

Parámetros de Solicitud por Lotes

Para retiros por lotes, usa el array assets en lugar de parámetros individuales:
ParámetroTipoRequeridoDescripción
assetsarrayArray de objetos de retiro (máximo 20 por lote)
Cada elemento en el array assets:
CampoTipoRequeridoDescripción
idstringEl UUID del activo a retirar
addressstringLa dirección de la billetera de destino
amountstringEl monto del retiro. Debe ser mayor que 0.
referencestringNoNota de referencia opcional para este retiro
notestringNoUn mensaje corto o nota interna. No visible en la blockchain.
metadataobjectNoPares 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": "0xDestinatario1...",
        "amount": "100",
        "reference": "pago-001",
        "note": "Salario enero"
      },
      {
        "id": "asset-uuid-usdc",
        "address": "0xDestinatario2...",
        "amount": "150",
        "reference": "pago-002",
        "note": "Salario enero"
      },
      {
        "id": "asset-uuid-usdt",
        "address": "0xDestinatario3...",
        "amount": "200",
        "reference": "pago-003",
        "note": "Pago proveedor"
      }
    ]
  }'

Respuesta de Retiro por Lotes

{
  "message": "Retiro por lotes iniciado exitosamente",
  "statusCode": 200,
  "data": {
    "success": [
      {
        "index": 0,
        "id": "tx-uuid-1",
        "hash": "0xabc...",
        "status": "PENDING",
        "amount": "100",
        "recipientAddress": "0xDestinatario1...",
        "reference": "pago-001"
      },
      {
        "index": 1,
        "id": "tx-uuid-2",
        "hash": "0xdef...",
        "status": "PENDING",
        "amount": "150",
        "recipientAddress": "0xDestinatario2...",
        "reference": "pago-002"
      },
      {
        "index": 2,
        "id": "tx-uuid-3",
        "hash": "0xghi...",
        "status": "PENDING",
        "amount": "200",
        "recipientAddress": "0xDestinatario3...",
        "reference": "pago-003"
      }
    ],
    "errors": []
  }
}

Manejo de Fallos Parciales

Los retiros por lotes soportan éxito parcial. Si algunos retiros fallan, otros aún se ejecutarán:
const result = await batchWithdrawal.json();

// Procesar retiros exitosos
result.data.success.forEach(tx => {
  console.log(`✓ ${tx.reference}: ${tx.hash}`);
});

// Manejar retiros fallidos
result.data.errors.forEach(error => {
  console.error(`✗ Índice ${error.index}: ${error.error}`);
  // Lógica de reintento o reporte de errores aquí
});

Reglas de Retiro por Lotes

ReglaValor
Tamaño máximo del lote20 retiros por solicitud
Tamaño mínimo del lote1 retiro
Orden de ejecuciónSecuencial
Manejo de erroresÉxito parcial (los fallos no detienen retiros posteriores)

Estimación de Comisiones de Red

Siempre estima las comisiones antes de ejecutar retiros para asegurar suficiente saldo de 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-aqui",
    "address": "0xDireccionDestinatario...",
    "amount": "100"
  }'

Respuesta de Comisión Individual

{
  "message": "Comisión de red obtenida exitosamente",
  "statusCode": 200,
  "data": {
    "networkFee": "0.00001247904",
    "networkFeeInUSD": "0.01",
    "transactionFee": "0",
    "nativeBalance": "0.5",
    "nativeBalanceInUSD": "450.00",
    "estimatedArrivalTime": 30
  }
}

Estimación de Comisión por Lotes

Estima las 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": "0xDestinatario1...",
        "amount": "100"
      },
      {
        "id": "asset-uuid-2",
        "address": "0xDestinatario2...",
        "amount": "50"
      }
    ]
  }'

Respuesta de Comisión por Lotes

{
  "message": "Comisión de red obtenida exitosamente",
  "statusCode": 200,
  "data": {
    "fees": [
      {
        "index": 0,
        "assetId": "asset-uuid-1",
        "address": "0xDestinatario1...",
        "amount": "100",
        "networkFee": "0.00001247904",
        "transactionFee": "0",
        "estimatedArrivalTime": 30
      },
      {
        "index": 1,
        "assetId": "asset-uuid-2",
        "address": "0xDestinatario2...",
        "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 Respuesta de Comisión

CampoDescripción
networkFeeComisión de gas en unidades de token nativo (retiro individual)
networkFeeInUSDComisión de gas convertida a USD (retiro individual)
feesArray de estimaciones de comisión individuales (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 de token nativo
nativeBalanceInUSDSaldo de token nativo en USD
estimatedArrivalTimeTiempo esperado de confirmación en segundos
errorsArray de estimaciones fallidas (retiro por lotes)

Modo Solo Firma

Firma transacciones sin transmitirlas a la blockchain. Útil para:
  • Firma offline: Prepara transacciones para envío posterior
  • Flujos multi-firma: Recopila firmas antes del envío
  • Inspección de transacciones: Revisa los detalles de la transacción antes de transmitir

Ejemplo de Solo Firma

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-aqui",
    "address": "0xDireccionDestinatario...",
    "amount": "100"
  }'

Respuesta de Solo Firma

{
  "message": "Transacción firmada exitosamente",
  "statusCode": 200,
  "data": {
    "id": "tx-uuid-123",
    "signedTransaction": "0xf86c...",
    "status": "SIGNED",
    "amount": "100",
    "recipientAddress": "0xDireccionDestinatario...",
    "createdAt": "2024-01-15T10:30:00Z"
  }
}

Retiros desde Dirección Hija

Retira desde direcciones hijas individuales en lugar de la billetera principal:
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-aqui",
    "address": "0xDireccionDestinatario...",
    "amount": "50",
    "reference": "retiro-usuario-123"
  }'
Los retiros desde dirección hija también soportan operaciones por lotes usando el array assets, siguiendo el mismo formato que los retiros por lotes de la billetera principal.

Eventos de Webhook

Monitorea la finalización de retiros a través de webhooks:
EventoDescripción
withdraw.successRetiro completado y confirmado en la blockchain
withdraw.failedEl retiro falló al ejecutarse
withdraw.cancelledEl retiro fue cancelado antes de completarse

Payload del Webhook

{
  "event": "withdraw.success",
  "data": {
    "id": "081d6315-159f-4c38-b02a-c4708836c5bd",
    "reference": "pago-12345",
    "senderAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
    "recipientAddress": "0x2455eC6700092991Ce0782365A89d5Cd89c8Fa22",
    "amount": "100",
    "amountPaid": "100",
    "fee": null,
    "currency": "USD",
    "blockNumber": 6928833,
    "hash": "0x5fcb7dd11cbb5a6d64da08cf7e0d63c1a1e7b9d1b89e3e8d1c6a5f4b3a2c1d0e",
    "status": "SUCCESS",
    "type": "WITHDRAW",
    "note": "Pago mensual",
    "asset": {
      "id": "asset-uuid",
      "name": "USD Coin",
      "symbol": "USDC",
      "decimals": 6
    },
    "wallet": {
      "id": "wallet-uuid",
      "name": "Tesorería Principal"
    },
    "blockchain": {
      "id": "blockchain-uuid",
      "name": "ethereum",
      "network": "mainnet"
    },
    "metadata": {
      "userId": "user_abc123",
      "payoutType": "salario"
    },
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-01-15T10:31:00Z"
  }
}

Ejemplo de Flujo Completo

Aquí hay una implementación completa que muestra el flujo de 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';

  // Paso 1: Estimar comisión de red
  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());

  // Paso 2: Verificar si tenemos suficiente saldo nativo para gas
  const fee = feeResponse.data;
  if (parseFloat(fee.nativeBalance) < parseFloat(fee.networkFee)) {
    throw new Error(`Gas insuficiente: necesario ${fee.networkFee}, disponible ${fee.nativeBalance}`);
  }

  // Paso 3: Mostrar comisión al usuario (en tu UI)
  console.log(`Comisión de red: ${fee.networkFee} (≈$${fee.networkFeeInUSD})`);
  console.log(`Tiempo estimado: ${fee.estimatedArrivalTime}s`);

  // Paso 4: Ejecutar retiro (después de confirmación del usuario)
  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: `retiro-${Date.now()}`
      })
    }
  ).then(r => r.json());

  console.log('Retiro iniciado:', withdrawal.data.id);
  console.log('Hash de transacción:', withdrawal.data.hash);

  // Paso 5: Escuchar webhook para confirmar finalización
  return withdrawal.data;
}

// Uso
processWithdrawal(
  'wallet-uuid',
  'asset-uuid-usdc',
  '0xDireccionDestinatario...',
  '100'
);

Respuestas de Error

{
  "message": "Saldo insuficiente para retiro",
  "statusCode": 400,
  "error": "INSUFFICIENT_BALANCE",
  "data": {
    "required": "100",
    "available": "50.25",
    "asset": "USDC"
  }
}
{
  "message": "Saldo insuficiente de token nativo para gas",
  "statusCode": 400,
  "error": "INSUFFICIENT_GAS",
  "data": {
    "required": "0.005",
    "available": "0.001",
    "token": "ETH"
  }
}
{
  "message": "Dirección de destinatario inválida",
  "statusCode": 400,
  "error": "INVALID_ADDRESS",
  "data": {
    "address": "direccion_invalida_aqui"
  }
}
{
  "message": "Activo no encontrado",
  "statusCode": 404,
  "error": "ASSET_NOT_FOUND",
  "data": {
    "assetId": "asset-uuid-invalido"
  }
}
{
  "message": "El monto debe ser mayor que 0",
  "statusCode": 400,
  "error": "INVALID_AMOUNT",
  "data": {
    "amount": "0"
  }
}
{
  "message": "El tamaño del lote excede el límite máximo",
  "statusCode": 400,
  "error": "BATCH_SIZE_EXCEEDED",
  "data": {
    "maximum": 20,
    "provided": 25
  }
}

Mejores Prácticas

Seguridad

  • Valida las direcciones: Siempre verifica las direcciones de destinatario antes de iniciar retiros
  • Usa referencias: Rastrea retiros con IDs de referencia únicos para reconciliación
  • Implementa webhooks: Escucha los eventos withdraw.success y withdraw.failed para confirmar el estado
  • Verifica AML: Blockradar examina automáticamente las direcciones—revisa cualquier transacción marcada

Gestión de Comisiones

  • Estima antes de ejecutar: Siempre llama al endpoint de network-fee antes de retiros
  • Monitorea el saldo nativo: Asegura suficiente ETH/BNB/MATIC para comisiones de gas
  • Usa lotes para eficiencia: Agrupa múltiples retiros para reducir llamadas API y sobrecarga operacional

Manejo de Errores

  • Maneja fallos parciales: En retiros por lotes, verifica ambos arrays success y errors
  • Implementa reintentos: Usa backoff exponencial para fallos transitorios
  • Registra todas las transacciones: Almacena IDs de transacción y hashes para depuración y reconciliación

Rendimiento

  • Usa tamaños de lote apropiados: Lotes más grandes reducen llamadas API pero aumentan el tiempo de solicitud individual
  • Cachea IDs de activos: Almacena IDs de activos localmente para evitar consultas repetidas
  • Implementa limitación de tasa: Respeta los límites de tasa de la API para evitar throttling

Referencia de API

Endpoints de Billetera Principal

EndpointDescripción
RetirarEjecutar retiro individual o por lotes
Comisión de RedEstimar comisiones de retiro
Solo FirmaFirmar sin transmitir

Endpoints de Dirección Hija

EndpointDescripción
RetirarEjecutar retiro individual o por lotes
Comisión de RedEstimar comisiones de retiro
Solo FirmaFirmar sin transmitir

Soporte

La API de Retiros proporciona una interfaz flexible para enviar stablecoins a direcciones externas. Comienza con retiros individuales y estimación de comisiones, luego incorpora operaciones por lotes para pagos masivos a medida que crezcan tus necesidades.