Saltar al contenido principal

Errores

Todos los errores tienen la misma forma:

{
"error": {
"type": "invalid_request",
"code": "insufficient_balance",
"message": "No hay saldo suficiente para esta operación.",
"param": "amount",
"request_id": "req_9f2a4c8b7e1d3a5f"
}
}

Ramifica sobre code. Es parte del contrato y no cambia. El message está escrito para que una persona lo entienda y puede cambiar de redacción sin aviso: comparar cadenas de texto es construir una integración que se rompe cuando alguien mejora un mensaje.

type agrupa por familia (invalid_request, authentication_error, permission_error, not_found, conflict, rate_limit_error, api_error) y sirve para el caso que no reconoces: te dice si tiene sentido reintentar.

:::note Un identificador mal escrito responde como uno que no existe GET /v1/withdrawals/no-es-un-uuid devuelve el mismo 404 withdrawal_not_found que un identificador con la forma correcta que no está en tu cuenta. No es un descuido: distinguirlos convertiría el endpoint en un oráculo de identificadores válidos, y probando se podría averiguar qué operaciones existen en la plataforma.

Consecuencia práctica: un 404 no te dice si te equivocaste al escribir o si el recurso no es tuyo. Revisa el identificador antes de suponer que se borró. :::


La regla de oro del reintento​

Código HTTP¿Reintentar?
400, 403, 404, 422No. Reintentar da lo mismo. Arregla la petición
401No, salvo que acabes de rotar la credencial
409Sí, pero espera: hay otra petición igual en curso
429Sí, después de los segundos que diga Retry-After
5xxSí, con espera creciente y la misma Idempotency-Key

:::danger Nunca reintentes un 5xx sin la misma clave de idempotencia Un 500 no significa que no se ejecutó: puede haber fallado al responderte, después de crear el cobro. Reintentar sin la clave crea un segundo cobro. Con ella, te devolvemos el primero. :::


Autenticación y permisos​

CódigoHTTPQué pasóQué hacer
invalid_api_key401Falta la cabecera, está mal formada, la credencial no existe, fue revocada, caducó, o la llamada viene de una IP no permitidaComprueba Authorization: Bearer bk_…. Si acabas de rotar, despliega el secreto nuevo
insufficient_scope403La credencial es válida pero no tiene el alcance que ese endpoint exigeEl mensaje nombra el alcance que falta. Emite una credencial con él
forbidden403La cuenta no puede hacer esa operaciónGenérico. Si la verificación está pendiente el código es más específico — ver Antes de poder cobrar

:::note Por qué el 401 es siempre el mismo Da igual si la credencial no existe, si fue revocada o si tu IP no está permitida: la respuesta es idéntica. Distinguirlos le confirmaría a quien prueba credenciales al azar cuáles existen. :::


Idempotencia​

CódigoHTTPQué pasóQué hacer
idempotency_key_required400Falta Idempotency-Key en una petición que crea o modificaAñádela. Es obligatoria, no opcional
idempotency_request_in_progress409Otra petición con esa misma clave se está ejecutando ahoraEspera y reintenta. No cambies la clave
idempotency_key_reused422Esa clave ya se usó con un cuerpo distintoUsa una clave nueva. Reutilizarla con otro contenido sería reemplazar en silencio
idempotency_unavailable503No pudimos garantizar la idempotenciaReintenta con la misma clave

Una clave vive 24 horas. Después se trata como nueva.


Límites​

CódigoHTTPQué hacer
rate_limit_exceeded429Espera lo que diga RateLimit-Reset

Las respuestas correctas traen RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset. Míralas antes de llegar al tope: es lo que te permite autorregularte en vez de descubrirlo a golpes.


Antes de poder cobrar​

Estos llegan con 403 y son los primeros que ve una integración nueva: la cuenta existe y la credencial es válida, pero todavía no puede mover dinero. No se arreglan desde la API — se resuelven en el panel del comercio.

CódigoQué pasóQué hacer
kyb_not_startedLa empresa no ha empezado la verificaciónEntrar al panel y completarla
kyb_incompleteEstá a mediasEl panel dice qué paso falta
kyb_pending_reviewCompleta, esperando nuestra revisiónEsperar. No hay nada más que hacer
kyc_not_startedLa persona titular no ha empezado la suyaPanel
kyc_incompleteLa de la persona titular está a mediasPanel
email_not_verifiedCorreo de la cuenta sin verificarPanel
phone_not_verifiedTeléfono de la cuenta sin verificarPanel
account_suspendedCuenta suspendidaEscríbenos
account_blockedCuenta bloqueadaEscríbenos
user_not_foundLa cuenta dueña de la credencial ya no existeEmitir una credencial nueva

:::tip Distínguelos de insufficient_scope Los dos son 403 y significan cosas opuestas. insufficient_scope es tuyo: emitiste la credencial sin ese alcance y lo arreglas en un minuto. Éstos son de la cuenta: ningún alcance los levanta. :::


Enlaces de pago​

CódigoHTTPQué pasóQué hacer
payment_link_not_found404No existe ese código en tu cuentaMismo error si no existe que si es de otra cuenta
payment_link_not_cancellable409Ya está pagado, cancelado o caducadoSólo un enlace active se puede cancelar
payment_link_not_deletable409Todavía puede cobrar (active) o ya cobró (paid)Cancélalo antes de borrarlo; uno pagado no se borra
invalid_request400El cuerpo no pasa validaciónEl param dice qué campo
payment_method_unavailable400Pediste un método en accepted_methods y no se pudo dejar listo en ese momento. No se creó el enlaceReintenta (suele bastar), o créalo sin ese método. Ver Si pides métodos concretos

Errores frecuentes al crear un enlace, y su causa real:

  • amount mandado como número → cadena decimal, siempre. Un float de JSON ya perdió precisión antes de llegarnos.
  • Un accepted_methods mal escrito → devuelve 400, no se ignora. Un método ignorado en silencio crea un enlace con métodos distintos de los que pediste, y eso se descubre cobrando.
  • Ningún método viable para ese importe → los mínimos y máximos dependen de la ruta. → Pagos cruzados

Checkout​

CódigoHTTPQué pasó
checkout_not_found404El código no existe. Puede estar incompleto o mal copiado

QR de mostrador​

Los códigos son específicos a propósito: en una caja hay que saber por qué no se pudo cobrar sin llamar a nadie.

CódigoHTTPQué pasóQué hacer
qr_not_found404La cuenta todavía no tiene QRSe crea desde el panel
qr_paused409El QR está pausadoPOST /v1/qr/resume
qr_revoked409El QR fue revocadoHay que crear otro desde el panel
qr_amount_not_positive400El importe es cero o negativoRevisa lo que teclea la caja
qr_amount_above_max_per_charge409Supera max_amount_per_chargeSube el tope o parte el cobro
qr_daily_limit_reached409Se agotó max_amount_per_dayCompara con amount_paid_today
qr_too_many_pending_charges409Demasiados cargos sin pagar acumuladosDeja que caduquen o cancélalos
qr_charge_unavailable409No se pudo generar el cargo por otro motivoReintenta; si persiste, escríbenos

qr_daily_limit_reached y qr_amount_above_max_per_charge son tus propios topes, no nuestros. Los pusiste tú con PATCH /v1/qr y los puedes cambiar cuando quieras. → Cobro con QR


Webhooks​

CódigoHTTPQué pasó
webhook_url_invalid_url400La URL no se puede interpretar
webhook_url_not_https400La URL no es https
webhook_url_embedded_credentials400La URL lleva usuario y contraseña dentro
webhook_url_private_host400El nombre resuelve a una dirección de red interna
webhook_url_dns_failure400El nombre no resuelve
webhook_endpoint_not_found404No existe ese destino en tu cuenta
webhook_endpoints_limit_reached400Ya tienes 10, que es el tope por cuenta
webhook_events_unknown400Algún evento no está en el catálogo

Los tres primeros son la defensa contra que un destino apunte a una red privada: la URL la eliges tú y nuestro servidor es quien la llama. → Webhooks


Mover dinero: retiros y conversiones​

Hasta hace poco todo rechazo de estas dos familias llegaba como invalid_request y el motivo vivía sólo en el message. Ya no: cada uno trae su código, y son pocos a propósito — están agrupados por lo que tienes que hacer al recibirlos, que es para lo que sirve un código. El detalle concreto (qué mínimo, en qué activo, cuánto llevas gastado) sigue en el message.

CódigoHTTPQué pasóQué hacer
amount_below_minimum400El importe no llega al mínimo del riel o de la rutaSúbelo. El message dice cuál es y en qué activo
amount_above_maximum400Pasa del máximo por operaciónPártelo en varias
invalid_amount400No tiene forma de importe (cero, negativo, texto)Manda una cadena decimal
amount_too_low400Tan pequeño que la comisión se lo come entero: no te quedaría nadaEl message dice a partir de cuánto sí
insufficient_balance400No hay saldo disponibleEs distinto de un límite: aquí el dinero no está
daily_limit_exceeded400Se agotó tu cupo diarioMañana vuelve a haber. No reintentes hoy
monthly_limit_exceeded400Se agotó tu cupo mensualEscríbenos si necesitas más

Sólo en retiros​

CódigoHTTPQué pasóQué hacer
payout_destination_not_found404Ese destination_id no está en tu cuentaVuelve a listar GET /v1/payout_destinations
destination_not_authorized400El destino existe pero no está verificado, o le falta el registro con el proveedorVuelve a darlo de alta
network_unavailable400Esa red no está disponible ahora para ese activoEl message enumera las que sí
invalid_address400La dirección no tiene la forma de esa redSólo se comprueba la forma: que sea la correcta es cosa tuya
travel_rule_data_required400El importe supera el umbral de la Regla de Viaje (FATF R.16)Manda beneficiary y repite
provider_rejected400Lo rechazó el proveedor del riel, no nosotrosEl message es suyo y puede cambiar sin aviso: ramifica por este código
not_allowed_in_state400La operación no cabe en el estado actual (cancelar uno que ya salió)Consulta el retiro para ver dónde está

Sólo en conversiones​

CódigoHTTPQué pasóQué hacer
same_asset400from_asset y to_asset son el mismo—
pair_not_supported400Ese par no se convierte, ni con otro importeNo todos los activos tienen ruta entre sí
quote_required400Falta quote_idUna conversión no se ejecuta sin una cotización aceptada
quote_expired400La cotización caducó o ya no estáPide otra. Viven poco a propósito: el precio se mueve
quote_mismatch400No es tuya, o el par y el importe no son los cotizadosEs lo que impide convertir algo distinto de lo que aceptaste
slippage_exceeded400La tasa empeoró más de lo que permite max_slippage_bpsNo se convirtió nada. Vuelve a cotizar

:::tip Ramifica por code, nunca por message Es la razón de que estos códigos existan. El message de provider_rejected lo redacta el proveedor y ni siquiera lo controlamos nosotros. :::


Registro y consultas​

CódigoHTTPQué pasó
invalid_cursor400El cursor no es uno nuestro. Usa el next_cursor tal cual
transaction_not_found404No hay ese movimiento en tu cuenta
request_log_not_found404No hay esa llamada registrada

Cuando nada de esto explica lo que ves​

CódigoHTTPQué hacer
internal_error500Reintenta con la misma Idempotency-Key. Si persiste, escríbenos

Guarda siempre el request_id. Va en toda respuesta —correcta o no— y en la cabecera X-Request-Id. Es lo primero que te vamos a pedir, y con él localizamos la llamada exacta en segundos.

Antes de abrir un ticket, mira tu propio registro:

curl "https://api.binkio.com/v1/request_logs?limit=25" \
-H "Authorization: Bearer bk_live_sec_…"

Si tu llamada no aparece ahí, no nos llegó — y el problema está entre tu servidor y nosotros, no en la API. Eso descarta la mitad de los casos sin esperar respuesta de nadie.