A nota fiscal, por API.
Uma chamada REST cria a nota; a emissão acontece de forma automática e você recebe o resultado por webhook. Feita para volume, com idempotência, sandbox e documentação direta ao ponto.
Emissão fiscal como API
A API da Emite.Ai emite notas fiscais eletrônicas de serviço (NFS-e) e de produto (NF-e) de forma programática. O modelo é assíncrono: você cria a nota com um POST, recebe imediatamente o identificador, e o resultado da emissão chega no seu endpoint por webhook. Sem polling, sem filas do seu lado.
- Base URL:
https://emitenota.ai/api/v1 - Autenticação: chave de API no header
Authorization: Bearer - Formato: JSON em requisição e resposta; valores monetários em reais na entrada (
150.00) e em centavos na resposta (15000)
Como funciona
A divisão de responsabilidade é simples: você orquestra do seu lado, a Emite faz toda a máquina fiscal do dela. Você nunca lida com XML, certificado, SEFAZ ou regra de município — envia dados de negócio, recebe uma nota fiscal válida.
Decide quando emitir, manda os dados de cada nota (comprador, valor, serviço) e o CNPJ emissor, e recebe o resultado por webhook para guardar/entregar no seu sistema.
Guarda a configuração fiscal do emissor (CNPJ, certificado A1, regime, município) e faz a emissão: monta e assina o XML, transmite ao órgão, gera o PDF, arquiva e reenvia em falha.
O formato da nota é padronizado por lei (o XML é do governo). O que varia por nota — código de serviço, descrição, valores, imposto — você controla em cada chamada. Você consome o resultado como JSON (resposta) + XML + PDF (via webhook/links).
Guia de integração
O caminho completo, do zero à emissão em produção.
- Pegue sua chave. Em Minhas chaves, gere uma chave de sandbox (
emite_test_) para desenvolver e uma de produção (emite_live_) para o go-live. - Cadastre a(s) empresa(s) emissora(s). Uma vez por CNPJ: POST /v1/companies e depois envie o certificado A1 em
/v1/companies/:id/certificate. Uma empresa só? A que já está na conta serve. - Emita. POST /v1/invoices com os dados da nota (e
companyId/cnpjse você tem vários). UseIdempotency-Key— sempre. Para volume, use /batch. - Receba o resultado. Cadastre um webhook e trate
invoice.emitted/invoice.failed— sem polling. Valide a assinatura HMAC. - Valide no sandbox. Rode o fluxo inteiro com a chave de teste (sandbox) — sem gerar documento real.
- Vá a produção. Troque a chave de teste pela de produção. A mesma requisição funciona nos dois ambientes.
Início rápido
Da chave à primeira nota em três passos.
1. Pegue sua chave de API
No painel, em Minhas chaves, gere uma chave. Ela começa com emite_live_ (produção) ou emite_test_ (sandbox) e é exibida uma única vez — guarde com segurança.
2. Emita uma nota
curl -X POST https://emitenota.ai/api/v1/invoices \
-H "Authorization: Bearer emite_live_sua_chave" \
-H "Idempotency-Key: pedido-8823" \
-H "Content-Type: application/json" \
-d '{
"buyerName": "João da Silva",
"buyerDocument": "123.456.789-01",
"buyerDocType": "CPF",
"buyerEmail": "joao@exemplo.com",
"valorNF": 150.00,
"descricaoServico": "Assinatura mensal — plano Pro",
"codigoServico": "01.05",
"aliquotaISS": 5
}'3. Receba o resultado por webhook
Cadastre um endpoint de webhook e a Emite avisa quando a nota é emitida, falha ou é cancelada — com o número, o PDF e o XML. Veja Webhooks.
Autenticação
Toda requisição é autenticada por uma chave de API enviada no header Authorization como Bearer token. Cada chave pertence a uma empresa e só enxerga os dados dela.
curl https://emitenota.ai/api/v1/organization \
-H "Authorization: Bearer emite_live_sua_chave"As chaves têm escopos (ex.: invoices:write, invoices:read), podem ter expiração e são revogáveis a qualquer momento. Nunca exponha a chave no front-end — use-a apenas do seu servidor.
Emitir uma nota POST /v1/invoices
Cria e dispara a emissão de uma nota. Responde 201 imediatamente com a nota em PENDING; a emissão prossegue em segundo plano.
Corpo da requisição
| Campo | Tipo | Descrição | |
|---|---|---|---|
| buyerName | string | obrigatório | Nome do tomador |
| buyerDocument | string | obrigatório | CPF ou CNPJ (com ou sem máscara) |
| buyerDocType | "CPF" | "CNPJ" | opcional | Padrão: CPF |
| buyerEmail | string | obrigatório | E-mail para envio da nota |
| valorNF | number | obrigatório | Valor em reais (ex.: 150.00) |
| descricaoServico | string | obrigatório | Descrição do serviço |
| codigoServico | string | obrigatório | Código do serviço (LC 116) |
| aliquotaISS | number | opcional | Alíquota de ISS em % (ex.: 5) |
| issRetido | boolean | opcional | ISS retido na fonte. Padrão: false |
| companyId | string | opcional | Empresa emissora (multi-CNPJ). Ver Empresas |
| cnpj | string | opcional | CNPJ emissor (alternativa a companyId) |
Cada nota carrega seu próprio serviço — codigoServico, descricaoServico, aliquotaISS e issRetido valem por nota, então você pode emitir serviços diferentes na mesma integração.
Exemplo — Node.js
const res = await fetch("https://emitenota.ai/api/v1/invoices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.EMITE_API_KEY}`,
"Idempotency-Key": pedidoId,
"Content-Type": "application/json",
},
body: JSON.stringify({
buyerName: "João da Silva",
buyerDocument: "12345678901",
buyerDocType: "CPF",
buyerEmail: "joao@exemplo.com",
valorNF: 150.0,
descricaoServico: "Assinatura mensal — plano Pro",
codigoServico: "01.05",
aliquotaISS: 5,
}),
});
const nota = await res.json();
// { id: "inv_a1b2c3d4", status: "PENDING", ... }Resposta — 201
{
"id": "inv_a1b2c3d4",
"status": "PENDING",
"valorNF": 15000,
"buyerName": "João da Silva",
"buyerDocument": "12345678901",
"createdAt": "2026-07-10T13:20:41.000Z",
"message": "NF criada e emissao iniciada"
}Empresas (multi-CNPJ) GET /v1/companies
Uma conta pode ter várias empresas emissoras (CNPJs). Para escolher por qual empresa emitir, envie companyId ou cnpj no corpo da emissão. Sem esses campos, emitimos pela empresa primária da conta.
Liste as empresas disponíveis e seus ids:
curl https://emitenota.ai/api/v1/companies \
-H "Authorization: Bearer emite_live_sua_chave"{
"data": [
{ "id": "co_a1b2", "cnpj": "11222333000144", "razaoSocial": "ACME LTDA",
"isPrimary": true, "municipio": "São Paulo", "uf": "SP" },
{ "id": "co_c3d4", "cnpj": "55666777000188", "razaoSocial": "ACME FILIAL LTDA",
"isPrimary": false, "municipio": "Rio de Janeiro", "uf": "RJ" }
]
}Emitindo por uma empresa específica
curl -X POST https://emitenota.ai/api/v1/invoices \
-H "Authorization: Bearer emite_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"companyId": "co_c3d4",
"buyerName": "João da Silva",
"buyerDocument": "12345678901",
"buyerEmail": "joao@exemplo.com",
"valorNF": 150.00,
"descricaoServico": "Assinatura",
"codigoServico": "01.05",
"aliquotaISS": 5
}'companyId/cnpj que não existe na conta retorna 422.Cadastrar empresa POST /v1/companies
Para onboarding de muitos CNPJs, cadastre empresas pela API. Depois envie o certificado A1 de cada uma.
curl -X POST https://emitenota.ai/api/v1/companies \
-H "Authorization: Bearer emite_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"cnpj": "11.222.333/0001-44",
"razaoSocial": "ACME LTDA",
"regimeTributario": "SIMPLES_NACIONAL",
"inscricaoMunicipal": "1234567",
"municipio": "São Paulo",
"uf": "SP",
"codigoMunicipio": "3550308",
"cep": "01001-000",
"logradouro": "Praça da Sé", "numero": "100", "bairro": "Sé"
}'Enviar certificado A1 POST /v1/companies/:id/certificate
O certificado .pfx vai em base64 no corpo JSON. Validamos o PFX, a senha e conferimos que o CNPJ do certificado bate com o da empresa.
curl -X POST https://emitenota.ai/api/v1/companies/co_a1b2/certificate \
-H "Authorization: Bearer emite_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"certificateBase64": "<conteúdo do .pfx em base64>",
"password": "senha-do-certificado"
}'{
"id": "cert_9x8y",
"commonName": "ACME LTDA:11222333000144",
"issuer": "AC Certificadora",
"expiresAt": "2027-01-15T12:00:00.000Z",
"status": "VALID"
}422.Emissão em lote POST /v1/invoices/batch
Para alto volume, envie até 500 notas numa única requisição. Cada item é independente — um erro em um não derruba os demais. Cada item aceita um idempotencyKey próprio (mesma garantia da emissão avulsa).
curl -X POST https://emitenota.ai/api/v1/invoices/batch \
-H "Authorization: Bearer emite_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{
"invoices": [
{ "idempotencyKey": "pedido-1", "buyerName": "João", "buyerDocument": "12345678901",
"buyerEmail": "joao@exemplo.com", "valorNF": 150.0,
"descricaoServico": "Assinatura", "codigoServico": "01.05", "aliquotaISS": 5 },
{ "idempotencyKey": "pedido-2", "buyerName": "Maria", "buyerDocument": "98765432100",
"buyerEmail": "maria@exemplo.com", "valorNF": 90.0,
"descricaoServico": "Assinatura", "codigoServico": "01.05", "aliquotaISS": 5 }
]
}'Resposta — 200 (ou 207 com falhas parciais)
{
"results": [
{ "index": 0, "status": "created", "id": "inv_a1b2", "invoiceStatus": "PENDING" },
{ "index": 1, "status": "error", "error": "Campos obrigatorios: ..." }
],
"summary": { "total": 2, "created": 1, "replayed": 0, "failed": 1 }
}207 quando há falhas parciais — verifique cada item em results. Acompanhe a emissão de cada nota pelos webhooks.Consultar status GET /v1/invoices/:id
Retorna o estado atual da nota, com número, links de PDF e XML quando emitida.
curl https://emitenota.ai/api/v1/invoices/inv_a1b2c3d4 \
-H "Authorization: Bearer emite_live_sua_chave"Estados possíveis: PENDING → PROCESSING → EMITTED · FAILED · CANCELLED. Em vez de consultar em loop, prefira os webhooks.
Listar notas GET /v1/invoices
Lista paginada, com filtros. Máximo de 100 por página.
| Parâmetro | Descrição |
|---|---|
| page | Página (padrão 1) |
| limit | Itens por página (padrão 20, máx 100) |
| status | Filtra por estado (EMITTED, FAILED, …) |
| buyerDocument | CPF/CNPJ do tomador |
| startDate · endDate | Intervalo (ISO 8601) |
curl "https://emitenota.ai/api/v1/invoices?status=EMITTED&limit=50" \
-H "Authorization: Bearer emite_live_sua_chave"Cancelar POST /v1/invoices/:id/cancel
Cancela uma nota. Para notas já emitidas, informe a justificativa (15 a 255 caracteres); o cancelamento é processado junto ao órgão e confirmado por webhook.
curl -X POST https://emitenota.ai/api/v1/invoices/inv_a1b2c3d4/cancel \
-H "Authorization: Bearer emite_live_sua_chave" \
-H "Content-Type: application/json" \
-d '{ "justificativa": "Cancelamento a pedido do cliente" }'Idempotência
Envie o header Idempotency-Key com um valor único por operação (ex.: o id do pedido no seu sistema). Se a mesma requisição for reenviada — por timeout, retry ou falha de rede — a Emite devolve a nota original em vez de emitir uma segunda.
409 Conflict.POST /api/v1/invoices
Authorization: Bearer emite_live_sua_chave
Idempotency-Key: pedido-8823Webhooks
Cadastre uma URL e a Emite envia um POST a cada mudança de estado terminal da nota. Assim você não precisa consultar status em loop.
| Evento | Quando dispara |
|---|---|
| invoice.emitted | Nota emitida com sucesso |
| invoice.failed | Emissão falhou (com a causa) |
| invoice.cancelled | Nota cancelada |
Payload
{
"event": "invoice.emitted",
"id": "inv_a1b2c3d4",
"status": "EMITTED",
"nfseNumero": "123456",
"nfsePdfUrl": "https://emitenota.ai/.../danfse.pdf",
"emittedAt": "2026-07-10T13:20:57.000Z"
}Verificando a assinatura
Cada entrega inclui o header X-Emite-Signature — um HMAC-SHA256 do corpo com o segredo do seu webhook. Valide antes de confiar no payload.
import { createHmac, timingSafeEqual } from "node:crypto";
function verificarAssinatura(rawBody, signature, secret) {
const esperado =
"sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(signature);
const b = Buffer.from(esperado);
return a.length === b.length && timingSafeEqual(a, b);
}Responda 2xx em até alguns segundos. Entregas que falham são reenviadas com backoff.
Sandbox
Gere uma chave que começa com emite_test_ em Minhas chaves. Requisições com chave de teste são validadas normalmente e retornam uma resposta simulada de emissão — sem gerar documento fiscal real, sem tocar o órgão fiscal e sem consumir cota. A resposta inclui "sandbox": true.
Rate limits
Cada resposta traz os headers X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset. Ao exceder, a API responde 429 com Retry-After. Limites são ajustados conforme o volume contratado — fale com a gente para operações de alto volume.
Erros
Respostas de erro usam o status HTTP adequado e trazem error + message legíveis no corpo.
// 422 — CNPJ do certificado não bate com a empresa
{
"error": "COMPANY_NOT_FOUND",
"message": "companyId 'co_x' não encontrado nesta conta."
}| Código | Significado |
|---|---|
| 400 | Requisição inválida (campo faltando ou mal formado) |
| 401 | Chave ausente, inválida ou expirada |
| 403 | Sem permissão (scope) ou limite do plano atingido |
| 404 | Recurso não encontrado |
| 409 | Conflito de idempotência (ou empresa/CNPJ já existe) |
| 422 | Dados válidos mas não processáveis (ex: companyId/CNPJ inexistente) |
| 429 | Rate limit excedido |
| 5xx | Erro interno — pode retentar (com Idempotency-Key) |
Endpoints
| POST | /v1/invoices | Cria e emite uma nota |
| POST | /v1/invoices/batch | Emite até 500 notas em lote |
| GET | /v1/invoices | Lista notas |
| GET | /v1/invoices/:id | Consulta uma nota |
| POST | /v1/invoices/:id/cancel | Cancela uma nota |
| GET | /v1/companies | Lista empresas emissoras (multi-CNPJ) |
| POST | /v1/companies | Cadastra uma empresa emissora |
| POST | /v1/companies/:id/certificate | Envia o certificado A1 (base64) |
| GET | /v1/products | Lista produtos |
| GET | /v1/organization | Dados fiscais da empresa |
Pronto para começar? Gere sua chave de API e emita a primeira nota.