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:
- Cadastrar a empresa que emitirá os documentos e obter o seu
empresaId. - Vincular o certificado digital A1 da empresa.
- Registrar um webhook para receber os resultados de emissão.
- Emitir uma NF-e.
- 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_secretemitido 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,timestampesign. 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.
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.
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"
{ "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.
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.
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"
{ "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.
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.
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ção | Resultado esperado |
|---|---|
Valor de token errado | HTTP 401, envelope code 10009002 (token inválido) |
Alterar BODY depois de calcular sign | HTTP 401, envelope code 10009003 (assinatura divergente) |
Reutilizar um timestamp com mais de 300 s | HTTP 401, envelope code 10009001 (timestamp) |
| Chamar um endpoint ao qual a sua aplicação não está subscrita | HTTP 403, envelope code 10009005 (não subscrito) |
| Cadastrar o mesmo CNPJ duas vezes | HTTP 400, [{"codigo":"10003002", ...}] |
Emitir com ambienteEmissao igual a Producao enquanto a empresa está em teste | HTTP 400, [{"codigo":"10004030", ...}] |
Consultar um nfeId desconhecido | HTTP 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.
