Saltar al contenido principal

Retiros

Cobrar por API y tener que entrar al panel para llevarte el dinero al banco era la mitad del trabajo. Esto cierra el círculo.


La regla que gobierna todo​

La API no puede inventarse un destino. Sólo envía a cuentas que ya están dadas de alta en tu panel, verificadas por nosotros y registradas con el proveedor.

No es una limitación provisional. Un retiro es la única llamada de la API que no se deshace: el dinero sale y no vuelve. Con destinos abiertos, un fallo de tu integración —o una credencial robada— manda tu saldo a cualquier parte. Con destinos cerrados, lo peor que puede pasar es que acabe en una cuenta que ya habías aprobado.

Para ti tiene una consecuencia buena: el cuerpo de un retiro no lleva ninguna CLABE. No puedes equivocarte al teclearla porque no la tecleas.

:::warning El alcance no viene marcado withdrawals:write es el único alcance que el panel no marca por defecto al emitir una credencial. Hay que marcarlo a mano, y conviene que la credencial que lo lleve no haga nada más. :::


1 · Mira a dónde puedes enviar​

curl https://api.binkio.com/v1/payout_destinations \
-H "Authorization: Bearer bk_live_sec_…"
{
"object": "list",
"data": [
{
"object": "payout_destination",
"id": "d41f8a2c-9b73-4e15-a6c8-3f0e7b2d1a94",
"rail": "spei",
"alias": "Cuenta principal",
"beneficiary_name": "Tienda Ejemplo SA de CV",
"bank_name": "BBVA México",
"last_four": "3456",
"currency": "MXN",
"usable": true,
"created_at": "2026-07-02T09:14:03.000Z"
}
],
"has_more": false,
"next_cursor": null
}

Mira usable antes de ordenar nada. Una cuenta recién dada de alta está esperando al proveedor: ordenar contra ella falla más adelante, con el saldo ya apartado.

Del número de cuenta se publican sólo los últimos cuatro dígitos. Sirven para reconocerla en una pantalla; para ordenar el retiro se usa el id.


2 · Ordena el retiro​

curl -X POST https://api.binkio.com/v1/withdrawals \
-H "Authorization: Bearer bk_live_sec_…" \
-H "Idempotency-Key: liquidacion-2026-W36" \
-H "Content-Type: application/json" \
-d '{
"destination_id": "d41f8a2c-9b73-4e15-a6c8-3f0e7b2d1a94",
"amount": "5000.00",
"concept": "Liquidacion semana 36"
}'

Tres campos. El riel —SPEI o transferencia internacional— lo decide el destino, no tú.

:::danger La clave de idempotencia importa más aquí que en ningún otro sitio Esta llamada no se deshace. Usa un identificador tuyo y estable —el número de la orden de pago, el del lote—, nunca un aleatorio. Un aleatorio convierte cada reintento en un retiro nuevo, y aquí eso significa mandar el dinero dos veces. :::

Quién paga la comisión​

fee_modePides 1 000LlegaSale de tu saldo
net_out (por defecto)1 0001 000 − comisión1 000
gross_up1 0001 000 exactos1 000 + comisión

Para pagarle a un proveedor casi siempre quieres gross_up: la factura es de 1 000 y tiene que recibir 1 000.


3 · Sigue el desenlace​

La respuesta llega en processing. Eso no es un fallo: el dinero está en camino. Un SPEI tarda minutos; una transferencia internacional, días.

curl https://api.binkio.com/v1/withdrawals/9f3b1c7e-… \
-H "Authorization: Bearer bk_live_sec_…"
EstadoQué significa
processingAceptado y en camino
completedEl dinero llegó al destino
failedNo salió. El saldo volvió a tu cuenta
cancelledCancelado antes de salir

Lo normal es no sondear: suscríbete a withdrawal.completed y withdrawal.failed. → Webhooks

Para conciliar​

  • amount es lo que salió de tu saldo. Es la cifra que cuadra tu libro.
  • net_amount es lo que recibió el destino. La diferencia es la comisión.
  • receipt_url trae el CEP, el comprobante oficial de Banxico, en cuanto el proveedor lo publica. Es lo que vale como prueba ante quien cobró — guárdalo.

Errores​

CódigoHTTPQué hacer
payout_destination_not_found404Ese destino no es tuyo. Sácalo de la lista
payout_destination_not_usable409Todavía sin verificar. Mira usable
payout_destination_rail_unsupported409Riel no cubierto por la API
wallet_insufficient_balance409No alcanza para el importe más la comisión
below_minimum400El importe no llega al mínimo del riel
invalid_request400Supera un límite tuyo, o el riel lo rechaza. El message es lo único que lo distingue

:::note Una aspereza que preferimos contarte Los rechazos por límite (por operación, diario, mensual) todavía no traen un code propio: llegan como invalid_request con el motivo en el message. Es del riel de retiros, no del contrato, y está en la lista para arreglarse. Mientras tanto, no ramifiques sobre el texto — trátalos como «no se pudo, mira el mensaje». :::


Retiros en cadena​

Enviar a una dirección de blockchain también está en la API, pero es otra llamada y otro alcance:

curl -X POST https://api.binkio.com/v1/withdrawals/crypto \
-H "Authorization: Bearer bk_live_sec_…" \
-H "Idempotency-Key: envio-2026-W37-3" \
-H "Content-Type: application/json" \
-d '{
"asset": "USDC",
"amount": "500.00",
"address": "0x9c8b7e1d3a5f6c2b0a9d8e7f6a5b4c3d2e1f0a9b",
"network": "ETHEREUM"
}'

:::danger Esto no se deshace, y no hay a quién reclamar El destino va en el cuerpo y no se valida contra ninguna lista: no hay direcciones dadas de alta que comprobar. Una dirección equivocada, o la red equivocada, pierde el dinero para siempre — no lo recupera soporte, ni el proveedor, ni nosotros.

Valida la dirección en tu lado antes de llamar, y no la construyas concatenando cadenas. :::

Por qué lleva alcance propio​

withdrawals:crypto está separado de withdrawals:write a propósito. Si el destino no se puede acotar, se acota la credencial: una clave que paga proveedores por transferencia no puede además mandar cripto a cualquier parte. Quien necesite las dos cosas marca las dos casillas, a sabiendas.

network es obligatorio y no tiene valor por defecto​

El mismo activo vive en varias redes y la dirección no dice en cuál. Deducirlo por ti sería acertar casi siempre y perder el dinero el resto de las veces.

Sácalo de GET /v1/deposit_instructions o de tu propia configuración — la API lo publica y lo acepta en la misma forma, en mayúsculas.

La Regla de Viaje​

A partir de cierto importe hace falta beneficiary (FATF R.16):

"beneficiary": {
"first_name": "Ana", "last_name": "Ruiz", "country": "MX",
"vasp_name": "Binance", "vasp_country": "MT"
}

vasp_name y vasp_country sólo si el destino es otra plataforma; se omiten para una cartera propia. Mándalos antes: por encima del umbral el proveedor rechaza el envío, y para entonces tu saldo ya está apartado.


Lo que se sigue haciendo desde el panel​

Dar de alta un destino bancario. Es la restricción del principio, y es deliberada: es lo que hace que un fallo de tu integración no pueda mandar el saldo a una cuenta que nadie aprobó.