API Notafly
Emita NFS-e automaticamente a cada venda. Um endpoint REST, certificado criptografado, sem burocracia.
Base URL
https://api.notafly.com.br/apiIntegrações comuns
Cobertura municipal
O Notafly emite para São Paulo via sistema municipal próprio (SOAP + mTLS) e está preparado para o NFS-e Nacional — o padrão da Receita Federal que cobre mais de 1.000 municípios.
| Município | Sistema | Status |
|---|---|---|
| São Paulo – SP | sistema municipal SOAP | Ativo |
| Campinas, Guarulhos, Osasco e outros | NFS-e Nacional REST | Em breve |
| Demais municípios conveniados | NFS-e Nacional REST | Em breve |
Se o CNPJ da emissora for de um município ainda não suportado, a API retorna 422 MUNICIPIO_NAO_SUPORTADO imediatamente — nenhuma cobrança é feita.
Autenticação
Todas as requisições precisam de uma API Key no header Authorization.
Authorization: Bearer nfly_live_sk_xxxxxxxxxxxxxxxxxxxxxxxxAs chaves começam com nfly_live_sk_ seguido de 32 caracteres aleatórios. A chave é exibida uma única vez na criação.
nfly_live_sk_••••••••••••••••••••••••••••••••
Nunca exponha sua API Key no frontend ou repositório público. Use sempre variáveis de ambiente no servidor.
Como funciona
Você envia os dados da nota. O Notafly assina o XML com seu certificado A1, envia à Prefeitura ou Receita Federal, e retorna o número autorizado.
- 200 OK — nota autorizada em até 30s. Contém número, código de verificação e link do PDF.
- 202 Accepted — prefeitura lenta. Nota entra na fila e é processada automaticamente.
- 422 — nota rejeitada. Campo
detailcontém o código exato da prefeitura.
Rate limits
Cada API Key tem limite de 60 requisições por minuto. Ao exceder retorna 429 Too Many Requests. Planos Enterprise têm limites customizados.
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 57 X-RateLimit-Reset: 1709823600 # Unix timestamp
Emitir NFS-e
Parâmetros
| Campo | Tipo | Descrição |
|---|---|---|
| empresaCnpjobrigatório | string | CNPJ da empresa emissora (14 dígitos). Deve estar cadastrado no Notafly com certificado A1. |
| tomadorCnpjcondicional | string | CNPJ do tomador (PJ). Obrigatório se não informar tomadorCpf. |
| tomadorCpfcondicional | string | CPF do tomador (PF). Obrigatório se não informar tomadorCnpj. |
| tomadorEmailopcional | string | E-mail do tomador. |
| tomadorNomeopcional | string | Nome ou razão social do tomador. |
| valorServicoobrigatório | number | Valor do serviço em reais (ex: 497.00). |
| discriminacaoobrigatório | string | Descrição do serviço prestado. |
| referenciaopcional | string | ID do seu sistema. Permite consultar a nota sem guardar o ID do Notafly. |
| dataCompetenciaopcional | string | Formato YYYY-MM. Padrão: mês atual. |
Exemplos
curl -X POST https://api.notafly.com.br/api/emit \ -H "Authorization: Bearer nfly_live_sk_xxx" \ -H "Content-Type: application/json" \ -d '{"empresaCnpj":"14099269000181","tomadorCnpj":"47715268000173","tomadorEmail":"cliente@empresa.com","valorServico":497.00,"discriminacao":"Assinatura mensal - Plano Pro - Marco/2026","referencia":"invoice_1234567"}'
const nota = await fetch('https://api.notafly.com.br/api/emit', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.NOTAFLY_API_KEY}` }, body: JSON.stringify({ empresaCnpj: '14099269000181', tomadorCnpj: '47715268000173', valorServico: 497.00, discriminacao: 'Assinatura mensal - Plano Pro', referencia: 'invoice_1234567' }) }).then(r => r.json()); // nota.numero → '000042851' / nota.linkPdf → URL do PDF
import requests, os nota = requests.post("https://api.notafly.com.br/api/emit", headers={"Authorization": f"Bearer {os.environ['NOTAFLY_API_KEY']}", "Content-Type": "application/json"}, json={"empresaCnpj": "14099269000181", "tomadorCnpj": "47715268000173", "valorServico": 497.00, "discriminacao": "Assinatura mensal", "referencia": "invoice_1234567"} ).json() print(nota["numero"], nota["linkPdf"])
$ch = curl_init('https://api.notafly.com.br/api/emit'); curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $_ENV['NOTAFLY_API_KEY']], CURLOPT_POSTFIELDS => json_encode(['empresaCnpj' => '14099269000181', 'tomadorCnpj' => '47715268000173', 'valorServico' => 497.00, 'discriminacao' => 'Assinatura mensal', 'referencia' => 'invoice_1234567'])]); $nota = json_decode(curl_exec($ch));
Resposta — 200 OK
{ "id": "nfly_nota_clxxx", "numero": "000042851", "codigoVerif": "ABX-9FKL", "dataEmissao": "2026-03-07T14:32:00-03:00", "municipio": "Sao Paulo", "valorServico": 497.00, "valorIss": 9.94, "status": "AUTORIZADA", "referencia": "invoice_1234567", "linkPdf": "https://api.notafly.com.br/api/notas/nfly_nota_xxx/pdf" }
Consultar nota
referencia. Ideal para rastrear sem armazenar o ID interno.Sempre use o campo referencia com o ID da sua transação. Você pode consultar a nota a qualquer momento sem depender do ID do Notafly.
Cancelar nota
Em São Paulo o prazo de cancelamento é 7 dias corridos da emissão.
Download do PDF
Gerenciar API Keys
Esses endpoints usam autenticação por JWT (sessão do dashboard).
Guia: Hotmart
Em Ferramentas → Webhooks, cadastre sua URL e selecione PURCHASE_APPROVED.
app.post('/webhooks/hotmart', async (req, res) => { const { event, data } = req.body; if (event !== 'PURCHASE_APPROVED') return res.sendStatus(200); const { buyer, purchase } = data; await fetch('https://api.notafly.com.br/api/emit', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.NOTAFLY_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ empresaCnpj: 'SEU_CNPJ', tomadorCpf: buyer.document.replace(/\D/g, ''), tomadorEmail: buyer.email, valorServico: purchase.price.value, discriminacao: purchase.product.name, referencia: purchase.transaction }) }); res.sendStatus(200); });
Guia: Kiwify
Configure em Configurações → Webhooks com o evento order.approved.
app.post('/webhooks/kiwify', async (req, res) => { const { event, data } = req.body; if (event !== 'order.approved') return res.sendStatus(200); await fetch('https://api.notafly.com.br/api/emit', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.NOTAFLY_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ empresaCnpj: 'SEU_CNPJ', tomadorCpf: data.Customer.cpf, tomadorEmail: data.Customer.email, valorServico: data.order_value / 100, discriminacao: data.Product.name, referencia: data.order_id }) }); res.sendStatus(200); });
Guia: Stripe
Ideal para SaaS com assinaturas recorrentes.
Salve o CNPJ/CPF nos metadados do Customer no Stripe (customer.metadata.cnpj) para automatizar completamente a integração.
import Stripe from 'stripe'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => { const event = stripe.webhooks.constructEvent(req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET); if (event.type === 'invoice.payment_succeeded') { const invoice = event.data.object; const customer = await stripe.customers.retrieve(invoice.customer); await fetch('https://api.notafly.com.br/api/emit', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.NOTAFLY_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ empresaCnpj: 'SEU_CNPJ', tomadorCnpj: customer.metadata.cnpj, tomadorEmail: customer.email, valorServico: invoice.amount_paid / 100, discriminacao: invoice.lines.data[0].description, referencia: invoice.id }) }); } res.sendStatus(200); });
Guia: n8n / Zapier
Use o nó HTTP Request do n8n ou Webhooks by Zapier.
- Método:
POST· URL:https://api.notafly.com.br/api/emit - Authentication: Header Auth → Name:
Authorization, Value:Bearer nfly_live_sk_xxx - Body: JSON com campos mapeados do nó anterior
No n8n use expressões: {{ $json.customer_email }}, {{ $json.amount / 100 }} etc.
Códigos de erro
Todos os erros seguem: {"statusCode": 422, "error": "CÓDIGO", "message": "..."}
| HTTP | Código | Causa e solução |
|---|---|---|
| 401 | UNAUTHORIZED | API Key ausente, inválida ou revogada. |
| 403 | NOTE_LIMIT_EXCEEDED | Limite mensal de notas atingido. Faça upgrade em Dashboard → Plano. |
| 404 | COMPANY_NOT_FOUND | O empresaCnpj não está cadastrado no Notafly. |
| 404 | NOTE_NOT_FOUND | ID ou referência não encontrado. |
| 422 | MUNICIPIO_NAO_SUPORTADO | Município da emissora ainda não suportado. |
| 422 | PREFEITURA_REJECTED | Nota rejeitada. Veja o campo detail para o código exato. |
| 429 | RATE_LIMIT_EXCEEDED | 60 req/min excedidos. Aguarde o reset em X-RateLimit-Reset. |
| 503 | PREFEITURA_OFFLINE | Prefeitura indisponível. Nota enfileirada e retentada automaticamente. |
Erros 503 são transitórios. O Notafly retenta com backoff exponencial.
Status da nota
| Status | Significado | |
|---|---|---|
| AUTORIZADA | Nota emitida e autorizada pela prefeitura. | |
| PROCESSANDO | Na fila do worker. Será transmitida automaticamente. | |
| AGENDADA | Agendada para emissão em data/hora futura. | |
| ERRO | Falha definitiva. Veja errorMessage. | |
| CANCELADA | Cancelamento transmitido com sucesso. | |
Changelog
v1.2 — Março 2026
- Endpoint
POST /api/emitpúblico via API Key - Validação de município com retorno
MUNICIPIO_NAO_SUPORTADO - Gerenciamento de API Keys via dashboard e API
- Header
X-RateLimit-Remainingem todas as respostas
v1.1 — Janeiro 2026
- Suporte a multi-município (estrutura base NFS-e Nacional)
- Campo
referenciaem todos os endpoints de consulta - Download de PDF via URL pública opaca
v1.0 — Novembro 2025
- Lançamento — emissão NFS-e São Paulo via SOAP + mTLS
- Agendamento com hora exata e recorrência
- Upload de certificado A1 com criptografia AES-256-GCM