TF Fiscal
Documentação

Primeiros passos

Início rápido

Cadastrar uma empresa, vincular o certificado, registrar um webhook, emitir uma NF-e e consultá-la, o caminho de integração em cinco passos da Open API da TF Fiscal.

Este guia percorre, em ordem, as cinco chamadas que toda integração de emissão faz:

  1. Cadastrar a empresa que emitirá os documentos e obter o seu empresaId.
  2. Vincular o certificado digital A1 da empresa.
  3. Registrar um webhook para receber os resultados de emissão.
  4. Emitir uma NF-e.
  5. Consultar a NF-e para obter o status e os links de download.

Todas as requisições vão para a URL base de produção https://api.v2.tffiscal.com; a URL completa é a URL base mais o caminho indicado em cada chamada. Os mesmos cinco passos valem para CT-e e DC-e: os passos 1 a 3 são compartilhados, só mudam os endpoints de emissão e consulta.

Pré-requisitos

  • Credencial da aplicação: um app_secret emitido para a sua aplicação. Ele é exibido apenas uma vez; guarde-o com segurança. Em caso de vazamento, solicite a rotação.
  • Subscrição de API: a plataforma concede à sua aplicação acesso a todos os endpoints usados abaixo. Chamar um endpoint não subscrito devolve HTTP 403 com o código 10009005.
  • Assinatura: toda requisição carrega os cabeçalhos token, timestamp e sign. A função auxiliar abaixo é usada em todos os exemplos desta página; a especificação completa está em Autenticação. Antes da primeira chamada real, valide a sua implementação com o Echo de teste.
bash
HOST="https://api.v2.tffiscal.com"
APP_SECRET="<APP_SECRET>"
# sign = lowercase hex MD5( token + path + body-without-CR-LF + timestamp )
# usage: sign "<path>" "<body>" "<timestamp>" (pass "" as body for GET / DELETE / multipart)
sign() {
printf '%s%s%s%s' "$APP_SECRET" "$1" "$(printf '%s' "$2" | tr -d '\r\n')" "$3" \
| md5sum | awk '{print $1}'
}

Passo 1: cadastrar a empresa

POST /openapi/v2/empresas envia os dados cadastrais do vendedor. A resposta traz o empresaId que toda chamada posterior usa como variável de caminho; persista-o.

bash
API_PATH="/openapi/v2/empresas"
BODY='{"cnpj":"14422279000106","inscricaoEstadual":"999999","razaoSocial":"Empresa teste LTDA","nomeFantasia":"Empresa teste","optanteSimplesNacional":true,"mei":false,"email":"empresa-teste@example.com","telefoneComercial":"6122222222","endereco":{"pais":"Brasil","uf":"MG","cidade":"Belo Horizonte","logradouro":"Rua Teste","numero":"999","bairro":"Bairro Teste","cep":"85100000"},"emissaoNFeProduto":{"ambienteProducao":{"sequencialNFe":1,"serieNFe":"10"}}}'
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
-d "$BODY"
json
{ "empresaId": "1934811222334455" }

O cadastro coloca a empresa na fila de aprovação da plataforma. A empresa só pode emitir depois que a operação a aprova e o certificado é vinculado; emitir antes disso devolve codigo 10004004. Cadastrar o mesmo CNPJ duas vezes devolve HTTP 400 com codigo 10003002. Referência campo a campo: Cadastrar empresa.

Passo 2: vincular o certificado digital

POST /openapi/v1/empresas/{empresaId}/certificadoDigital aceita o certificado A1 (.pfx / .p12) como upload multipart/form-data ou como JSON com o conteúdo do arquivo em Base64. O formato JSON é usado aqui porque o seu corpo é assinado como o de qualquer outra requisição JSON. Gere Base64 padrão sem quebras de linha para que o corpo assinado e o corpo enviado não divirjam.

bash
EMPRESA_ID="1934811222334455"
API_PATH="/openapi/v1/empresas/$EMPRESA_ID/certificadoDigital"
BODY=$(printf '{"senha":"certpass123","arquivoBase64":"%s"}' "$(base64 -w0 certificate.pfx)")
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
--data-binary "$BODY"

O sucesso é HTTP 200 sem corpo, e o upload substitui o certificado anterior da empresa. Senha incorreta devolve HTTP 400 com codigo CER0005; Base64 inválido ou arquivo acima de 1 MB após decodificação devolve 10003035; certificado cujo CNPJ não corresponde à empresa devolve 10003010, e certificado vencido 10003011. O formato multipart, que assina a string vazia como corpo, está descrito em Vincular certificado.

Passo 3: registrar o webhook

POST /openapi/v1/webhooks registra a URL que recebe os resultados de emissão. O token que você escolhe é devolvido sem alteração no cabeçalho token de todo callback, para que o seu receptor verifique a origem; além disso, a plataforma assina toda entrega com o cabeçalho X-Tffiscal-Signature.

bash
API_PATH="/openapi/v1/webhooks"
BODY='{"uri":"https://example.com/tffiscal/callback","contentType":"application/json","token":"dGt6eXp5ZGRra2tzc3Nra2hoaGFha2tha2FhamFoaGFoNzc3Nz"}'
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
-d "$BODY"
json
{ "webHookId": "550001" }

Há uma única configuração de callback por aplicação; chamar o endpoint de novo a sobrescreve. O registro subscreve você aos eventos de resultado, autorizado e negado. O seu receptor deve responder 2xx; qualquer outra resposta é reenviada com backoff. Veja Registrar webhook e Webhooks.

Passo 4: emitir uma NF-e

Com a empresa aprovada, POST /openapi/v2/empresas/{empresaId}/nf-e aceita uma requisição de emissão. O id é gerado por você e é a chave para consulta, cancelamento e idempotência. ambienteEmissao deve corresponder ao ambiente atual da empresa; empresas recém-cadastradas começam em Homologacao.

bash
API_PATH="/openapi/v2/empresas/$EMPRESA_ID/nf-e"
BODY='{"id":"NFe-000014553","ambienteEmissao":"Homologacao","pedido":{"presencaConsumidor":"OperacaoPelaInternet","pagamento":{"formas":[{"tipo":"CartaoDeCredito","valor":28.47}]}},"cliente":{"tipoPessoa":"F","nome":"Demo Client","email":"demo.client@mail.com","cpfCnpj":"88533234775","endereco":{"uf":"PR","cidade":"4106902","logradouro":"Rua Presidente Wilson","numero":"911","bairro":"Uberaba","cep":"81570440"}},"itens":[{"cfop":"6403","codigo":"000068","descricao":"Kingston DataTraveler SE9 DTSE9H 16GB USB Drive","ncm":"85235190","ean":"619659000424","quantidade":1,"unidadeMedida":"UN","valorUnitario":28.47,"impostos":{"icms":{"situacaoTributaria":"101"},"pis":{"situacaoTributaria":"49"},"cofins":{"situacaoTributaria":"49"}}}]}'
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
-d "$BODY"

Uma requisição aceita devolve HTTP 200 sem corpo e entra no fluxo assíncrono de emissão. O resultado chega pelo webhook registrado no passo 3 ou pela consulta do passo 5. 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. Dicionário completo da requisição: Emitir NF-e.

Passo 5: consultar a NF-e

GET /openapi/v2/empresas/{empresaId}/nf-e/{nfeId} devolve o status atual, os dados da nota e, uma vez autorizada, os links de download do DANFE e do XML. nfeId é o id enviado no passo 4. Requisições GET assinam a string vazia como corpo; as variáveis de caminho fazem parte do caminho assinado.

bash
NFE_ID="NFe-000014553"
API_PATH="/openapi/v2/empresas/$EMPRESA_ID/nf-e/$NFE_ID"
TS=$(date +%s)
curl -sS -X GET "$HOST$API_PATH" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "" "$TS")"

O campo status passa de AguardandoAutorizacao para Autorizada (ou Negada, com um motivoStatus explicando o motivo). Uma vez autorizada, linkDanfe e linkDownloadXml podem ser baixados com um GET simples, veja Download de arquivos. Referência da resposta: Consultar NF-e.

Verifique os caminhos de falha

Cada linha é uma alteração de uma linha na sequência acima e confirma que o seu cliente falha da forma esperada:

AlteraçãoResultado esperado
Valor de token erradoHTTP 401, envelope code 10009002 (token inválido)
Alterar BODY depois de calcular signHTTP 401, envelope code 10009003 (assinatura divergente)
Reutilizar um timestamp com mais de 300 sHTTP 401, envelope code 10009001 (timestamp)
Chamar um endpoint ao qual a sua aplicação não está subscritaHTTP 403, envelope code 10009005 (não subscrito)
Cadastrar o mesmo CNPJ duas vezesHTTP 400, [{"codigo":"10003002", ...}]
Emitir com ambienteEmissao igual a Producao enquanto a empresa está em testeHTTP 400, [{"codigo":"10004030", ...}]
Consultar um nfeId desconhecidoHTTP 404, [{"codigo":"NFe0001", ...}]

Falhas de autenticação usam o envelope da plataforma; falhas de negócio dos endpoints de emissão usam um array de erros. Os dois formatos estão descritos em Convenções gerais.

Próximos passos

  • NF-e: cancelamento e cartas de correção (CC-e) além das chamadas acima.
  • CT-e e DC-e: os outros tipos de documento emitidos, compartilhando a mesma empresa, certificado e webhook.
  • Verificação de NF-e: verificar NF-e de terceiros por XML ou chave de acesso.
  • Consulta cadastral: consultas cadastrais de CNPJ e CPF.
  • Webhooks: cargas de callback, verificação de assinatura e tentativas.
  • Ambientes: como uma empresa passa de teste para produção.