Visão geral
Cada empresa tem as suas chaves de API (em Configurações → Integração via API). A nota é emitida com o certificado, o ambiente e os dados da empresa dona da chave; uma chave nunca acessa dados de outra empresa.
- Base:
https://e-nfse.com.br/api/v1(somente HTTPS) - Formato: JSON (
Content-Type: application/json), codificação UTF-8 - Emissão síncrona: a resposta do
POST /nfsejá traz o resultado (número, chave e links) ou a rejeição da SEFIN - Limite: 120 requisições por minuto por chave (
429comRetry-Afterse exceder)
Autenticação
Envie a chave no cabeçalho Authorization. Guarde-a como segredo (não a coloque em código público nem em aplicativos de celular/navegador).
Authorization: Bearer enfse_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Também é aceito o cabeçalho X-API-Key: enfse_... (só a chave, sem Bearer). Chave ausente, inválida, revogada ou de empresa desativada retorna 401; chamada sem HTTPS, 403 https_obrigatorio; plano sem acesso à API, 403 plano_sem_api.
Endpoints
| Método | Caminho | Descrição |
|---|---|---|
| GET | /ping | Saúde do serviço (sem autenticação). |
| GET | /me | Confere a chave e mostra a situação da empresa (ambiente, certificado, pendências de cadastro) e da assinatura (plano, limite de notas, se já pode emitir em produção e o motivo quando não pode). |
| GET | /codigos-municipais?codigo_tributacao_nacional= | Códigos de tributação municipal válidos para o serviço, no município da empresa (veja Código de tributação municipal). |
| POST | /nfse | Cria e emite a NFS-e (201). Com o cabeçalho Prefer: respond-async entra na fila de emissão e responde 202 (recomendado para lotes). |
| GET | /nfse?external_id=... | Consulta pelo seu identificador. |
| GET | /nfse?status=&limit=&offset= | Lista as mais recentes (limit até 100, padrão 20). status: emitida, erro, processando, na_fila, rascunho ou cancelada. |
| GET | /nfse/{id} | Consulta uma nota pelo ID. |
| GET | /nfse/{id}/xml | XML da NFS-e autorizada. |
| POST | /nfse/{id}/enviar | Envia a NFS-e emitida ao tomador por e-mail e/ou WhatsApp, com as integrações da própria empresa (veja Enviar a nota ao cliente). |
| GET | /relatorios/mensal?mes=AAAA-MM&ambiente=producao | Totais do mês com e sem retenção de ISS e a lista das notas emitidas (para conciliação e contabilidade). ambiente: producao (padrão), homologacao ou todos. Com &formato=csv devolve a planilha. |
Emitir uma NFS-e — POST /nfse
O mínimo é o seu identificador do pedido, o tomador e o serviço:
curl -X POST https://e-nfse.com.br/api/v1/nfse \
-H "Authorization: Bearer $CHAVE" \
-H "Content-Type: application/json" \
-d '{
"external_id": "pedido-12345",
"tomador": { "cpf_cnpj": "217.981.762-20", "nome": "Antonio Brito Lima" },
"servico": {
"descricao": "Serviço de suporte técnico em informática",
"valor": 150.00,
"codigo_tributacao_nacional": "01.07.01"
}
}'
Com tomador pessoa jurídica (endereço obrigatório), código municipal, desconto e retenções:
{
"external_id": "pedido-12346",
"tomador": {
"cpf_cnpj": "11.222.333/0001-81",
"nome": "Cliente Exemplo Ltda",
"email": "financeiro@cliente.com.br",
"telefone": "(92) 99999-2222",
"endereco": {
"cep": "69082-551", "logradouro": "Rua Exemplo", "numero": "29",
"bairro": "Coroado", "codigo_ibge": "1302603"
}
},
"servico": {
"descricao": "Suporte técnico - setembro/2026",
"valor": 1000.00,
"desconto": 100.00,
"codigo_tributacao_nacional": "01.07.01",
"codigo_municipal": "100",
"pedido": "PED-98765"
},
"retencao_iss": true,
"aliquota_iss": 2.5,
"retencoes_federais": { "irrf": 1.5, "csll": 1, "pis": 0.65, "cofins": 3, "inss": 11 }
}
Campos
| Campo | Obrigatório | Descrição |
|---|---|---|
external_id | sim | Identificador do seu pedido: 1 a 100 caracteres (letras, números, . - _ :); acima disso é recusado. Garante que a nota não seja emitida duas vezes se você repetir a chamada. Não diferencia maiúsculas de minúsculas (PED-1 e ped-1 são o mesmo pedido). Pode vir no cabeçalho Idempotency-Key quando o corpo não traz o campo. |
tomador.cpf_cnpj | sim | CPF (11 dígitos) ou CNPJ (14), com ou sem máscara; os dígitos verificadores são conferidos. Envie como texto (um número JSON perde os zeros à esquerda). |
tomador.nome | sim | Nome ou razão social, até 150 caracteres. |
tomador.email | não | E-mail válido, até 80 caracteres. Vai na nota e é usado no envio automático ao cliente. |
tomador.telefone | não | Com DDD, de 6 a 20 dígitos (a máscara é ignorada). |
tomador.inscricao_municipal | não | Só os números são usados (até 15 dígitos). Um texto sem números, como "Isento", conta como não informado. |
tomador.endereco | CNPJ: sim CPF: não | Objeto com cep (8 dígitos), logradouro (até 255), numero (até 60), bairro (até 60), complemento (até 156; fica no cadastro, não sai na nota) e o município: codigo_ibge (7 dígitos, conferido na lista oficial do IBGE) ou cidade + uf (sigla). Sem codigo_ibge, a cidade é procurada pelo nome na lista oficial (acentos, hífens e maiúsculas não importam); sem uf, só quando o nome é único no país. Com CNPJ, cep, logradouro, numero, bairro e o município são obrigatórios em toda emissão (regra E0235 da SEFIN). Com CPF o endereço é opcional; se vier com cep, logradouro, numero e bairro, ele vai na nota e o município também é obrigatório. O cadastro do cliente fica com o nome e a UF oficiais do município. |
servico.descricao | sim | Descrição do serviço, até 2000 caracteres. |
servico.valor | sim | Valor em reais, maior que zero, com até 2 casas decimais (mais que isso é recusado): número (150.5) ou texto ("150.50" ou "150,50"; sem separador de milhar). |
servico.desconto | não | Desconto incondicionado, no mesmo formato e menor que o valor (vazio ou null = sem desconto). Reduz a base do ISS e das retenções. |
servico.codigo_tributacao_nacional | sim | Código de tributação nacional de 6 dígitos ("010301" ou "01.03.01"). |
servico.codigo_municipal | não (recomendado) | Código de tributação municipal de 3 dígitos ("100"; também aceita "01.03.01.100"). Cada prefeitura define o seu: se omitido, o sistema descobre e usa o código do município quando houver um só; se informado, é conferido (veja abaixo). |
servico.nbs | não | Código NBS de 9 dígitos (com ou sem pontos). |
servico.informacoes_complementares (até 2000), pedido (até 60), documento_referencia (até 255) | não | Textos que saem na nota. |
retencao_iss | não | true se o tomador retém o ISS; ausente = false. Aceita true/false (também 1/0 e "true"/"false"; vazio ou null = false). Informe em cada nota: a API não usa a marcação "retém ISS" do cadastro do cliente no painel. |
aliquota_iss | não | Alíquota do ISS em %, de 0 a 5 (2.5, "2.5" ou "2,5"). Para ME/EPP com retenção, vai na nota; omitida ou 0 = 5%, como no emissor nacional. Sem retenção (MEI, ME e EPP do Simples Nacional) o ISS é recolhido no DAS, a nota não leva alíquota e o campo é ignorado. MEI nunca leva alíquota. |
retencoes_federais | não | Tributos federais retidos pelo tomador, em % sobre o valor do serviço menos o desconto: {"irrf": 1.5, "csll": 1, "pis": 0.65, "cofins": 3, "inss": 11}. Só essas chaves; de 0 a 30 cada, com até 2 casas decimais; informe só os retidos (vazio ou null = não retido). Vale para qualquer regime. A soma de todas as retenções (federais + ISS retido) não pode passar do valor do serviço menos o desconto (422 dados_invalidos). |
assincrono | não | true = modo assíncrono (o mesmo que o cabeçalho Prefer: respond-async). |
retencao_iss, aliquota_iss, retencoes_federais e assincrono ficam na raiz do JSON, fora de servico (dentro de servico são recusados com 400). Valores acima do limite ou de tipo errado são recusados com 400, nunca cortados. Campos desconhecidos são ignorados.Retenções
Os valores retidos são calculados sobre o valor do serviço menos o desconto e vão no leiaute da DPS (tpRetISSQN/pAliq do ISS; vRetIRRF, vRetCSLL, vRetCP e o grupo PIS/COFINS com o tipo de retenção). A resposta traz os valores em retencoes (R$; 0.0 quando não há). No segundo exemplo acima (valor 1.000,00, desconto 100,00, base 900,00), para uma ME/EPP:
"retencoes": { "iss": 22.5, "irrf": 13.5, "csll": 9.0, "pis": 5.85, "cofins": 27.0, "inss": 99.0 }
Para MEI com retencao_iss: true, a nota sai como retida pelo tomador, sem alíquota, e retencoes.iss é 0.0.
O que vem do cadastro (não envie)
- Prestador: CNPJ, inscrição municipal (a registrada no CNC NFS-e do ambiente), município e regime (MEI, ME ou EPP) vêm do cadastro da empresa dona da chave; o nome e o endereço do prestador a SEFIN completa pelo cadastro dela.
- Ambiente (homologação ou produção), série e número da DPS.
- Data de emissão e competência: o dia do envio à SEFIN (no modo assíncrono, o do processamento da fila).
- Local da prestação: o município da empresa. ISS sempre tributável (imunidade, exportação e não incidência não são emitidas pela API) e sem deduções.
Cadastro do tomador
Cada emissão cria ou atualiza o tomador no cadastro de clientes da empresa (pelo CPF/CNPJ) com os campos informados. Campos omitidos mantêm o que já está no cadastro e também vão na nota (por exemplo, o e-mail ou o telefone cadastrados no painel, ou o endereço de um tomador com CPF). Tomador com CNPJ precisa do endereço completo em toda emissão. Um município novo informado substitui o anterior.
Código de tributação municipal
Cada prefeitura define um código de 3 dígitos para cada serviço (em Manaus, 01.03.01 → 100 e 01.03.02 → 200; em São Paulo, 01.07.01 → 001 ou 002) e a SEFIN recusa (E0314) um código que o município não administra. O sistema consulta a base nacional de parâmetros municipais e guarda o resultado; por isso:
- Código informado e inexistente no município: a nota não é criada e a resposta é
422com"erro": "codigo_municipal_invalido"e, emdetalhes[0].codigos_validos, os códigos que existem. - Código omitido e município com um único código para o serviço: ele é preenchido automaticamente (igual ao portal nacional), exceto
000(que significa "sem desdobro"). - Código omitido e município com vários códigos: a nota é emitida sem código municipal e a resposta traz
"avisos": [...]. Informe o código desejado para escolher um. - Base nacional indisponível (ou município sem parâmetros): a emissão segue normalmente e a SEFIN decide. MEI não tem o código conferido pela SEFIN, então nada é bloqueado.
- Menos de 3 dígitos são completados com zeros à esquerda (
"1"→"001").
Para saber os códigos antes de emitir: GET /codigos-municipais?codigo_tributacao_nacional=010701. A primeira consulta de um serviço pode levar alguns segundos; as seguintes vêm do catálogo.
{
"municipio": { "ibge": "1302603", "nome": "Manaus", "uf": "AM" },
"codigo_tributacao_nacional": "010701",
"situacao": "encontrado",
"validacao_ativa": true,
"codigos_municipais": [ { "codigo": "100", "aliquota": 5.0 } ],
"sugerido": "100",
"motivo": null
}
situacao: encontrado, nao_encontrado (nenhum código nas combinações mais comuns; o serviço pode não usar código municipal), indisponivel (veja motivo), mei ou sem_municipio.
Resposta de sucesso — 201 Created
{
"id": 42,
"external_id": "pedido-12345",
"status": "emitida",
"valor": 150.0,
"retencoes": { "iss": 0.0, "irrf": 0.0, "csll": 0.0, "pis": 0.0, "cofins": 0.0, "inss": 0.0 },
"numero_dps": "31",
"serie_dps": "1",
"origem": "e-nfse",
"criada_em": "2026-09-30T14:20:11-03:00",
"nfse": {
"numero": "74",
"chave": "13026032204038227000187000000000007426093101234567",
"data_emissao": "2026-09-30T14:20:12-03:00",
"ambiente": "producao"
},
"links": {
"danfse": "https://e-nfse.com.br/d/AbCd...",
"xml": "https://e-nfse.com.br/x/AbCd...",
"consulta_publica": "https://www.nfse.gov.br/ConsultaPublica?tpc=1&chave=..."
}
}
valor é o valor bruto do serviço. Quando houver, vem também "avisos": [...] (por exemplo, código municipal não escolhido). Os links danfse e xml são públicos (não pedem login) e difíceis de adivinhar: podem ser enviados ao cliente por e-mail. Para conferir os demais dados emitidos, use GET /nfse/{id}/xml.
Repetindo a chamada (idempotência)
Se você repetir o POST com o mesmo external_id de uma nota já emitida, recebe 200 com a mesma nota e "ja_emitida": true — sem emitir outra e sem alterar nada, mesmo que o corpo seja diferente. É seguro repetir em caso de timeout de rede, mesmo que depois o certificado tenha vencido. Os dados do corpo são conferidos antes dessa verificação: repita com o mesmo corpo da primeira chamada.
Rejeição pela SEFIN
{
"id": 43,
"external_id": "pedido-12347",
"status": "erro",
"valor": 150.0,
"retencoes": { "iss": 0.0, "irrf": 0.0, "csll": 0.0, "pis": 0.0, "cofins": 0.0, "inss": 0.0 },
"numero_dps": "32",
"serie_dps": "1",
"origem": "e-nfse",
"criada_em": "2026-09-30T14:21:40-03:00",
"nfse": null,
"links": null,
"erros": [
{ "codigo": "E0314", "descricao": "O código de tributação municipal informado não existe ...", "complemento": "" }
],
"mensagem": "E0314: O código de tributação municipal informado não existe ..."
}
O corpo é a própria nota e o HTTP indica o tipo de falha: 422 (a SEFIN rejeitou; status erro com erros), 502 (falha de comunicação ou erro interno da SEFIN; status erro) ou 409 (a mesma nota já estava sendo enviada por outra chamada; consulte em instantes). A nota fica salva. Corrija os dados e envie o mesmo external_id novamente: a mesma nota (mesmo número de DPS) é atualizada e reenviada, inclusive se a correção for o tomador. Nota cancelada não pode ser reenviada (422 dados_invalidos). Se o envio foi interrompido (a nota ficou em processando por mais de 10 minutos), reenviar com o mesmo external_id retoma a mesma nota.
Emissão em massa: modo assíncrono (fila) — 202 Accepted
Cada emissão direta (201) mantém a sua conexão aberta por alguns segundos enquanto a SEFIN responde. Para lotes grandes (centenas de notas de uma vez), peça o modo assíncrono: a nota é validada e gravada, a resposta é imediata (202) e a emissão acontece em segundo plano, uma nota por empresa por vez, em ordem de chegada. Isso protege o seu lote e o serviço: nenhuma empresa consegue travar as outras.
curl -X POST https://e-nfse.com.br/api/v1/nfse \
-H "Authorization: Bearer $CHAVE" \
-H "Content-Type: application/json" \
-H "Prefer: respond-async" \
-d '{ "external_id": "pedido-12345", ... }' # ou, no corpo: "assincrono": true
HTTP/1.1 202 Accepted
Location: https://e-nfse.com.br/api/v1/nfse/42
Retry-After: 5
Preference-Applied: respond-async
{
"id": 42,
"external_id": "pedido-12345",
"status": "na_fila",
"valor": 150.0,
"retencoes": { ... },
"numero_dps": "31",
"serie_dps": "1",
"origem": "e-nfse",
"criada_em": "2026-09-30T14:20:11-03:00",
"nfse": null,
"links": null,
"posicao_na_fila": 7,
"mensagem": "NFS-e recebida e na fila de emissão. Consulte o andamento em GET /api/v1/nfse/42."
}
Acompanhe com GET /nfse/{id} (ou GET /nfse?external_id=...) a cada poucos segundos: o status vai de na_fila para processando e termina em emitida (com nfse e links) ou erro (com erros; reenvie o mesmo external_id depois de corrigir). GET /nfse?status=na_fila lista o que ainda aguarda. Repetir o POST com o mesmo external_id de uma nota que ainda está na fila devolve 202 com "ja_na_fila": true, sem duplicar (com ou sem o modo assíncrono).
- Na entrada são conferidos os dados, o cadastro da empresa, o certificado e a situação da assinatura: problemas voltam na hora (
400,402,422). O limite de notas do plano é conferido a cada emissão: num lote maior que o saldo do mês, as notas além do limite terminam emerrocom o códigolimite_notas. Se a assinatura for bloqueada enquanto a nota espera, ela também termina emerrocom o motivo. - A fila de cada empresa tem um teto (1.000 notas por padrão): acima dele a API responde
429fila_cheiacomRetry-After. Envie o resto depois que parte da fila for emitida. - No modo síncrono (sem o cabeçalho), se houver emissões demais em andamento para a empresa ou no servidor, a API responde
429(muitas_emissoes_simultaneasouservidor_ocupado) comRetry-After: aguarde e repita, ou passe a usar o modo assíncrono.
Enviar a nota ao cliente — POST /nfse/{id}/enviar
Envia a NFS-e já emitida ao tomador por e-mail e/ou WhatsApp, usando o e-mail e a Z-API da própria empresa, configurados no painel em Configurações → Envio da NFS-e ao cliente (e-mail pelo Google com senha de app, ou outro SMTP). O cliente recebe os links do DANFSe e do XML (e o XML anexado, no e-mail).
O envio também pode ser automático: com a opção ligada no painel, toda nota de produção emitida (pelo painel ou pela API, inclusive no modo assíncrono) é enviada ao tomador em até 1 minuto, usando o e-mail e o telefone do cadastro do tomador (atualizados com os dados informados na emissão; para o WhatsApp, um celular já cadastrado tem preferência sobre um telefone fixo). Notas de homologação não são enviadas automaticamente.
curl -X POST https://e-nfse.com.br/api/v1/nfse/42/enviar \
-H "Authorization: Bearer $CHAVE" \
-H "Content-Type: application/json" \
-d '{ "canais": ["email", "whatsapp"], "email": "outro@cliente.com.br", "telefone": "(92) 99999-2222" }'
Todos os campos são opcionais e o corpo pode ser omitido: sem canais tenta e-mail e WhatsApp; email e telefone valem só para este envio (sem eles, usa os do cadastro do tomador). Se enviar corpo, ele precisa ser application/json (senão 415) com até 4 KB.
{
"enviados": ["email"],
"resultados": {
"email": { "ok": true, "destino": "outro@cliente.com.br", "mensagem": "E-mail enviado para outro@cliente.com.br." },
"whatsapp": { "ok": false, "destino": "5592999992222", "mensagem": "WhatsApp não configurado: informe a Z-API da empresa em Configurações." }
}
}
Resposta 200 se pelo menos um canal enviou; 422 com "erro": "envio_falhou" e resultados (o motivo de cada canal) se nenhum enviou; 409 (nao_emitida) se a nota ainda não foi autorizada; 404 se a nota não existe. Há um limite de envios por dia por empresa e um intervalo de 1 minuto para repetir o mesmo destino.
Códigos de resposta
| HTTP | erro | Quando |
|---|---|---|
| 200 / 201 | — | Sucesso (201 = emitida agora; 200 = consulta ou nota já emitida). |
| 202 | — | Nota recebida e na fila de emissão (modo assíncrono). Consulte o andamento em GET /nfse/{id} (cabeçalho Location). |
| 400 | validacao, json_invalido, corpo_vazio | Dados inválidos. Em detalhes vem a lista [{campo, mensagem}]. |
| 401 | nao_autenticado | Chave ausente, inválida ou revogada. |
| 402 | assinatura_em_teste, assinatura_pendente, assinatura_bloqueada, assinatura_cancelada, limite_notas | Só no POST /nfse em produção: a assinatura não permite emitir agora (período de teste, aguardando pagamento, bloqueada por falta de pagamento, cancelada) ou o limite mensal de notas do plano foi atingido. A nota não é enviada à SEFIN; no modo síncrono ela fica salva como rascunho com o external_id (repita a chamada depois de regularizar). A empresa regulariza em "Minha assinatura" no painel; consulte GET /me (assinatura.pode_emitir_producao). Em homologação nunca ocorre. |
| 403 | https_obrigatorio, plano_sem_api | Chamada sem HTTPS / o plano da empresa não inclui o acesso à API. |
| 422 (relatório) | mes_invalido, ambiente_invalido | Parâmetros de /relatorios/mensal inválidos. |
| 404 | nao_encontrada, rota_inexistente | Nota inexistente (ou de outra empresa) / caminho errado. |
| 405 | metodo_nao_permitido | Método HTTP não aceito no caminho (cabeçalho Allow diz quais são). |
| 409 | em_processamento, nao_emitida | Já existe envio em andamento para o external_id (consulte em instantes) / XML ou envio ao cliente pedido para nota não autorizada. |
| 413 / 415 | corpo_grande, tipo_invalido | Corpo acima de 256 KB / sem application/json. |
| 422 (envio) | envio_falhou, envio_invalido | Em POST /nfse/{id}/enviar: nenhum canal conseguiu enviar (veja resultados) / o pedido é inválido. |
| 422 | empresa_incompleta, sem_certificado, certificado_vencido, codigo_municipal_invalido, dados_invalidos ou status erro | A empresa não está pronta para emitir (empresa_incompleta: a mensagem lista o que falta no cadastro; certificado ausente ou vencido), o código municipal não existe no município (veja detalhes), as retenções somadas passam do valor do serviço menos o desconto ou a nota foi cancelada (dados_invalidos), ou a SEFIN rejeitou a nota (corpo = nota com status erro e erros). |
| 429 | limite_excedido, muitas_emissoes_simultaneas, servidor_ocupado, fila_cheia | Mais de 120 requisições/minuto; emissões simultâneas demais (empresa ou servidor) no modo síncrono; ou fila de emissão da empresa cheia. Aguarde o tempo de Retry-After (e, para lotes, use o modo assíncrono). |
| 502 | — | Falha de comunicação ou erro interno da SEFIN (corpo = nota com status erro); a nota ficou salva, reenvie com o mesmo external_id. |
| 500 | erro_interno | Erro inesperado no servidor. A nota pode ter ficado salva: repita com o mesmo external_id. |
Corpo de erro padrão: {"erro": "codigo", "mensagem": "texto", "detalhes": [...]} (detalhes só aparece quando há itens: [{campo, mensagem}] na validação, com codigos_validos no código municipal). Falhas de envio à SEFIN devolvem a própria nota, com status erro e erros.
Exemplos
PHP
$ch = curl_init('https://e-nfse.com.br/api/v1/nfse');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NFSE_CHAVE'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'external_id' => 'pedido-' . $pedidoId,
'tomador' => ['cpf_cnpj' => $cpf, 'nome' => $nome],
'servico' => ['descricao' => 'Mensalidade', 'valor' => 99.90, 'codigo_tributacao_nacional' => '010701'],
]),
CURLOPT_TIMEOUT => 60,
]);
$resposta = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http === 201 || $http === 200) { /* $resposta['links']['danfse'] */ }
Node.js
const r = await fetch('https://e-nfse.com.br/api/v1/nfse', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.NFSE_CHAVE}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
external_id: `pedido-${pedido.id}`,
tomador: { cpf_cnpj: pedido.cpf, nome: pedido.nome },
servico: { descricao: 'Mensalidade', valor: 99.9, codigo_tributacao_nacional: '010701' },
}),
});
const nota = await r.json(); // r.status === 201 => nota.links.danfse
Boas práticas
- Para emitir em massa, use o modo assíncrono (
Prefer: respond-async) e consulte o andamento depois; evite disparar centenas de chamadas síncronas ao mesmo tempo. - Use sempre um
external_idestável por pedido (por exemplo, o ID do pagamento) e repita a chamada em caso de timeout ou erro 5xx: não há risco de duplicar a nota. - Emita a nota depois da confirmação do pagamento e guarde o
nfse.chavee os links. - Acompanhe o vencimento do certificado digital da empresa (
GET /memostra a validade) — com ele vencido nenhuma nota é emitida. - Mantenha a chave em segredo e revogue-a no painel se suspeitar de vazamento.