Como tratar erros
Os formatos de erro da API, como distinguir erro HTTP de cobrança recusada, e quando é seguro repetir uma chamada.
Uma integração de pagamento convive com três tipos de "não deu certo", e cada um pede uma reação diferente:
| Tipo | Como chega | Exemplo | Reação |
|---|---|---|---|
| Erro da requisição | HTTP 4xx | Valor com decimais, CEP ausente | Corrigir a requisição. Repetir igual não adianta. |
| Pagamento recusado | HTTP 201 com status: "Failed" | Saldo insuficiente no cartão | Orientar o comprador. A requisição estava certa. |
| Falha temporária | HTTP 5xx, 429, tempo esgotado | Indisponibilidade momentânea | Repetir com a mesma chave de idempotência, com espera crescente. |
Formato dos erros de cobrança
Os erros das rotas de cobrança usam Problem Details. O código está em type. title é genérico e detail é texto para pessoas, que pode mudar.
{
"title": "PaymentIntent Creation Failed",
"detail": "amount must be an integer in the currency's minor unit",
"status": 400,
"type": "amount_must_be_integer_minor_units"
}Erros de formato do JSON (campo com tipo errado, enum desconhecido, JSON malformado) chegam com type em URL e os detalhes em errors:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": { "$.paymentMethods[0].type": ["The JSON value could not be converted to PaymentMethodType."] },
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}Pagamento recusado
Uma cobrança recusada volta com 201 e o motivo em lastPaymentError:
"lastPaymentError": {
"code": "51",
"message": "Saldo insuficiente",
"category": "issuer_decline"
}Use category para escolher a mensagem ao comprador e code para diagnóstico. category pode vir null.
category | Significa | Mensagem sugerida ao comprador |
|---|---|---|
issuer_decline | O banco emissor recusou. | "O banco recusou o pagamento. Tente outro cartão ou fale com o seu banco." |
card_data_invalid | Dados do cartão inválidos. | "Confira os dados do cartão." |
authentication | A autenticação 3DS falhou ou não pôde ser feita. | "Não foi possível confirmar a sua identidade. Tente de novo." |
contract_validation | A requisição não atendeu a uma regra, por exemplo 3DS exigido sem sessão. | Erro de integração: corrija antes de oferecer nova tentativa. |
merchant_config | Configuração da conta incompleta. | Erro de integração: fale com a equipe de integração. |
acceptance | A cobrança não é aceita para a conta, o cartão, a moeda ou o parcelamento. | "Este meio de pagamento não está disponível. Tente outro." |
provider_unavailable | Indisponibilidade no processamento. | "Não foi possível processar agora. Tente em alguns minutos." |
provider_rejected | O processador recusou a transação, por exemplo parcelamento não disponível. | "Não foi possível concluir com essas condições." |
ambiguous | Resultado incerto. | Mantenha o pedido em processamento e consulte a cobrança. |
internal | Falha interna. | "Não foi possível processar agora." |
Não mostre ao comprador o code nem a message técnicos. Guarde-os com o id da cobrança para diagnóstico.
Quando repetir
| HTTP | Repetir? | Como |
|---|---|---|
400 | Não | Leia type e detail, corrija e crie com nova chave de idempotência. |
401, 403 | Não | Confira chave, ambiente e permissões. Veja Autenticação. |
404 | Às vezes | Logo depois de criar ou de um webhook, repita a consulta após alguns segundos antes de concluir que não existe. |
409 | Depende do código | idempotency_key_in_flight: aguarde Retry-After e repita. idempotency_key_payload_mismatch: não repita; a chave já pertence a outra compra. |
422 | Não, com os mesmos dados | A requisição está bem formada, mas não pode ser processada nas condições atuais: configuração da conta, instrumento ou estado da cobrança. |
429 | Sim | Reduza a frequência e respeite Retry-After quando presente. |
500, 502, 503, tempo esgotado | Sim | Não presuma que nada aconteceu. Repita com a mesma chave e o mesmo corpo, e consulte a cobrança se tiver o id. |
Erro depois do processamento
Um 400 PaymentIntentCreationError ou um 5xx podem acontecer depois que a cobrança já foi processada. Trate o resultado como indeterminado: preserve a chave e o corpo e reconcilie antes de qualquer nova tentativa. Se não conseguir recuperar o PaymentIntent, fale com a equipe de integração. high_risk_transaction é uma recusa e não deve gerar repetição automática.
Formatos de outras rotas
| Rota | Onde está o código |
|---|---|
| Cobranças e estornos | type |
Sessão 3DS (/v1/3ds/device-data-sessions) | title |
Tokenização (/api/v1/card-tokens) | code, num envelope { code, message } |
| Saques | type |
| Extrato | error, com retryable |
Borda da API (401, 403, 429 da borda, chave inválida) | message |
O catálogo completo está em Códigos de erro.