Os erros da API Pix da xFlow seguem um formato único: o status HTTP indica a família do problema e o corpo JSON traz o código exato em error, uma explicação em message e o request_id da chamada. Ler o error, e não só o status, é o que permite tratar cada caso no código. Abaixo estão todos os códigos listados na documentação da API, com causa e solução. Para o panorama da integração, veja o guia da API Pix.
Formato de um erro
{
"error": "validation",
"message": "...",
"request_id": "req_kJ2m9..."
}O request_id também vem no header x-request-id. Ele existe em toda resposta, inclusive nas de sucesso. Nos erros 400 validation, confira também o campo details, que aponta o que está errado no corpo.
Use error para decidir o que fazer no código e message para o log: o texto foi escrito para leitura humana. Um if (erro.code === "insufficient_balance") é mais claro e mais seguro do que procurar palavras na mensagem.
Sobre o 401: além do HTTP Basic com pk_live_...:sk_live_..., a API ainda aceita o formato legado Authorization: Bearer sk_live_..., só com o segredo. Ele aceita apenas segredos sk_live_ e sk_test_. Se a chamada usa outro formato, a resposta é 401 unauthorized.
Tabela de erros da API Pix
| HTTP | Código | Quando acontece | Como resolver |
|---|---|---|---|
| 400 | validation |
Corpo inválido: campo obrigatório ausente, tipo errado ou valor fora do mínimo e do máximo da conta. | Leia details e corrija. Os limites de valor ficam no painel, em Empresa > Limites e taxas. |
| 400 | invalid_url |
URL de webhook inacessível ou apontando para rede interna. | Use uma URL https:// pública. |
| 400 | endpoint_limit |
A conta já tem 20 endpoints de webhook. | Remova um endpoint com DELETE /api/v1/webhooks/{id}. |
| 401 | unauthorized |
Chave ausente, inválida ou revogada, ou IP fora da allowlist. | Confira as chaves e a allowlist em Chaves de API. |
| 403 | account_inactive |
Conta em análise ou bloqueada. | Confira o cadastro no painel. Enquanto isso, integre com chave de teste. |
| 403 | api_withdrawal_disabled |
Saque via API desabilitado para a conta. | Fale com o suporte. |
| 403 | test_mode_unsupported |
Recurso indisponível com chave de teste, como saques. | Teste esse fluxo com chave de produção. |
| 403 | test_mode_only |
Endpoint de simulação chamado com chave de produção. | Use a chave pk_test_ em POST /test/charges/{id}/pay. |
| 404 | not_found |
Cobrança ou saque não encontrado. | Confira o id enviado na URL. |
| 409 | idempotency_conflict |
Idempotency-Key já usada com um corpo diferente. |
Gere uma chave nova por pedido. |
| 422 | transfer_failed |
Saque recusado, por exemplo por saldo insuficiente ou QR Code não aceito pelo provedor. | Confira o saldo em GET /balance. Com QR não aceito, nada é debitado: use chave Pix. |
| 422 | charge_not_refundable |
Estorno de cobrança que não está paid. |
Estorne só cobranças pagas. |
| 422 | refund_window_expired |
Estorno pedido mais de 90 dias após o pagamento. | O estorno pela API não está mais disponível. |
| 422 | insufficient_balance |
Saldo disponível não cobre o estorno. O corpo traz shortfallCents. |
Aguarde saldo e tente de novo. |
| 422 | refund_not_supported |
O provedor da cobrança não oferece estorno via API. | Fale com o suporte, citando o request_id. |
| 429 | rate_limited |
Muitas requisições. O limite é por conta. | Espere o retry-after e use backoff. |
| 502 | charge_failed |
Falha ao gerar a cobrança no provedor. | Tente de novo com backoff. |
| 502 | refund_failed |
O PSP recusou ou não respondeu ao estorno. A retenção foi liberada. | Peça o estorno de novo mais tarde. |
Dois casos respondem 400 sem código próprio na lista: splits enviados com chave de teste e split inválido em produção. Os detalhes de estorno e saque estão em estorno Pix por API e API de saque Pix.
Quais erros vale repetir
Nem todo erro melhora com retentativa. Separe em três grupos:
- Repita com espera:
429 rate_limited(depois doretry-after),502 charge_failede502 refund_failed. - Corrija antes de repetir:
400,401,404e409. Repetir o mesmo pedido dá o mesmo erro. - Depende de algo fora do código:
403e422. Conta, configuração, saldo ou prazo precisam mudar primeiro.
Ao repetir uma criação de cobrança ou de saque, mantenha a mesma Idempotency-Key. É ela que garante que um retry não gere um segundo Pix nem debite o saldo duas vezes. O mecanismo está explicado em idempotência em API de pagamento.
async function comRetentativa(chamada, tentativas = 3) {
for (let i = 0; ; i++) {
try {
return await chamada();
} catch (erro) {
const repetivel = erro.status === 429 || erro.status === 502;
if (!repetivel || i === tentativas - 1) throw erro;
const espera = erro.retryAfter ? erro.retryAfter * 1000 : 2 ** i * 1000;
await new Promise((r) => setTimeout(r, espera));
}
}
}A função espera um erro com status e retryAfter, como o do cliente em API Pix em Node.js.
Limite de requisições
Toda resposta autenticada traz três headers:
x-ratelimit-limit: o limite da sua conta.x-ratelimit-remaining: quanto ainda resta.x-ratelimit-reset: quando o contador zera, em epoch (segundos).
Monitore x-ratelimit-remaining para desacelerar antes do 429. A causa mais comum de estouro é polling em laço de GET /api/v1/charges/{id}. Troque o polling pelo webhook Pix, que avisa quando a cobrança é paga.
request_id e Logs da API
O request_id (req_...) é a ferramenta principal de depuração. Grave esse valor no seu log em toda chamada que falhar:
resp = requests.post(url, auth=auth, json=corpo, timeout=30)
if resp.status_code >= 400:
erro = resp.json()
logger.error("xflow %s %s request_id=%s", resp.status_code, erro.get("error"), resp.headers.get("x-request-id"))No painel, em Integrações > Logs da API, cada requisição autenticada aparece com status, duração e código de erro. A retenção é de 30 dias. Com o request_id, você acha a chamada exata sem abrir chamado. Se precisar do suporte, cite o mesmo request_id: é por ele que a chamada é localizada.
Problemas que não aparecem como código de erro
- Assinatura do webhook não confere. Quase sempre o corpo foi convertido em JSON antes da validação. O HMAC-SHA256 do header
x-webhook-signatureé calculado sobre o corpo cru. - Pedido real baixado por evento de teste. Eventos gerados com chave de teste trazem
livemode: falsenodata. Filtre por esse campo. - QR Code de teste não paga. No sandbox, o
pix.copyPasteé um marcador que não pode ser pago. Simule comPOST /api/v1/test/charges/{id}/pay, como mostra o sandbox da API Pix. - Entrega de webhook repetida. Sem resposta
2xx, o mesmo evento é reenviado até 3 vezes. Se o seu sistema não tratar repetição, um pedido pode ser processado duas vezes.
Perguntas frequentes
O que significa 401 unauthorized na API Pix?
A chave está ausente, inválida ou revogada, ou o IP do servidor está fora da allowlist configurada na conta. Com allowlist ativa, o 401 aparece mesmo com a credencial certa.
Como resolver o erro 409 idempotency_conflict?
Ele aparece quando a mesma Idempotency-Key é enviada com um corpo diferente. Use a mesma chave só para repetir exatamente o mesmo pedido. Para uma cobrança ou saque novo, gere uma chave nova.
Onde vejo o histórico das minhas requisições à API?
No painel, em Integrações > Logs da API. Cada requisição autenticada aparece com status, duração e código de erro, com retenção de 30 dias. Busque pelo request_id que veio na resposta.
O que fazer quando a API responde 429?
Espere o número de segundos do header retry-after e tente de novo com backoff. O limite é por conta, e os headers x-ratelimit-limit, x-ratelimit-remaining e x-ratelimit-reset mostram quanto ainda resta.