Skip to Content

Issuance API

Issue NF-e documents on behalf of sellers. The domain exposes six endpoints, used in the order below:

StepEndpointNotes
1POST /openapi/v2/empresasRegister the seller’s company; returns empresaId, the path variable of every later call
2POST /openapi/v1/empresas/{empresaId}/certificadoDigitalUpload the seller’s A1 digital certificate (.pfx) and its password
3POST /openapi/v1/webhooksRegister the callback URL for issuance results (authorized / denied)
4POST /openapi/v2/empresas/{empresaId}/nf-eAccepted immediately; authorized asynchronously with SEFAZ
5GET /openapi/v2/empresas/{empresaId}/nf-e/{nfeId}Status, invoice data, DANFE / XML download links
6DELETE /openapi/v2/empresas/{empresaId}/nf-e/{nfeId}Within 24 hours of authorization

All endpoints require the three signature headers — see Authentication & Signing. GET, DELETE and multipart requests sign the empty string as body; path variables are part of the signed path. Responses are bare (no platform envelope) and business errors come as an array of {codigo, mensagem} — see General Conventions.

Company status and prerequisites

  • Registration places the company in the platform’s approval queue. The company can issue only after operations approve it and the certificate is linked. Issuing before that returns codigo 10004004 (company not issuable).
  • Every company has one current environment: test (Homologacao) or production (Producao). Newly registered companies default to test; switching to production is an operations action. The ambienteEmissao of an issuance request must match the company’s current environment, otherwise the request is rejected with 10004030 — a hard guard against test invoices being issued into production. See Environments.

Company registration

POST /openapi/v2/empresas Content-Type: application/json

Request

{ "cnpj": "14422279000106", "inscricaoMunicipal": "999999", "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" } } }
FieldTypeRequiredDescription
cnpjstringyes14 digits
inscricaoMunicipalstringnoMunicipal registration, up to 15 characters
inscricaoEstadualstringyesState registration (IE). NF-e issuance requires an IE; missing returns 10003006
razaoSocialstringyesLegal name, up to 60
nomeFantasiastringnoTrade name, up to 60
optanteSimplesNacionalbooleanyesWhether the company is in the Simples Nacional regime
meibooleanyesWhether the company is an MEI. Tax regime derivation: mei=true → MEI; else optanteSimplesNacional=true → Simples; else regular regime
emailstringyesContact e-mail
telefoneComercialstringyesBusiness phone, digits only including area code
endereco.paisstringyesCountry
endereco.ufstringyesState code, 2 letters
endereco.cidadestringyesCity name; the platform resolves the IBGE municipality code from it — unknown or ambiguous within the state returns GW001
endereco.logradourostringyesStreet
endereco.numerostringyesStreet number, up to 16
endereco.complementostringnoAdditional info
endereco.bairrostringyesDistrict
endereco.cepstringyesPostal code, 8 digits
emissaoNFeProduto.ambienteProducao.sequencialNFenumberyesThe next NF-e number to issue (from 1); the platform manages the sequence automatically afterwards
emissaoNFeProduto.ambienteProducao.serieNFestringyesNF-e series (1–3 digits); a dedicated series for invoices issued through the platform is recommended

Response (HTTP 200)

{ "empresaId": "1934811222334455" }
FieldTypeDescription
empresaIdstringCompany identifier, the path variable of every later API — persist it. A numeric string

A successful registration enters the approval queue; registering the same CNPJ again returns HTTP 400 with codigo 10003002.

Digital certificate association

POST /openapi/v1/empresas/{empresaId}/certificadoDigital Content-Type: multipart/form-data
Form fieldTypeRequiredDescription
senhatextyesCertificate password
arquivofileyesA1 digital certificate file (.pfx / .p12)

Platform checks: password matches (CER0005 otherwise), certificate not expired (10003011), certificate CNPJ matches the company (10003010), not identical to the currently active certificate (10003012). Success is HTTP 200 with no body. A successful upload replaces the company’s previous certificate.

Signing note: for multipart requests the body is the empty string.

APP_SECRET="<APP_SECRET>" P="/openapi/v1/empresas/1934811222334455/certificadoDigital" TS=$(date +%s) SIGN=$(printf '%s' "${APP_SECRET}${P}${TS}" | md5sum | cut -d' ' -f1) curl -X POST "https://api.v2.tffiscal.com${P}" \ -H "token: ${APP_SECRET}" -H "timestamp: ${TS}" -H "sign: ${SIGN}" \ -F "senha=certpass123" -F "arquivo=@uploaded-cert.pfx"

Webhook registration

POST /openapi/v1/webhooks Content-Type: application/json

Request

{ "uri": "https://example.com/tffiscal/callback", "contentType": "application/json", "token": "dGt6eXp5ZGRra2tzc3Nra2hoaGFha2tha2FhamFoaGFoNzc3Nz" }
FieldTypeRequiredDescription
idstringrequired for updateThe webHookId returned on creation; omit to create, include to update (must belong to this application)
uristringyesPublic https/http URL that receives callbacks
contentTypestringyesOnly application/json is supported at present
tokenstringyesVerification token of your choosing; sent back verbatim in the token request header of every callback so your receiver can verify the origin

Response (HTTP 200)

{ "webHookId": "550001" }

One callback configuration per application: webHookId is the application identifier, and calling again overwrites the configuration. Registration automatically subscribes to the two result events, authorized and denied. An invalid registration (id mismatch or a non-JSON contentType) returns 10009033. The callback payload is documented in Webhooks — Issuance result callback.

NF-e issuance

POST /openapi/v2/empresas/{empresaId}/nf-e Content-Type: application/json

Accepted requests return HTTP 200 with no body and enter the asynchronous issuance flow; the result arrives via webhook or the query endpoint. Re-submitting the same id within the idempotency window reuses the original task.

Request

{ "id": "NFe-000014553", "ambienteEmissao": "Homologacao", "pedido": { "presencaConsumidor": "OperacaoPelaInternet", "pagamento": { "formas": [{ "tipo": "CartaoDeCredito", "valor": 28.47, "credenciadoraCartao": { "tipoIntegracaoPagamento": "NaoIntegradoAoSistemaDeGestao", "bandeira": "Mastercard" } }] } }, "cliente": { "tipoPessoa": "F", "nome": "Demo Client", "email": "demo.client@mail.com", "cpfCnpj": "88533234775", "telefone": "(41) 3278-0217", "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" } } }] }
FieldTypeRequiredDescription
idstringyesUnique issuance request id (generated by you, up to 64); also the nfeId for query / cancellation and the idempotency key
ambienteEmissaostringyesHomologacao / Producao; must match the company’s current environment
pedido.presencaConsumidorstringyesOnly OperacaoPelaInternet (internet sale) is supported at present
pedido.pagamento.formas[]arrayyesPayment methods — exactly one entry at present
pedido.pagamento.formas[].tipostringyesSee the payment type table below
pedido.pagamento.formas[].valornumberyesPayment amount
pedido.pagamento.formas[].credenciadoraCartaoobjectnoCard processor info (tipoIntegracaoPagamento / bandeira); accepted but not written into the NF-e
cliente.tipoPessoastringyesF individual / J legal entity; must be consistent with the length of cpfCnpj
cliente.nomestringyesName, up to 60
cliente.emailstringnoE-mail
cliente.cpfCnpjstringyesCPF (11 digits) or CNPJ (14 digits), digits only
cliente.telefonestringnoPhone; accepted but not written into the NF-e
cliente.endereco.paisstringnoCountry
cliente.endereco.ufstringyesState code
cliente.endereco.cidadestringyesIBGE 7-digit municipality code (note: the registration endpoint takes a city name)
cliente.endereco.logradourostringyesStreet, 2–60
cliente.endereco.numerostringyesStreet number
cliente.endereco.complementostringnoAdditional info
cliente.endereco.bairrostringyesDistrict, 2–60
cliente.endereco.cepstringyesPostal code, 8 digits
itens[].cfopstringyesCFOP, 4 digits
itens[].codigostringyesItem code, up to 60
itens[].descricaostringyesItem description, up to 120
itens[].ncmstringyesNCM, 8 digits
itens[].eanstringnoGTIN barcode; SEM GTIN is written when absent
itens[].ceststringnoCEST, 7 digits (required for ST goods)
itens[].quantidadenumberyesQuantity, greater than 0
itens[].unidadeMedidastringyesUnit of measure, up to 6
itens[].valorUnitarionumberyesUnit price
itens[].impostos.icms.situacaoTributariastringyesICMS tax code: 2-digit CST or 3-digit CSOSN
itens[].impostos.pis.situacaoTributariastringyesPIS CST, 2 digits
itens[].impostos.cofins.situacaoTributariastringyesCOFINS CST, 2 digits

The line total is computed by the platform as quantidade × valorUnitario rounded to two decimals; do not send it.

Tax codes and rates: the request carries tax codes only. Combinations that need no rate — CSOSN 102 / 103 / 300 / 400 for Simples Nacional companies together with PIS / COFINS 49 — issue directly; codes that require a rate (for example the ICMS rate for CST 00 under the regular regime, or the credit percentage for CSOSN 101) are currently rejected by the tax engine with 10005000 and will be enabled once the rate table is connected.

formas[].tipo values:

ValueMeaningValueMeaning
DinheiroCashValeCombustivelFuel voucher
ChequeChequeBoletoBancarioBank slip (boleto)
CartaoDeCreditoCredit cardDepositoBancarioBank deposit
CartaoDeDebitoDebit cardPagamentoInstantaneoPixPix
CreditoLojaStore creditTransferenciaBancariaBank transfer
ValeAlimentacaoFood voucherProgramaDeFidelidadeLoyalty programme
ValeRefeicaoMeal voucherSemPagamentoNo payment
ValePresenteGift voucherOutrosOther

Scope of this phase

ItemSupport
Invoice purposeRegular sales invoices only (finNFe=1)
Consumer presenceOperacaoPelaInternet only
Payment methodsOne entry; card processor info not written into the NF-e
FreightFixed to no transport (modFrete=9)
Tax ratesTax codes only; rate-free combinations issue directly, rate-dependent codes await the rate table
DANFE linkAvailable in the query response; absent from the callback payload
digestValue / customer phone / address complementNot provided at present

Values outside this range (presencaConsumidor, multiple payments, unknown payment type, tipoPessoa inconsistent with the document) are rejected with 10004031.

NF-e query

GET /openapi/v2/empresas/{empresaId}/nf-e/{nfeId}

nfeId is the id sent at issuance. Unknown ids return HTTP 404 with codigo NFe0001.

Response (HTTP 200)

{ "id": "NFe-000014553", "tipo": "NF-e", "status": "Autorizada", "ambienteEmissao": "Homologacao", "enviadaPorEmail": false, "dataCriacao": "2024-11-27T20:56:46Z", "dataUltimaAlteracao": "2024-11-27T20:56:56Z", "forcarEmissaoContingencia": false, "pedido": { "presencaConsumidor": "OperacaoPelaInternet", "pagamento": { "tipo": "PagamentoAVista", "formas": [{ "tipo": "CartaoDeCredito", "valor": 28.47 }] } }, "cliente": { "indicadorContribuinteICMS": "NaoContribuinte", "tipoPessoa": "F", "nome": "Demo Client", "email": "demo.client@mail.com", "cpfCnpj": "88533234775", "endereco": { "uf": "PR", "cidade": "Curitiba", "logradouro": "Rua Presidente Wilson", "numero": "911", "bairro": "Uberaba", "cep": "81570440" } }, "numero": "262", "serie": "10", "dataEmissao": "2024-11-27T20:56:46Z", "chaveAcesso": "35241104893402000113550020000002621202427463", "transporte": { "frete": { "modalidade": "SemFrete", "valor": 0 } }, "dataAutorizacao": "2024-11-27T20:56:55Z", "linkDanfe": "https://api.v2.tffiscal.com/open/files/8802?token=eyJh...", "linkDownloadXml": "https://api.v2.tffiscal.com/open/files/8801?token=eyJh...", "linkConsultaPorChaveAcesso": "", "protocolo": { "numero": "135240009194753" }, "emitidaEmContingencia": false, "itens": [{ "cfop": "6403", "codigo": "000068", "descricao": "Kingston DataTraveler SE9 DTSE9H 16GB USB Drive", "ncm": "85235190", "quantidade": 1, "unidadeMedida": "UN", "valorUnitario": 28.47, "valorTotal": 28.47 }], "valorTotal": 28.47 }

Top-level fields:

FieldTypeDescription
idstringIssuance request id
tipostringAlways NF-e
statusstringAguardandoAutorizacao processing / Autorizada authorized / Negada denied / Cancelada cancelled
motivoStatusstringDenial reason: SEFAZ status code + description, e.g. 778 - Rejeicao: NCM inexistente; present only for Negada
ambienteEmissaostringHomologacao / Producao
enviadaPorEmailbooleanAlways false (the platform does not e-mail invoices)
dataCriacaostringTime the issuance request was accepted, ISO-8601 UTC
dataUltimaAlteracaostringLast update time
forcarEmissaoContingenciabooleanAlways false
pedidoobjectOrder info — see below
clienteobjectCustomer info — see below
numerostringInvoice number nNF (string)
seriestringSeries
dataEmissaostringIssuance time
chaveAcessostring44-digit access key
transporte.frete.modalidadestringFreight modality, currently always SemFrete
transporte.frete.valornumberFreight cost, currently always 0
dataAutorizacaostringSEFAZ authorization time; empty until authorized
linkDanfestringDANFE PDF download link (10-minute token), Autorizada only; the first query triggers rendering
linkDownloadXmlstringAuthorized XML download link (10-minute token), when an XML exists
linkConsultaPorChaveAcessostringAlways the empty string
protocolo.numerostringAuthorization protocol number
protocolo.digestValuestringSignature digest, not provided at present
emitidaEmContingenciabooleanWhether issued in contingency mode
itens[]arrayLine items: cfop / codigo / descricao / ncm / ean / cest / quantidade / unidadeMedida / valorUnitario / valorTotal / impostos
valorTotalnumberInvoice total
informacoesAdicionaisstringAdditional information, not provided at present
informacoesAdicionaisFiscostringAdditional information for the tax authority, not provided at present

pedido:

FieldTypeDescription
presencaConsumidorstringAlways OperacaoPelaInternet
pagamento.tipostringAlways PagamentoAVista
pagamento.formas[].tipostringPayment type (as sent at issuance)
pagamento.formas[].valornumberPayment amount = invoice total
pagamento.formas[].cnpjEstabelecimentoPagamentostringAcquirer CNPJ, not provided at present
pagamento.formas[].ufEstabelecimentoPagamentostringAcquirer state, not provided at present
intermediadorTransacaoobjectTransaction intermediary, not provided at present

cliente:

FieldTypeDescription
indicadorContribuinteICMSstringNaoContribuinte / ContribuinteICMS
tipoPessoastringF / J (derived from the document length)
nome / email / cpfCnpjstringAs sent at issuance
inscricaoMunicipal / inscricaoEstadualstringNot provided at present
telefonestringNot provided at present
endereco.ufstringState code
endereco.cidadestringCity name (the issuance request carries the IBGE code; it is resolved to the name here)
endereco.logradouro / numero / bairro / cepstringAs sent at issuance
endereco.complementostringNot provided at present

Status semantics: AguardandoAutorizacao from acceptance until SEFAZ replies; Autorizada once authorized; Negada when rejected (motivoStatus explains why — fix and resubmit under a new id); Cancelada after a successful cancellation.

NF-e cancellation

DELETE /openapi/v2/empresas/{empresaId}/nf-e/{nfeId}

Cancels an authorized invoice; success is HTTP 200 with no body, and the query endpoint then returns Cancelada. Rules:

  • Only Autorizada invoices can be cancelled; other statuses return 10004012.
  • Within 24 hours of authorization (some states allow more, per platform configuration); outside the window returns 10004013, and only a return invoice can be issued instead.
  • A SEFAZ refusal returns 10004014 with the SEFAZ status code and reason.
  • Unknown nfeId returns HTTP 404 with codigo NFe0001.

Business error codes

codigoHTTPScenarioAction
GW001400Registration: city / state cannot be resolved to an IBGE code; issuance: customer IBGE municipality code does not existCheck the UF and city name / IBGE code
CER0005400Certificate password mismatchCheck the password
NFe0001404The nfeId for query / cancellation does not existCheck the id sent at issuance and the empresaId
10003002400CNPJ already registeredThe company exists — use the original empresaId
10003000404empresaId does not exist or does not belong to this applicationCheck the empresaId
10003006400Registration data missing the IEProvide inscricaoEstadual
10003010 / 10003011 / 10003012400Certificate CNPJ mismatch / expired / identical to the current oneUse the correct certificate
10004004400Company not issuable (not yet approved or certificate not ready)Wait for approval / link the certificate
10004030400ambienteEmissao does not match the company’s current environmentSubmit under the company environment or ask operations to switch it
10004031400Value not supported in this phase (presencaConsumidor / multiple payments / unknown payment type / tipoPessoa inconsistent with the document)Adjust to the supported range
10004002400Too many pending issuance tasks for the CNPJRetry later
10004012400Cancellation: invoice not in authorized statusQuery to confirm the status
10004013400Cancellation: outside the 24-hour windowIssue a return invoice instead
10004014400Cancellation: refused by SEFAZ (status code and reason attached)Act on the SEFAZ reason
10005000400Insufficient tax parameters (e.g. a tax code that needs a rate)See “Tax codes and rates” above
10009033400Invalid webhook registration (id mismatch / non-JSON contentType)Fix as described
10001001400Request field validation failed (one entry per field)Fix per mensagem

Authentication-layer errors (401 / 403 / 429) use the platform envelope — see Authentication & Signing. The full cross-domain table is in Error Codes.

Integration checklist

  1. Register a company → 200 + empresaId; register the same CNPJ again → 400 + 10003002.
  2. Link the certificate → 200 with no body; wrong password → 400 + CER0005.
  3. Register the webhook → 200 + webHookId.
  4. After approval, issue with ambienteEmissao=Homologacao → 200 with no body; then query → AguardandoAutorizacao becomes Autorizada, and linkDanfe / linkDownloadXml download successfully.
  5. Receive the authorized callback: the token header equals the registered value and the payload has nfeStatus=Autorizada.
  6. Negative cases: ambienteEmissao=Producao → 400 + 10004030; presencaConsumidor=OperacaoPresencial → 400 + 10004031.
  7. Cancel the just-authorized invoice → 200; query again → Cancelada; cancel an unknown id → 404 + NFe0001.
  8. Failure paths: wrong sign → 401 + 10009003; unsubscribed endpoint → 403 + 10009005.

Troubleshooting

Issuance stuck in AguardandoAutorizacao? While the company is in the test environment, this depends on the availability of the SEFAZ test environment; if it persists for more than a few minutes, contact the platform with the empresaId and nfeId.

Issuance returns 10004004? The company has not been approved yet, or its certificate is not linked / has expired. Complete approval and certificate association after registration first.

Callbacks not arriving? Make sure uri is a publicly reachable https/http address that returns 2xx; the platform retries with backoff and trips a circuit breaker after consecutive failures — calling the registration endpoint again restores delivery.

Last updated on