Skip to Content
View as Markdown

Erros

Toda resposta 4xx/5xx carrega o mesmo envelope JSON:

{ "code": 400, "message": "invalid_input", "details": [ { "field": "items[0].unit_price", "message": "must be a positive decimal string" } ] }
  • code — o status HTTP numérico (400, 401, 404, …). Útil para tratamento genérico na camada HTTP, mas para lógica de ramificação faça switch em message em vez disso — code não vai desambiguar entre, digamos, invalid_input e payment_method_not_supported (ambos 400).
  • message — o nome sentinela em lower-snake-case (por exemplo, INVALID_INPUT vira "invalid_input"). Estável entre releases — faça switch nisso.
  • details — preenchido em erros de validação. Array de objetos { field, message } para que o cliente possa amarrar erros a inputs. Omitido caso contrário.

Os corpos de erro não incluem trace ID nem timestamp. Para reportar um problema, envie ao suporte o header Date da resposta, os headers X-RateLimit-*, o ID do seu lojista, o endpoint e o horário aproximado da requisição.

Falhas de autenticação usam um formato diferente. O envelope acima é o que a API retorna na maioria dos erros. Requisições rejeitadas antes de serem processadas (um X-Signature ausente/inválido, um X-Client-ID desconhecido ou um X-Timestamp velho numa chamada /b2b/v1/*) voltam como { "error": "...", "message": "..." }, onde error é um slug grosseiro (unauthorized / bad_request / service_unavailable) e message carrega as especificidades. Não há code numérico nem details. Ramifique primeiro pelo status HTTP, depois leia message. Exemplo (401):

{ "error": "unauthorized", "message": "invalid signature" }

Status HTTP → códigos típicos

HTTPValores típicos de codeO que significa
400INVALID_INPUT, MISSING_REQUIRED, INVALID_FORMAT, INVALID_LENGTH, INVALID_VALUE, PAYMENT_METHOD_NOT_SUPPORTED, AMOUNT_BELOW_MINIMUMRequisição ruim — olhe details
401INVALID_CREDENTIALS, INVALID_TOKEN, TOKEN_EXPIRED, INVALID_SIGNATURE (B2B); SESSION_EXPIRED (só dashboard)Auth falhou — chave ruim, timestamp expirado, assinatura errada. Os códigos de login do dashboard não são relevantes para integrações B2B.
402INSUFFICIENT_CREDITSaldo pré-pago do lojista acabou — recarregue antes de retentar
403FORBIDDEN, IP_BLOCKEDChave é válida, mas não tem o escopo/permissão de IP para esta chamada
404NOT_FOUND, RECORD_NOT_FOUNDRecurso não existe (ou não existe para este lojista)
409ALREADY_EXISTSReplay de idempotência com body diferente, ou a máquina de estados recusou a transição
429TOO_MANY_REQUESTS, TOO_MANY_ATTEMPTSRate limit batido; backoff e retente
500INTERNAL_SERVER_ERROR, EXTERNAL_SERVICE_ERRORErro nosso; seguro retentar com backoff.
503SERVICE_UNAVAILABLEUma dependência downstream caiu. Retente com backoff

Referência completa de códigos

Os valores de code que você pode ver:

Autenticação (401)

  • INVALID_CREDENTIALS — combinação de chaves de API rejeitada
  • INVALID_TOKEN — token não-parseável ou adulterado
  • TOKEN_EXPIRED — token expirado
  • SESSION_EXPIRED — sessão do dashboard expirou
  • INVALID_SIGNATURE — assinatura HMAC não bate em chamadas B2B / webhook

Autorização (403)

  • FORBIDDEN — autenticado, mas você não tem permissão para realizar esta ação
  • IP_BLOCKED — requisições deste endereço IP estão bloqueadas

Não encontrado (404)

  • NOT_FOUND — genérico
  • RECORD_NOT_FOUND — linha ausente para o ID dado

Conflito (409)

  • ALREADY_EXISTS — genérico

Validação (400)

  • INVALID_INPUT — genérico; cheque details
  • MISSING_REQUIRED — um campo obrigatório estava ausente
  • INVALID_FORMAT — valor não combinou com o formato esperado (por exemplo, UUID, URL, e-mail)
  • INVALID_LENGTH — valor muito curto ou muito longo
  • INVALID_VALUE — valor fora do enum/range permitido
  • PAYMENT_METHOD_NOT_SUPPORTED — combinação provider/ativo não está habilitada para o lojista
  • AMOUNT_BELOW_MINIMUM — valor do pedido abaixo do piso por rede ou por ambiente. A resposta traz details.floor_usd com o piso configurado (em USD), então você pode exibi-lo diretamente; o texto de message também o informa.
  • INSUFFICIENT_BALANCE — a carteira do comprador não tem saldo suficiente do ativo de pagamento para cobrir a transferência.
  • INSUFFICIENT_GAS — a carteira do comprador não tem gas nativo suficiente para transmitir a transferência.

Pagamento / faturamento (402)

  • INSUFFICIENT_CREDIT — saldo pré-pago do lojista não consegue cobrir a taxa de rede (gas) / taxa da plataforma. Recarregue pelo dashboard, depois retente

Rate limiting (429)

  • TOO_MANY_REQUESTS — rate limit de IP excedido
  • TOO_MANY_ATTEMPTS — tentativas falhadas repetidas no mesmo recurso (por exemplo, OTP) dispararam um throttle

Erros de servidor (500)

  • EXTERNAL_SERVICE_ERROR — um provedor terceiro falhou
  • INTERNAL_SERVER_ERROR — erro inesperado; fale com o suporte informando o header Date da resposta e os headers X-RateLimit-*

Disponibilidade (503)

  • SERVICE_UNAVAILABLE — o serviço está temporariamente indisponível; retente com backoff

Erros de validação (400)

Quando o problema é um body de requisição malformado, details é um array para que você possa mapear erros de volta para campos:

{ "code": 400, "message": "invalid_input", "details": [ { "field": "items[0].unit_price", "message": "must be a positive decimal string" }, { "field": "success_url", "message": "must be a valid https URL" } ] }

Erros de auth (401)

INVALID_SIGNATURE tem três causas comuns:

  • Chave secreta errada (re-cheque a env var)
  • Defasagem de timestamp > 5 min (sincronize NTP)
  • String canônica errada (mais comum: esqueceu os separadores \n ou assinou um body parseado-e-re-stringificado que difere do que você mandou)

Veja Autenticação para o algoritmo exato de assinatura.

Rate limits (429)

SuperfícieLimite
Todas as rotas da API (incl. /b2b/v1/*)Por endereço IP — 500 req/min, bucket compartilhado. Não por lojista.
Checkout público (/checkout/*)Sub-bucket mais estrito — 20 req/min por IP

X-RateLimit-Limit e X-RateLimit-Remaining são incluídos em toda resposta com rate limit, não só nas de sucesso. Trate como o orçamento vivo para o seu IP.

Respostas com rate-limit incluem um header Retry-After (segundos até a janela resetar) — honre-o. Como fallback, backoff com jitter — 1s base + exponencial até 30s.

Os rate limits podem mudar. Se você os atinge com tráfego legítimo (por exemplo, reconciliando uma faixa histórica grande), fale com o suporte.

Crédito insuficiente (402)

INSUFFICIENT_CREDIT (HTTP 402 Payment Required) significa que o seu saldo pré-pago não consegue cobrir a taxa de rede (gas) e a taxa da plataforma para a operação que você tentou, tipicamente liquidar um pagamento cripto ou uma ação on-chain cuja taxa de rede é patrocinada. Recarregue pelo dashboard do lojista (Billing → Add credit), depois retente a operação. Operações já em andamento continuam automaticamente depois que o saldo é recarregado.

Erros de servidor (5xx)

Um 500 significa que a gente não conseguiu processar a requisição. Retente com backoff — a sua idempotency_key garante que você não vai cobrar em dobro se a requisição original parcialmente teve sucesso.

Se as retentativas não recuperam em um minuto, exiba um genérico “pagamento temporariamente indisponível” para o comprador e fale com o suporte com o endpoint que falhou, o ID do seu lojista, o header Date da resposta e os valores X-RateLimit-*, e o horário aproximado da requisição — isso é o suficiente para a gente localizar a requisição.

Erros de entrega de webhook

Entregas de webhook são um canal de falha separado — não aparecem como erros de API porque não é o seu servidor que está chamando. Quando uma entrega retorna não-2xx (ou dá timeout), ela é retentada com backoff exponencial em 0s, 1min, 5min, 15min, 1h, 6h (seis tentativas no total, o mesmo cronograma de Webhooks → Visão geral). O histórico completo por entrega aparece em Developers → Webhooks → [endpoint] → Delivery log no dashboard. Depois da sexta tentativa a entrega é marcada como “Failed” no dashboard, e você pode reenviá-la manualmente assim que o seu servidor estiver saudável.