La documentación completa en un archivo
Copia o descarga toda la referencia en Markdown y entrégala a tu asistente de código para generar la integración de una vez.
Inicio rápido
Tres pasos hasta el primer cobro en producción. Todos los valores en centavos, fechas en ISO 8601 (UTC).
curl -X GET https://finance.zendry.co/api/public/v1/balance \ -H "Authorization: Bearer gw_sua_chave_aqui"Autenticación
Toda solicitud exige tu clave de API en el encabezado Authorization: Bearer <clave> o x-api-key: <clave> — se aceptan ambos formatos. Genera y revoca claves en Integraciones.
- Valores monetarios siempre en centavos (entero). Fechas en ISO 8601 (UTC).
- Con IPs permitidas registradas en Integraciones, las llamadas desde otras IPs reciben 403.
- La confirmación de pagos es por webhook — los GET sirven para reconsulta, no para polling agresivo.
Pix
Crear cobro Pix
Genera un cobro y devuelve el código copia-y-pega de Pix. La confirmación del pago llega por el webhook pix.received — no hagas polling.
- state: pending → paid, o expired si vence sin pago.
- external_id no deduplica: dos llamadas iguales crean dos cobros. Guarda el id devuelto.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| amount_cents | entero | Sí | Valor en centavos. De 1 a 100000000 (R$ 1 millón). |
| description | texto | No | Hasta 140 caracteres. |
| external_id | texto | No | Tu identificador. Vuelve en los webhooks. No deduplica. |
curl -X POST https://finance.zendry.co/api/public/v1/charges \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 15000, "description": "Pedido #1234", "external_id": "1234"}'{ "id": "3f1c...", "state": "pending", "amount_cents": 15000, "description": "Pedido #1234", "external_id": "1234", "pix_code": "00020126...5303986540515.00...", "created_at": "2026-01-01T12:00:00Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Consultar cobro
Devuelve el estado actual de un cobro Pix o boleto (el mismo endpoint atiende ambos — la respuesta sigue el formato del tipo de cobro).
- 404 si el id no existe o pertenece a otra cuenta.
curl -X GET https://finance.zendry.co/api/public/v1/charges/:id \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "3f1c...", "state": "paid", "amount_cents": 15000, "description": "Pedido #1234", "external_id": "1234", "pix_code": "00020126...", "created_at": "2026-01-01T12:00:00Z", "paid_at": "2026-01-01T12:04:11Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Enviar Pix (retiro)
Debita el saldo disponible y envía un Pix a la clave indicada. El valor + tarifa se reservan al instante; el resultado final llega por el webhook pix.sent.
- state: sending → completed o failed — aviso por el webhook pix.sent; en falla el valor reservado vuelve al saldo.
- 409 cuando el saldo no alcanza para valor + tarifa.
- Idempotencia: envía el header Idempotency-Key. Repetir la llamada con la MISMA clave devuelve el retiro ya creado, sin duplicar el débito.
- Sin ese header, no repitas tras un timeout antes de consultar GET /payouts/{id}: el débito puede ya estar reservado.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| amount_cents | entero | Sí | Valor en centavos. De 1 a 100000000. |
| pix_key | texto | Sí | Clave Pix del beneficiario. |
| pix_key_type | cpf | cnpj | email | phone | evp | No | Sin este campo, el tipo se infiere del formato de la clave. |
| description | texto | No | Hasta 140 caracteres. |
curl -X POST https://finance.zendry.co/api/public/v1/payouts \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 5000, "pix_key": "cliente@email.com", "pix_key_type": "email", "description": "Transferencia"}'{ "id": "9ac2...", "state": "sending", "amount_cents": 5000, "fee_cents": 149, "reserved_cents": 5149, "idempotent_id": "b7e1...", "created_at": "2026-01-01T12:00:00Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Consultar retiro
Devuelve el estado actual de un retiro por el id de la creación. Úsalo cuando falle la entrega del webhook pix.sent o para conciliar.
- 404 si el id no existe o pertenece a otra cuenta. La clave de prueba solo ve retiros de sandbox.
- failure_reason solo viene en failed, con una de cuatro frases en portugués: "Chave Pix inválida.", "Saque cancelado.", la falla simulada del sandbox, o "Não foi possível concluir a operação. Tente novamente em alguns instantes.". Es texto para mostrar, no para interpretar. end_to_end_id solo en completed.
curl -X GET https://finance.zendry.co/api/public/v1/payouts/{id} \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "9ac2...", "state": "failed", "amount_cents": 5000, "fee_cents": 149, "reserved_cents": 5149, "pix_key": "cliente@email.com", "pix_key_type": "email", "description": "Transferencia", "idempotent_id": "b7e1...", "end_to_end_id": null, "failure_reason": "Não foi possível concluir a operação. Tente novamente em alguns instantes.", "created_at": "2026-01-01T12:00:00Z", "completed_at": null, "failed_at": "2026-01-01T12:00:07Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Listar retiros
Lista los retiros de la cuenta, del más reciente al más antiguo. Filtra por estado para encontrar los que siguen en curso.
- status=sending devuelve lo que aún no tiene desenlace — es la consulta para conciliar cuando el webhook no llegó.
- 422 si el estado no es uno de los tres.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| status | sending | completed | failed | No | Sin este campo, devuelve todos. |
| limit | entero | No | De 1 a 100. Predeterminado 50. |
curl -X GET https://finance.zendry.co/api/public/v1/payouts \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "payouts": [ { "id": "9ac2...", "state": "sending", "amount_cents": 5000, "fee_cents": 149, "reserved_cents": 5149, "pix_key": "cliente@email.com", "pix_key_type": "email", "description": "Transferencia", "idempotent_id": "b7e1...", "end_to_end_id": null, "failure_reason": null, "created_at": "2026-01-01T12:00:00Z", "completed_at": null, "failed_at": null } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Boleto
Crear cobro por boleto
Emite un boleto (comprobante bancario brasileño) para el comprador indicado. La confirmación llega por el webhook boleto.paid (compensación bancaria, normalmente D+1).
- Exige tarjeta habilitada para la cuenta.
- data_limite es el último día en que el boleto sigue siendo aceptado tras el vencimiento. linha_digitavel es la línea digitable; codigo_barras el código de barras.
- pdf_url es la página del boleto, para imprimir o guardar en PDF.
- Consúltalo por el mismo GET /charges/:id.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| amount_cents | entero | Sí | Valor en centavos. |
| due_date | fecha (AAAA-MM-DD) | Sí | Vencimiento del boleto. |
| buyer | objeto | Sí | first_name, last_name, email y taxpayer_id (CPF o CNPJ). |
| buyer.address | objeto | No | line1, neighborhood, city, state, postal_code. Opcional como un todo. |
| description | texto | No | Hasta 140 caracteres. |
| external_id | texto | No | Tu identificador. |
curl -X POST https://finance.zendry.co/api/public/v1/charges/boleto \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 15000, "description": "Pedido #1234", "external_id": "1234", "due_date": "2026-01-15", "buyer": { "first_name": "Maria", "last_name": "Souza", "email": "maria@email.com", "taxpayer_id": "12345678900", "address": { "line1": "Av. Paulista, 1000", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP", "postal_code": "01310100" } }}'{ "id": "3f1c...", "state": "pending", "amount_cents": 15000, "description": "Pedido #1234", "external_id": "1234", "due_date": "2026-01-15", "deadline_date": "2026-01-17", "typeable_line": "23791.23456 78900.123456 ...", "barcode": "23797890000015000123456...", "pdf_url": "https://finance.zendry.co/boleto/8f1c.../pdf", "created_at": "2026-01-01T12:00:00Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Tarjeta
Checkout & 3DS — paso a paso
El 3DS de Zendry es inteligente (data-only): en la mayoría de las ventas la autenticación ocurre tras bambalinas, sin pantalla — basta enviar los datos del dispositivo del comprador. El desafío en el navegador (iframe del banco) solo aparece cuando el emisor lo exige, y Zendry.js se encarga de él. El SDK nunca ve el número de la tarjeta ni credenciales.
Comprador
Rellena la tarjeta en tu página de checkout.
Tu front
Zendry.js recoge el device (idioma, pantalla, huso). La tarjeta no pasa por el SDK.
Tu backend
POST /card_payments con tarjeta, device, ip_address y user_agent.
Zendry
Autentica con el emisor y responde a tu servidor.
Emisor
Decide sin pantalla (data-only) o pide desafío al comprador.
200 approved
Data-only: autenticó tras bambalinas, sin pantalla.
201 requires_action
El emisor pidió desafío — Zendry.js lo concluye en el navegador.
402 declined
failure_reason trae el motivo. Ofrece otra tarjeta.
Webhook card.approved / card.declined
El desenlace oficial. Libera el pedido solo aquí — nunca por el retorno del SDK.
É o mesmo arquivo dos dois lados. O envio não sai do simulador: o desfecho abaixo é escolhido por você. Numa venda real, quem confirma é sempre o webhook.
Carga el SDK y recoge el device
Pon el script en la página de checkout y llama Zendry.threeDS() justo antes de enviar el formulario. Devuelve un objeto pequeño con idioma, pantalla y huso del comprador — ningún dato de tarjeta pasa por el SDK. La página entera está en el simulador de arriba, en la pestaña Código.
<script src="https://api.zendry.co/sdk/v1/zendry.js"></script> const threeds = await Zendry.threeDS();// threeds.device → { language, screen_height, screen_width, time_zone_offset }Crea la venta en tu backend
Tu clave nunca va al navegador: quien llama a Zendry es tu servidor. Reenvía el device recibido del front y agrega el ip_address y el user_agent del comprador — son ellos los que sostienen la autenticación sin pantalla.
app.post("/checkout/pagar", async (req, res) => { const r = await fetch("https://finance.zendry.co/api/public/v1/card_payments", { method: "POST", headers: { Authorization: `Bearer ${process.env.ZENDRY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ amount_cents: req.body.amount_cents, installments: 1, external_id: req.body.pedido_id, buyer: req.body.buyer, card: req.body.card, device: req.body.device, ip_address: req.headers["x-forwarded-for"]?.split(",")[0], user_agent: req.headers["user-agent"], }), }); const venta = await r.json(); switch (venta.status) { case "aprovada": return res.json({ status: "approved", id: venta.id }); case "requires_action": // devuelve la action al front — Zendry.js concluye el desafío return res.json({ status: "requires_action", action: venta.action, id: venta.id }); default: return res.status(402).json({ status: "declined", motivo: venta.failure_reason }); }});Concluye el desafío cuando llegue 201 requires_action
La action es opaca: devuélvela a tu front exactamente como llegó y llama Zendry.completeThreeDS. Sin desafío real (frictionless), se resuelve en segundos, sin pantalla.
const desenlace = await Zendry.completeThreeDS(venta.action); if (desenlace.status === "authorized") mostrarExito();else if (desenlace.status === "expired") pedirNuevoIntento();else mostrarRechazo(); // esto es UX. El pedido solo se libera tras la confirmación de tu servidor.Confirma el desenlace en el servidor
El retorno del SDK es para la pantalla; la verdad es el webhook (o el GET /api/public/v1/card_payments/:id). Valida la firma HMAC antes de liberar cualquier pedido.
import crypto from "node:crypto"; app.post("/webhooks/zendry", express.raw({ type: "*/*" }), (req, res) => { const firma = req.headers["x-zendry-signature"]; const esperado = crypto .createHmac("sha256", process.env.ZENDRY_WEBHOOK_SECRET) .update(req.body) .digest("hex"); if (firma !== esperado) return res.status(401).end(); const evento = JSON.parse(req.body.toString()); if (evento.event === "card.approved") liberarPedido(evento.data.external_id); if (evento.event === "card.declined") cancelarPedido(evento.data.external_id); res.status(200).end();});| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| aprovada (200) | muestra el éxito | No | El webhook card.approved confirma. Libera el pedido ahí. |
| requires_action (201) | llama completeThreeDS | No | Tras el desafío llega card.approved o card.declined. Sin conclusión en 15 min, la venta expira. |
| recusada (200) | ofrece otra tarjeta | No | failure_reason trae el motivo. Webhook card.declined. |
| 422 | corrige la solicitud | No | error_type nombra la causa (ej.: INVALID_REQUEST con device ausente en postura reforzada). |
- Envía device en TODA venta: aumenta la tasa de aprobación, y las cuentas con postura de riesgo reforzada rechazan la solicitud sin él (422).
- action.session_id es de un solo uso y expira en 15 minutos — si el comprador no concluye, la venta expira y es rechazada.
- Nunca liberes el pedido por el retorno del SDK: solo el webhook (o el GET) es el resultado oficial.
- No reutilices la misma action en otro intento — crea una venta nueva.
En el sandbox la tarjeta se simula sin 3DS real: cualquier número válido aprueba y 4000 0000 0000 0002 rechaza (usa la consola del endpoint Pago con tarjeta). El desafío 3DS de verdad solo ocurre en producción.
Pago con tarjeta
Cobra una tarjeta de crédito server-to-server. Exige tarjeta habilitada para la cuenta. El número de la tarjeta nunca se almacena.
- Sandbox (clave gw_test_): la autorización es simulada — cualquier número de tarjeta válido APRUEBA y 4000 0000 0000 0002 RECHAZA; sin 3DS; el reembolso también es simulado.
- 201 + status requires_action: concluye en el navegador con Zendry.completeThreeDS(respuesta.action) — mira la guía Checkout & 3DS arriba. El desenlace oficial llega por el webhook card.approved / card.declined y por el GET de abajo.
- Un rechazo NO es error HTTP: llega 200 con state declined y failure_reason legible.
- Los errores de negocio llegan como 422 en el formato { error, error_type, error_code, retry } — catálogo en la sección Errores y límites.
- Si tu plataforma revende a comercios (gateway en cadena), envía ip_address y user_agent del comprador final — los encabezados HTTP traen tu servidor, no al comprador.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| amount_cents | entero | Sí | Valor en centavos. |
| installments | entero | No | 1 a 12. Predeterminado 1. |
| buyer | objeto | Sí | name, email y taxpayer_id (CPF, 11 dígitos). |
| card | objeto | Sí | holder_name, number, expiration_month (MM), expiration_year (AAAA) y security_code. |
| billing | objeto | No | Dirección de facturación. |
| device | objeto | No | Datos del dispositivo del comprador recogidos por Zendry.js (Zendry.threeDS()). Aumenta la aprobación — y las cuentas con postura de riesgo reforzada EXIGEN este campo. Campos: language, screen_height, screen_width, time_zone_offset (horas, Brasil = -3). |
| ip_address | texto | No | IP del COMPRADOR. Obligatorio en la práctica en integraciones en cadena. |
| user_agent | texto | No | User-agent del COMPRADOR. |
| external_id | texto | No | Tu identificador. |
curl -X POST https://finance.zendry.co/api/public/v1/card_payments \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 15000, "installments": 1, "external_id": "1234", "buyer": { "name": "Maria Souza", "email": "maria@email.com", "taxpayer_id": "12345678900" }, "card": { "holder_name": "MARIA SOUZA", "number": "4111111111111111", "expiration_month": "12", "expiration_year": "2030", "security_code": "123" }, "ip_address": "203.0.113.10", "user_agent": "Mozilla/5.0 ..."}'{ "id": "7d21...", "charge_id": "1b8e...", "state": "approved", "amount_cents": 15000, "installments": 1, "external_id": "1234", "created_at": "2026-01-01T12:00:00Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Consultar transacción de tarjeta
Devuelve la transacción por el id entregado en la creación — incluso para seguir el desenlace de un 3DS.
- state: approved | declined | refunded | requires_action.
- nsu: el NSU del comprobante. null cuando la venta no llegó a la red (rechazo antes de la autorización, sandbox).
curl -X GET https://finance.zendry.co/api/public/v1/card_payments/:id \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "7d21...", "charge_id": "1b8e...", "state": "approved", "amount_cents": 15000, "gross_cents": 15000, "fee_cents": 899, "net_cents": 14101, "installments": 1, "external_id": "1234", "failure_reason": null, "nsu": "Z000186-1049...", "refunded_at": null, "created_at": "2026-01-01T12:00:00Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Reembolsar transacción
Reembolso total. Disponible solo para transacciones aprobadas y dentro de las 24 horas de la aprobación.
- Tras 24h o en una transacción no aprobada: 422 con la razón en el campo error.
- El evento card.refunded se dispara en el webhook de recepción.
curl -X POST https://finance.zendry.co/api/public/v1/card_payments/:id/refund \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "7d21...", "state": "refunded", "refunded_at": "2026-01-01T18:22:40Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Cripto (USDT)
Convertir a USDT y enviar (retiro cripto)
Convierte el valor en reales a USDT a la cotización del momento y lo envía a la billetera indicada. Los reales salen del saldo al instante; el USDT queda bloqueado hasta la confirmación on-chain, que llega por el webhook crypto.sent.
- state: requested → completed (webhook crypto.sent, con tx_hash) o failed (webhook crypto.failed; el USDT vuelve al saldo disponible en USDT — la conversión de los reales no se deshace).
- usdt_amount es lo que llega a la billetera: el USDT convertido, menos la tarifa de salida en USDT (fee_usdt_minor). applied_rate es la cotización de la conversión: reales pagados por USDT convertido (amount_cents ÷ (usdt_amount_minor + fee_usdt_minor), en las unidades de cada moneda). En el envío desde el saldo en USDT no hay conversión: applied_rate viene 0.
- 409 cuando el saldo en reales es insuficiente. 422 cuando la conversión BRL → USDT no está habilitada para la cuenta o el valor rompe un límite de retiro.
- Idempotencia: envía el header Idempotency-Key. Repetir la llamada con la MISMA clave devuelve el retiro ya creado, sin convertir de nuevo.
- Envío desde el saldo en USDT: manda usdt_amount_minor en lugar de amount_cents. Es el camino para reenviar un retiro fallido (el USDT vuelve al saldo, no a reales). amount_cents en la respuesta viene 0 en ese caso.
- Sandbox: el desenlace es inmediato — un valor terminado en 99 centavos simula falla, los demás concluyen sin tx_hash (el sandbox no llega a la red; un identificador de red nunca se inventa).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| amount_cents | inteiro | No | Valor en reales, en centavos. De 1 a 100000000. Aplican el mínimo, el máximo y el tope diario de retiro de la cuenta. |
| usdt_amount_minor | inteiro | No | Alternativa a amount_cents: envía USDT que ya está en tu saldo (unidad mínima, 6 decimales) sin convertir. Informa solo uno de los dos. |
| wallet | texto | Sí | Dirección de la billetera de destino, en la red elegida. |
| network | trc20 | erc20 | bep20 | polygon | Sí | Red del envío: TRON (TRC20), Ethereum (ERC20), BNB Smart Chain (BEP20) o Polygon. |
| description | texto | No | Hasta 140 caracteres. |
curl -X POST https://finance.zendry.co/api/public/v1/crypto_payouts \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 50000, "wallet": "TKcXiZ1ovginwWvoCHZwwSPn7ZUhCA7Ndg", "network": "trc20", "description": "Repasse"}'{ "id": "5b7d...", "state": "requested", "amount_cents": 50000, "usdt_amount": 94.754323, "usdt_amount_minor": 94754323, "fee_usdt_minor": 0, "applied_rate": 5.276804, "wallet": "TKcXiZ1ovginwWvoCHZwwSPn7ZUhCA7Ndg", "network": "trc20", "description": "Repasse", "tx_hash": null, "failure_reason": null, "conversion_id": "c0a1...", "created_at": "2026-01-01T12:00:00Z", "completed_at": null, "failed_at": null}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Consultar retiro cripto
Devuelve el estado actual de un retiro USDT por el id de la creación. Úsalo cuando la entrega del webhook crypto.sent falló o para conciliar.
- 404 si el id no existe o pertenece a otra cuenta. La clave de prueba solo ve retiros sandbox.
- tx_hash solo viene en completed; failure_reason solo en failed.
curl -X GET https://finance.zendry.co/api/public/v1/crypto_payouts/{id} \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "5b7d...", "state": "completed", "amount_cents": 50000, "usdt_amount": 94.754323, "usdt_amount_minor": 94754323, "fee_usdt_minor": 0, "applied_rate": 5.276804, "wallet": "TKcXiZ1ovginwWvoCHZwwSPn7ZUhCA7Ndg", "network": "trc20", "description": "Repasse", "tx_hash": "7f3a9c...e21b", "failure_reason": null, "conversion_id": "c0a1...", "created_at": "2026-01-01T12:00:00Z", "completed_at": "2026-01-01T12:03:40Z", "failed_at": null}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Listar retiros cripto
Lista los retiros USDT de la cuenta, del más reciente al más antiguo. Filtra por status para encontrar lo que sigue en curso.
- status=requested devuelve lo que aún no tiene desenlace — es la consulta para conciliar cuando el webhook no llegó.
- 422 si el estado no es uno de los tres.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| status | requested | completed | failed | No | Sin este campo, devuelve todos. |
| limit | inteiro | No | De 1 a 100. Por defecto 50. |
curl -X GET https://finance.zendry.co/api/public/v1/crypto_payouts \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "crypto_payouts": [ { "id": "5b7d...", "state": "requested", "amount_cents": 50000, "usdt_amount": 94.754323, "usdt_amount_minor": 94754323, "fee_usdt_minor": 0, "applied_rate": 5.276804, "wallet": "TKcXiZ1ovginwWvoCHZwwSPn7ZUhCA7Ndg", "network": "trc20", "description": "Repasse", "tx_hash": null, "failure_reason": null, "conversion_id": "c0a1...", "created_at": "2026-01-01T12:00:00Z", "completed_at": null, "failed_at": null } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Disputas
Listar disputas
Disputas (MED y chargeback) de tu cuenta, de las más recientes a las más antiguas. La apertura llega por el webhook dispute.opened; usa la lista para seguir el estado.
- El valor de la disputa es siempre el de la transacción entera — no existe disputa parcial.
- Mientras está viva, el valor queda retenido del saldo disponible; el desenlace llega por el webhook dispute.closed (outcome won/lost).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| status | open | closed | exacto | No | open = vivas (open, under_defense, under_review); closed = won y lost; o un state exacto. |
| limit | entero | No | De 1 a 100. Predeterminado 50. |
curl -X GET https://finance.zendry.co/api/public/v1/disputes \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "disputes": [ { "id": "19ba...", "type": "med", "state": "open", "amount_cents": 15000, "currency": "BRL", "transaction_reference": "469208464", "transaction_identifier": "d6f1849fe1654d83a4049db495f26ee8", "charge_id": "94a9f429-dc23-4b32-861a-351499d91790", "transaction_identifier": "d6f1849fe1654d83a4049db495f26ee8", "charge_id": "94a9f429-dc23-4b32-861a-351499d91790", "reason": "MED REFUND_REQUEST", "opened_at": "2026-01-01T12:00:00Z", "defense_deadline": "2026-01-08T12:00:00Z", "responded_at": null, "closed_at": null } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Consultar disputa
Detalle completo: datos de la disputa, historial de mensajes (author: seller = tú, zendry = nosotros) y evidencias ya adjuntadas.
- 404 si el id no existe o pertenece a otra cuenta.
curl -X GET https://finance.zendry.co/api/public/v1/disputes/:id \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "19ba...", "type": "med", "state": "under_defense", "amount_cents": 15000, "currency": "BRL", "transaction_reference": "469208464", "transaction_identifier": "d6f1849fe1654d83a4049db495f26ee8", "charge_id": "94a9f429-dc23-4b32-861a-351499d91790", "reason": "MED REFUND_REQUEST", "opened_at": "2026-01-01T12:00:00Z", "defense_deadline": "2026-01-08T12:00:00Z", "responded_at": "2026-01-02T09:30:00Z", "closed_at": null, "messages": [ { "author": "seller", "text": "Servicio prestado, comprobante adjunto.", "created_at": "2026-01-02T09:30:00Z" } ], "evidence": [ { "name": "comprobante-entrega.pdf", "content_type": "application/pdf", "size_bytes": 182044, "created_at": "2026-01-02T09:29:00Z" } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Enviar defensa
Registra tu defensa por escrito y mueve la disputa a under_defense. Adjunta las evidencias antes o después — la defensa puede complementarse mientras la disputa esté viva.
- 422 si la disputa ya está cerrada (won o lost).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| text | texto | Sí | La argumentación de la defensa. De 5 a 4000 caracteres. |
curl -X POST https://finance.zendry.co/api/public/v1/disputes/:id/defense \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "text": "Servicio prestado el 01/01, aceptación del cliente en la app. Comprobante adjunto."}'{ "id": "19ba...", "state": "under_defense"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Adjuntar evidencia
Envía UN archivo de evidencia (comprobante de entrega, aceptación, conversación con el cliente). El cuerpo es multipart/form-data con el campo `file` — el archivo en sí, no base64. Para varios archivos, repite la llamada.
- Ejemplo: curl -X POST .../disputes/{id}/evidence -H "Authorization: Bearer …" -F "file=@comprobante.pdf"
- 413 por encima de 15MB; 415 si el formato no es uno de los aceptados; 422 si la disputa ya está cerrada.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| file | archivo | Sí | Hasta 15MB. PDF, imagen (PNG, JPEG, GIF, WEBP, HEIC), documento (DOC, DOCX, ODT, RTF, TXT) u hoja de cálculo (XLS, XLSX, ODS, CSV). |
curl -X POST https://finance.zendry.co/api/public/v1/disputes/:id/evidence \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "19ba...", "name": "comprobante-entrega.pdf", "size_bytes": 182044}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
No contestar
Declara que no vas a defenderte de esta disputa. Sigue a análisis y el desenlace se comunica por el webhook dispute.closed.
- Acepta solo disputas en open o under_defense (422 en los demás estados).
curl -X POST https://finance.zendry.co/api/public/v1/disputes/:id/accept \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "19ba...", "state": "under_review"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Consultas
Consultar saldo
Devuelve el saldo disponible de la cuenta autenticada.
curl -X GET https://finance.zendry.co/api/public/v1/balance \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "balance_cents": 84851, "currency": "BRL"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Extracto
Lista los movimientos de la cuenta, de los más recientes a los más antiguos (hasta 200 ítems).
- Límite fijo de 200 ítems por llamada — pagina por período con from/to.
- Para conciliación en tiempo real prefiere los webhooks; el extracto es la fuente para cierre y auditoría.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| from | fecha (AAAA-MM-DD) | No | Día inicial, huso de Brasilia. |
| to | fecha (AAAA-MM-DD) | No | Día final, huso de Brasilia. |
| type | texto | No | Filtra por el campo "type" de las respuestas (ej.: pagamento_confirmado). |
curl -X GET https://finance.zendry.co/api/public/v1/statement \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "transactions": [ { "id": "9ac2...", "type": "pagamento_confirmado", "gross_cents": 15000, "fee_cents": 299, "net_cents": 14701, "end_to_end_id": "E18236120202601011204a1b2c3", "description": "Pedido #1234", "counterparty": "Maria Souza", "created_at": "2026-01-01T12:04:11Z" } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Endpoints de webhook
Listar eventos suscribibles
Catálogo de los eventos que un endpoint puede suscribir, con familia y descripción. Usa el nombre exacto en el campo events.
- Solo entran eventos que ya tienen emisor — el catálogo crece sin romper suscripciones existentes.
- "*" no aparece en la lista, pero se acepta en events: suscribe todos los eventos, incluso los futuros.
curl -X GET https://finance.zendry.co/api/public/v1/webhook_events \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "events": [ { "event": "pix.received", "family": "Pix", "description": "Cobro Pix pagado" }, { "event": "pix.sent", "family": "Retiro Pix", "description": "Retiro Pix completado" }, { "event": "dispute.opened", "family": "Disputa", "description": "Disputa (MED/chargeback) abierta" } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Listar endpoints
Todos los endpoints de la cuenta, incluidos los espejos de los canales fijos (managed: true).
- managed: true es el espejo de un canal fijo (recepción, retiro, infracción): URL y eventos cambian en la pantalla Integraciones; la API solo lee, prueba y consulta entregas.
curl -X GET https://finance.zendry.co/api/public/v1/webhook_endpoints \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "endpoints": [ { "id": "e7a1...", "url": "https://tutienda.com/webhooks/retiros", "label": "ERP financiero", "events": ["pix.sent", "crypto.sent", "crypto.failed"], "active": true, "dialect": "en", "managed": false, "consecutive_failures": 0, "last_delivered_at": "2026-09-05T12:04:12Z", "last_failed_at": null, "created_at": "2026-09-05T11:00:00Z", "updated_at": "2026-09-05T11:00:00Z" } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Crear endpoint
Registra una URL y los eventos que recibe. El mismo evento puede ir a varias URLs; cada entrega se firma con el secreto de la cuenta.
- Hasta 10 endpoints por cuenta (los espejos de los canales fijos no cuentan) — 422 webhook_endpoint_limit_reached.
- 422 webhook_url_invalid para una URL fuera de la regla; 422 webhook_event_unknown para un evento fuera del catálogo.
- Prueba la URL apenas la crees (POST /webhook_endpoints/:id/test).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| url | texto | Sí | HTTPS con host público (sin IP privada, localhost ni puerto fuera del estándar). |
| events | lista de texto | Sí | Nombres del catálogo, o ["*"] para todos. |
| label | texto | No | Nombre visible, hasta 80 caracteres. |
| active | booleano | No | Por defecto true. Inactivo no recibe nada. |
| dialect | en | pt | No | Por defecto en. pt entrega los campos en el formato legado (solo para quien migró de zendry.com). |
curl -X POST https://finance.zendry.co/api/public/v1/webhook_endpoints \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "url": "https://tutienda.com/webhooks/retiros", "label": "ERP financiero", "events": [ "pix.sent", "crypto.sent", "crypto.failed" ]}'{ "id": "e7a1...", "url": "https://tutienda.com/webhooks/retiros", "label": "ERP financiero", "events": ["pix.sent", "crypto.sent", "crypto.failed"], "active": true, "dialect": "en", "managed": false, "consecutive_failures": 0, "last_delivered_at": null, "last_failed_at": null, "created_at": "2026-09-05T11:00:00Z", "updated_at": "2026-09-05T11:00:00Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Consultar, actualizar o eliminar endpoint
GET devuelve el endpoint; PATCH cambia solo los campos enviados; DELETE lo elimina (204, sin cuerpo).
- 404 webhook_endpoint_not_found si el id no existe o es de otra cuenta.
- 409 webhook_endpoint_managed en PATCH/DELETE de un espejo de canal fijo — cámbialo en la pantalla Integraciones.
- Las fallas seguidas quedan en consecutive_failures y last_failed_at; el endpoint nunca se desactiva solo — síguelo y corrige la URL.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| url | texto | No | Misma regla que en la creación. |
| events | lista de texto | No | Reemplaza la lista completa. |
| label | texto | No | Hasta 80 caracteres. |
| active | booleano | No | false pausa las entregas sin borrar el endpoint. |
| dialect | en | pt | No | Formato de los campos de data. |
curl -X PATCH https://finance.zendry.co/api/public/v1/webhook_endpoints/:id \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "events": [ "pix.sent" ], "active": true}'{ "id": "e7a1...", "url": "https://tutienda.com/webhooks/retiros", "label": "ERP financiero", "events": ["pix.sent"], "active": true, "dialect": "en", "managed": false, "consecutive_failures": 0, "last_delivered_at": "2026-09-05T12:04:12Z", "last_failed_at": null, "created_at": "2026-09-05T11:00:00Z", "updated_at": "2026-09-05T12:30:00Z"}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Probar endpoint
Entrega al instante un evento de ejemplo, firmado como una entrega real, con test: true en el sobre y el encabezado X-Zendry-Test.
- Un solo intento, sin reintentos; el resultado también queda en el historial de entregas.
- Ignora las entregas con test: true en tu procesamiento de negocio — los ids en data son ficticios.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| event | texto | Sí | Evento del catálogo cuyo ejemplo se enviará. |
curl -X POST https://finance.zendry.co/api/public/v1/webhook_endpoints/:id/test \ -H "Authorization: Bearer gw_tu_clave_aqui" \ -H "Content-Type: application/json" \ -d '{ "event": "pix.sent"}'{ "result": "delivered", "http_status": 200, "duration_ms": 184, "response": "ok", "error": null}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Entregas de un endpoint
Últimos intentos de entrega al endpoint, del más reciente al más antiguo.
- message_id es el X-Zendry-Webhook-Id de ese mensaje: reentregas y reintentos comparten el valor.
- result: delivered, failed o no_destination.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| limit | entero | No | Query string. Por defecto 50, máximo 200. |
| event | texto | No | Query string. Filtra por evento. |
curl -X GET https://finance.zendry.co/api/public/v1/webhook_endpoints/:id/deliveries \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "deliveries": [ { "id": "d41c...", "message_id": "b0d3c1e2-...", "event": "pix.sent", "source_event": "pix.sent", "result": "delivered", "http_status": 200, "duration_ms": 184, "error": null, "attempt": 1, "resent_from": null, "created_at": "2026-09-05T12:04:12Z" } ]}Crea tu cuenta para ejecutar esta llamada en el sandbox, con clave de prueba y datos aislados.
Webhooks
Cómo funcionan
Configura en Integraciones los canales fijos — recepción (cobros, tarjeta, suscripciones), retiro (pix.sent y demás salidas) e infracción (disputas) — o registra endpoints por evento, eligiendo qué eventos recibe cada URL. Enviamos un POST JSON con los encabezados X-Zendry-Event, X-Zendry-Webhook-Id y X-Zendry-Signature: sha256=<hmac>.
{ "id": "b0d3c1e2-...", "event": "pix.received", "sent_at": "2026-01-01T12:04:12Z", "data": { ...campos del evento... }}{ "charge_id": "3f1c...", "external_id": "1234", "amount_cents": 15000, "description": "Pedido #1234", "end_to_end_id": "E1823612...", "environment": "producao", "state": "paid"}const crypto = require("node:crypto"); function firmaValida(cuerpoCrudo, encabezado, secreto) { const esperada = "sha256=" + crypto.createHmac("sha256", secreto).update(cuerpoCrudo).digest("hex"); return ( encabezado?.length === esperada.length && crypto.timingSafeEqual(Buffer.from(esperada), Buffer.from(encabezado)) );}// firmaValida(rawBody, req.headers["x-zendry-signature"], SECRETO)- Responde 2xx en hasta 10 segundos; procesa de forma asíncrona si hace falta.
- En falla (red, timeout o status ≥ 400) reintentamos hasta 3 veces, con espera creciente.
- Toda entrega y reentrega queda registrada en Integraciones — desde ahí reenvías un evento perdido.
- Trata las entregas por charge_id/payout_id de forma idempotente: pueden ocurrir reentregas del mismo evento.
Endpoints por evento
Además de los canales fijos, registra hasta 10 URLs y elige los eventos de cada una — en la pantalla Integraciones o por la API (/api/public/v1/webhook_endpoints). El mismo evento puede ir a varias URLs; events: ["*"] suscribe todo, incluso los eventos futuros.
- Toda entrega lleva X-Zendry-Webhook-Id (el mismo valor en id, dentro del sobre). Las reentregas repiten el valor — úsalo para deduplicar.
- Los canales fijos aparecen en la lista como espejos (managed: true): URL y eventos se editan en los campos fijos; ahí los pruebas y sigues su salud.
- El secreto de firma es uno solo por cuenta: el mismo HMAC vale para todos los endpoints.
- Las fallas seguidas quedan visibles (consecutive_failures, last_failed_at); nada se desactiva automáticamente.
Catálogo de eventos
- pix.receivedCobro Pix pagado (canal de recepción)
- pix.sentRetiro Pix completado o fallido (canal de retiro)
- boleto.paidBoleto compensado
- card.approvedTransacción aprobada (incluso tras 3DS). El campo nsu trae el NSU del comprobante
- card.declinedTransacción rechazada
- card.refundedTransacción reembolsada
- charge.expiredCobro expiró sin pago
- charge.canceledCobro cancelado
- dispute.openedDisputa (chargeback/MED) abierta — webhook de infracción
- dispute.closedDisputa cerrada — webhook de infracción
- subscription.createdSuscripción creada
- subscription.charge_approvedCobro recurrente aprobado
- subscription.charge_declinedCobro recurrente rechazado
- subscription.retry_scheduledNuevo intento agendado
- subscription.retries_exhaustedIntentos agotados
- subscription.canceledSuscripción cancelada
- subscription.completedSuscripción completada
- crypto.sentEnvío cripto completado
- crypto.failedEnvío cripto falló
- intl.deposit.receivedDepósito internacional recibido
- intl.payout.sentEnvío internacional completado
Sandbox
Ambiente de pruebas
Genera una clave de prueba en la página Integraciones (prefijo gw_test_). Usa la misma URL base y las mismas rutas, pero opera un ambiente aislado: saldo, extracto y cobros de prueba quedan separados de producción y no circula dinero real — el Pix se simula internamente, sin mover dinero.
- Cobertura: Pix completo, boleto y tarjeta (creación, consulta, pago/autorización simulados, reembolso) — con webhooks y saldo de prueba.
- Boleto: emite con números de prueba (línea digitable/código de barras falsos) y se paga por el mismo POST /charges/:id.
- Tarjeta: simulada sin 3DS — cualquier número válido aprueba; 4000 0000 0000 0002 rechaza; el reembolso también es simulado.
- Los webhooks son reales (misma URL y firma HMAC), con environment: "sandbox" en el payload.
- Los identificadores de la red (end_to_end_id, nsu, tx_hash) vienen null en el sandbox: nada se inventa.
- La clave de prueba no ve datos de producción, y viceversa.
- El retiro de prueba concluye al instante (webhook pix.sent). Un valor terminado en 99 centavos (ej.: 10099) simula falla — el valor vuelve al saldo.
Simular pago (sandbox)
Marca el cobro de prueba (Pix O boleto) como pagado: lo asienta en el saldo sandbox y dispara el webhook real (pix.received o boleto.paid), con firma HMAC. Exclusivo de la clave de prueba — en producción devuelve 403.
- Solo funciona con clave gw_test_ y cobro del ambiente sandbox (si no, 403/404).
- Idempotente: un cobro ya pagado responde con already_paid: true.
- Un cobro expirado no puede pagarse (422).
curl -X POST https://finance.zendry.co/api/public/v1/charges/:id \ -H "Authorization: Bearer gw_tu_clave_aqui"{ "id": "3f1c...", "state": "paid", "paid_at": "2026-01-01T12:04:11Z"}Crea tu cuenta para simular pagos en el sandbox con tu clave de prueba.
Errores y límites
Envelope estándar
Todo error sale en este formato. code es el contrato estable — decide por él, nunca por el mensaje, que existe para el humano que lee el log y puede cambiar. retryable dice si repetir la MISMA solicitud puede funcionar, y details solo aparece cuando hay algo que mostrar (el campo inválido, el límite y el importe enviado).
{ "error": "Amount is above the maximum for this operation", "code": "amount_above_maximum", "retryable": false}| code | HTTP | retryable | error (clave nueva) |
|---|---|---|---|
| Autenticación y acceso | |||
| missing_credentials | 401 | false | Credential missing |
| invalid_credentials | 401 | false | Invalid credential |
| ip_not_allowed | 403 | false | IP not allowed for this key |
| Solicitud inválida | |||
| invalid_json | 400 | false | Request body is not valid JSON |
| invalid_payload | 422 | false | Invalid payload |
| sandbox_only | 422 | false | Only available in the sandbox environment |
| Límites e importes | |||
| amount_below_minimum | 422 | false | Amount is below the minimum for this operation |
| amount_above_maximum | 422 | false | Amount is above the maximum for this operation |
| daily_limit_exceeded | 422 | false | Daily limit exceeded |
| Saldo y bloqueos | |||
| insufficient_balance | 409 | false | Insufficient balance |
| Recurso y estado | |||
| charge_not_found | 404 | false | Charge not found |
| payout_not_found | 404 | false | Payout not found |
| charge_already_paid | 422 | false | Charge already paid |
| charge_expired | 422 | false | Charge expired |
| charge_finalized | 422 | false | Charge already finalized |
| transaction_not_found | 404 | false | Transaction not found |
| Pago | |||
| payment_method_not_enabled | 422 | false | This payment method is not enabled for this account |
| card_declined | 422 | false | The card payment was declined |
| Disputas y archivos | |||
| dispute_not_found | 404 | false | Dispute not found |
| dispute_closed | 422 | false | Dispute already closed |
| dispute_action_not_allowed | 422 | false | This dispute no longer accepts this action |
| file_missing | 422 | false | Send multipart/form-data with a `file` field |
| file_too_large | 413 | false | File is larger than 15MB |
| file_type_not_allowed | 415 | false | Send a PDF, image, document or spreadsheet |
| Webhooks | |||
| webhook_endpoint_not_found | 404 | false | Webhook endpoint not found |
| webhook_url_invalid | 422 | false | Webhook URL must use https and a public host |
| webhook_event_unknown | 422 | false | Unknown webhook event |
| webhook_endpoint_limit_reached | 422 | false | Maximum number of webhook endpoints reached |
| webhook_endpoint_managed | 409 | false | This endpoint mirrors a fixed channel; edit it in the integration settings |
| Falla nuestra | |||
| service_unavailable | 503 | true | The operation could not be completed. Please try again in a few moments. |
| internal_error | 500 | true | The operation could not be completed. Please try again in a few moments. |
- Las claves antiguas (contrato heredado) siguen recibiendo el mensaje en portugués y el status HTTP de siempre; `code`, `retryable` y `details` entran al lado, sin romper a quien ya integra.
- Ningún detalle interno aparece en la respuesta. La operación que no se pudo completar ahora se convierte en `service_unavailable` (503); la falla inesperada de nuestro lado, en `internal_error` (500). El motivo queda en nuestro log.
- Antes de repetir un POST que mueve dinero tras un error `retryable`, consulta el recurso con GET — la API no acepta clave de idempotencia del cliente.
Códigos HTTP
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| 400 | formato | No | El cuerpo no es JSON válido. |
| 401 | auth | No | Credencial ausente, inválida o revocada. |
| 403 | acceso | No | IP fuera de la lista permitida. |
| 404 | recurso | No | Recurso inexistente o de otra cuenta. |
| 409 | conflicto | No | Saldo insuficiente en el retiro, o endpoint que refleja un canal fijo. |
| 413 | archivo | No | Evidencia de disputa mayor a 15MB. |
| 415 | archivo | No | Evidencia de disputa en un formato no aceptado. |
| 422 | validación | No | Payload inválido, límite de la cuenta o regla de negocio. Trae details. |
| 500 | nuestro | No | Falla inesperada de nuestro lado; retryable: true. |
| 503 | no disponible | No | La operación no se pudo completar ahora; reintente en instantes (retryable: true). |
{ "error": "Payload inválido", "details": [ { "path": ["amount_cents"], "message": "Number must be greater than or equal to 1" } ]}Errores de tarjeta
Las rutas de tarjeta usan un formato propio en el 422 — retry indica si vale la pena reintentar la misma solicitud.
{ "error": "Meio de pagamento não habilitado para esta conta", "error_type": "INVALID_REQUEST", "error_code": "payment_method_not_enabled", "retry": false}| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| PAYMENT_DECLINED | retry: false | No | Pago rechazado; ofrece otra tarjeta. |
| INVALID_REQUEST | retry: false | No | Dato inválido, o tarjeta no habilitada para la cuenta (error_code payment_method_not_enabled). |
| PENDING_CHECK | retry: false | No | Pago en verificación; espera el webhook o consulta el GET antes de repetir. |
| TEMPORARY_ERROR | retry: true | No | No se pudo completar ahora; intenta de nuevo en instantes. |
| INTERNAL_ERROR | retry: true | No | Falla nuestra; intenta de nuevo. |
Límites y buenas prácticas
- Cada cuenta tiene mínimo y máximo por medio (Pix, tarjeta, boleto y retiro), y el retiro tiene tope diario; el retiro en USDT tiene máximo y tope diario propios, en USDT. Fuera del rango la API rechaza con amount_below_minimum, amount_above_maximum o daily_limit_exceeded. La respuesta no trae los valores de los límites: están en el panel.
- Idempotencia: la API no acepta clave de idempotencia del cliente. En un timeout de un POST que mueve dinero (retiro, tarjeta), consulta el extracto/GET antes de repetir.
- La confirmación de pago es por webhook; si reconsultas, limita la frecuencia (ej.: cada 30s) — el tráfico abusivo puede ser bloqueado por el firewall.