Download OpenAPI specification:
API para consultar e gerenciar, de forma programática, as NFS-e (notas de serviço) monitoradas pela sua conta IntegroBR: os mesmos dados que aparecem no painel, disponíveis para integração com o seu ERP, sistema contábil ou automação interna.
Toda chamada exige uma chave de API no cabeçalho Authorization:
Authorization: Bearer ibr_live_xxxxxxxxxxxxxxxxxxxxxxxx
Gere uma chave em Painel → Chaves de API
(/painel/chaves-api). Ela é exibida uma única vez no momento da
criação — se perder, revogue e crie outra.
Existem dois ambientes de chave, e eles nunca se misturam:
| Prefixo | Ambiente | O que você vê |
|---|---|---|
ibr_test_... |
Sandbox | Só empresas cadastradas como SANDBOX — dados de teste, nunca reais, nunca geram cobrança. |
ibr_live_... |
Produção | Só empresas cadastradas como PRODUCAO — dados fiscais reais da sua conta. |
Tentar acessar um recurso do ambiente errado com uma chave (ex.: pedir o detalhe de uma empresa de produção usando uma chave sandbox) devolve 404 — nunca 403 — pra não revelar se o recurso existe no outro ambiente.
Clientes oficiais, de código aberto, cobrindo todas as rotas desta página (incluindo paginação por cursor e verificação de assinatura de webhook).
| Linguagem | Instalação | Repositório |
|---|---|---|
| Node.js / TypeScript | npm install @integrobr/nfse-sdk |
github.com/integrobr/integrobr-sdk-node |
| PHP | composer require integrobr/nfse-sdk |
github.com/integrobr/integrobr-sdk-php |
| Ruby | gem install integrobr-nfse-sdk |
github.com/integrobr/integrobr-sdk-ruby |
Não usa Node, PHP ou Ruby? Qualquer cliente HTTP serve — a API é REST simples, sem exigir nenhum SDK.
O MCP (Model Context Protocol) é o padrão aberto que permite a um assistente de IA consultar sistemas externos. Com o servidor MCP da IntegroBR instalado, você pergunta em português no Claude, no ChatGPT ou em qualquer cliente compatível, e ele responde com os seus dados reais:
Gere uma chave em Painel → Chaves de API e adicione ao arquivo de
configuração do seu cliente MCP. No Claude Desktop, é o
claude_desktop_config.json:
{
"mcpServers": {
"integrobr": {
"command": "npx",
"args": ["-y", "@integrobr/mcp-server"],
"env": { "INTEGROBR_API_KEY": "ibr_live_..." }
}
}
}
Pacote no npm: @integrobr/mcp-server,
código aberto sob licença MIT. Uma chave de sandbox (ibr_test_...)
funciona igual e não toca em dado de produção: é o jeito seguro de
experimentar antes de apontar pra conta real.
| Ferramenta | O que faz |
|---|---|
consultar_conta |
Nome, status e ambiente da conta ligada à chave |
consultar_consumo |
Franquia usada no ciclo, saldo e excedente |
listar_empresas |
CNPJs monitorados e o estado de cada um |
detalhar_empresa |
Detalhe de um CNPJ, incluindo certificado |
listar_documentos |
NFS-e, NF-e e CT-e capturadas, com filtro de período, fornecedor, valor, tipo e papel |
detalhar_documento |
Documento completo, com prestador, tomador, valores e tributos |
Valores em listar_documentos são filtrados em centavos: R$ 1.500,00
é 150000. A própria descrição da ferramenta avisa isso ao modelo.
O servidor MCP da IntegroBR não emite nota, não cancela, não cria empresa e não remove nada. Ele só lê. Os endpoints de escrita desta API existem e funcionam, mas nenhum deles é exposto ao agente.
O motivo é o modelo de ameaça do MCP. Um servidor MCP entrega as ferramentas a um modelo que decide sozinho quando chamá-las, a partir de texto que pode ter vindo de qualquer lugar, inclusive do conteúdo de um documento fiscal que a própria ferramenta acabou de trazer. A descrição do serviço de uma nota é texto livre que qualquer fornecedor escreve. Num servidor que sabe emitir nota, esse texto passa a ser uma superfície de injeção com consequência fiscal real.
Quem precisa automatizar emissão usa a API REST direto, com código que passa por revisão e por um deploy, e não por um modelo decidindo no meio de uma conversa.
Internamente, todo acesso do servidor MCP passa por uma única função que
só faz GET. Expor escrita exigiria mudar essa função de propósito, e
isso é o atrito que se quer.
A NFE.io também publica um servidor MCP, e as duas escolhas de arquitetura são opostas. Vale entender a diferença antes de decidir, porque ela não é de tamanho, é de modelo de confiança. Dados públicos consultados em 2 de setembro de 2026.
| IntegroBR | NFE.io | |
|---|---|---|
| Onde roda | Local, na sua máquina, por stdio | Servidor remoto deles (mcp.nfe.io) |
| Para onde vai sua chave de API | Não sai da sua máquina | Trafega até o servidor deles, que a usa em seu nome |
| O agente pode escrever? | Não. Somente leitura | Sim. Emite NFS-e e cria empresas |
| Dá pra auditar o código? | Sim, MIT no npm | Não. O servidor é fechado |
| Notas recebidas de fornecedor | Sim, NFS-e, NF-e e CT-e | Não é o escopo do produto deles |
| Quantidade de ferramentas | 6, todas sobre os seus dados fiscais | 21, incluindo consultas públicas (IBGE, CNAE, Selic) |
Onde eles são mais convenientes, e é justo dizer: por ser remoto, o deles não exige Node instalado, e boa parte das ferramentas responde sem autenticação nenhuma, o que torna o teste inicial mais rápido.
Onde nós somos mais seguros, e é o que importa quando o agente toca dado fiscal de verdade: sua chave de API nunca sai da sua máquina, e nenhum agente consegue emitir uma nota fiscal em nome da sua empresa através do nosso servidor. Um servidor MCP remoto que emite nota concentra as duas coisas ao mesmo tempo: recebe a sua credencial e tem permissão de escrita com ela.
E, na parte que é a razão de existir da IntegroBR, não há sobreposição: o monitoramento das notas que a sua empresa recebe de fornecedores, incluindo NFS-e, que costuma ser justamente a que fica descoberta.
GET /documents usa paginação por cursor (é a única lista que pode
crescer sem limite prático). A resposta sempre traz:
{ "itens": [ /* ... */ ], "proximoCursor": "id-do-ultimo-item-ou-null" }
Passe o valor de proximoCursor de volta no parâmetro cursor da
próxima chamada — ele é o id do último item da página anterior, não um
token opaco. proximoCursor: null significa que não há mais páginas.
Um cursor que não existe mais (nunca existiu, ou o item foi removido
entre uma chamada e outra) não gera erro — a resposta vem com
itens: [] e proximoCursor: null, como se a paginação tivesse
chegado ao fim.
GET /companies não é paginado — devolve um array direto com todas
as empresas da conta (o volume esperado é baixo o suficiente pra não
precisar).
120 requisições por minuto, por chave de API (janela fixa de 60s).
Passar do limite devolve 429 Too Many Requests:
{ "message": "Limite de requisições excedido. Tente novamente em instantes.", "code": "RATE_LIMITED" }
Erros seguem sempre o mesmo formato:
{ "statusCode": 404, "message": "Empresa não encontrada nesta conta.", "error": "Not Found" }
message pode ser uma string única ou uma lista de strings (erro de
validação de campos, um item por campo inválido).
Configure webhooks pelo painel (Painel → Webhooks) para ser
avisado em tempo real, sem precisar ficar consultando GET /documents.
Dois eventos existem hoje:
NOTA_RECEBIDA — uma nota nova foi capturada.EVENTO_FISCAL_RECEBIDO — um evento (cancelamento, substituição etc.)
foi capturado para uma nota já conhecida.Toda entrega é um POST com o corpo:
{ "tipo": "NOTA_RECEBIDA", "dados": { /* mesmo formato de um item de GET /documents */ } }
E dois cabeçalhos:
| Cabeçalho | Conteúdo |
|---|---|
X-IntegroBR-Event |
O mesmo valor de tipo do corpo. |
X-IntegroBR-Signature |
HMAC-SHA256 (hex) do corpo bruto da requisição, usando o segredo do seu webhook como chave. |
Verifique a assinatura antes de confiar no payload (exemplo em Node.js):
const crypto = require("crypto");
function assinaturaValida(corpoBruto, assinaturaRecebida, segredo) {
const esperada = crypto.createHmac("sha256", segredo).update(corpoBruto).digest("hex");
return crypto.timingSafeEqual(Buffer.from(esperada), Buffer.from(assinaturaRecebida));
}
Entregas com falha (timeout, conexão recusada, resposta não-2xx) são reenviadas com backoff exponencial. O segredo do webhook só é exibido uma vez, na criação (ou ao rotacionar) — guarde com o mesmo cuidado de uma senha.
Identifica a conta dona da chave de API usada na requisição.
{- "id": "5f9a1c2e-7b3d-4e11-9c2a-1a2b3c4d5e6f",
- "nome": "Empresa Exemplo LTDA",
- "status": "ATIVA",
- "ambiente": "PRODUCAO",
- "criadaEm": "2026-03-10T13:22:00.000Z"
}Franquia, consumo e excedente do ciclo em andamento. Com uma chave
SANDBOX, sempre devolve { "temCicloAtivo": false, "ambiente": "SANDBOX" }
— sandbox nunca gera cobrança.
{- "temCicloAtivo": true,
- "ciclo": {
- "id": "b7f63b53-584e-4e3c-ac1f-dcf47d1188f9",
- "status": "ATIVO",
- "dataInicio": "2026-07-17T16:50:46.690Z",
- "dataFim": "2026-08-16T16:50:46.690Z",
- "plano": {
- "id": "cb898015-0152-4d5b-8de4-7a4a5d34c860",
- "nome": "Growth",
- "precoMensal": "349",
- "franquiaEventos": 2000,
- "precoUnitarioExcedente": "0.19"
}
}, - "franquiaEventos": 2000,
- "eventosIncluidos": 340,
- "eventosExcedentes": 0,
- "saldoExcedenteAberto": 0,
- "limiteExcedenteAberto": 174.5,
- "porEmpresa": [
- {
- "empresaId": "32cecfd5-4d1d-4421-b901-16fadabafe15",
- "quantidade": 340
}
], - "pausadaPorExcedente": false,
- "destravaDisponivel": false
}Só devolve empresas do mesmo ambiente da chave usada (sandbox ou produção).
[- {
- "id": "string",
- "cnpj": "string",
- "ambiente": "SANDBOX",
- "ambienteAdn": "HOMOLOGACAO",
- "escopoMonitoramento": "RECEBIDAS",
- "nomeExibicao": "string",
- "razaoSocial": "string",
- "estado": "DRAFT",
- "nsuInicial": "string",
- "nsuUltimoConfirmado": "string",
- "ultimaConsultaEm": "2019-08-24T14:15:22Z",
- "monitorarDesde": "2019-08-24T14:15:22Z",
- "certificadoValidoAte": "2019-08-24T14:15:22Z",
- "criadaEm": "2019-08-24T14:15:22Z",
- "atualizadaEm": "2019-08-24T14:15:22Z"
}
]Cadastra o CNPJ na conta. Ele nasce em estado DRAFT (produção) —
o próximo passo é enviar o certificado A1 em
POST /companies/{id}/certificate. Com chave sandbox, a empresa já
nasce ACTIVE, sem certificado.
| cnpj required | string >= 11 characters Só dígitos. |
| nomeExibicao | string |
| nsuInicial | integer >= 0 Avançado — de onde retomar a consulta ao ADN, se este CNPJ já era monitorado por outro sistema. Ausência = 0 (histórico completo). |
{- "cnpj": "12345678000195",
- "nomeExibicao": "Filial São Paulo"
}{- "id": "string",
- "cnpj": "string",
- "ambiente": "SANDBOX",
- "ambienteAdn": "HOMOLOGACAO",
- "escopoMonitoramento": "RECEBIDAS",
- "nomeExibicao": "string",
- "razaoSocial": "string",
- "estado": "DRAFT",
- "nsuInicial": "string",
- "nsuUltimoConfirmado": "string",
- "ultimaConsultaEm": "2019-08-24T14:15:22Z",
- "monitorarDesde": "2019-08-24T14:15:22Z",
- "certificadoValidoAte": "2019-08-24T14:15:22Z",
- "criadaEm": "2019-08-24T14:15:22Z",
- "atualizadaEm": "2019-08-24T14:15:22Z"
}| id required | string Id da empresa (o mesmo devolvido em |
{- "id": "string",
- "cnpj": "string",
- "ambiente": "SANDBOX",
- "ambienteAdn": "HOMOLOGACAO",
- "escopoMonitoramento": "RECEBIDAS",
- "nomeExibicao": "string",
- "razaoSocial": "string",
- "estado": "DRAFT",
- "nsuInicial": "string",
- "nsuUltimoConfirmado": "string",
- "ultimaConsultaEm": "2019-08-24T14:15:22Z",
- "monitorarDesde": "2019-08-24T14:15:22Z",
- "certificadoValidoAte": "2019-08-24T14:15:22Z",
- "criadaEm": "2019-08-24T14:15:22Z",
- "atualizadaEm": "2019-08-24T14:15:22Z"
}Inicia a remoção definitiva da empresa. Uma vez que ela já foi
monitorada de verdade (passou por ACTIVE), a remoção é um
processo de dois passos com um período de segurança entre eles,
pra preservar o histórico fiscal — o segundo passo (confirmação)
é feito pelo painel, não pela API pública.
| id required | string Id da empresa (o mesmo devolvido em |
{- "statusCode": 401,
- "message": "Chave de API inválida ou revogada.",
- "error": "Unauthorized"
}Multipart/form-data com o arquivo .pfx/.p12 no campo
certificado e a senha no campo senha. O certificado precisa ser
o e-CNPJ da própria empresa cadastrada — certificados de outro CNPJ
são rejeitados. Não disponível para empresas SANDBOX (nunca usam
certificado real).
Se a empresa já estiver ativa e monitorando (certificado vencendo ou revogado), enviar um novo aqui só troca o material — o monitoramento continua de onde parou, sem reiniciar a análise de histórico.
| id required | string Id da empresa (o mesmo devolvido em |
| certificado required | string <binary> Arquivo do certificado A1 (.pfx ou .p12), até 10MB. |
| senha required | string Senha do certificado. |
{- "id": "string",
- "cnpj": "string",
- "ambiente": "SANDBOX",
- "ambienteAdn": "HOMOLOGACAO",
- "escopoMonitoramento": "RECEBIDAS",
- "nomeExibicao": "string",
- "razaoSocial": "string",
- "estado": "DRAFT",
- "nsuInicial": "string",
- "nsuUltimoConfirmado": "string",
- "ultimaConsultaEm": "2019-08-24T14:15:22Z",
- "monitorarDesde": "2019-08-24T14:15:22Z",
- "certificadoValidoAte": "2019-08-24T14:15:22Z",
- "criadaEm": "2019-08-24T14:15:22Z",
- "atualizadaEm": "2019-08-24T14:15:22Z"
}Volta a consultar o Ambiente de Dados Nacional a partir do último NSU confirmado — nunca reprocessa notas já vistas.
| id required | string Id da empresa (o mesmo devolvido em |
{- "retomada": true
}Lista paginada por cursor, com filtros combináveis.
| cnpjs | string Example: cnpjs=12345678000190,98765432000110 Um ou vários CNPJs separados por vírgula. Ausente = todos os CNPJs da conta. |
| situacao | string (SituacaoNota) Enum: "AUTORIZADA" "CANCELADA" "SUBSTITUIDA" |
| papel | string (PapelNota) Enum: "RECEBIDA" "EMITIDA" Ausente = respeita o escopo de monitoramento configurado em cada empresa. |
| prestador | string Filtra por CNPJ/CPF ou nome do prestador (contém, sem diferenciar maiúsculas). |
| numero | string Número da nota (contém). |
| chaveAcesso | string |
| valorMinCentavos | integer >= 0 |
| valorMaxCentavos | integer >= 0 |
| dataInicio | string <date-time> Filtra por data de emissão (ISO 8601), início do intervalo. |
| dataFim | string <date-time> Filtra por data de emissão (ISO 8601), fim do intervalo. |
| cursor | string Id do último item da página anterior. |
| limite | integer [ 1 .. 100 ] Default: 20 |
{- "itens": [
- {
- "id": "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
- "numero": "1024",
- "nsu": "720",
- "chaveAcesso": "35260712345678000190550010000010241123456789",
- "prestador": {
- "documento": "12345678000190",
- "nome": "Prestador Exemplo LTDA"
}, - "cnpjTomador": "98765432000110",
- "papel": "RECEBIDA",
- "valorServicos": "1500.00",
- "situacao": "AUTORIZADA",
- "dataEmissao": "2026-07-15T10:30:00.000Z",
- "recebidaEm": "2026-07-15T10:31:12.000Z",
- "quantidadeEventos": 0
}
], - "proximoCursor": null
}Inclui o XML original e a linha do tempo de eventos (cancelamento, substituição etc.).
| id required | string |
{- "id": "string",
- "empresaId": "string",
- "chaveAcesso": "string",
- "cnpjTomador": "string",
- "papel": "RECEBIDA",
- "prestador": {
- "documento": "string",
- "nome": "string"
}, - "numero": "string",
- "serie": "string",
- "dataEmissao": "2019-08-24T14:15:22Z",
- "municipio": "string",
- "descricaoServico": "string",
- "valorServicos": "string",
- "situacao": "AUTORIZADA",
- "nsu": "string",
- "recebidaEm": "2019-08-24T14:15:22Z",
- "xmlOriginal": "string",
- "eventos": [
- {
- "id": "string",
- "tipo": "string",
- "sequencia": 0,
- "dataEvento": "2019-08-24T14:15:22Z",
- "recebidoEm": "2019-08-24T14:15:22Z",
- "nsu": "string",
- "situacaoResultante": "AUTORIZADA",
- "xmlOriginal": "string"
}
]
}