Skip to Content
API Reference (English)Quick Start

Quick Start

This guide walks through the five calls every issuing integration makes, in order:

  1. Register the company that will issue invoices and obtain its empresaId.
  2. Link the company’s A1 digital certificate.
  3. Register a webhook to receive issuance results.
  4. Issue an NF-e.
  5. Query the NF-e for its status and download links.

All requests go to the production base URL https://api.v2.tffiscal.com; the full URL is the base URL plus the path shown for each call.

Prerequisites

  • Application credential — an app_secret issued for your application. It is displayed only once; store it securely. If it leaks, request a rotation.
  • API subscription — the platform grants your application access to every endpoint used below. Calling an endpoint you are not subscribed to returns HTTP 403 with code 10009005.
  • Signing — every request carries the token, timestamp and sign headers. The helper below is used by all examples on this page; the full specification is in Authentication & Signing. If this is your first call, verify your signing implementation against the echo endpoint first (see Verify signing with echo).
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}' }

Step 1 — Register the company

POST /openapi/v2/empresas submits the seller’s company data. The response carries the empresaId that every later call uses as a path variable — persist it.

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" }

Registration places the company in the platform’s approval queue. The company can issue only after operations approve it and the certificate is linked; registering the same CNPJ twice returns HTTP 400 with codigo 10003002. Field-by-field reference: Issuance API — Company registration.

POST /openapi/v1/empresas/{empresaId}/certificadoDigital is a multipart/form-data upload of the A1 certificate file and its password. For multipart requests the signed body is the empty string.

EMPRESA_ID="1934811222334455" API_PATH="/openapi/v1/empresas/$EMPRESA_ID/certificadoDigital" TS=$(date +%s) curl -sS -X POST "$HOST$API_PATH" \ -H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "" "$TS")" \ -F "senha=certpass123" -F "arquivo=@certificate.pfx"

Success is HTTP 200 with no body. A wrong password returns HTTP 400 with codigo CER0005.

Step 3 — Register the webhook

POST /openapi/v1/webhooks registers the URL that receives issuance results. The token you choose is sent back verbatim in the token request header of every callback, so your receiver can verify the origin.

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" }

There is one callback configuration per application; calling the endpoint again overwrites it. Registration subscribes you to the two result events, authorized and denied — see Webhooks.

Step 4 — Issue an NF-e

Once the company is approved, POST /openapi/v2/empresas/{empresaId}/nf-e accepts an issuance request. The id is generated by you and is the key for query, cancellation and idempotency. ambienteEmissao must match the company’s current environment; newly registered companies start in 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"

An accepted request returns HTTP 200 with no body and enters the asynchronous issuance flow. The result arrives through the webhook registered in step 3, or through the query in step 5. Full request dictionary: Issuance API — NF-e issuance.

Step 5 — Query the NF-e

GET /openapi/v2/empresas/{empresaId}/nf-e/{nfeId} returns the current status, the invoice data and, once authorized, the DANFE and XML download links. nfeId is the id you sent in step 4. GET requests sign the empty string as body; the path variables are part of the signed path.

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")"

The status field moves from AguardandoAutorizacao to Autorizada (or Negada with a motivoStatus explaining why). Response reference: Issuance API — NF-e query.

Verify the failure modes

Each row is a one-line change to the sequence above and confirms your client fails the way you expect:

ChangeExpected result
Wrong token valueHTTP 401, envelope code 10009002 (invalid token)
Change BODY after computing signHTTP 401, envelope code 10009003 (signature mismatch)
Reuse a timestamp older than 300 sHTTP 401, envelope code 10009001 (timestamp)
Call an endpoint your app is not subscribed toHTTP 403, envelope code 10009005 (not subscribed)
Register the same CNPJ twiceHTTP 400, [{"codigo":"10003002", ...}]
Issue with ambienteEmissao set to Producao while the company is in testHTTP 400, [{"codigo":"10004030", ...}]
Query an unknown nfeIdHTTP 404, [{"codigo":"NFe0001", ...}]

Authentication failures use the platform envelope; business failures of the issuance endpoints use an error array. Both shapes are described in General Conventions.

Next steps

  • Issuance API — the six endpoints of the issuing domain, including cancellation.
  • Verification API — verify third-party NF-e documents by XML or access key.
  • Identity API — CNPJ and CPF registry lookups.
  • Webhooks — callback payloads, signature verification and retries.
  • Environments — how a company moves from test to production.
Last updated on