Erros HTTP em API de infraestrutura e o que fazer com cada um
Equipe AltiviaCloud · 5 de setembro de 2026 · 4 min de leitura
Um guia de tradução: o que 400, 401, 409, 429 e 504 significam de verdade, quais merecem retentativa, e por que ramificar lógica pela mensagem em vez do código vira incidente.
Ler o corpo do erro leva dois segundos e economiza duas horas. Este é um guia de tradução: o que cada status significa numa API de infraestrutura, e o que fazer com ele.
Trate o código, não a mensagem
Antes dos casos, uma regra que evita retrabalho:
// frágil — a mensagem muda sem aviso
if (erro.message.includes("saldo")) { ... }
// estável
if (erro.code === "INSUFFICIENT_BALANCE") { ... }
Mensagem existe para humano ler; ela é reescrita, traduzida, melhorada. Código é contrato. Ramificar lógica por texto é combinar que qualquer melhoria de redação vira incidente.
400 — a requisição está errada
Falta campo, formato inválido, valor fora do domínio. Não repita: vai falhar igual.
O corpo diz o que houve. País ou serviço inexistente aparece aqui, e a causa costuma ser identificador escrito à mão em vez de vindo do catálogo. Puxe as listas da API e não digite código de país no meio do seu código.
401 — chave inválida ou ausente
Cheque, nessa ordem: o cabeçalho está indo mesmo (Authorization: Bearer ...); a chave é a do ambiente certo; ela não foi revogada.
Um caso que confunde: 401 depois de tudo estar funcionando há semanas. Quase sempre é chave revogada por alguém, ou variável de ambiente que sumiu num deploy — rotação sem procedimento causa exatamente isso.
Se você recebe 401 quando estourou a cota, o problema é da API que você está consumindo: cota estourada deve ser 429. Vale reportar, porque leva o integrador a achar que a chave morreu.
402 / saldo insuficiente
Adicione saldo. Repetir sem isso é ruído.
Vale tratar antes de acontecer: se a operação vai custar mais que o saldo, verifique primeiro e falhe com mensagem clara em vez de deixar a API recusar no meio de um lote.
404 — não existe, ou não é seu
Recurso inexistente ou de outra conta. Boa API responde 404 nos dois casos de propósito: dizer "existe, mas não é seu" vazaria informação.
Se você tem certeza de que o id está certo, confira se está usando a chave da mesma conta que criou o recurso.
409 — conflito de estado
A operação não cabe no estado atual. Cancelar um pedido já cancelado, finalizar um que expirou.
Não repita. Leia o estado atual e decida a partir dele.
422 — semanticamente inválido
A requisição está bem formada, mas o conteúdo não faz sentido: combinação país+serviço que não existe, valor fora da faixa aceita. Como o 400, não adianta repetir.
429 — cota estourada
O único erro de cliente que deve ser repetido — depois de esperar o que o cabeçalho Retry-After indicar. Repetir antes é o que transforma limite temporário em bloqueio.
if (res.status === 429) {
const espera = Number(res.headers.get("Retry-After") ?? 60);
await dormir(espera * 1000);
return tentarDeNovo();
}
Se você bate nisso com frequência, o problema não é a cota — é a estratégia de retentativa do seu lado.
500 — falhou do outro lado
Repita, com intervalo crescente e um teto de tentativas. Se persistir por minutos, pare de tentar e falhe rápido: manter a fila crescendo contra um serviço fora do ar só derruba o seu também.
502, 503, 504 — indisponível ou lento
Transitórios por natureza. Mesmo tratamento do 500: espera crescente com ruído, e circuito abrindo se não melhorar.
O 504 merece nota: alguma coisa no caminho desistiu de esperar. Se você está criando um recurso, ele pode ter sido criado mesmo com o timeout. Antes de repetir um POST, verifique se a operação já aconteceu — repetir criação sem essa checagem cria duas.
Resumo em uma tabela
| Status | Repetir? | Primeira coisa a fazer |
|---|---|---|
| 400 | não | ler o corpo, corrigir a requisição |
| 401 | não | conferir cabeçalho, ambiente e revogação |
| 402 | não | adicionar saldo |
| 404 | não | conferir id e conta |
| 409 | não | ler o estado atual |
| 422 | não | conferir a combinação enviada |
| 429 | sim | esperar o Retry-After |
| 500 | sim | espera crescente, com teto |
| 502/503/504 | sim | idem, e checar se a operação passou |
O erro sem status
O pior caso não tem código: a requisição fica pendurada. É o que acontece quando o cliente HTTP não tem timeout — e é o único item desta lista que derruba o seu sistema, não a integração. Uma linha resolve:
fetch(url, { signal: AbortSignal.timeout(10_000) })
Os erros da API de números virtuais seguem esse formato: code estável para o seu código e message para quem lê o log.