API de NF-e
Integre o seu sistema e emita NF-e
A API recebe os dados da nota, confere, assina com o certificado A1 da empresa e transmite à SEFAZ. O seu sistema informa os tributos; a API confere as contas e as regras e devolve o que estiver errado antes de gastar um número.
nfe_test_.nfe_live_.Todas as chamadas usam HTTPS e JSON (Content-Type: application/json). Valores em dinheiro e quantidades vão como texto com ponto decimal ("150.00"), para não perder centavos.
Guia rápido
- Crie a conta em painel.esesistemas.com.br e confirme o e-mail.
- Cadastre a empresa e envie o certificado A1 (.pfx). Ele comprova que a empresa é sua e fica guardado cifrado; a API nunca o devolve.
- Configure a empresa em “Abrir painel da empresa”: dados do emitente, série e próximo número de homologação.
- Crie uma chave de homologação em “Chaves de API” e guarde no seu sistema (nunca no código-fonte).
- Emita notas de teste até sair tudo autorizado, inclusive cancelamento e carta de correção, se usar.
- Libere a produção no painel, crie a chave de produção e troque o endereço e a chave no seu sistema.
Autenticação
Envie a chave em todas as chamadas, num destes cabeçalhos:
Authorization: Bearer nfe_test_...
X-API-Key: nfe_test_...
Cada chave pertence a uma empresa e a um ambiente, e só pode o que foi marcado ao criá-la: emitir, consultar, cancelar, inutilizar e configurar. Uma chave de homologação não funciona em produção, e vice-versa. Para conferir a chave:
Emitir uma NF-e
POST /v1/nfe/emissoes (permissão emitir). Mande sempre um Idempotency-Key único por nota: se a conexão cair e você repetir a chamada com a mesma chave e o mesmo documento, recebe a mesma emissão de volta, sem gastar outro número.
O corpo (nota.json), numa venda dentro do estado para consumidor final:
{
"document": {
"external_id": "venda-1001",
"nature_of_operation": "Venda de mercadoria",
"operation": {"final_consumer": true, "presence_indicator": "1"},
"recipient": {
"document": "11444777000161",
"name": "CLIENTE LTDA",
"state_registration_indicator": "9",
"address": {"postal_code": "01001000", "street": "Praca da Se", "number": "1", "district": "Se",
"municipality": "Sao Paulo", "municipality_ibge_code": "3550308", "state": "SP"}
},
"items": [{
"code": "TINTA-18L", "description": "Tinta acrilica 18L", "ncm": "32091010", "cfop": "5102", "unit": "UN",
"quantity": "2", "unit_price": "150.00", "discount": "10.00",
"icms": {"origin": "0", "csosn": "101", "credit_rate": "1.25", "credit_amount": "3.63"},
"pis": {"cst": "01", "base": "290.00", "rate": "0.65", "amount": "1.89"},
"cofins": {"cst": "01", "base": "290.00", "rate": "3.00", "amount": "8.70"}
}],
"freight_mode": "9",
"payments": [{"method": "17", "amount": "290.00", "indicator": "0", "integration_type": "2"}],
"expected_total": "290.00"
},
"transmit": true
}
external_id- A sua referência (número do pedido ou da venda). Só pode existir uma nota ativa por referência; use-a para buscar depois.
transmittrue: prepara e transmite na mesma chamada.false: só prepara e assina; transmita depois comPOST /v1/nfe/{id}/transmitir.expected_total- O total que o seu sistema calculou. Se a soma dos itens ou dos pagamentos não bater, a nota é recusada antes de gastar o número.
payments[].method- Código tPag da SEFAZ (01 dinheiro, 03 crédito, 04 débito, 15 boleto, 17 PIX…). Cartão e PIX pedem
integration_type.
A resposta traz a emissão, com o número, a chave de acesso e, se transmitiu, o resultado da SEFAZ (resumida):
{
"emission": {
"emission_id": "6f0c…", "state": "autorizada", "environment": "homologacao",
"series": 1, "invoice_number": 1201, "access_key": "3526…",
"protocol": "135260000000001", "response_cstat": "100", "response_reason": "Autorizado o uso da NF-e"
},
"external_id": "venda-1001",
"replayed": false,
"transmission": {"attempted": true, "delivery": "...", "http_status": 200}
}
A transmissão é feita uma vez por chamada, nunca repetida por conta própria. Se a SEFAZ não confirmar a tempo, a nota fica em falha_ambigua e a API consulta a situação antes de qualquer reenvio, para nunca autorizar a mesma venda duas vezes.
Estados da nota
response_reason). Corrija e use a nova tentativa.Consultar, XML e DANFE
GET /v1/nfe/{id} | Estado atual da nota. |
GET /v1/nfe/emissoes?external_id=venda-1001 | Busca pela sua referência. |
POST /v1/nfe/{id}/consultar-situacao | Pergunta à SEFAZ (útil em falha_ambigua e processando). |
GET /v1/nfe/{id}/xml-autorizado | XML autorizado (nfeProc), o que deve ser guardado por 5 anos e enviado ao cliente. |
GET /v1/nfe/{id}/danfe | DANFE em PDF. |
GET /v1/nfe/{id}/eventos | Histórico de eventos (cancelamento, cartas de correção). |
Em vez de consultar repetidamente, prefira os webhooks: a API avisa o seu sistema quando a nota muda de estado.
Rejeição e nova tentativa
Quando a SEFAZ rejeita, corrija o que o motivo indicar e chame POST /v1/nfe/emissoes/{id}/nova-tentativa com o documento corrigido (mesmo external_id, mesmos itens e quantidades). A nota é preparada com a mesma série, número e chave, sem buraco na numeração.
Cancelar
POST /v1/nfe/{id}/cancelar (permissão cancelar), em nota autorizada e dentro do prazo da SEFAZ. O confirm: true é obrigatório: sem ele nada é enviado.
{"confirm": true, "justification": "Pedido cancelado pelo cliente antes da entrega", "operator": "Maria (financeiro)"}
A justificativa precisa ter de 15 a 255 caracteres. O XML do evento fica em GET /v1/nfe/{id}/cancelamento/xml.
Carta de correção
POST /v1/nfe/{id}/carta-correcao corrige dados que não mudam valores, impostos, destinatário nem data. Cada carta substitui a anterior, então envie o texto completo.
{"confirm": true, "text": "Onde se le Rua das Flores 100, leia-se Rua das Flores 1000.", "operator": "Maria (financeiro)"}
O texto vai de 15 a 1000 caracteres. As cartas ficam em GET /v1/nfe/{id}/cartas-correcao.
Inutilizar números
Se um número foi pulado e nunca vai ser usado, inutilize-o: POST /v1/nfe/inutilizacoes (permissão inutilizar). GET /v1/nfe/inutilizacoes/pendentes mostra os buracos da numeração.
{"confirm": true, "series": 1, "number_from": 1205, "number_to": 1205,
"justification": "Numero pulado por falha no sistema de vendas", "operator": "Maria (financeiro)"}
Webhooks
Cadastre um endereço HTTPS do seu sistema com POST /v1/webhooks/endpoints (permissão configurar). O segredo whsec_… aparece só nessa resposta: guarde-o.
{"url": "https://meusistema.com.br/nfe/webhook", "events": ["nfe.autorizada", "nfe.rejeitada", "nfe.cancelada"]}
Eventos: nfe.autorizada, nfe.rejeitada, nfe.denegada, nfe.cancelada e nfe.resultado_pendente (lista vazia = todos). O corpo:
{"id": "evt_…", "type": "nfe.autorizada", "created_at": "2026-11-04T13:00:00Z",
"data": {"emission_id": "6f0c…", "external_id": "venda-1001", "state": "autorizada", "previous_state": "transmitindo",
"environment": "homologacao", "series": 1, "invoice_number": 1201, "access_key": "3526…",
"protocol": "135260000000001", "cstat": "100", "reason": "Autorizado o uso da NF-e"}}
Toda entrega é assinada no cabeçalho X-NFe-Assinatura: t=<unix>,v1=<hex>, com v1 = HMAC-SHA256 do segredo sobre "<t>.<corpo>". Confira antes de confiar no conteúdo, recuse t com mais de 5 minutos e use X-NFe-Entrega para ignorar repetições (a entrega é “pelo menos uma vez”).
Responda com 2xx em até 5 segundos. Sem 2xx, a API tenta de novo em 1 min, 5 min, 30 min, 2 h e 6 h. GET /v1/webhooks/entregas mostra as tentativas, e POST /v1/webhooks/endpoints/{id}/teste manda um evento de teste.
Erros
Os erros vêm com {"detail": ...}. Na emissão, as pendências da nota vêm todas juntas, uma por campo, e nada é gravado:
{"detail": {"message": "O documento tem pendências; nada foi gravado nem enviado", "issues": [
{"field": "items[0].pis.amount", "code": "tributo_divergente",
"message": "valor 1.90 não confere com base × alíquota (1.89)"}
]}}
401 | Chave ausente, errada ou revogada. |
403 | A chave não tem a permissão desta rota, ou é de outro ambiente. |
404 | Nota não encontrada para esta empresa. |
402 | A cota do plano grátis acabou no mês. A emissão em produção volta no mês seguinte ou ao assinar um plano; a homologação segue liberada. |
409 | Conflito: external_id já tem nota ativa, Idempotency-Key repetida com outro conteúdo, ou produção ainda não liberada. |
422 | Dados da nota com pendências (veja issues), certificado ausente ou vencido, empresa não configurada. |
429 | Muitas chamadas à SEFAZ em pouco tempo. Espere e tente de novo. |
Escopo e limites
- Hoje: NF-e modelo 55, emitente do Simples Nacional (CRT 1 ou 4), venda (finalidade 1), CSOSN 101, 102, 103, 300, 400 e 500.
- Ainda não: NFC-e, regime normal, ICMS-ST, IPI, frete/seguro/outras despesas, DIFAL, importação e exportação, devolução. Esses casos são recusados com o motivo, nunca ignorados.
- Planos: conta cada documento autorizado em produção, somando as empresas da conta. O plano grátis tem 60 por mês e para na cota; os pagos seguem emitindo e cobram o excedente. Veja em “Plano e uso” no painel.
- SEFAZ: até 5 autorizações, 10 consultas e 5 eventos a cada 10 minutos por empresa e ambiente.
- Certificado: o painel avisa quando o A1 estiver perto de vencer. Troque em “Empresas → Trocar o certificado”.
Vindo de outro emissor
- Mantenha a numeração. A série e o próximo número de produção são os da última nota autorizada no emissor antigo, mais 1. Confira com o contador antes de liberar.
- Traga o histórico. Em “Abrir painel da empresa → Importar notas”, envie XMLs autorizados (ou um ZIP): a API sugere o cadastro de produtos e regras a partir deles. Os arquivos não ficam guardados.
- Teste em paralelo. Integre em homologação enquanto o emissor antigo continua em produção.
- Vire num momento calmo. Pare de emitir no antigo, confira o último número, libere a produção aqui e troque endereço e chave no seu sistema.
- Guarde os XMLs antigos. Notas emitidas antes continuam valendo e precisam ser guardadas por 5 anos; cancelamentos e cartas delas seguem no emissor antigo.
Ir para produção
- Notas autorizadas em homologação com os seus casos reais (consumidor final, empresa, PIX, cartão…).
- Cancelamento e carta de correção testados, se o seu sistema usa.
- Webhooks recebendo e conferindo a assinatura.
- XML autorizado sendo guardado e enviado ao cliente.
- Série e próximo número de produção conferidos com o contador.
- Verificação em duas etapas ativa no painel (exigida para liberar a produção).
No painel, o administrador libera a produção em “Empresas → Liberar a produção” e cria a chave de produção. No seu sistema, troque o endereço para https://api.esesistemas.com.br e a chave para a nfe_live_…. Os campos do corpo não mudam.