Nota Plena · API

Documentação da API

Com a API da Nota Plena, o sistema da sua empresa emite, cancela e consulta as próprias NFS-e (notas de serviço), baixa o PDF de cada nota e recebe webhooks quando o resultado sai na prefeitura.

Para quem é

  • Uma clínica que emite a nota assim que a consulta é paga no sistema de agendamento e guarda o PDF no prontuário financeiro.
  • Uma consultoria que fecha as horas do mês na planilha ou no ERP e emite as notas de todos os clientes de uma vez, com conciliação automática pela lista de notas.
  • Um SaaS que emite em nome dos seus clientes (por exemplo, um sistema de gestão para prestadores de serviço). Esse modelo usa a API para plataformas, liberada por acordo comercial. Veja como solicitar.

Acesso e cobertura

Chave de API: incluída no plano Negócio. Os planos e o que cada um inclui estão em notaplena.com.br/precos.

Cobertura. A emissão está em produção em São Paulo (capital), Bertioga e Itupeva. Nas demais cidades, a Nota Plena está pronta para as 2.886 cidades do padrão nacional. Antes de integrar, confira a sua cidade em notaplena.com.br/nfse ou consulte GET /api/v1/integrations/tenant/readiness com a sua chave.

Contador. A Nota Plena exporta as notas e os XMLs do período (em Histórico, no painel) para você enviar ao seu contador. Não há integração direta com sistemas contábeis: a troca é por exportação de XML.

Autenticação

Toda requisição usa uma chave de empresa, que só acessa a empresa que a criou. O dono da empresa cria a chave no painel, em Configurações → Integrações → Nova chave. A chave aparece uma única vez; guarde-a em um cofre de segredos.

Envie a chave no header de toda requisição:

Authorization: Bearer np_live_xxxxxxxx
Chave só de leitura. Ao criar a chave, você pode escolher Só leitura: ela consulta a empresa, a lista e o status das notas e baixa o PDF, mas qualquer emissão, cancelamento, link ou webhook novo responde 403. É a opção indicada para assistentes de IA, planilhas e ferramentas financeiras.

Limite de uso

Cada chave é limitada a 120 requisições por minuto (janela deslizante) nas rotas de emissão e cancelamento. Acima disso, a resposta é 429.

URL base

https://api.notaplena.com.br

Todos os endpoints abaixo usam essa origem. As respostas são JSON, e o corpo de erro segue o formato:

{ "detail": "Mensagem em português explicando o erro" }
Não existe ambiente de testes para a chave de empresa. A sua empresa já está em produção: toda emissão bem-sucedida é uma nota fiscal real na prefeitura e conta na cota do plano. Teste com um serviço de verdade ou cancele a nota em seguida.

Especificação OpenAPI das rotas da chave de empresa, sem autenticação: api.notaplena.com.br/api/v1/integrations/tenant/openapi.json (só as rotas de leitura: ?scope=read).

Consultar a empresa e as notas

Qual empresa é esta chave

GET/api/v1/integrations/tenant
curl https://api.notaplena.com.br/api/v1/integrations/tenant \
  -H "Authorization: Bearer np_live_xxxxxxxx"

Devolve id, cnpj, razao_social, nome_fantasia, a cidade (ibge_city_code) e o regime. Serve como teste de conexão.

O que falta para emitir

GET/api/v1/integrations/tenant/readiness
{
  "can_emit": false,
  "blocks": [
    {
      "code": "no_cert",
      "message": "Você ainda não pode emitir: falta o certificado digital A1 da empresa. ...",
      "action_label": "Enviar certificado",
      "action_url": "https://notaplena.com.br/settings#certificado"
    }
  ],
  "default_codigo_servico": "02684",
  "default_descricao": "Consultoria",
  "servicos_usados": [
    {
      "codigo_servico": "02684",
      "aliquota_iss": "0.0200",
      "exemplo_discriminacao": "Consultoria de outubro",
      "notas": 41,
      "ultima_em": "2026-10-20T14:00:00Z"
    }
  ]
}
  • Cada item de blocks é um passo que só a pessoa faz (certificado A1, inscrição municipal, plano), com o link da tela que resolve. Certificado e senha nunca passam pela API.
  • servicos_usados: os pares de código de serviço e alíquota com que a empresa já emitiu (até 10, os mais usados primeiro). Use-os na emissão em vez de adivinhar.

Listar as notas

GET/api/v1/integrations/tenant/emissions
curl "https://api.notaplena.com.br/api/v1/integrations/tenant/emissions?status=success,imported&period_start=2026-10-01T00:00:00-03:00&period_end=2026-10-31T23:59:59-03:00&limit=200&offset=0" \
  -H "Authorization: Bearer np_live_xxxxxxxx"

Resposta 200

{
  "items": [
    {
      "id": "9c1fa402-3c29-4bbb-9210-baf4cc2a4231",
      "created_at": "2026-10-14T13:02:11-03:00",
      "status": "success",
      "source": "emitted",
      "numero_nfse": "1023",
      "codigo_verificacao": "NMTBGWKL",
      "tomador_nome": "Ana Maria Pereira",
      "tomador_documento": "12345678901",
      "valor_servicos": "650.00",
      "discriminacao": "Consulta de fisioterapia — 4 sessões",
      "codigo_servico": "04.08",
      "aliquota_iss": "0.02",
      "error_message": null,
      "cancelled_at": null
    }
  ],
  "total": 1,
  "limit": 200,
  "offset": 0
}
  • As mais novas vêm primeiro. limit vai até 200; avance o offset até passar de total.
  • status: success (emitida), imported (emitida fora da Nota Plena e importada), error ou pending. Para vários, separe por vírgula; sem o filtro, vem tudo.
  • Nota cancelada: cancelled_at preenchido.
  • period_start e period_end filtram pela data de registro da nota (ISO 8601 com fuso).

Emitir NFS-e

POST/api/v1/integrations/tenant/nfse

Emite uma NFS-e do CNPJ da sua chave. A Nota Plena escolhe o caminho (sistema da prefeitura ou padrão nacional), assina com o certificado A1 da empresa e devolve a nota.

curl -X POST https://api.notaplena.com.br/api/v1/integrations/tenant/nfse \
  -H "Authorization: Bearer np_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: fatura-2026-10-0042" \
  -d '{
    "valor_servicos": "4800.00",
    "discriminacao": "Consultoria financeira — outubro/2026",
    "codigo_servico": "17.01",
    "aliquota_iss": "0.02",
    "tomador_nome": "Comercial Exemplo LTDA",
    "tomador_documento": "11222333000181",
    "tomador_email": "financeiro@exemplo.com.br",
    "tomador_cep": "04023-062"
  }'

Resposta 200

{
  "emission_id": "9c1fa402-3c29-4bbb-9210-baf4cc2a4231",
  "status": "success",
  "numero_nfse": "1023",
  "codigo_verificacao": "NMTBGWKL",
  "numero_rps": "88",
  "serie_rps": "A",
  "valor_servicos": "4800.00",
  "error_message": null,
  "error": null
}

status: success (emitida na prefeitura), error (recusada; error_message e o objeto error trazem o motivo) ou pending (em processamento; a nota ainda não tem número. Aguarde o webhook nfse.emitted ou nfse.failed e não reenvie).

Uma recusa da prefeitura (dados fiscais errados, por exemplo) chega como HTTP 200 com status: "error", e não como erro HTTP. Use o objeto estruturado error ({ code, field, hint }) para decidir o que fazer no seu código; error_message é o texto original da prefeitura. Veja Erros e retentativas.

Opcional, só para tomador com CNPJ: tomador_inscricao_municipal (inscrição municipal do tomador, só números, de 1 a 12 dígitos). Envie apenas se o cliente pediu.

Idempotência

O header Idempotency-Key (até 80 caracteres) é obrigatório na emissão: sem ele, a resposta é 422 IDEMPOTENCY_KEY_REQUIRED e nada é emitido. Reenviar a mesma chave devolve a mesma nota, nunca uma segunda. Use uma referência única do seu sistema, como o número da fatura ou do atendimento.

Uma chave vale para um único desfecho, inclusive erro. Depois que uma chamada registra um resultado (nota emitida ou erro retentável), reenviar a mesma Idempotency-Key só devolve aquele desfecho. Para retentar de verdade, mande a mesma raiz com um sufixo: <chave>-r2, -r3… A Nota Plena reconhece que é a mesma venda e, se a tentativa anterior já tiver virado nota, devolve a nota existente.

Bloqueio de cobrança (402)

Se a assinatura estiver em atraso ou suspensa, a emissão é negada com 402 e a mensagem explica o que fazer:

HTTP/1.1 402 Payment Required
{
  "detail": "Conta suspensa por atraso de pagamento. Regularize em notaplena.com.br/billing."
}

Se a empresa não está mais no plano Negócio, a resposta é 402 com error.code = "PLAN_NOT_ELIGIBLE". A chave continua existindo (é possível ler e revogar), mas não emite nem cancela.

Cancelar NFS-e

POST/api/v1/integrations/tenant/nfse/{emission_id}/cancel

Cancela na prefeitura uma NFS-e da sua empresa. As regras são as mesmas do cancelamento pelo painel: o prazo de 180 dias e a confirmação para nota de mês anterior não podem ser contornados pela API. Quando o cancelamento é concluído, o webhook nfse.cancelled é enviado.

curl -X POST https://api.notaplena.com.br/api/v1/integrations/tenant/nfse/9c1fa402-3c29-4bbb-9210-baf4cc2a4231/cancel \
  -H "Authorization: Bearer np_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Consulta desmarcada — pagamento estornado",
    "confirm_outside_window": false
  }'

Resposta 200

{
  "success": true,
  "error_message": null,
  "requires_extra_confirmation": false,
  "days_since_emission": 0
}
  • reason é obrigatório (mínimo de 3 caracteres) e vai para a prefeitura como motivo. Vazio responde 422.
  • Nota de um mês anterior, ainda dentro de 180 dias: a primeira chamada volta success: false com requires_extra_confirmation: true. Repita com confirm_outside_window: true para confirmar.
  • Nota com mais de 180 dias: o cancelamento comum não é mais permitido. A resposta é success: false e o error_message explica o caminho (nota de substituição ou processo na prefeitura).
  • 409: a nota já estava cancelada.
  • 502: o pedido foi enviado, mas a prefeitura não respondeu. Repita a chamada: ela confere o estado antes de pedir de novo.
  • 404: a nota não existe ou não é da sua empresa.

Ler uma NFS-e

GET/api/v1/integrations/emissions/{emission_id}

Retorna os dados de uma NFS-e. O emission_id é o UUID devolvido na emissão ou na lista de notas.

curl https://api.notaplena.com.br/api/v1/integrations/emissions/9c1fa402-3c29-4bbb-9210-baf4cc2a4231 \
  -H "Authorization: Bearer np_live_xxxxxxxx"

Resposta 200

{
  "id": "9c1fa402-3c29-4bbb-9210-baf4cc2a4231",
  "created_at": "2026-10-14T13:02:11-03:00",
  "status": "success",
  "numero_nfse": "1023",
  "codigo_verificacao": "NMTBGWKL",
  "tomador_nome": "Comercial Exemplo LTDA",
  "tomador_documento": "11222333000181",
  "valor_servicos": "4800.00",
  "discriminacao": "Consultoria financeira — outubro/2026",
  "pdf_url": null
}

pdf_url é o link de impressão no site da prefeitura e só existe para São Paulo (nas outras cidades vem null). Para o PDF de qualquer cidade, use Baixar o PDF. Uma emissão com status: "error" traz também error_message e error.

Baixar o PDF da NFS-e

GET/api/v1/integrations/emissions/{emission_id}/pdf

Devolve o PDF da nota (DANFSe), pronto para mostrar ou anexar, em todas as cidades em que a nota foi emitida.

curl https://api.notaplena.com.br/api/v1/integrations/emissions/9c1fa402-3c29-4bbb-9210-baf4cc2a4231/pdf \
  -H "Authorization: Bearer np_live_xxxxxxxx" \
  -o NF-1023.pdf
  • 200 com Content-Type: application/pdf e nome de arquivo NF-<número>.pdf.
  • 409: a nota ainda não foi emitida com sucesso.
  • 502: não foi possível gerar o PDF agora; tente de novo em instantes.

Webhooks

Cada chave tem as próprias assinaturas. Cada assinatura recebe um secret que assina o corpo do evento (HMAC-SHA256); o secret aparece uma única vez, na criação.

Eventos

  • nfse.emitted: NFS-e emitida com sucesso.
  • nfse.failed: emissão recusada pela prefeitura.
  • nfse.cancelled: NFS-e cancelada.

Garantias de entrega

  • Cada desfecho chega. Se o envio de um evento se perder, uma varredura periódica percebe a falta e envia o evento com o mesmo conteúdo.
  • Uma vez por nota. O mesmo evento sobre a mesma nota é enfileirado no máximo uma vez por assinatura. Ainda assim, trate o receptor como idempotente por emission_id: uma entrega cuja confirmação HTTP se perdeu é reenviada.
  • "failed" só quando há certeza. Quando o desfecho é incerto (o pedido pode ter chegado à prefeitura e a resposta se perdeu), nenhum webhook é enviado até a confirmação.

Criar, listar e revogar

POST/api/v1/integrations/tenant/webhooks
GET/api/v1/integrations/tenant/webhooks
DELETE/api/v1/integrations/tenant/webhooks/{subscription_id}
curl -X POST https://api.notaplena.com.br/api/v1/integrations/tenant/webhooks \
  -H "Authorization: Bearer np_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://seu-sistema.com.br/webhooks/nota-plena",
    "events": ["nfse.emitted", "nfse.failed"]
  }'

events vazio ([]) assina todos os eventos. Evento desconhecido responde 422. O secret não volta na listagem; se perdê-lo, revogue a assinatura e crie outra.

Erros e retentativas

A regra geral: o status HTTP diz de quem é o problema. Retentar do jeito errado ou repete o mesmo erro ou arrisca uma nota duplicada. Abaixo, cada desfecho e a ação indicada.

Prefeitura fora do ar — 503 PREFEITURA_UNAVAILABLE

A prefeitura não respondeu. O seu pedido está correto e é seguro retentar, com a mesma raiz e o sufixo -r2, -r3… (a mesma chave só devolve este erro). Esta resposta não traz Retry-After: aguarde alguns minutos antes de retentar.

HTTP/1.1 503 Service Unavailable
{
  "detail": {
    "message": "O servidor da prefeitura está offline. Tente novamente mais tarde com uma Idempotency-Key de RETENTATIVA — a mesma raiz com sufixo -r2, -r3 …",
    "error": { "code": "PREFEITURA_UNAVAILABLE", "retriable": true }
  }
}

Emissão pausada no município — 503 EMISSAO_PAUSADA_MUNICIPIO

A prefeitura recusou várias emissões seguidas desta empresa por um motivo que não está na nota (por exemplo, o cadastro municipal), e as emissões foram pausadas para não gastar RPS. Nenhuma nota nem Idempotency-Key foi consumida: respeite o header Retry-After (em segundos) e reenvie o mesmo pedido com a mesma chave.

Duplicidade não verificável — 422 DUPLICATE_RISK_UNVERIFIABLE

Uma tentativa anterior desta mesma venda pode ter chegado à prefeitura sem confirmação. Não retente às cegas. Confira no portal da prefeitura ou em notaplena.com.br/problemas e, se a nota de fato não existir, emita novamente.

Chave reusada para outra venda — 422 IDEMPOTENCY_KEY_REUSED

A Idempotency-Key já pertence a outra nota, com dados diferentes. Nenhuma nota nova foi emitida. Use uma chave nova para esta venda.

Validação — 422

Recusado antes de ir à prefeitura: campo obrigatório ausente, tipo errado, certificado ausente ou vencido (NO_CERT / CERT_EXPIRED), inscrição municipal faltando (NO_INSCRICAO_MUNICIPAL), cidade ainda não atendida (CITY_UNSUPPORTED) ou código de tributação nacional ausente ou inválido (CTRIBNAC_MISSING / CTRIBNAC_INVALID). Corrija o pedido; repetir igual não muda o resultado.

Resumo

DesfechoRetentar?Como
503 PREFEITURA_UNAVAILABLESimMesma raiz + -rN
503 EMISSAO_PAUSADA_MUNICIPIOSim, após Retry-AfterMesma chave, mesmo pedido
422 DUPLICATE_RISK_UNVERIFIABLESó após conferirConfira no portal ou em /problemas
422 IDEMPOTENCY_KEY_REUSEDSim, com chave novaChave nova para a venda nova
422 validação, certificado ou cidadeSó após corrigirAjuste o pedido conforme o hint
200 status: "error"Só após corrigir os dadosCorrija conforme error.hint; chave nova ou -rN
402 cobrançaNão, até regularizarMostre a mensagem de detail a quem administra a conta
status: "pending"NãoAguarde o webhook
429SimEspere alguns segundos; limite de 120 req/min por chave

Códigos de status

StatusSignificado
400Requisição inválida (JSON malformado, header faltando)
401Chave ausente, mal formada ou revogada
402Emissão bloqueada por cobrança ou por plano sem API
403Chave só de leitura em rota de escrita, ou link de visualização que não é desta nota
404O recurso não existe ou não é da sua empresa
409Conflito de estado (nota já cancelada, PDF de nota não emitida)
422Validação falhou; o detail diz o campo
429Limite de 120 requisições por minuto por chave
502 / 503Prefeitura sem resposta ou emissão pausada; veja Erros e retentativas

Para plataformas: emitir em nome dos seus clientes

Se o seu produto é um SaaS ou ERP e você quer emitir as notas dos seus clientes (cada um com o próprio CNPJ e certificado), use a API para plataformas. Ela é liberada por acordo comercial, com condições definidas caso a caso. Fale com o nosso time comercial para avaliar a integração.

Como começar

  1. Assine o plano Negócio e cadastre a empresa, com o certificado A1, pelo painel.
  2. Crie a chave em Configurações → Integrações e confira GET /integrations/tenant/readiness.
  3. Emita com uma Idempotency-Key derivada da sua fatura ou atendimento e assine os webhooks.

Com a sua autorização, usamos Meta Pixel e tag do Google para entender de onde vêm as visitas e se os nossos anúncios funcionam. Isso envia o seu endereço IP e a página que você está vendo para Meta Platforms, Inc. e Google LLC. Nada disso carrega antes de você decidir, e recusar não muda nada no site nem no uso da plataforma. Política de Privacidade.