engineAPIengine·API

Erros e Rejeições

Referência completa de erros HTTP e rejeições SEFAZ. Causas, soluções e estratégia de retry.

Erros e Rejeições

A Engine API segue o padrão HTTP para códigos de status e acrescenta campos específicos para rejeições da SEFAZ.


Formato de Erro

json
{
  "statusCode": 422,
  "error": "Unprocessable Entity",
  "message": "Nota rejeitada pela SEFAZ",
  "sefazCode": 539,
  "sefazMessage": "Duplicidade de NFe, com diferença na Chave de Acesso"
}

| Campo | Presente em | Descrição | |-------|------------|-----------| | statusCode | Todos os erros | Código HTTP | | error | Todos os erros | Descrição HTTP do status | | message | Todos os erros | Mensagem legível | | sefazCode | Somente 422 | Código de rejeição SEFAZ | | sefazMessage | Somente 422 | Mensagem oficial da SEFAZ |


Códigos HTTP

| Código | Significado | Quando ocorre | |--------|-------------|--------------| | 200 | Sucesso | Requisição processada com sucesso | | 400 | Bad Request | JSON inválido, campos faltando ou com formato errado | | 401 | Unauthorized | Token ausente, inválido ou expirado | | 403 | Forbidden | Sem permissão ou assinatura sem plano ativo | | 404 | Not Found | Recurso (nota, empresa, webhook) não encontrado | | 409 | Conflict | Recurso já existe (ex: certificado duplicado) | | 422 | Unprocessable Entity | SEFAZ rejeitou o documento | | 429 | Too Many Requests | Rate limit do plano excedido | | 500 | Internal Server Error | Erro interno. Contate o suporte | | 503 | Service Unavailable | SEFAZ temporariamente indisponível |


Rejeições SEFAZ (422): Top 20


Estratégia de Retry

Nem todo erro deve ser retentado. Siga esta lógica:

| Tipo de erro | Retry? | Quando | |-------------|--------|--------| | 400 Bad Request | Não Não | Corrija os dados primeiro | | 401 Unauthorized | Não Não | Faça login e obtenha novo token | | 403 Forbidden | Não Não | Verifique permissões do plano | | 404 Not Found | Não Não | Recurso não existe | | 422 Rejeição SEFAZ | Não Não | Corrija conforme sefazCode | | 429 Rate Limit | Sim Sim | Aguarde e tente novamente | | 500 Server Error | Sim Sim | Retry com backoff exponencial | | 503 SEFAZ indisponível | Sim Sim | Retry após 5 minutos |

Implementando Retry com Backoff Exponencial

typescript
async function emitirComRetry(data: any, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const resp = await fetch('https://api.engineapi.com.br/nfe/emitir', {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });

      if (resp.ok) return await resp.json();

      const error = await resp.json();

      // Não fazer retry em erros de dados
      if ([400, 401, 403, 404, 422].includes(resp.status)) {
        throw new Error(`Erro não recuperável: ${error.message}`);
      }

      // Retry em 500 e 503
      if (attempt < maxRetries - 1) {
        const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

    } catch (err) {
      if (attempt === maxRetries - 1) throw err;
    }
  }
}

Rate Limits

| Plano | Requests/min | Requests/dia | |-------|-------------|-------------| | Dev | 5 | 100 | | Starter | 60 | 1.000 | | Growth | 300 | 10.000 | | Scale | 600 | Ilimitado | | Enterprise | Ilimitado | Ilimitado |

Quando o limite é excedido:

json
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Rate limit excedido. Seu plano permite 60 requests/min.",
  "retryAfter": 45
}

Use o campo retryAfter (em segundos) para saber quando tentar novamente.


Próximos passos