Tratamento de erros
A Pix Processamento retorna os códigos HTTP padrão. Sua estratégia depende da categoria.
Tabela de tratamento
| Código | O que significa | O que fazer |
|---|---|---|
200 | Sucesso na operação. | Processar resposta. |
201 | Recurso criado (cobrança, saque). | Processar resposta. |
400 | Payload inválido. | Não retentar. Logue message + requestId e ajuste o código. |
401 | Token ausente, inválido ou revogado. | Não retentar. Verifique o token (espaço, encoding, rotação). |
403 | Token válido mas sem permissão para o endpoint. | Não retentar. Contate o suporte para validar habilitação da conta. |
404 | Recurso não encontrado. | Não retentar. Confirme id ou clientReference. |
409 | Conflito (duplicado, recurso em estado inválido). | Não retentar. Consulte via GET o estado atual antes de tentar novamente. |
422 | Validação semântica falhou. | Não retentar. Corrija o payload conforme message. |
424 | Falha, recusa, timeout ou indisponibilidade da instituição financeira. | Retry com backoff. Em criação (depósito, saque, transferência) com timeout, consulte por clientReference antes de recriar. |
429 | Rate limit atingido. | Aguarde, faça backoff exponencial e tente de novo. |
5xx | Erro do servidor Pix Processamento. | Retry com backoff exponencial (1s → 2s → 4s → 8s, máx 4 tentativas). |
| Timeout | Sem resposta dentro do prazo. | A operação pode ter sido aplicada. Consulte por clientReference antes de recriar. |
Helper de retry
Retry em 429, 5xx e 424. Nos demais 4xx, nunca.
ATTEMPTS=4
DELAY=1
for i in $(seq 1 $ATTEMPTS); do
STATUS=$(curl -s -o /tmp/resp.json -w "%{http_code}" \
-X POST https://api.exemplo.processamento.com/v1/pix \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"amount":99.90,"clientReference":"order-1234"}')
case $STATUS in
2*) cat /tmp/resp.json; exit 0 ;;
424|429|5*) sleep $DELAY; DELAY=$((DELAY*2)) ;;
*) echo "Erro $STATUS"; cat /tmp/resp.json; exit 1 ;;
esac
done
echo "Max retries excedido"
exit 1async function withRetry<T>(
fn: () => Promise<Response>,
attempts = 4,
): Promise<T> {
let lastErr: unknown;
for (let i = 0; i < attempts; i++) {
try {
const res = await fn();
if (res.ok) return res.json();
if (res.status >= 400 && res.status < 500 && res.status !== 429 && res.status !== 424) {
const body = await res.text();
throw new Error(`Client error ${res.status}: ${body}`);
}
} catch (err) {
lastErr = err;
}
const delay = Math.min(8000, 1000 * 2 ** i) + Math.random() * 250;
await new Promise((r) => setTimeout(r, delay));
}
throw lastErr ?? new Error('Max retries exceeded');
}import time, random, requests
def with_retry(fn, attempts=4):
last_err = None
for i in range(attempts):
try:
res = fn()
if res.ok:
return res.json()
if 400 <= res.status_code < 500 and res.status_code != 429 and res.status_code != 424:
raise RuntimeError(f'Client error {res.status_code}: {res.text}')
except Exception as e:
last_err = e
delay = min(8.0, 1.0 * (2 ** i)) + random.random() * 0.25
time.sleep(delay)
raise last_err or RuntimeError('Max retries exceeded')func WithRetry(fn func() (*http.Response, error), attempts int) ([]byte, error) {
var lastErr error
for i := 0; i < attempts; i++ {
res, err := fn()
if err == nil {
body, readErr := io.ReadAll(res.Body)
res.Body.Close()
switch {
case readErr != nil:
lastErr = readErr
case res.StatusCode >= 200 && res.StatusCode < 300:
return body, nil
case res.StatusCode >= 400 && res.StatusCode < 500 && res.StatusCode != 429 && res.StatusCode != 424:
return nil, fmt.Errorf("client error %d: %s", res.StatusCode, body)
default:
lastErr = fmt.Errorf("retryable status %d: %s", res.StatusCode, body)
}
} else {
lastErr = err
}
delay := time.Duration(math.Min(8000, 1000*math.Pow(2, float64(i)))) * time.Millisecond
time.Sleep(delay + time.Duration(rand.Intn(250))*time.Millisecond)
}
return nil, lastErr
}Timeout: a armadilha do "pode ter dado certo"
Timeout não é equivalente a falha. A Pix Processamento pode ter recebido, processado e gravado a transação, e a resposta apenas não voltou. Sua app não sabe.
Solução: use clientReference único e consulte antes de retentar.
async function createOrRetry(orderId: string, amount: number) {
const ref = `order-${orderId}`;
try {
return await withRetry(() => postPix({ amount, clientReference: ref }));
} catch (err) {
// pode ter dado certo apesar do erro/timeout
const existing = await fetch(
`https://api.exemplo.processamento.com/v1/pix?clientReference=${ref}`,
{ headers },
).then((r) => (r.ok ? r.json() : null));
if (existing) return existing;
throw err;
}
}Observabilidade do erro
Sempre logue, no mínimo:
| Campo | Por quê |
|---|---|
requestId | Vem nas respostas de erro Pix Processamento. Suporte rastreia direto. |
id local | Seu identificador (pedido, saque). |
id Pix Processamento | Se já houver. |
endToEndId | Útil para rastrear no Bacen em disputa. |
clientReference | A chave de correlação universal. |
| HTTP status + message | A causa raiz quase sempre está em message. |
| Tentativa N de M | Diferencia primeira tentativa de retry. |
log.error('Pix Processamento /pix falhou', {
requestId: body.requestId,
status: res.status,
message: body.message,
clientReference: ref,
attempt: i + 1,
attempts,
});Mensagens de erro úteis para o usuário final
Não exponha message cru. Traduza para algo acionável:
| Erro Pix Processamento | Mensagem para o usuário |
|---|---|
401 Unauthorized | "Erro de configuração. Contate o suporte com o código requestId." |
400 amount must be >= 1 | "Valor mínimo da cobrança é R$ 1,00." |
400 invalid pixKey | "Chave Pix inválida. Confira e tente novamente." |
424 (instituição financeira) | "Instituição financeira instável no momento. Tente em instantes." |
429 Too Many Requests | "Estamos com muitas requisições. Tente em instantes." |
5xx | "Sistema temporariamente indisponível. Já estamos olhando." |
Armadilhas comuns
| Armadilha | Sintoma |
|---|---|
Retentar em 400 | Spam contra a API, mesmo erro N vezes |
Retentar em 401 sem rotacionar token | Token vaza ainda mais no log |
| Sem backoff (retry imediato em loop) | Vira rate limit, depois fica banido |
| Sem jitter no backoff | N clientes batem ao mesmo tempo, "thundering herd" |
| Tratar timeout como falha definitiva | Cliente cobra 2x do usuário |
Não logar requestId | Suporte não consegue investigar |
Abrir suporte com o requestId
Tem o requestId salvo? Manda direto pro time.
Segurança
Token Bearer é a única credencial da Pix Processamento. Trate como senha. Esta página cobre armazenamento, rotação, mascaramento em log e proteção do webhook por IP e por assinatura.
Checklist de produção
Lista verificável dos itens que sua integração precisa antes de receber tráfego real. Cobre idempotência, callbacks, dinheiro, segurança, conciliação e observabilidade.