A chamada funciona em desenvolvimento. Agora você está escrevendo a parte que roda em produção: o bloco catch. Um erro HTTP de uma API de terceiros, por si só, é opaco: um código de status em vermelho e nenhuma resposta óbvia para a única pergunta que importa às 3 da manhã – o problema está na minha requisição, na minha chave, no meu plano ou nos servidores deles? E, desses casos, quais eu devo tentar de novo e quais devo mostrar ao usuário?
O Lingo.dev resolve isso com estrutura. Todo erro – de qualquer endpoint, síncrono ou assíncrono – retorna no mesmo objeto JSON, com o código de status sempre vindo da mesma tabela fixa. O código de status não é um rótulo, é uma instrução: ele diz se você precisa corrigir a requisição, trocar a chave, adicionar créditos à conta, reduzir o ritmo ou tentar de novo. Leia o código e saiba qual é o próximo passo. Um único handler de erros, orientado pelo status, cobre a API inteira.
Nesta página
- O formato do erro
- Códigos de status
- Quais erros tentar de novo
- 402 vs 429: dois limites diferentes
- Onde ficam os erros de jobs assíncronos
O formato do erro#
Toda resposta fora de 2xx tem o mesmo corpo: um objeto JSON com um único campo message descrevendo o que deu errado.
{
"message": "Invalid API key"
}Esse é o contrato inteiro. Não há envelope para desempacotar, nem formato de erro específico por endpoint para tratar como exceção. Um 400 de /process/localize e um 404 de uma consulta de job retornam o mesmo formato – só mudam o código de status e o texto de message.
Use o código de status, não o texto da mensagem
O código de status HTTP é o sinal estável – baseie seu tratamento de erros nele. A string message foi escrita para um humano lendo um log; trate-a como uma descrição, não como um código de erro legível por máquina, e não faça matching pelo texto exato.
Códigos de status#
Sete códigos de status cobrem todas as respostas. Eles estão agrupados aqui por quem resolve o problema – porque esse agrupamento também define sua política de retry.
Você enviou algo que a requisição não consegue atender (corrija a requisição, não tente de novo às cegas):
| Status | Significado |
|---|---|
400 Bad Request | A validação da requisição falhou – um campo ausente, um idioma inválido, uma callbackUrl HTTP (e não HTTPS), uma payload malformada. |
401 Unauthorized | O cabeçalho X-API-Key está ausente ou é inválido. Veja Autenticação. |
403 Forbidden | A chave é válida, mas não tem acesso ao recurso solicitado. |
404 Not Found | O recurso – um engine, um job, um grupo de jobs – não existe. |
Sua organização atingiu um limite da conta (resolva no faturamento):
| Status | Significado |
|---|---|
402 Payment Required | A organização atingiu seu limite de crédito. |
429 Too Many Requests | A organização atingiu sua cota diária de tokens. Faça upgrade do plano para aumentar esse limite. |
Algo falhou do nosso lado (transitório – tente de novo):
| Status | Significado |
|---|---|
500 Internal Server Error | Uma falha inesperada – um erro de banco de dados ou uma chamada de tradução que falhou em todos os modelos configurados no engine. |
Um 401 e um 403 parecem parecidos, mas não são o mesmo problema: 401 significa que não conseguimos identificar quem fez a chamada; 403 significa que identificamos a chave, mas ela não tem permissão de acesso. A correção para 401 está na própria chave (troque-a ou verifique-a); a correção para 403 está no acesso da chave.
Quais erros tentar de novo#
A primeira pergunta de um integrador cético diante de qualquer tabela de erros é justamente a que ela normalmente deixa sem resposta: quais desses erros eu devo tentar de novo? O agrupamento acima é a resposta.
- 4xx – não tente de novo às cegas. Um
400,401,403ou404descreve uma condição na sua requisição. Repetir a mesma requisição produz o mesmo erro. Corrija a entrada, a chave ou o id do recurso e envie de novo. - 402 e 429 – recue e depois resolva o limite. Eles não são transitórios no nível da requisição; a próxima requisição vai bater na mesma barreira até que o limite subjacente mude. Pare de tentar de novo em loop apertado, exponha o limite e resolva-o (adicione créditos ou faça upgrade do plano).
- 500 – tente de novo com backoff. Esta é a única classe genuinamente transitória. Um
500pode significar que todos os modelos configurados deram timeout naquela chamada; uma nova tentativa pode cair em um modelo saudável. Use backoff exponencial e um teto de tentativas.
A API assíncrona informa resultados de outro jeito
Esta política de retry vale para chamadas síncronas feitas por você. A API de localização assíncrona não retorna um código de status para o resultado do trabalho: um POST retorna 202 assim que a requisição é aceita, e cada idioma de destino roda como um job independente por meio de workflows duráveis em segundo plano. Em vez de capturar um código de status na chamada original, você consulta o job ou recebe um webhook com o resultado. Veja onde ficam os erros de jobs assíncronos.
402 vs 429: dois limites diferentes#
Os dois códigos no nível da conta soam parecidos – ambos passam a ideia de "você esgotou" – e confundi-los leva o desenvolvedor à correção errada. São limites distintos, com resoluções distintas:
402 Payment Required– a organização atingiu seu limite de crédito. Este é um limite de faturamento. A próxima chamada continuará falhando até que a situação de faturamento da organização mude.429 Too Many Requests– a organização atingiu sua cota diária de tokens. Este é um teto de consumo que é redefinido, e você o aumenta ao fazer upgrade do plano.
O motivo para manter os dois separados no seu handler: um 402 exige uma ação de faturamento tomada por uma pessoa; um 429 é uma cota que você ou espera resetar ou aumenta com um upgrade. Direcionar ambos para uma mensagem genérica de "problema de pagamento" esconde qual alavanca o operador realmente precisa acionar.
Um corpo 402 se parece com qualquer outro erro – é o código de status que mostra que se trata de um limite de crédito:
{
"message": "Organization has reached its credit limit"
}Onde ficam os erros de jobs assíncronos#
Vale traçar essa linha, porque é exatamente aí que um handler baseado em código de status deixa de ser a ferramenta certa.
Os códigos de status desta página são de nível de transporte: eles descrevem se a API aceitou e conseguiu atender à sua requisição HTTP. Um 202 da API assíncrona significa que sua requisição foi aceita – não que a tradução deu certo. Um job assíncrono pode ser aceito sem problemas e ainda assim falhar depois, quando um modelo dá timeout no meio da execução. Essa falha não aparece como um código de status HTTP na chamada original; ela fica registrada no próprio job.
Por isso, falhas assíncronas aparecem em três lugares, e nenhum deles é esta tabela:
- Status por job. Um idioma com falha traz
status: "failed"e umerrorMessageno job. Veja status de jobs. - Status do grupo. Quando alguns idiomas dão certo e outros falham, o grupo informa
partial– os idiomas concluídos com sucesso ainda são entregues. Veja acompanhar um grupo de jobs. - Entrega de webhook. Uma falha é entregue como um evento
translation.failedcom um campoerror. Veja entrega de webhook.
Há mais uma distinção que costuma pegar muita gente: a falha de uma etapa não crítica do pipeline não faz o job falhar. O job é concluído com completed_with_warnings e avisos por etapa, em vez de um erro. Isso é uma questão de observabilidade do pipeline, não um código de erro – veja observar execuções de pipeline.
Próximos passos#
Um bom handler de erros começa pelos dois códigos que você provavelmente verá primeiro na integração – autenticação e os pontos em que o trabalho assíncrono informa seu próprio resultado.
