Pular para o conteúdo

Tratamento de erros

A API do FazNota retorna erros em duas formas distintas:

  1. Erros HTTP (401, 403, 404, 405, 429) — autenticação, autorização e rate limit.
  2. Erros de domínio (HTTP 200 + body.status: "999") — validação ou erros internos.

Erros HTTP

401 Unauthorized

Token ausente, inválido ou expirado.

{ "error": { "status": 401, "message": "Token não autorizado." } }

Ação: revise o header Authorization. Se o Token foi rotacionado, atualize.

403 Forbidden

Contrato inapto.

{ "error": { "status": 403, "message": "Este contrato está inapto..." } }

Ação: entre em contato com o FazNota para regularizar o contrato.

404 Not Found

Recurso não existe (endpoint errado).

{ "error": { "status": 404, "message": "Resource not found." } }

Ação: confira o path. Se for consulta por recibo, prefira o body.status: "500" (que vem com mais contexto).

405 Method Not Allowed

Método HTTP errado para o endpoint.

{ "error": { "status": 405, "message": "The specified HTTP method is not allowed..." } }

Ação: confira se você está usando o verbo correto (GET, POST, PUT, DELETE).

429 Too Many Requests

Limite de consumo atingido.

{ "error": { "status": 429, "message": "Você atingiu o limite de consumo de API..." } }

Ação:

  1. Pare de enviar requisições imediatamente.
  2. Leia o header X-RateLimit-Reset (Unix timestamp) para saber quando retomar.
  3. Implemente backoff exponencial em retries.

Erros de domínio (status: 999)

Sempre HTTP 200. O detalhe está em data.erro:

{
"status": "999",
"descricao": "Ocorreu um erro interno com a nota.",
"data": {
"erro": "Campo nfe@chave deve ter 44 caracteres."
},
"meta": {
"request_id": "req_01HXY8ZG3J4K5M6N7P8Q9R0S1T",
"timestamp": "2026-05-13T14:32:01.234Z"
}
}

Mensagens de validação

Padrão: "Campo <recurso>@<campo> <regra>".

Exemplos comuns:

MensagemSignificado
Campo nfe@chave não pode ser vazio.Falta o campo.
Campo nfe@chave deve ter 44 caracteres.Tamanho incorreto.
Campo nfe@serie inválido.Não é numérico ou tem >3 dígitos (limite 1-999).
Campo nfe@serie permite séries apenas entre 1 a 999.Valor fora do range.
Campo nfe@motivo deve ter entre 15 e 255 caracteres.Texto curto/longo demais.
Campo nfe@transporte@placa-veiculo inválido.Não bate com regex AAA-9999 ou Mercosul.
Campo nfe@cliente documento não pertence a um cliente cadastrado.CPF/CNPJ não está cadastrado.
Campo nfe@itens não pode ser vazio.Array vazio.

Mensagens de erro interno

Mensagens não-controladas (vindas de exceções inesperadas) são substituídas por uma frase genérica para não vazar detalhes da infraestrutura:

{
"status": "999",
"data": {
"erro": "Erro interno ao processar a requisição. Tente novamente em instantes ou entre em contato com o suporte informando o request-id."
},
"meta": { "request_id": "req_..." }
}

Status terminais que não são “erro técnico” mas falha de negócio

Estes códigos não são erros da API, mas indicam que a operação não deu certo. Trate-os no nível de negócio:

statusSignificadoTratamento
050Duplicidade de numero-origemNão é erro; é proteção. Use o recibo retornado.
500Recibo não existeVerifique se você salvou o recibo correto.
900Rejeição SEFAZVeja data.sefaz.codigo e data.sefaz.mensagem. Corrija e emita nova nota.

Padrão de tratamento recomendado

class ApiError extends Error {
constructor(
public httpStatus: number,
message: string,
public payload: unknown,
public requestId?: string
) {
super(message);
}
}
async function call(method, path, body, token) {
const res = await fetch(`${BASE}${path}`, {
method,
headers: {
Authorization: `Token ${token}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json().catch(() => ({}));
// Erro HTTP
if (!res.ok) {
const reqId = res.headers.get('x-request-id') ?? json?.meta?.request_id;
throw new ApiError(res.status, json.error?.message ?? `HTTP ${res.status}`, json, reqId);
}
// Erro de domínio
if (json.status === '999') {
throw new ApiError(200, json.data?.erro ?? 'Erro interno', json, json.meta?.request_id);
}
return json;
}

Quando acionar o suporte

SintomaAcionar suporte?Como
Mensagem de validação clara❌ Corrija o payload.
status: "050"❌ Use o recibo retornado.
status: "900" com sefaz.mensagem claro❌ Corrija e emita de novo.
status: "999" com mensagem genérica✅ SimCite meta.request_id.
HTTP 401 persistente após gerar Token novo✅ SimCite X-Request-Id.
Padrão repetitivo de 429 em volume normal✅ SimCite janela e Token.
Polling que nunca termina (002 por > 5 min)✅ SimCite recibo e meta.request_id.