Desenvolvedores

Documentação completa em um arquivo

Copie ou baixe toda a referência em Markdown e entregue ao seu assistente de código para gerar a integração de uma vez.

Início rápido

finance.zendry.co

Três passos até a primeira cobrança em produção. Todos os valores em centavos, datas em ISO 8601 (UTC).

1 · Chave
Abra sua conta
Exibida uma única vez na criação. Restrinja por IP se puder.
2 · Teste
GET /balance
Confirma que a credencial e o IP estão liberados.
3 · Webhook
URLs de recebimento e saque
A confirmação de pagamento chega por evento, não por polling.
Primeira chamada
200
curl -X GET https://finance.zendry.co/api/public/v1/balance \  -H "Authorization: Bearer gw_sua_chave_aqui"

Autenticação

Toda requisição exige sua chave de API no cabeçalho Authorization: Bearer <chave> ou x-api-key: <chave> — os dois formatos são aceitos. Gere e revogue chaves em Integrações.

  • Valores monetários sempre em centavos (inteiro). Datas em ISO 8601 (UTC).
  • Com IPs permitidos cadastrados em Integrações, chamadas de outros IPs recebem 403.
  • A confirmação de pagamentos é por webhook — os GETs servem para reconsulta, não para polling agressivo.

Pix

POST
/api/public/v1/charges

Criar cobrança Pix

Gera uma cobrança e retorna o código copia e cola. A confirmação do pagamento chega pelo webhook pix.received — não faça polling.

  • state: pending → paid (ou expired se vencer sem pagamento).
  • external_id não deduplica: duas chamadas iguais criam duas cobranças. Guarde o id retornado.
Parâmetros
CampoTipoObrigatórioDescrição
amount_centsinteiro
Sim
Valor em centavos. De 1 a 100000000 (R$ 1 milhão).
descriptiontextoNãoAté 140 caracteres.
external_idtextoNãoSeu identificador. Volta nos webhooks. Não deduplica.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/charges \  -H "Authorization: Bearer gw_sua_chave_aqui" \  -H "Content-Type: application/json" \  -d '{  "amount_cents": 15000,  "description": "Pedido #1234",  "external_id": "1234"}'
Resposta
200
{  "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"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/charges/:id

Consultar cobrança

Retorna o estado atual de uma cobrança Pix ou boleto (o mesmo endpoint atende os dois — a resposta segue o formato do tipo da cobrança).

  • 404 se o id não existir ou pertencer a outra conta.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/charges/:id \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

POST
/api/public/v1/payouts

Enviar Pix (saque)

Debita o saldo disponível e envia um Pix para a chave informada. O valor + tarifa são reservados na hora; o resultado final chega pelo webhook pix.sent.

  • state: sending → completed ou failed (aviso via webhook pix.sent; em falha o valor reservado é devolvido ao saldo).
  • 409 quando o saldo é insuficiente para valor + tarifa.
  • Idempotência: mande o header Idempotency-Key. Repetir a chamada com a MESMA chave devolve o saque já criado, sem duplicar o débito.
  • Sem esse header, não repita após um timeout antes de consultar GET /payouts/{id}: o débito pode já ter sido reservado.
Parâmetros
CampoTipoObrigatórioDescrição
amount_centsinteiro
Sim
Valor em centavos. De 1 a 100000000.
pix_keytexto
Sim
Chave do favorecido.
pix_key_typecpf | cnpj | email | phone | evpNãoSem este campo, o tipo é inferido do formato da chave.
descriptiontextoNãoAté 140 caracteres.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/payouts \  -H "Authorization: Bearer gw_sua_chave_aqui" \  -H "Content-Type: application/json" \  -d '{  "amount_cents": 5000,  "pix_key": "cliente@email.com",  "pix_key_type": "email",  "description": "Repasse"}'
Resposta
200
{  "id": "9ac2...",  "state": "sending",  "amount_cents": 5000,  "fee_cents": 149,  "reserved_cents": 5149,  "idempotent_id": "b7e1...",  "created_at": "2026-01-01T12:00:00Z"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/payouts/{id}

Consultar saque

Devolve o estado atual de um saque pelo id da criação. Use quando a entrega do webhook pix.sent falhar ou para reconciliar.

  • 404 se o id não existir ou pertencer a outra conta. Chave de teste só enxerga saque sandbox.
  • failure_reason só vem preenchido em failed, com uma de quatro frases: "Chave Pix inválida.", "Saque cancelado.", a falha simulada do sandbox, ou "Não foi possível concluir a operação. Tente novamente em alguns instantes.". É texto para exibir, não para interpretar. end_to_end_id só em completed.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/payouts/{id} \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "id": "9ac2...",  "state": "failed",  "amount_cents": 5000,  "fee_cents": 149,  "reserved_cents": 5149,  "pix_key": "cliente@email.com",  "pix_key_type": "email",  "description": "Repasse",  "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"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/payouts

Listar saques

Lista os saques da conta, do mais recente para o mais antigo. Filtre por status para achar o que ainda está em andamento.

  • status=sending devolve o que ainda não teve desfecho — é a consulta para conciliar quando o webhook não chegou.
  • 422 se o status não for um dos três.
Parâmetros
CampoTipoObrigatórioDescrição
statussending | completed | failedNãoSem este campo, devolve todos.
limitinteiroNãoDe 1 a 100. Padrão 50.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/payouts \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "payouts": [    {      "id": "9ac2...",      "state": "sending",      "amount_cents": 5000,      "fee_cents": 149,      "reserved_cents": 5149,      "pix_key": "cliente@email.com",      "pix_key_type": "email",      "description": "Repasse",      "idempotent_id": "b7e1...",      "end_to_end_id": null,      "failure_reason": null,      "created_at": "2026-01-01T12:00:00Z",      "completed_at": null,      "failed_at": null    }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

Boleto

POST
/api/public/v1/charges/boleto

Criar cobrança por boleto

Emite um boleto para o comprador informado. A confirmação chega pelo webhook boleto.paid (compensação bancária, normalmente D+1).

  • Exige cartão habilitado para a conta.
  • data_limite é o último dia em que o boleto ainda é aceito após o vencimento.
  • pdf_url é a página do boleto, para imprimir ou salvar em PDF.
  • Consulte pelo mesmo GET /charges/:id.
Parâmetros
CampoTipoObrigatórioDescrição
amount_centsinteiro
Sim
Valor em centavos.
due_datedata (AAAA-MM-DD)
Sim
Vencimento do boleto.
buyerobjeto
Sim
first_name, last_name, email e taxpayer_id (CPF ou CNPJ).
buyer.addressobjetoNãoline1, neighborhood, city, state, postal_code. Opcional inteiro.
descriptiontextoNãoAté 140 caracteres.
external_idtextoNãoSeu identificador.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/charges/boleto \  -H "Authorization: Bearer gw_sua_chave_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"    }  }}'
Resposta
200
{  "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"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

Cartão

Checkout & 3DS — passo a passo

Zendry.js

O 3DS da Zendry é inteligente (data-only): na maioria das vendas a autenticação acontece nos bastidores, sem tela — basta enviar os dados do dispositivo do comprador. O desafio no navegador (iframe do banco) só aparece quando o emissor exige, e o Zendry.js cuida dele. O SDK nunca vê o número do cartão nem credenciais.

Como o dado circula
  1. Comprador

    Preenche o cartão na sua página de checkout.

  2. Seu front

    Zendry.js coleta o device (idioma, tela, fuso). O cartão não passa pelo SDK.

  3. Seu backend

    POST /card_payments com cartão, device, ip_address e user_agent.

  4. Zendry

    Autentica com o emissor e responde ao seu servidor.

  5. Emissor

    Decide sem tela (data-only) ou pede desafio ao comprador.

Resposta ao seu servidor

200 approved

Data-only: autenticou nos bastidores, sem tela.

201 requires_action

O emissor pediu desafio — Zendry.js conclui no navegador.

402 declined

failure_reason traz o motivo. Ofereça outro cartão.

Webhook card.approved / card.declined

O desfecho oficial. Só libere o pedido aqui — nunca pelo retorno do SDK.

Simulador da página de checkout
simulação

É 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.

1

Carregue o SDK e colete o device

Coloque o script na página de checkout e chame Zendry.threeDS() logo antes de enviar o formulário. Ele devolve um objeto pequeno com idioma, tela e fuso do comprador — nenhum dado de cartão passa pelo SDK. A página inteira está no simulador acima, na aba Código.

Na sua página de checkout
<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 }
2

Crie a venda no seu backend

Sua chave nunca vai ao navegador: quem chama a Zendry é o seu servidor. Repasse o device recebido do front e acrescente o ip_address e o user_agent do comprador — são eles que sustentam a autenticação sem tela.

Seu endpoint /checkout/pagar
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 venda = await r.json();   switch (venda.status) {    case "aprovada":      return res.json({ status: "approved", id: venda.id });    case "requires_action":      // devolva a action ao front — o Zendry.js conclui o desafio      return res.json({ status: "requires_action", action: venda.action, id: venda.id });    default:      return res.status(402).json({ status: "declined", motivo: venda.failure_reason });  }});
3

Conclua o desafio quando vier 201 requires_action

O action é opaco: devolva-o ao seu front exatamente como veio e chame Zendry.completeThreeDS. Sem desafio de fato (frictionless), ele resolve em segundos, sem tela.

No navegador
201
const desfecho = await Zendry.completeThreeDS(venda.action); if (desfecho.status === "authorized") mostrarSucesso();else if (desfecho.status === "expired") pedirNovaTentativa();else mostrarRecusa(); // isto é UX. O pedido só é liberado depois da confirmação do seu servidor.
4

Confirme o desfecho no servidor

O retorno do SDK é para a tela; a verdade é o webhook (ou o GET /api/public/v1/card_payments/:id). Valide a assinatura HMAC antes de liberar qualquer pedido.

Recebendo card.approved
import crypto from "node:crypto"; app.post("/webhooks/zendry", express.raw({ type: "*/*" }), (req, res) => {  const assinatura = req.headers["x-zendry-signature"];  const esperado = crypto    .createHmac("sha256", process.env.ZENDRY_WEBHOOK_SECRET)    .update(req.body)    .digest("hex");   if (assinatura !== 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();});
Desfechos
CampoTipoObrigatórioDescrição
aprovada (200)mostre o sucessoNãoWebhook card.approved confirma. Libere o pedido nele.
requires_action (201)chame completeThreeDSNãoApós o desafio chega card.approved ou card.declined. Sem conclusão em 15 min, a venda expira.
recusada (200)ofereça outro cartãoNãofailure_reason traz o motivo. Webhook card.declined.
422corrija a requisiçãoNãoerror_type nomeia a causa (ex.: INVALID_REQUEST com device ausente em postura reforçada).
  • Envie device em TODA venda: aumenta a taxa de aprovação, e contas com postura de risco reforçada recusam a requisição sem ele (422).
  • action.session_id é de uso único e expira em 15 minutos — se o comprador não concluir, a venda expira e é recusada.
  • Nunca libere o pedido pelo retorno do SDK: só o webhook (ou o GET) é o resultado oficial.
  • Não reaproveite o mesmo action em outra tentativa — crie uma nova venda.
Experimentar

No sandbox o cartão é simulado sem 3DS real: qualquer número válido aprova e 4000 0000 0000 0002 recusa (use o console do endpoint Pagamento com cartão). O desafio 3DS de verdade só acontece em produção.

POST
/api/public/v1/card_payments

Pagamento com cartão

Cobra um cartão de crédito server-to-server. Exige cartão habilitado para a conta. O número do cartão nunca é armazenado.

  • Sandbox (chave gw_test_): a autorização é simulada — qualquer número de cartão válido APROVA e 4000 0000 0000 0002 RECUSA; sem 3DS; o estorno também é simulado.
  • 201 + status requires_action: conclua no navegador com Zendry.completeThreeDS(resposta.action) — veja o guia Checkout & 3DS acima. O desfecho oficial chega pelo webhook card.approved / card.declined e pelo GET abaixo.
  • Recusa NÃO é erro HTTP: vem 200 com state declined e failure_reason legível.
  • Erros de negócio vêm como 422 no formato { error, error_type, error_code, retry } — catálogo na seção Erros & limites.
  • Se sua plataforma revende para lojistas (gateway em cadeia), envie ip_address e user_agent do comprador final — os cabeçalhos HTTP trazem o seu servidor, não o comprador.
Parâmetros
CampoTipoObrigatórioDescrição
amount_centsinteiro
Sim
Valor em centavos.
installmentsinteiroNão1 a 12. Padrão 1.
buyerobjeto
Sim
name, email e taxpayer_id (CPF, 11 dígitos).
cardobjeto
Sim
holder_name, number, expiration_month (MM), expiration_year (AAAA) e security_code.
billingobjetoNãoEndereço de cobrança.
deviceobjetoNãoDados do dispositivo do comprador coletados pelo Zendry.js (Zendry.threeDS()). Aumenta a aprovação — e contas com postura de risco reforçada EXIGEM este campo. Campos: language, screen_height, screen_width, time_zone_offset (horas, Brasil = -3).
ip_addresstextoNãoIP do COMPRADOR. Obrigatório na prática em integração em cadeia.
user_agenttextoNãoUser-agent do COMPRADOR.
external_idtextoNãoSeu identificador.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/card_payments \  -H "Authorization: Bearer gw_sua_chave_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 ..."}'
Resposta — aprovada ou recusada
200
{  "id": "7d21...",  "charge_id": "1b8e...",  "state": "approved",  "amount_cents": 15000,  "installments": 1,  "external_id": "1234",  "created_at": "2026-01-01T12:00:00Z"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/card_payments/:id

Consultar transação de cartão

Retorna a transação pelo id devolvido na criação — inclusive para acompanhar o desfecho de um 3DS.

  • state: approved | declined | refunded | requires_action.
  • nsu: o NSU do comprovante. null quando a venda não chegou à rede (recusa antes da autorização, sandbox).
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/card_payments/:id \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

POST
/api/public/v1/card_payments/:id/refund

Estornar transação

Estorno total. Disponível apenas para transações aprovadas e dentro de 24 horas da aprovação.

  • Após 24h ou em transação não aprovada: 422 com a razão no campo error.
  • O evento card.refunded é disparado no webhook de recebimento.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/card_payments/:id/refund \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "id": "7d21...",  "state": "refunded",  "refunded_at": "2026-01-01T18:22:40Z"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

Cripto (USDT)

POST
/api/public/v1/crypto_payouts

Converter em USDT e enviar (saque cripto)

Converte o valor em reais para USDT na cotação do momento e envia para a carteira informada. Os reais saem do saldo na hora; o USDT fica bloqueado até a confirmação on-chain, que chega pelo webhook crypto.sent.

  • state: requested → completed (webhook crypto.sent, com tx_hash) ou failed (webhook crypto.failed; o USDT volta ao saldo disponível em USDT — a conversão dos reais não é desfeita).
  • usdt_amount é o que chega na carteira: o USDT convertido, menos a tarifa de saída em USDT (fee_usdt_minor). applied_rate é a cotação da conversão: reais pagos por USDT convertido (amount_cents ÷ (usdt_amount_minor + fee_usdt_minor), nas unidades de cada moeda). No envio a partir do saldo em USDT não há conversão: applied_rate vem 0.
  • 409 quando o saldo em reais é insuficiente. 422 quando a conversão BRL → USDT não está liberada para a conta ou o valor fere um limite de saque.
  • Idempotência: mande o header Idempotency-Key. Repetir a chamada com a MESMA chave devolve o saque já criado, sem converter de novo.
  • Envio a partir do saldo em USDT: mande usdt_amount_minor em vez de amount_cents. É o caminho para reenviar um saque que falhou (o USDT volta ao saldo, não a reais). amount_cents na resposta vem 0 nesse caso.
  • Sandbox: o desfecho é imediato — valor terminado em 99 centavos simula falha, os demais concluem sem tx_hash (o sandbox não vai à rede; identificador de rede nunca é inventado).
Parâmetros
CampoTipoObrigatórioDescrição
amount_centsinteiroNãoValor em reais, em centavos. De 1 a 100000000. Valem o mínimo, o máximo e o teto diário de saque da conta.
usdt_amount_minorinteiroNãoAlternativa a amount_cents: envia USDT que já está no seu saldo (menor unidade, 6 casas), sem converter. Informe um dos dois.
wallettexto
Sim
Endereço da carteira de destino, na rede escolhida.
networktrc20 | erc20 | bep20 | polygon
Sim
Rede do envio: TRON (TRC20), Ethereum (ERC20), BNB Smart Chain (BEP20) ou Polygon.
descriptiontextoNãoAté 140 caracteres.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/crypto_payouts \  -H "Authorization: Bearer gw_sua_chave_aqui" \  -H "Content-Type: application/json" \  -d '{  "amount_cents": 50000,  "wallet": "TKcXiZ1ovginwWvoCHZwwSPn7ZUhCA7Ndg",  "network": "trc20",  "description": "Repasse"}'
Resposta
200
{  "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}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/crypto_payouts/{id}

Consultar saque cripto

Devolve o estado atual de um saque USDT pelo id da criação. Use quando a entrega do webhook crypto.sent falhar ou para reconciliar.

  • 404 se o id não existir ou pertencer a outra conta. Chave de teste só enxerga saque sandbox.
  • tx_hash só vem preenchido em completed; failure_reason só em failed.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/crypto_payouts/{id} \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/crypto_payouts

Listar saques cripto

Lista os saques USDT da conta, do mais recente para o mais antigo. Filtre por status para achar o que ainda está em andamento.

  • status=requested devolve o que ainda não teve desfecho — é a consulta para conciliar quando o webhook não chegou.
  • 422 se o status não for um dos três.
Parâmetros
CampoTipoObrigatórioDescrição
statusrequested | completed | failedNãoSem este campo, devolve todos.
limitinteiroNãoDe 1 a 100. Padrão 50.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/crypto_payouts \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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    }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

Disputas

GET
/api/public/v1/disputes

Listar disputas

Disputas (MED e chargeback) da sua conta, das mais recentes para as mais antigas. A abertura chega pelo webhook dispute.opened; use a lista para acompanhar o estado.

  • `transaction_identifier` é o mesmo valor da coluna Identificador da sua lista de transações, e `charge_id` é a cobrança — use um dos dois para achar a venda no portal. `transaction_reference` continua existindo para quem já integrou.
  • O valor da disputa é sempre o da transação inteira — não existe disputa parcial.
  • Enquanto viva, o valor fica retido do saldo disponível; o desfecho chega pelo webhook dispute.closed (outcome won/lost).
Parâmetros
CampoTipoObrigatórioDescrição
statusopen | closed | exatoNãoopen = vivas (open, under_defense, under_review); closed = won e lost; ou um state exato.
limitinteiroNãoDe 1 a 100. Padrão 50.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/disputes \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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    }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/disputes/:id

Consultar disputa

Detalhe completo: dados da disputa, histórico de mensagens (author: seller = você, zendry = nós) e evidências já anexadas.

  • 404 se o id não existir ou pertencer a outra conta.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/disputes/:id \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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": "Serviço prestado, comprovante anexo.", "created_at": "2026-01-02T09:30:00Z" }  ],  "evidence": [    { "name": "comprovante-entrega.pdf", "content_type": "application/pdf", "size_bytes": 182044, "created_at": "2026-01-02T09:29:00Z" }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

POST
/api/public/v1/disputes/:id/defense

Enviar defesa

Registra a sua defesa por escrito e move a disputa para under_defense. Anexe as evidências antes ou depois — a defesa pode ser complementada enquanto a disputa estiver viva.

  • 422 se a disputa já estiver encerrada (won ou lost).
Parâmetros
CampoTipoObrigatórioDescrição
texttexto
Sim
A argumentação da defesa. De 5 a 4000 caracteres.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/disputes/:id/defense \  -H "Authorization: Bearer gw_sua_chave_aqui" \  -H "Content-Type: application/json" \  -d '{  "text": "Serviço prestado em 01/01, aceite do cliente no app. Comprovante anexo."}'
Resposta
200
{  "id": "19ba...",  "state": "under_defense"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

POST
/api/public/v1/disputes/:id/evidence

Anexar evidência

Envia UM arquivo de evidência (comprovante de entrega, aceite, conversa com o cliente). O corpo é multipart/form-data com o campo `file` — o arquivo em si, não base64. Para vários arquivos, repita a chamada.

  • Exemplo: curl -X POST .../disputes/{id}/evidence -H "Authorization: Bearer …" -F "file=@comprovante.pdf"
  • 413 acima de 15MB; 415 se o formato não for um dos aceitos; 422 se a disputa já estiver encerrada.
Form-data
CampoTipoObrigatórioDescrição
filearquivo
Sim
Até 15MB. PDF, imagem (PNG, JPEG, GIF, WEBP, HEIC), documento (DOC, DOCX, ODT, RTF, TXT) ou planilha (XLS, XLSX, ODS, CSV).
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/disputes/:id/evidence \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "id": "19ba...",  "name": "comprovante-entrega.pdf",  "size_bytes": 182044}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

POST
/api/public/v1/disputes/:id/accept

Não contestar

Declara que você não vai se defender desta disputa. Ela segue para análise e o desfecho é comunicado pelo webhook dispute.closed.

  • Aceita apenas disputas em open ou under_defense (422 nos demais estados).
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/disputes/:id/accept \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "id": "19ba...",  "state": "under_review"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

Consultas

GET
/api/public/v1/balance

Consultar saldo

Retorna o saldo disponível da conta autenticada.

Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/balance \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "balance_cents": 84851,  "currency": "BRL"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/statement

Extrato

Lista as movimentações da conta, das mais recentes para as mais antigas (até 200 itens).

  • Limite fixo de 200 itens por chamada — use from/to para paginar por período.
  • Para conciliação em tempo real prefira os webhooks; o extrato é a fonte para fechamento e auditoria.
Parâmetros de query
CampoTipoObrigatórioDescrição
fromdata (AAAA-MM-DD)NãoDia inicial, fuso de Brasília.
todata (AAAA-MM-DD)NãoDia final, fuso de Brasília.
typetextoNãoFiltra pelo campo "type" das respostas (ex.: pagamento_confirmado).
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/statement \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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"    }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

Endpoints de webhook

GET
/api/public/v1/webhook_events

Listar eventos assináveis

Catálogo dos eventos que um endpoint pode assinar, com família e descrição. Use o nome exato no campo events.

  • Só entram eventos que já têm emissor — o catálogo cresce sem quebrar assinaturas existentes.
  • "*" não aparece na lista, mas é aceito em events: assina todos os eventos, inclusive os futuros.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/webhook_events \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "events": [    { "event": "pix.received", "family": "Pix", "description": "Cobrança Pix paga" },    { "event": "pix.sent", "family": "Saque Pix", "description": "Saque Pix concluído" },    { "event": "dispute.opened", "family": "Disputa", "description": "Disputa (MED/chargeback) aberta" }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/webhook_endpoints

Listar endpoints

Todos os endpoints da conta, inclusive os espelhos dos canais fixos (managed: true).

  • managed: true é o espelho de um canal fixo (recebimento, saque, infração): URL e eventos mudam pela tela Integrações; a API só lê, testa e consulta entregas.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/webhook_endpoints \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "endpoints": [    {      "id": "e7a1...",      "url": "https://sualoja.com/webhooks/saques",      "label": "ERP financeiro",      "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"    }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

POST
/api/public/v1/webhook_endpoints

Criar endpoint

Cadastra uma URL e os eventos que ela recebe. O mesmo evento pode ir para várias URLs; cada entrega é assinada com o segredo da conta.

  • Até 10 endpoints por conta (os espelhos dos canais fixos não contam) — 422 webhook_endpoint_limit_reached.
  • 422 webhook_url_invalid para URL fora da regra; 422 webhook_event_unknown para evento fora do catálogo.
  • Teste a URL logo após criar (POST /webhook_endpoints/:id/test).
Parâmetros
CampoTipoObrigatórioDescrição
urltexto
Sim
HTTPS com host público (sem IP privado, localhost ou porta fora do padrão).
eventslista de texto
Sim
Nomes do catálogo, ou ["*"] para todos.
labeltextoNãoNome de exibição, até 80 caracteres.
activebooleanoNãoPadrão true. Inativo não recebe nada.
dialecten | ptNãoPadrão en. pt entrega os campos no formato legado (só para quem migrou do zendry.com).
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/webhook_endpoints \  -H "Authorization: Bearer gw_sua_chave_aqui" \  -H "Content-Type: application/json" \  -d '{  "url": "https://sualoja.com/webhooks/saques",  "label": "ERP financeiro",  "events": [    "pix.sent",    "crypto.sent",    "crypto.failed"  ]}'
Resposta
201 Created
{  "id": "e7a1...",  "url": "https://sualoja.com/webhooks/saques",  "label": "ERP financeiro",  "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"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

PATCH
/api/public/v1/webhook_endpoints/:id

Consultar, atualizar ou remover endpoint

GET devolve o endpoint; PATCH altera só os campos enviados; DELETE remove (204, sem corpo).

  • 404 webhook_endpoint_not_found se o id não existir ou for de outra conta.
  • 409 webhook_endpoint_managed em PATCH/DELETE num espelho de canal fixo — altere pela tela Integrações.
  • Falhas seguidas ficam em consecutive_failures e last_failed_at; o endpoint não é desativado sozinho — acompanhe e corrija a URL.
Parâmetros
CampoTipoObrigatórioDescrição
urltextoNãoMesma regra da criação.
eventslista de textoNãoSubstitui a lista inteira.
labeltextoNãoAté 80 caracteres.
activebooleanoNãofalse pausa as entregas sem apagar o endpoint.
dialecten | ptNãoFormato dos campos de data.
Requisição
finance.zendry.co
curl -X PATCH https://finance.zendry.co/api/public/v1/webhook_endpoints/:id \  -H "Authorization: Bearer gw_sua_chave_aqui" \  -H "Content-Type: application/json" \  -d '{  "events": [    "pix.sent"  ],  "active": true}'
Resposta
200
{  "id": "e7a1...",  "url": "https://sualoja.com/webhooks/saques",  "label": "ERP financeiro",  "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"}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

POST
/api/public/v1/webhook_endpoints/:id/test

Testar endpoint

Entrega na hora um evento de exemplo, assinado como uma entrega real, com test: true no envelope e o cabeçalho X-Zendry-Test.

  • Uma tentativa só, sem repetição; o resultado também fica no histórico de entregas.
  • Ignore entregas com test: true no seu processamento de negócio — os ids em data são fictícios.
Parâmetros
CampoTipoObrigatórioDescrição
eventtexto
Sim
Evento do catálogo cujo exemplo será enviado.
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/webhook_endpoints/:id/test \  -H "Authorization: Bearer gw_sua_chave_aqui" \  -H "Content-Type: application/json" \  -d '{  "event": "pix.sent"}'
Resposta
200
{  "result": "delivered",  "http_status": 200,  "duration_ms": 184,  "response": "ok",  "error": null}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

GET
/api/public/v1/webhook_endpoints/:id/deliveries

Entregas de um endpoint

Últimas tentativas de entrega ao endpoint, da mais recente para a mais antiga.

  • message_id é o X-Zendry-Webhook-Id daquela mensagem: reentregas e repetições compartilham o valor.
  • result: delivered, failed ou no_destination.
Parâmetros
CampoTipoObrigatórioDescrição
limitinteiroNãoQuery string. Padrão 50, máximo 200.
eventtextoNãoQuery string. Filtra por evento.
Requisição
finance.zendry.co
curl -X GET https://finance.zendry.co/api/public/v1/webhook_endpoints/:id/deliveries \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "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"    }  ]}
Experimentar

Crie sua conta para executar esta chamada no sandbox, com chave de teste e dados isolados.

Webhooks

Como funcionam

Configure em Integrações os canais fixos — recebimento (cobranças, cartão, assinaturas), saque (pix.sent e demais saídas) e infração (disputas) — ou cadastre endpoints por evento, escolhendo quais eventos cada URL recebe. Enviamos um POST JSON com os cabeçalhos X-Zendry-Event, X-Zendry-Webhook-Id e X-Zendry-Signature: sha256=<hmac>.

Envelope
{  "id": "b0d3c1e2-...",  "event": "pix.received",  "sent_at": "2026-01-01T12:04:12Z",  "data": { ...campos do evento... }}
Exemplos de data
{  "charge_id": "3f1c...",  "external_id": "1234",  "amount_cents": 15000,  "description": "Pedido #1234",  "end_to_end_id": "E1823612...",  "environment": "producao",  "state": "paid"}
Verificando a assinatura (HMAC-SHA256 sobre o corpo bruto)
const crypto = require("node:crypto"); function assinaturaValida(corpoBruto, cabecalho, segredo) {  const esperada =    "sha256=" + crypto.createHmac("sha256", segredo).update(corpoBruto).digest("hex");  return (    cabecalho?.length === esperada.length &&    crypto.timingSafeEqual(Buffer.from(esperada), Buffer.from(cabecalho))  );}// assinaturaValida(rawBody, req.headers["x-zendry-signature"], SEGREDO)
  • Responda 2xx em até 10 segundos; processe de forma assíncrona se precisar.
  • Em falha (rede, timeout ou status ≥ 400) tentamos até 3 vezes, com espera crescente.
  • Toda entrega e reentrega fica registrada em Integrações — de lá você reenvia um evento perdido.
  • Trate entregas por charge_id/payout_id de forma idempotente: reentregas do mesmo evento podem ocorrer.

Endpoints por evento

Além dos canais fixos, cadastre até 10 URLs e escolha os eventos de cada uma — pela tela Integrações ou pela API (/api/public/v1/webhook_endpoints). O mesmo evento pode ir para mais de uma URL; events: ["*"] assina tudo, inclusive eventos futuros.

  • Toda entrega leva X-Zendry-Webhook-Id (o mesmo valor em id, no envelope). Reentregas repetem o valor — use-o para deduplicar.
  • Os canais fixos aparecem na lista como espelhos (managed: true): URL e eventos editam-se nos campos fixos; ali você testa e acompanha a saúde.
  • O segredo de assinatura é um só por conta: o mesmo HMAC vale para todos os endpoints.
  • Falhas seguidas ficam visíveis (consecutive_failures, last_failed_at); nada é desativado automaticamente.

Catálogo de eventos

21 eventos
Pix
  • pix.receivedCobrança Pix paga (canal de recebimento)
  • pix.sentSaque Pix concluído ou falhou (canal de saque)
Boleto
  • boleto.paidBoleto compensado
Cartão
  • card.approvedTransação aprovada (inclusive após 3DS). O campo nsu traz o NSU do comprovante
  • card.declinedTransação recusada
  • card.refundedTransação estornada
Cobrança
  • charge.expiredCobrança expirou sem pagamento
  • charge.canceledCobrança cancelada
Disputas
  • dispute.openedContestação (chargeback/MED) aberta — webhook de infração
  • dispute.closedContestação encerrada — webhook de infração
Assinaturas
  • subscription.createdAssinatura criada
  • subscription.charge_approvedCobrança recorrente aprovada
  • subscription.charge_declinedCobrança recorrente recusada
  • subscription.retry_scheduledNova tentativa agendada
  • subscription.retries_exhaustedTentativas esgotadas
  • subscription.canceledAssinatura cancelada
  • subscription.completedAssinatura concluída
Cripto & Internacional
  • crypto.sentEnvio cripto concluído
  • crypto.failedEnvio cripto falhou
  • intl.deposit.receivedDepósito internacional recebido
  • intl.payout.sentEnvio internacional concluído

Sandbox

Ambiente de testes

Gere uma chave de teste na página Integrações (prefixo gw_test_). Ela usa a mesma URL base e as mesmas rotas, mas opera um ambiente isolado: saldo, extrato e cobranças de teste ficam separados de produção e nenhum dinheiro real circula — o Pix é simulado internamente, sem movimentar dinheiro.

  • Cobertura: Pix completo, boleto e cartão (criação, consulta, pagamento/autorização simulados, estorno) — com webhooks e saldo de teste.
  • Boleto: emite com números de teste (linha digitável/código de barras fake) e paga pelo mesmo POST /charges/:id.
  • Cartão: simulado sem 3DS — qualquer número válido aprova; 4000 0000 0000 0002 recusa; estorno também é simulado.
  • Os webhooks são reais (mesma URL e assinatura HMAC), com environment: "sandbox" no payload.
  • Identificadores da rede (end_to_end_id, nsu, tx_hash) vêm null no sandbox: nada é inventado.
  • Chave de teste não enxerga dados de produção, e vice-versa.
  • Saque de teste conclui na hora (webhook pix.sent). Valor terminado em 99 centavos (ex.: 10099) simula falha — o valor volta ao saldo.
POST
/api/public/v1/charges/:id

Simular pagamento (sandbox)

Marca a cobrança de teste (Pix OU boleto) como paga: lança no saldo sandbox e dispara o webhook real (pix.received ou boleto.paid), com assinatura HMAC. Exclusivo da chave de teste — em produção retorna 403.

  • Só funciona com chave gw_test_ e cobrança do ambiente sandbox (senão 403/404).
  • Idempotente: cobrança já paga responde com already_paid: true.
  • Cobrança expirada não pode ser paga (422).
Requisição
finance.zendry.co
curl -X POST https://finance.zendry.co/api/public/v1/charges/:id \  -H "Authorization: Bearer gw_sua_chave_aqui"
Resposta
200
{  "id": "3f1c...",  "state": "paid",  "paid_at": "2026-01-01T12:04:11Z"}
Experimentar

Crie sua conta para simular pagamentos no sandbox com sua chave de teste.

Erros & limites

Envelope padrão

Todo erro sai neste formato. code é o contrato estável — trate por ele, nunca pela mensagem, que existe para o humano que lê o log e pode mudar. retryable diz se repetir a MESMA requisição pode dar certo, e details só aparece quando há o que mostrar (campo inválido, limite e valor enviado).

Formato
422
{  "error": "Amount is above the maximum for this operation",  "code": "amount_above_maximum",  "retryable": false}
Catálogo de códigos
codeHTTPretryableerror (chave nova)
Autenticação e acesso
missing_credentials
401
falseCredential missing
invalid_credentials
401
falseInvalid credential
ip_not_allowed
403
falseIP not allowed for this key
Requisição inválida
invalid_json
400422 na chave legada
falseRequest body is not valid JSON
invalid_payload
422
falseInvalid payload
sandbox_only
422
falseOnly available in the sandbox environment
Limites e valores
amount_below_minimum
422
falseAmount is below the minimum for this operation
amount_above_maximum
422
falseAmount is above the maximum for this operation
daily_limit_exceeded
422
falseDaily limit exceeded
Saldo e bloqueios
insufficient_balance
409
falseInsufficient balance
Recurso e estado
charge_not_found
404
falseCharge not found
payout_not_found
404
falsePayout not found
charge_already_paid
422
falseCharge already paid
charge_expired
422
falseCharge expired
charge_finalized
422
falseCharge already finalized
transaction_not_found
404
falseTransaction not found
Pagamento
payment_method_not_enabled
422
falseThis payment method is not enabled for this account
card_declined
422
falseThe card payment was declined
Disputas e arquivos
dispute_not_found
404
falseDispute not found
dispute_closed
422
falseDispute already closed
dispute_action_not_allowed
422
falseThis dispute no longer accepts this action
file_missing
422
falseSend multipart/form-data with a `file` field
file_too_large
413
falseFile is larger than 15MB
file_type_not_allowed
415
falseSend a PDF, image, document or spreadsheet
Webhooks
webhook_endpoint_not_found
404
falseWebhook endpoint not found
webhook_url_invalid
422
falseWebhook URL must use https and a public host
webhook_event_unknown
422
falseUnknown webhook event
webhook_endpoint_limit_reached
422
falseMaximum number of webhook endpoints reached
webhook_endpoint_managed
409
falseThis endpoint mirrors a fixed channel; edit it in the integration settings
Falha nossa
service_unavailable
503422 na chave legada
true
The operation could not be completed. Please try again in a few moments.
internal_error
500422 na chave legada
true
The operation could not be completed. Please try again in a few moments.
  • Chaves antigas (contrato legado) seguem recebendo a mensagem em português e o status HTTP de sempre; `code`, `retryable` e `details` entram ao lado, sem quebrar quem já integra.
  • Nenhum detalhe interno aparece na resposta. A operação que não pôde ser concluída agora vira `service_unavailable` (503); falha inesperada do nosso lado, `internal_error` (500). As duas dizem "Não foi possível concluir a operação. Tente novamente em alguns instantes.", e o motivo fica no nosso log.
  • Antes de repetir um POST que movimenta dinheiro depois de um erro `retryable`, consulte o recurso pelo GET — a API não aceita chave de idempotência do cliente.

Códigos HTTP

Status
CampoTipoObrigatórioDescrição
400formatoNãoCorpo não é JSON válido.
401authNãoCredencial ausente, inválida ou revogada.
403acessoNãoIP fora da lista de permitidos.
404recursoNãoRecurso inexistente ou de outra conta.
409conflitoNãoSaldo insuficiente no saque, ou endpoint que espelha canal fixo.
413arquivoNãoEvidência de disputa acima de 15MB.
415arquivoNãoEvidência de disputa num formato não aceito.
422validaçãoNãoPayload inválido, limite da conta ou regra de negócio. Traz details.
500nossoNãoFalha inesperada do nosso lado; retryable: true.
503indisponívelNãoA operação não pôde ser concluída agora; tente de novo em instantes (retryable: true).
422 — payload inválido
422
{  "error": "Payload inválido",  "details": [    { "path": ["amount_cents"], "message": "Number must be greater than or equal to 1" }  ]}

Erros de cartão

As rotas de cartão usam um formato próprio no 422 — retry indica se vale tentar novamente a mesma requisição.

Formato
422
{  "error": "Meio de pagamento não habilitado para esta conta",  "error_type": "INVALID_REQUEST",  "error_code": "payment_method_not_enabled",  "retry": false}
error_type
CampoTipoObrigatórioDescrição
PAYMENT_DECLINEDretry: falseNãoPagamento recusado; ofereça outro cartão.
INVALID_REQUESTretry: falseNãoDado inválido, ou cartão não habilitado para a conta (error_code payment_method_not_enabled).
PENDING_CHECKretry: falseNãoPagamento em verificação; aguarde o webhook ou consulte o GET antes de repetir.
TEMPORARY_ERRORretry: trueNãoNão foi possível concluir agora; tente novamente em instantes.
INTERNAL_ERRORretry: trueNãoFalha nossa; tente novamente.

Limites & boas práticas

Valor por operação
Definido por conta
Mínimo e máximo por meio; 100.000.000 centavos é o teto absoluto do payload.
Cartão
1 a 12 parcelas
Estorno total em até 24h da aprovação.
Textos
140 caracteres
description e external_id.
Extrato
200 itens por chamada
Pagine por from/to.
  • Cada conta tem mínimo e máximo por meio (Pix, cartão, boleto e saque), e o saque tem teto diário; o saque em USDT tem máximo e teto diário próprios, em USDT. Fora da faixa a API recusa com amount_below_minimum, amount_above_maximum ou daily_limit_exceeded. A resposta não traz os valores dos limites: eles ficam no painel.
  • Idempotência: a API não aceita chave de idempotência do cliente. Em timeout de um POST que movimenta dinheiro (saque, cartão), consulte o extrato/GET antes de repetir.
  • Confirmação de pagamento é por webhook; se fizer reconsulta, limite a frequência (ex.: a cada 30s) — tráfego abusivo pode ser bloqueado pelo firewall.