Pular para o conteúdo principal

Referência da API

Leads e catálogo público de cidades

GET /api/cidades?q= aceita ao menos três caracteres e retorna até oito itens { ibgeCodigo, nome, uf }, priorizando SP. A busca é por prefixo do nome completo, sem diferença de acento ou caixa. Cada consulta pode ser armazenada em cache por cinco minutos.

  • Consulta com menos de três caracteres retorna [].
  • 429: limite de 60 consultas por IP a cada minuto; aguarde antes de repetir.

POST /api/leads recebe nome, email, telefone, whatsappOptIn e ibgeMunicipio. O IBGE é obrigatório, deve ter sete dígitos e existir no catálogo. O nome da cidade é sempre derivado do catálogo.

Envelope e códigos de erro

As rotas REST v1 usam { "erro": { "codigo", "mensagem", "detalhes" } }; detalhes é opcional. A resposta anterior { "sucesso": false, "erros": [...] } não é mais emitida pela API REST (breaking change). O MCP conserva seu contrato próprio de resultado de ferramenta.

CódigoSignificado
VALIDACAOCorpo ou campo inválido.
CONFIGEmpresa emissora não pôde ser resolvida.
PERFIL_TRIBUTARIOPerfil inválido, inativo ou não encontrado.
BILLINGPlano ou limite bloqueou a emissão (HTTP 402).
CONTEUDO_INADEQUADOConteúdo fiscal recusado pela política.
RECONCILIACAO_INDISPONIVELResultado da transmissão não pôde ser confirmado.
REJEICAO_FISCALA prefeitura rejeitou a emissão; o código original permanece em detalhes[0].codigo.
EMISSAOFalha de emissão sem código fiscal específico.
IDEMPOTENCIA_CONFLITOMesma chave com corpo diferente.
IDEMPOTENCIA_MODOChave já usada no outro modo de emissão.
EM_PROCESSAMENTORequisição idempotente ainda em andamento.
LOTE_GRANDE, LOTE_VAZIO, CSV_INVALIDOErros de lote.
INTERNOFalha interna não detalhada.

Servidor MCP

O NotasPJ também oferece um servidor MCP remoto em POST /api/mcp. Ele permite que clientes compatíveis, como Claude Code, Cursor e ChatGPT, consultem dados e emitam NFS-e por linguagem natural. O transporte é Streamable HTTP stateless: cada chamada é independente e não mantém sessão SSE.

A autenticação usa exclusivamente a API key do NotasPJ no header Bearer:

Authorization: Bearer <chave>

O escopo LEITURA permite as ferramentas de consulta e bloqueia emitir_nfse. O escopo EMISSAO permite todas as ferramentas. A emissão é real e deve ser confirmada pelo usuário antes da chamada. Não há ferramenta de cancelamento na v1.

Solução de problemas

  • HTTP 401 indica chave ausente ou inválida, ou escopo incompatível com a operação solicitada.
  • HTTP 402 indica que o plano atual não inclui integrações.
  • Antes de usar em produção, valide a conexão e as ferramentas com a URL do ambiente de homologação.
FerramentaEscopoFinalidade
listar_empresasLEITURALista empresas emissoras ativas da conta.
listar_clientesLEITURABusca clientes por nome ou documento, com paginação.
listar_perfis_tributariosLEITURALista perfis cadastrados com filtros e paginação.
sugerir_perfil_tributarioLEITURASugere um perfil cadastrado para empresa, cliente e serviço.
consultar_nfseLEITURAConsulta notas por empresa, período, status ou tomador.
obter_nfseLEITURAObtém o detalhe pela chave de acesso e o link da DANFSe.
emitir_nfseEMISSAOEmite uma NFS-e real com o mesmo contrato estruturado da API pública.
status_usoLEITURAInforma notas emitidas no mês e limite do plano.

Claude Code

claude mcp add --transport http notaspj https://www.notaspj.com.br/api/mcp --header "Authorization: Bearer <chave>"

Cursor

Adicione ao mcp.json:

{
"mcpServers": {
"notaspj": {
"url": "https://www.notaspj.com.br/api/mcp",
"headers": {
"Authorization": "Bearer <chave>"
}
}
}
}

ChatGPT

No modo desenvolvedor, abra Configurações → Conectores, crie um conector MCP remoto com a URL https://www.notaspj.com.br/api/mcp e configure o header Authorization como Bearer <chave>.

Para validar a integração antes do uso em produção, substitua o domínio dos exemplos por https://homologacao.notaspj.com.br e use uma chave criada no ambiente de homologação.

API REST para integração de ERPs/sistemas externos. Base: /api/v1.

Autenticação

Emissão, idempotência e formatos

POST /api/v1/nfse aceita números decimais em formato JSON, pt-BR (1.500,00) ou en-US (1,500.00). Booleanos aceitam boolean, 1/0 e sim/nao (sem distinção entre maiúsculas e minúsculas). Uma Idempotency-Key não pode ser compartilhada entre emissão síncrona e assíncrona; isso retorna IDEMPOTENCIA_MODO. Reuso com outro corpo retorna IDEMPOTENCIA_CONFLITO. Em lotes, a chave é derivada por linha; quando um header é informado, cada linha usa <header>:<linha>. O MCP aceita idempotencyKey e, quando omitida, deriva uma chave estável do tenant e do formulário.

GET /api/v1/nfse aceita page, limit, status, q, empresaId, competencia (AAAA-MM), de e ate (datas inclusivas). A paginação e o filtro por status derivado são aplicados no banco.

Toda requisição exige uma API key do tenant (criada em /integracoes):

Authorization: Bearer nfse_xxxxxxxxxxxxxxxxxxxx
# ou
X-API-Key: nfse_xxxxxxxxxxxxxxxxxxxx
  • A chave carrega um escopo: LEITURA (somente GET) ou EMISSAO (total). Rotas de emissão exigem EMISSAO, senão 403 ESCOPO_INSUFICIENTE.
  • O acesso de Integrações é revalidado em cada chamada. Se a assinatura deixar de estar vigente ou o plano não incluir Integrações, a API retorna 403 PLANO_SEM_INTEGRACOES até a regularização.
  • Chaves podem expirar e ser rotacionadas (gera nova, invalida a anterior) ou revogadas.
  • Rate limit (120 req/min por chave → 429 com Retry-After) é entregue pela camada de confiabilidade do Sprint A consolidado no rollout.

Endpoints

MétodoRotaEscopoDescrição
POST/api/v1/nfseEMISSAOEmite uma NFS-e. Síncrono por padrão; assíncrono com ?async=true (ou header x-async: true), que retorna um job.
GET/api/v1/nfseLEITURALista notas do tenant (filtros: status, paginação).
GET/api/v1/nfse/{chaveAcesso}LEITURADetalha uma nota.
GET/api/v1/nfse/{chaveAcesso}/danfseLEITURABaixa a DANFSe (PDF).
POST/api/v1/nfse/loteEMISSAOEmissão em lote.
GET/api/v1/empresasLEITURALista empresas emissoras ativas.
GET/api/v1/perfis-tributariosLEITURALista perfis tributários cadastrados.
GET/api/v1/perfis-tributarios/{id}LEITURAConsulta um perfil tributário.
GET/api/v1/perfis-tributarios/sugerirLEITURASugere um perfil cadastrado.
GET/api/v1/clientesLEITURALista ou busca clientes.
GET/api/v1/jobs/{id}LEITURAConsulta o status de um job assíncrono.
POST/api/v1/recorrentesEMISSAOCria uma recorrência.
GET/api/v1/recorrentes/{id}LEITURAConsulta uma recorrência.
PATCH/api/v1/recorrentes/{id}EMISSAOAltera uma recorrência.
DELETE/api/v1/recorrentes/{id}EMISSAODesativa uma recorrência.

Empresas

GET /api/v1/empresas devolve as empresas ativas com ID, razão social, CNPJ, município, alíquota padrão e regime tributário. Use o id como empresaId nas demais chamadas.

Perfis tributários

GET /api/v1/perfis-tributarios aceita empresaId, ativo (padrão true), clienteId, codigoTribNac, page e limit. O detalhe usa GET /api/v1/perfis-tributarios/{id}. Para uma sugestão, chame GET /api/v1/perfis-tributarios/sugerir?empresaId=7&clienteId=11&codigoTribNac=010101; apenas empresaId é obrigatório.

O fluxo recomendado é listar empresas, listar ou sugerir um perfil já cadastrado na tela Perfis tributários e enviar o ID escolhido como perfilTributarioId no POST da nota. API, lote e MCP não aplicam perfis automaticamente.

Emissão em lote

O JSON recebe notas com as mesmas propriedades aceitas pela emissão avulsa. O CSV oferece essas propriedades como colunas, aceita ;, , ou tabulação e decodifica UTF-8 ou Windows-1252. O corpo é limitado a 2 MB. O perfilTributarioId de cada item deve ser obtido na tela ou em GET /api/v1/perfis-tributarios.

Sem async=true, o processamento é síncrono e aceita no máximo 5 linhas; lotes maiores retornam 413 LOTE_GRANDE e devem usar ?async=true. O modo assíncrono aceita até 500 linhas. Quando há mais de uma empresa emissora ativa, toda nota deve informar empresaId; sua ausência retorna 400 CONFIG antes de enfileirar. O campo codigo de erro é normalizado e codigoOriginal preserva o código da prefeitura quando forem diferentes. | POST | /api/v1/clientes | EMISSAO | Cadastra um cliente (tomador reutilizável). |

Use clienteId (retornado por POST /api/v1/clientes) nos campos de tomador de POST /api/v1/nfse e POST /api/v1/recorrentes para vincular o cliente cadastrado.

Perfil tributário na emissão

POST /api/v1/nfse, cada item de POST /api/v1/nfse/lote e POST /api/v1/recorrentes aceitam o campo opcional perfilTributarioId. Informe o ID numérico inteiro positivo do perfil, não sua descrição ou código fiscal. O perfil deve existir, estar ativo e pertencer ao mesmo tenant e à empresa emissora.

Os campos não nulos definidos pelo perfil (aliquotaISSQN, tpRetISSQN, codigoTribNac, codigoTribMun, locPrestacaoIBGE e deducaoBaseISS) prevalecem sobre os valores enviados no payload. Campos nulos no perfil mantêm o valor do payload ou o padrão atual. Sem perfilTributarioId, nenhum perfil é aplicado automaticamente.

NFS-e síncrona

POST /api/v1/nfse

{
"empresaId": 7,
"perfilTributarioId": 21,
"tomadorTipo": "CNPJ",
"tomadorDoc": "12345678000190",
"tomadorNome": "Cliente Exemplo",
"descricaoServico": "Consultoria",
"codigoTribNac": "010101",
"codigoTribMun": "0101",
"dataCompetencia": "2026-08",
"valorServico": 1000
}

NFS-e assíncrona

Use o mesmo payload em POST /api/v1/nfse?async=true ou envie o header X-Async: true. O perfilTributarioId é preservado no job.

{
"empresaId": 7,
"perfilTributarioId": 21,
"tomadorTipo": "CNPJ",
"tomadorDoc": "12345678000190",
"tomadorNome": "Cliente Exemplo Assíncrono",
"descricaoServico": "Consultoria mensal",
"codigoTribNac": "010101",
"codigoTribMun": "0101",
"dataCompetencia": "2026-08",
"valorServico": 1200
}

Lote JSON ou CSV

Cada item pode escolher seu próprio perfil. Uma linha inválida é reportada sem impedir o processamento das demais.

{
"notas": [
{
"empresaId": 7,
"perfilTributarioId": 21,
"tomadorTipo": "CNPJ",
"tomadorDoc": "12345678000190",
"tomadorNome": "Cliente do Lote",
"descricaoServico": "Consultoria",
"codigoTribNac": "010101",
"codigoTribMun": "0101",
"dataCompetencia": "2026-08",
"valorServico": 1000
}
]
}

No CSV, use a coluna opcional perfilTributarioId; cada célula preenchida deve conter o ID numérico do perfil. O modelo atualizado pode ser baixado em GET /api/nfse/lote.

Cobrança recorrente

MétodoRotaEfeito
GET/api/v1/recorrentes?page=1&limit=20&empresaId=7&ativo=trueLista paginada e filtrada. pagina/limite seguem aceitos como aliases.
GET/api/v1/recorrentes/{id}Consulta o registro completo.
POST/api/v1/recorrentesCria uma recorrência.
PATCH/api/v1/recorrentes/{id}Altera os campos informados.
DELETE/api/v1/recorrentes/{id}Desativa de forma irreversível.

Os campos são os mesmos da tela: empresa e perfil; tomador completo, inclusive telefone, NIF e endereço estrangeiro; os 18 campos do intermediário; serviço; valores, descontos e dedução; observações; e-mail; boleto; tipo ILIMITADA ou LIMITADA, quantidade, status e dia (1–28). locPrestacaoIBGE é opcional; quando omitido, usa o município da empresa.

{
"empresaId": 7,
"perfilTributarioId": 21,
"descricao": "Mensalidade de consultoria",
"tomadorDoc": "12345678000190",
"tomadorNome": "Cliente Recorrente",
"descricaoServico": "Consultoria mensal",
"codigoTribNac": "010101",
"codigoTribMun": "0101",
"valorServico": 1000,
"valorDescontoCondicionado": 50,
"deducaoBaseISS": 100,
"tomadorTelefone": "11999999999",
"tipoRecorrencia": "ILIMITADA",
"emailPara": "financeiro@example.com"
}

Erros 400 do perfil

SituaçãoCódigoMensagem
ID não inteiro, texto, zero ou negativoPERFIL_TRIBUTARIOperfilTributarioId deve ser um número inteiro positivo.
Perfil inexistente ou de outro tenantPERFIL_TRIBUTARIOPerfil tributário não encontrado.
Perfil inativoPERFIL_TRIBUTARIOPerfil tributário selecionado está inativo.
Perfil de outra empresa emissoraPERFIL_TRIBUTARIOPerfil tributário não pertence à empresa emissora.

No lote síncrono, o erro aparece no resultado da linha. No lote assíncrono, erros de formato detectados antes da fila aparecem em erros; validações de existência e vínculo feitas pelo núcleo aparecem no status do job correspondente.

Idempotência

Em POST /api/v1/nfse, envie Idempotency-Key: <uuid>. Retry com a mesma chave não gera nota duplicada — devolve a resposta original. Reuso da chave com payload diferente é detectado (hash do corpo).

Erros

Formato: { "erro": { "codigo": "...", "mensagem": "..." } }. Códigos comuns: NAO_AUTORIZADO (401), ESCOPO_INSUFICIENTE (403), PLANO_SEM_INTEGRACOES (403), VALIDACAO (400), NAO_ENCONTRADO (404), rate limit (429), INTERNO (500). PLANO_SEM_INTEGRACOES indica que a assinatura ou o plano atual não dá acesso à API. Emissão bloqueada por billing retorna 402.

Webhooks

Cadastre endpoints em /integracoes. Eventos: nfse.autorizada, nfse.rejeitada, nfse.cancelada.

  • Entrega POST com corpo JSON do evento.
  • Assinatura HMAC-SHA256 no header X-NotasPJ-Signature (verifique com o segredo do webhook).
  • Reentrega automática com backoff (Sprint A consolidado) e reenvio manual no painel.

Não confunda com o webhook do Stripe (/api/billing/webhook), que é interno ao billing da plataforma (assinaturas/faturas), não exposto a integradores.