TF Fiscal
Documentação

Primeiros passos

Convenções gerais

Os dois formatos de resposta (respostas simples vs. envelope da plataforma), formatos de erro, tipificação de erros, referência de status HTTP, idempotência, limites de taxa, localização, tipos de dados, a estrutura da chave de acesso da NF-e e os links de download de arquivos.

Convenções compartilhadas pelos endpoints da Open API da TF Fiscal.

Formatos de resposta

A API tem dois formatos de resposta, e qual deles você recebe depende do endpoint e da camada que produziu a resposta.

Respostas simples (endpoints padrão)

Todos os endpoints padrão (empresas, NF-e, CT-e, DC-e, verificação, consulta cadastral, registro de webhook) respondem sem envelope:

Grupo de endpointsFormato de sucesso
Cadastro de empresa, registro de webhookObjeto simples ({ "empresaId": ... }, { "webHookId": ... })
Vinculação de certificado, emissão e cancelamento de NF-e / CT-e / DC-eHTTP 200 sem corpo; o resultado chega de forma assíncrona
Consulta de NF-e / CT-e / DC-e, registro de carta de correção e de eventosObjeto simples: o documento, o protocolo ou a lista de eventos
Verificação por XML, consulta por chaveObjeto simples: a nota interpretada (a verificação por XML acrescenta o bloco validation)
Consulta de CNPJ, consulta de CPFObjeto simples: o registro cadastral

Os erros de negócio e de requisição dos endpoints padrão vêm em dois formatos de erro, conforme a família do endpoint.

Família de emissão (empresas, NF-e, CT-e, DC-e, registro de webhook; HTTP 400 / 404): um array de erros, cada um com codigo e mensagem. Falhas de validação do corpo produzem uma entrada por campo:

json
[
{ "codigo": "NFe0001", "mensagem": "A Nota fiscal nao foi encontrada. Por favor, verifique se o id foi informado corretamente" }
]

codigo é uma string: os três códigos GW001 (cidade / estado inválido), CER0005 (senha do certificado incorreta) e NFe0001 (nota não encontrada) mantêm os seus valores alfanuméricos, assim como os códigos DCe* da família DC-e; todas as demais entradas carregam o código de erro da plataforma como string numérica.

Famílias de verificação e consulta cadastral (HTTP 400, e 422 / 428 / 451 / 503 na consulta cadastral): um objeto simples com code e message:

json
{ "code": 10015004, "message": "Invoice not found" }
CampoTipoDescrição
codeintegerCódigo de erro da plataforma
messagestringExplicação legível, localizada

Envelope da plataforma

Usado pelo endpoint de echo (POST /openapi/demo/echo) em toda resposta, pelo endpoint de download de arquivos nas suas falhas e pelo gateway da plataforma para os erros da camada de autenticação em todo endpoint (HTTP 401 / 403 / 429), produzidos antes de a requisição chegar ao endpoint:

json
{ "success": true, "message": "OK", "data": { } }
json
{ "success": false, "errorType": 1, "code": 10009003, "message": "Signature error" }
CampoTipoPresençaDescrição
successbooleansemprefalse em todo erro
errorTypeintegerem erroClasse do erro, veja Tipificação de erros
codeintegerem erroCódigo de erro da plataforma, veja Códigos de erro
messagestringsempreExplicação legível, localizada
dataobject | nullem sucessoCarga do endpoint; não preenchida em erros

Tratando os dois formatos

O seu tratador de erros deve aceitar o envelope e os formatos de erro simples. Uma regra robusta:

  1. Trate HTTP 400 ou superior como falha e, adicionalmente, success: false quando o corpo for um envelope.
  2. Interprete o corpo como JSON. Se for um array, leia codigo de cada entrada; se for um objeto, leia code.
  3. Ramifique pelo código, nunca pelo texto de message / mensagem (eles são localizados).

Tipificação de erros (errorType)

Os erros em envelope carregam um campo errorType que classifica a origem da falha:

errorTypeClasseSignificado
1Erro de APIRejeição de autenticação, autorização ou de negócio pela TF Fiscal
2Rejeição da SEFAZA autoridade fiscal brasileira rejeitou a operação
3Falha de sistemaFalha inesperada da plataforma; seguro repetir com backoff
4Falha de validaçãoA validação dos campos da requisição falhou

Referência rápida de status HTTP

HTTPCenárioFormato do corpo
200Requisição aceita; na verificação por XML isso inclui uma validação reprovada (verifique o bloco validation)Dados simples, ou sem corpo
400Requisição inválida ou regra de negócio violada[{codigo, mensagem}] (emissão) ou {code, message} (verificação / consulta cadastral)
404empresaId / id do documento não encontrado (família de emissão)[{codigo, mensagem}]
401Falha de autenticação (token / sign / timestamp), ou link de download inválido ou vencidoEnvelope da plataforma
403Aplicação desativada / não vigente / integrador desativado / não subscritoEnvelope da plataforma
422 / 428 / 451Consulta de CPF retida por lei (titular de 16 a 17 anos / idade não verificável / titular menor de 16); não repita{code, message}, sem campos pessoais
429Limite de taxa excedidoEnvelope da plataforma
503Fonte de dados upstream indisponível (consulta cadastral, 10016020) ou arquivo ainda não renderizado (download, 10009037); repita após Retry-After{code, message} ou envelope da plataforma
5xxFalha do lado da plataformaRepita com backoff; se persistir, contate a plataforma com o timestamp e o caminho da falha

Idempotência

  • A emissão de NF-e é idempotente pelo id da requisição que você gera: reenviar o mesmo id reutiliza a tarefa original. Se a tentativa anterior foi negada (Negada), reenviar o mesmo id com os campos corrigidos emite de novo com a nova carga, sem necessidade de novo id. Alterar campos-chave como o destinatário enquanto a tentativa anterior ainda está em processamento ou já foi autorizada é rejeitado com codigo 10004032.
  • A emissão de CT-e e DC-e também é idempotente pelo id: uma mensagem idêntica reutiliza a tarefa original, uma mensagem diferente sob o mesmo id é rejeitada (10017030 para CT-e, 10019030 para DC-e), e uma falha terminal (Falha) reabre a tarefa com a nova mensagem.
  • A verificação por XML é idempotente pela chave de acesso (chave): reenviar enquanto uma verificação está em andamento devolve o progresso atual, e vereditos terminais são reutilizados por 24 horas. Para forçar uma nova verificação, envie o cabeçalho forceRevalidate: true no endpoint de XML (o cabeçalho não faz parte da assinatura). A consulta por chave é um GET fixo e não tem canal de reverificação; para forçar uma nova verificação, reenvie pelo endpoint de XML. Um REJECTED da camada 1 não tem registro de camada 2; a reverificação exige reenviar o XML.
  • As entregas de webhook são idempotentes por event_id: toda tentativa e todo destino de um mesmo evento carregam o mesmo valor, então deduplique por ele. Veja Webhooks.

Limite de taxa e backoff

  • Cota por aplicação: excedê-la devolve HTTP 429 com o código 10009006. Os limites são aplicados por aplicação e por grupo de endpoints. Recue e repita (comece em 1 s, dobre até 30 s, adicione jitter) e suavize a sua taxa de chamadas.
  • Anti-flood por CNPJ: se uma empresa acumular tarefas de emissão pendentes demais, novos envios são rejeitados com codigo 10004002 até a fila esvaziar; repita mais tarde.
  • Janela do timestamp: requisições com timestamp fora de ±300 s do relógio do servidor são rejeitadas (10009001), o que também limita o replay de requisições capturadas.
  • 401 e 403 são erros de configuração; repeti-los sem corrigir só consome cota.
  • Downloads de arquivos contam no limite da aplicação em grupo próprio e não são cobrados.

Localização das respostas

Os campos message, mensagem e *Description seguem o idioma da requisição: o cabeçalho Language (zh / en / pt / es) tem precedência, depois Accept-Language (aceita pt-BR e valores q). Sem cabeçalho de idioma, as respostas usam por padrão português (pt). Os cabeçalhos de idioma não fazem parte da assinatura.

As cargas de webhook carregam apenas valores de enumeração independentes de idioma; não há campos *Description nelas. Para decisões programáticas, use sempre códigos e campos de enumeração (code, codigo, status, validationStatus, errors[].code, situacao.codigo), nunca texto descritivo.

Horários e tipos de dados

  • Horários produzidos pela plataforma (dataCriacao, dataAutorizacao dos documentos emitidos, occurred_at de webhook, verifiedAt, serverTime do echo) são ISO-8601 UTC com o sufixo Z, em todo ambiente.
  • Horários extraídos de um documento de terceiros pela API de verificação (dataEmissao, dataAutorizacao) são devolvidos sem alteração, com o fuso do documento, por exemplo 2026-07-23T11:20:05-03:00.
  • O cabeçalho timestamp da requisição é tempo Unix em segundos, não milissegundos.
  • Identificadores são strings mesmo quando numéricos (empresaId, webHookId, event_id), para evitar perda de precisão numérica em JavaScript. Trate todos os ids como strings opacas; o id de documento que você gera também é uma string.
  • Números de documento (numero) e séries (serie) são strings. Valores e quantidades são números JSON.
  • Variáveis de caminho como cnpj, cpf e chave são strings só de dígitos, sem caracteres de formatação; a data de nascimento do CPF (nascimento) é DDMMYYYY.

A chave de acesso da NF-e (chave)

A chave de acesso é o identificador nacionalmente único de 44 dígitos de uma NF-e. Ela aparece como chaveAcesso nas respostas de consulta e verificação e como variável de caminho da consulta por chave. Sua estrutura:

PosiçõesTamanhoCampoSignificado
1 a 22cUFCódigo IBGE do estado emissor (ex.: 35 = SP)
3 a 64AAMMAno e mês de emissão (AAMM)
7 a 2014CNPJCNPJ do emitente
21 a 222modModelo do documento fiscal (55 = NF-e)
23 a 253serieSérie da nota
26 a 349nNFNúmero da nota
351tpEmisTipo de emissão
36 a 438cNFCódigo numérico aleatório
441cDVDígito verificador (módulo 11)

Observações:

  • Armazene e transmita sempre a chave como uma string de 44 caracteres (zeros à esquerda são significativos).
  • A consulta por chave valida tamanho, caracteres e dígito verificador localmente antes de qualquer consulta; uma chave malformada devolve HTTP 400 com o código 10015104.
  • As chaves de CT-e (modelo 57) e DC-e (modelo 99) compartilham o mesmo layout de 44 dígitos com o seu próprio valor de mod.

Os links de download nas respostas de consulta e nas cargas de callback (linkDanfe, linkDownloadXml, linkDacce e seus equivalentes de CT-e / DC-e) têm o formato https://api.v2.tffiscal.com/openapi/files/{kind}/{ref}?token=.... Eles não precisam de cabeçalhos de assinatura: basta um GET simples que siga o redirecionamento 302. O token é vinculado ao caminho, ao integrador e à aplicação, então use o link exatamente como devolvido. Os links valem por 7 dias por padrão e toda consulta emite links novos; um link vencido devolve 401 com 10009036. Detalhes: Download de arquivos.