# GereNota API — guia para integradores e para a sua IA > Gerado do código pela suíte (`scripts/gera_doc_api.py`); versão 0.1.0 · API v1 em `https://api.gerenota.com.br` · site https://gerenota.com.br. Este arquivo é o `llms-full.txt` do GereNota: cole-o inteiro no seu assistente ou aponte-o para ele. ## Comece aqui: uma nota em cinco chamadas Tudo fica sob `https://api.gerenota.com.br/api/v1` e leva o cabeçalho `Authorization: Bearer gnk_live_…` (a chave é criada em Painel → Integrações). Guarde a chave numa variável de ambiente; os exemplos usam `$GERENOTA_KEY`. 1. **Quem sou eu.** `GET /me` devolve a conta, o papel efetivo da chave, o plano e o uso das cotas. Se vier 401, a chave está errada ou revogada; se vier 402 `RECURSO_FORA_DO_PLANO`, o plano da conta não inclui a API — ela entra a partir do Plano Individual, que o dono da conta assina na página Cobrança do painel. 2. **Escolha a empresa.** A GereNota atende empresas do Simples Nacional e MEI (o cadastro de não optante volta 422 `EMPRESA_FORA_DO_SIMPLES`). `GET /companies` lista as empresas emissoras da conta; use o `id` de uma com `status: "ativa"` e certificado válido (`GET /companies/{id}/status` diz se pode emitir). Uma empresa pode ser cadastrada pela API (`POST /companies`), mas o certificado A1 e a validação são feitos pelo dono no painel: até lá ela não emite. 3. **Emita em teste.** `POST /companies/{id}/nfse` com `"ambiente": "teste"` valida a nota inteira no Sistema Nacional sem efeito fiscal. É o jeito de conferir código de serviço, valores e tomador antes de valer. 4. **Emita valendo.** A mesma chamada sem `ambiente` (ou com `"producao"`), com o cabeçalho `Idempotency-Key`. A resposta traz `numero` (o número oficial), `chave_acesso` e `id`. 5. **Pegue o documento.** `GET /nfse/{id}/pdf` é o DANFSE; `GET /nfse/{id}/xml` é o XML autorizado; `POST /nfse/{id}/enviar-email` manda ao cliente. ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/$EMPRESA/nfse" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "dCompet": "2026-09-16", "servico": { "cTribNac": "010501", "descricao": "Licença de uso de software — setembro/2026" }, "valores": { "vServ": "350.00" }, "tomador": { "tipo": "CNPJ", "documento": "11222333000181", "nome": "Cliente Exemplo Ltda", "email": "financeiro@cliente.com.br" } }' ``` Série, regime tributário e a alíquota do Simples do mês saem do cadastro da empresa; você não os informa na chamada. Empresa do Simples (ME/EPP) ainda sem alíquota nenhuma — nem calculada pelo PGDAS-D, nem confirmada no painel — recebe 422 `ALIQUOTA_NAO_CONFIRMADA`: o dono autoriza a consulta ao PGDAS-D, ou alguém com acesso fiscal à empresa (dono, operador ou contabilidade) confirma a alíquota no painel — ou você manda `valores.pTotTribSN` (veja Regras de emissão). O tomador é opcional: sem ele a nota sai sem identificação do cliente, quando a legislação permite. ## Autenticação e escopos - **Chave de API** (`gnk_live_…`): criada pelo dono da conta em Painel → Integrações, mostrada uma única vez; só o hash fica guardado. Mande em toda chamada: `Authorization: Bearer gnk_live_…`. - **Escopo por chave:** `emissao` lê e escreve (emitir, cancelar, cadastrar); `leitura` só lê. Escrever com chave de leitura dá 403. - **Papel efetivo:** é sempre o menor entre o escopo da chave e o papel de quem a criou, e uma chave nunca tem o papel de dono. Por isso ações de dono (enviar o certificado A1, validar a empresa, gerir acessos e cobrança) não existem nesta API: são feitas no painel. Pelo mesmo motivo, os erros de limite nunca trazem `upgrade` para uma chave: o plano que resolve vem só no `hint` (veja Erros). - **Plano:** a API e o conector MCP entram a partir do Plano Individual. A chave de uma conta cujo plano deixou de incluir a API recebe 402 `RECURSO_FORA_DO_PLANO` em qualquer chamada, com o Plano Individual no `hint`. No conector MCP, a conexão de uma conta sem o plano para numa página que diz o plano que resolve; se o plano muda com o conector já ligado, cada chamada — menos as de cobrança e a do link do painel, que seguem abertas para a assinatura — responde 403 `RECURSO_FORA_DO_PLANO`, com o `upgrade` (o Plano Individual, o preço e o link para assinar) quando quem conectou é o dono da conta; a conexão cai na renovação seguinte, em até 1 hora. - **Revogação:** revogar a chave no painel vale na hora; a chamada seguinte recebe 401. - **Não use** a chave em código-fonte, em URL nem em log. Uma chave por sistema integrado facilita revogar sem derrubar os outros. - Assistentes conversacionais (Claude e compatíveis) não usam chave: conectam pelo MCP com login por código no e-mail (veja a última seção). - **Antes da primeira escrita:** `GET /me` devolve `escopo` (`emissao` ou `leitura`) e `role`; uma chave de leitura recebe 403 em emissão, cancelamento e substituição. ## Teste × valendo - `"ambiente": "teste"` em `POST /companies/{id}/nfse` valida a nota inteira no Sistema Nacional (ambiente de produção restrita do gov.br) e devolve a mesma estrutura de resposta, **sem efeito fiscal**: não conta na cota, não aparece em `GET /nfse` nem nos totais, e o PDF sai com marca de rascunho. Notas de teste são apagadas em 24 horas. - Sem `ambiente` (ou `"producao"`), a nota é emitida de verdade: numerada, assinada com o certificado da empresa e transmitida ao gov.br. - **Prévia sem transmitir:** `POST /companies/{id}/nfse/rascunho-pdf` recebe o mesmo corpo da emissão e devolve um PDF de rascunho gerado localmente, sem tocar o Sistema Nacional. Use para mostrar ao usuário antes de emitir. - O que o Sistema Nacional rejeita em teste rejeitaria valendo: um 422 com o código do gov.br (por exemplo `E0312`, município não aderente para o serviço) na mensagem é o mesmo nos dois ambientes. ## Idempotência: nunca emita duas vezes - Mande o cabeçalho `Idempotency-Key` com um valor único por intenção de emissão (um UUID serve) em `POST /companies/{id}/nfse` e em `POST /nfse/{id}/substituir`. - No cancelamento (`POST /nfse/{id}/cancelar`) a chave vale o mesmo: repetir com ela devolve o **mesmo cancelamento** (200, `X-Idempotent-Replay: true`) em vez do 409 `NFSE_NAO_ATIVA` da nota já cancelada, e a chamada simultânea recebe 409 `CANCELAMENTO_EM_ANDAMENTO`. Ali a chave é da nota: a mesma chave usada numa emissão não se confunde com ela. - Repetir a chamada com a mesma chave devolve a **mesma nota** (resposta idêntica, cabeçalho `X-Idempotent-Replay: true`) por 24 horas. É seguro repetir depois de timeout, queda de rede ou 5xx. - Uma chamada **simultânea** com a mesma chave, enquanto a primeira ainda não terminou, recebe 409 `EMISSAO_EM_ANDAMENTO`. Espere a primeira responder e repita, se precisar. - Se a emissão falhou (por exemplo, 422 de validação), a chave é liberada: a próxima chamada com ela tenta de novo. - Se o Sistema Nacional não responder a tempo, a emissão confere a nota pelo número da DPS antes de responder: se ela saiu, a resposta é a nota. Sem como confirmar, vem 503 `EMISSAO_INCERTA` e a chave **não** é liberada: repita com a **mesma** chave em alguns minutos — a repetição confere primeiro se a nota saiu e, se não saiu, emite com o mesmo número. Uma chave nova poderia emitir uma segunda nota. - A chave é por conta: duas contas podem usar o mesmo valor sem se cruzar. Quem tem acesso a só algumas empresas (o membro com recorte, ou quem opera uma empresa compartilhada por outra conta) tem as chaves dele: elas nunca se cruzam com as do dono da conta nem com as de outra pessoa. - Sem o cabeçalho, cada chamada emite uma nota nova. Em integrações automáticas isso é um erro caro: use sempre. ## Erros Todo erro volta com este envelope, em qualquer status 4xx ou 5xx: ```json { "code": "EMPRESA_NAO_ENCONTRADA", "message": "Empresa não encontrada", "hint": "…", "field": "…", "erros": [ … ], "volta_em": "…", "upgrade": { … } } ``` - `code` é estável: programe por ele. `message` é para mostrar a uma pessoa. `hint` diz como resolver quando há o que fazer. `field` aponta o campo do corpo, quando houver. `erros` (só no 422) detalha cada campo: `loc`, `type`, `msg`. `volta_em` e `upgrade` só aparecem nos erros de limite (veja o fim desta seção). - **Status:** 401 chave ausente, inválida ou revogada · 402 plano sem o recurso, teto do plano atingido (empresas, automações, acessos), cota do mês esgotada ou conta com a renovação vencida (`CONTA_BLOQUEADA`, a de quem é dono da empresa compartilhada inclusive) · 403 escopo de leitura tentando escrever, papel insuficiente, empresa fora do acesso da chave ou, no conector MCP, plano sem o conector · 404 não existe nesta conta · 409 conflito com o estado atual (nota já cancelada, empresa inativa, emissão em andamento, arquivo indisponível, links abertos no teto) · 413 arquivo acima de 8 MB · 422 dados inválidos ou rejeição do Sistema Nacional · 429 muitas chamadas, ou o teto do dia acabou · 502 o Sistema Nacional ou a Receita respondeu com erro · 503 serviço externo indisponível. - **Rejeição do gov.br:** vem como 422 com o código oficial (`E0312`, `E0625`, …) no `code` e a explicação na `message`. Corrija o corpo e repita; a `Idempotency-Key` é liberada em falha. A partir de 1º/11/2026, a recusa de uma ME ou EPP de cidade sem adesão por uma das regras do convênio do município (`E0016`, `E0037`, `E0038` ou `E0039`) não se corrige no corpo: a `message` explica, e repetir a mesma nota não muda o resultado. - **Códigos que valem conhecer:** `EMPRESA_NAO_ENCONTRADA`, `EMPRESA_NAO_ATIVA`, `EMPRESA_FORA_DO_RECORTE`, `EMISSAO_EM_ANDAMENTO`, `EMISSAO_INCERTA` (503: repita com a mesma `Idempotency-Key`), `NFSE_NAO_ENCONTRADA`, `ARQUIVO_INDISPONIVEL`, `RECURSO_FORA_DO_PLANO`, `LIMITE_DO_PLANO`, `COTA_ESGOTADA`, `COTA_CONSULTAS_ESGOTADA`, `DOCUMENTO_INVALIDO`, `RATE_LIMIT`, `DADOS_INVALIDOS`. - **Dos tetos de uso** (a proteção das consultas e dos envios pagos): `LIMITE_CONSULTAS_DIA` (429: as consultas de CNPJ/CPF do dia da conta acabaram), `CONSULTAS_PAUSADAS` (503: as consultas da plataforma pararam até a virada do dia; siga com o cadastro manual), `LIMITE_EMAILS_DO_DIA` (429: 100 notas por e-mail por dia) e `LIMITE_RODAR_AGORA` (429: o "rodar agora" de uma automação de relatório, 3 vezes por dia). Os 429 do dia renovam à 0h de Brasília, o instante que vem em `volta_em`. - **Do cliente pelo CNPJ** (o cadastro e a emissão só com o CNPJ, que buscam na Receita): `CNPJ_NAO_ENCONTRADO_NA_RECEITA` (422: a Receita não conhece o número — confira os dígitos com o cliente; a resposta da Receita é cobrada) e `TOMADOR_SEM_NOME` (422: a prévia em PDF, a substituição e as automações continuam exigindo o `tomador.nome`). Quando a busca não sai — `COTA_CONSULTAS_ESGOTADA`, `LIMITE_CONSULTAS_DIA`, `RATE_LIMIT`, `CONSULTAS_PAUSADAS`, Receita fora —, o erro aponta o `field` do nome (`nome` no cadastro, `tomador.nome` na emissão), com o `volta_em` e o `upgrade` do limite quando há: mande o nome e o pedido segue sem a Receita, sem custo. `NOME_OBRIGATORIO` (422): CPF sem nome. - **Só Simples Nacional e MEI:** `EMPRESA_FORA_DO_SIMPLES` (422) no cadastro de não optante (o regime `1`, ou o CNPJ que a consulta à Receita da conta mostrou como não optante) e na emissão da empresa que saiu do Simples — o `hint` diz o caminho: quando ela voltar, o "Conferir na Receita" (painel, Empresas → Editar tributação) libera na hora. - **Do Simples e dos pacotes:** `ALIQUOTA_NAO_CONFIRMADA` (422: empresa ME/EPP sem alíquota nenhuma — o `hint` diz os três caminhos), `TETO_DIARIO_PGDAS` (429: 3 consultas pagas do PGDAS-D por empresa e dia pela API — volta à 0h de Brasília, em `volta_em`), `PGDAS_PAUSADO` (503: as consultas pagas da plataforma pararam até a virada do dia), `ACEITE_SO_DO_DONO` (403: só o dono assina o termo de consulta), `EXPORT_NAO_CONCLUIDO` (409: o pacote ainda não está pronto — ou terminou em `erro`, e aí é preciso pedir de novo) e `VOLUME_NAO_ENCONTRADO` (404: volume fora da lista do pacote). ### Erros de limite: quando volta e o plano que resolve Os erros de limite — `LIMITE_DO_PLANO` (402: empresas, automações ou acessos no teto do plano), `COTA_ESGOTADA` (402: a cota de notas do mês), `RECURSO_FORA_DO_PLANO` (402: relatórios automáticos ou API fora do plano; 403 no conector MCP da conta cujo plano não o inclui), `COTA_CONSULTAS_ESGOTADA` (402), `LIMITE_CONSULTAS_DIA` (429), `LIMITE_DE_LINKS_DO_DIA` (429) e `LINKS_ABERTOS_NO_TETO` (409) — podem trazer, além da dica, dois campos: - `volta_em`: quando o limite volta sozinho, em ISO 8601 e UTC — `"2026-11-01T03:00:00Z"` é a 0h de Brasília do dia 1º de novembro. Vem nas cotas do mês (`COTA_ESGOTADA` e `COTA_CONSULTAS_ESGOTADA`: a 0h de Brasília do dia 1º) e em todo teto do dia (`LIMITE_CONSULTAS_DIA` e `LIMITE_DE_LINKS_DO_DIA`, e também `LIMITE_EMAILS_DO_DIA`, `LIMITE_RODAR_AGORA` e `TETO_DIARIO_PGDAS`, que não têm plano que resolva: a 0h de Brasília do dia seguinte), para qualquer credencial: é o instante para agendar a nova tentativa. O limite que só libera com uma ação — remover uma empresa, excluir uma automação, usar ou cancelar um link, assinar outro plano — vem sem ele. - `upgrade`: o plano que resolve o limite batido (a regra de cada limite está em Limites, cotas e custos). `plano` traz `id`, `nome`, `rotulo` (o nome pronto para um texto: "Plano Multi"), `preco_base` (o preço do mês em reais, como texto: `"79.90"`) e `preco_anual` (o do ciclo anual, ou `null`); `limite_no_plano` é o teto daquele recurso no plano que resolve (`null` = sem limite, como as notas dos planos pagos, ou recurso incluído, como a API); `link` abre a página Cobrança do painel com o plano que resolve já marcado e o motivo do limite — os dois vão na URL (`https://app.gerenota.com.br/billing?plano=plan_multi&motivo=empresas`). O `motivo` é um de: `empresas`, `automacoes`, `acessos`, `notas`, `consultas`, `consultas_dia`, `links`, `relatorios`, `api`. - **Só o dono da conta recebe o `upgrade`** — no login do dono, pelo painel ou pelo conector MCP. A chave de API nunca é do dono (veja Autenticação): com ela o `upgrade` não vem, e o `hint` já nomeia o plano que resolve, sem preço, e diz quem assina ("quem assina é o dono da conta, na página Cobrança") — é o texto para mostrar a quem usa o seu sistema. Numa empresa compartilhada vale o papel de quem a acessa: quem opera a empresa de outra conta também não recebe. - **Sem plano que resolva, sem `upgrade`, nem para o dono:** o Plano Escritório no teto, os planos fora da vitrine (como o Plano Cortesia) e os tetos que são só de segurança — as consultas à Receita e os links de cadastro dos planos pagos. O `hint` dá o caminho sem plano e, onde cabe, o contato: "Para mais, fale com a gente: faleaqui@gerenota.com.br". A segunda empresa no Plano Individual (que inclui 1; o Plano Multi, 5), como o dono recebe — 402 `LIMITE_DO_PLANO` com o `upgrade`: ```json { "code": "LIMITE_DO_PLANO", "message": "O Plano Individual inclui 1 empresa — e a conta já usa 1", "hint": "No Plano Multi cabem até 5 empresas; quem assina é o dono da conta, na página Cobrança — ou libere uma vaga removendo uma empresa que não usa (inclusive na lista de espera)", "upgrade": { "plano": { "id": "plan_multi", "nome": "Multi", "rotulo": "Plano Multi", "preco_base": "79.90", "preco_anual": "799.00" }, "limite_no_plano": 5, "link": "https://app.gerenota.com.br/billing?plano=plan_multi&motivo=empresas" } } ``` O mesmo pedido pela chave de API, ou por quem não é dono: a mesma mensagem e a mesma dica, sem o `upgrade`. ```json { "code": "LIMITE_DO_PLANO", "message": "O Plano Individual inclui 1 empresa — e a conta já usa 1", "hint": "No Plano Multi cabem até 5 empresas; quem assina é o dono da conta, na página Cobrança — ou libere uma vaga removendo uma empresa que não usa (inclusive na lista de espera)" } ``` E um limite que volta sozinho, sem plano que resolva — as consultas do mês do Plano Individual, um teto de segurança: ```json { "code": "COTA_CONSULTAS_ESGOTADA", "message": "As 20 consultas de CNPJ/CPF do mês do Plano Individual acabaram", "hint": "O CNPJ consultado nos últimos 7 dias e o CPF nas últimas 24 h saem do cache sem gastar; o limite renova no dia 1º. Para mais, fale com a gente: faleaqui@gerenota.com.br", "volta_em": "2026-11-01T03:00:00Z" } ``` ## Regras de emissão que você precisa saber - **`dCompet`**: a data da competência do serviço, `AAAA-MM-DD`. Define o mês em que a nota conta. - **`servico.cTribNac`**: o código de tributação nacional do serviço, 6 dígitos sem pontos (ex.: `010501` = licenciamento de software). Ele decide alíquota, retenções e se o município do serviço precisa ser informado. `servico.descricao` é o texto que vai na nota. - **Não sabe o código?** `POST /servicos/sugerir` com a descrição livre do serviço devolve os candidatos do catálogo nacional com o código e a semelhança; `GET /servicos/codigo/{codigo}` confere um código que veio de fora e diz se o ISS é devido no local da prestação. Confirme o candidato antes de emitir: o código decide a tributação. - **Valores como texto decimal** com ponto e duas casas: `"350.00"`. `valores.vServ` é o valor do serviço; descontos incondicionais e condicionais são opcionais. - **Vários itens:** `servico.itens` (descrição, quantidade, valor unitário) soma o total e escreve o detalhamento nas informações complementares; nesse caso não mande `vServ`. - **Tributação:** `tributacao.tribISSQN` (1 = operação tributável) e `tributacao.tpRetISSQN` (1 = ISS não retido, 2 = retido pelo tomador, 3 = pelo intermediário). Quando há retenção numa ME/EPP do Simples, omita `pAliq`: a plataforma preenche com o ISS efetivo do mês da prestação — o da competência (`dCompet`), pela regra da retenção (LC 123, art. 21, § 4º, I). A nota do mês da alíquota em vigor (`mes.mes`, normalmente o corrente) leva o de `mes.p_aliq_iss`; a de outro mês, o ISS daquele mês: o do `historico` de `GET /companies/{id}/aliquotas` ou, na empresa em modo automático (`tributacao_modo` `auto`), o da conta pelas declarações PGDAS-D arquivadas — a mesma do dia 1º, com o anexo e o impedimento daquele período; o mês calculado entra no `historico` quando uma nota retida sai com esse número. Fora disso (modo manual sem aquele mês confirmado — inclusive o corrente, antes da confirmação —, ou quando a conta pelas declarações não fecha para o período) a plataforma não tem o ISS daquele mês e não usa o de outro: 422 `ALIQUOTA_ISS_DO_MES_AUSENTE` — mande a `pAliq` daquele mês (o contador tem). A mesma resposta vem quando o mês da nota não tem o ISS confirmado. Com o ISS fora do DAS — a declaração mostra o impedimento pelo sublimite, ou o cadastro tem `reg_ap_trib_sn` 2 ou 3 —, a nota vai sem `pAliq` e o município aplica a dele. Fora do Simples, informe `pAliq` (a alíquota do município). Sem retenção, não mande `pAliq` (422 `ALIQUOTA_SEM_RETENCAO`). O percentual total de tributos do Simples (`pTotTribSN`) sai da alíquota do mês em uso da empresa; só mande para sobrepor. - **Alíquota do Simples (ME/EPP):** a da nota é a do mês, pela regra da retenção (Resolução CGSN 140/2018, art. 27): a faixa vem da receita bruta dos 12 meses que a lei manda contar (os que antecedem o mês anterior ao da nota — também de 2027 em diante, quando passa a valer a tabela da Resolução CGSN 190/2026; da declaração de janeiro de 2027 em diante, a declaração de um mês só confere aquele mesmo mês, já fechado, sem mudar a alíquota em vigor), lida das declarações PGDAS-D da empresa. Ela é fixada no dia 1º, e a do mês seguinte é calculada no dia 21, quando a declaração do mês anterior já foi transmitida. Só muda no meio do mês em três casos, com aviso ao dono e a quem cuida da empresa por outra conta (operador e contabilidade) — o da correção pela declaração sempre; os outros dois, salvo se "Alíquota do mês e conferências" estiver desligado nas Notificações de quem recebe: quando ela era estimada (faltava uma declaração) e a declaração chega; quando a do mês ainda não tinha saído (as notas usavam a do mês anterior) e a declaração chega; ou quando a conta por uma declaração dá outra alíquota — aí muda na hora, e o aviso traz as notas com retenção afetadas. `GET /companies/{id}/aliquotas` mostra a alíquota em vigor com a conta, a próxima e a última conferência. No regime de caixa, cada declaração traz os dois números do mês — `rpa_competencia` (o faturado, que forma a RBT12 e a alíquota) e `rpa_caixa` (o recebido, base do DAS) — em `GET /companies/{id}/pgdas/declaracoes` e nas `declaracoes` do dossiê; a conferência da receita compara as notas com o faturado e traz o recebido ao lado (`conferencia.receita.rpa_caixa`). Se o seu sistema manda `pTotTribSN` ou `pAliq` diferente da calculada — nem a do mês da prestação, nem a em uso (mais de 0,01 ponto) —, a nota sai como veio e o dono recebe um aviso por mês. Empresa ME/EPP sem alíquota nenhuma (nem pelo PGDAS-D, nem confirmada) recebe 422 `ALIQUOTA_NAO_CONFIRMADA`; com a alíquota de um mês anterior ainda gravada (a do mês não saiu), a nota sai com ela no total (`pTotTribSN`) — a retida sem `pAliq`, não: o ISS de outro mês não vai à nota (veja a Tributação, acima). O MEI não tem alíquota efetiva: a nota dele sai sem `pTotTribSN` (vai `indTotTrib` 0 — o Sistema Nacional recusa o percentual para o MEI, E0710) e sem ISS retido (E0583); mandar um ou outro volta 422 `MEI_NAO_INFORMA_PTOTTRIBSN` ou `MEI_NAO_TEM_RETENCAO`. - **Tomador:** opcional. `tipo` CNPJ, CPF, NIF (estrangeiro com identificação) ou naoNIF; `documento` sem pontuação (o CPF com 11 números; o CNPJ com 14 caracteres, que podem ter letras nas 12 primeiras posições); endereço obrigatório para alguns serviços (a validação em teste avisa). Tomadores salvos em `POST /tomadores` podem ser reaproveitados, e `GET /tomadores/{documento}/sugestao` devolve o que a última nota daquele cliente usou. - **Local da prestação:** para os serviços em que o ISS é devido onde o serviço acontece (construção, eventos, limpeza etc.), mande `servico.cMunPrestacao` com o código IBGE do município; `GET /consultas/municipio?q=&uf=` acha o código pelo nome e `GET /municipios/{cmun}` diz se o município já aderiu ao Sistema Nacional. - **Quem preenche o resto:** série, regime tributário, a alíquota do Simples do mês e a inscrição municipal vêm do cadastro da empresa; o número da nota é dado pelo gov.br e volta em `numero`. ## Documentos e entregas - **DANFSE:** `GET /nfse/{id}/pdf` (binário `application/pdf`). Nota de teste sai marcada como rascunho; nota cancelada sai com a marca de cancelamento. - **XML:** `GET /nfse/{id}/xml` é o XML da NFS-e autorizado pelo gov.br. - **E-mail ao cliente:** `POST /nfse/{id}/enviar-email` manda o PDF e o XML; sem `para`, vai para o e-mail do tomador cadastrado. O envio fica registrado na trilha da nota. - **WhatsApp** é canal do próprio GereNota: os avisos chegam lá a quem os recebe — o dono da conta, as pessoas escolhidas no bloco Avisos de cada automação e, numa empresa compartilhada, quem tem acesso a ela pelo papel —, cada um com as Notificações da própria conta; não há envio por API para números arbitrários. - **Lote para o contador:** `POST /exports` gera um ZIP por período. É assíncrono: a resposta 202 traz o `id`, a montagem entra numa fila justa entre as contas, e você consulta `GET /exports/{id}` até `status: "concluido"`. O download (`GET /exports/{id}/download`) responde **302** para um link temporário do arquivo: siga o redirecionamento (`curl -L -o pacote.zip`) e, para baixar de novo, chame a rota de novo. A faixa é a mesma da listagem: `periodo_por` (`competencia`, `emissao` ou `evento`) com `de`/`ate`. Dentro: `relatorio.html` (o relatório do período para ler e imprimir — cabeçalho com a empresa, totais, fechamento por competência e uma linha por nota, cada uma com link para os arquivos do próprio pacote; a soma é só das ativas), `relatorio.csv`, as notas ATIVAS na raiz de `xml/` e `pdf/`, canceladas e substituídas em `xml/canceladas/` e `xml/substituidas/`, e `eventos/` com o XML de cada cancelamento ou substituição — quem importa `xml/` sem recursão recebe só o que vale. Os arquivos levam a data de emissão (Brasília) no nome, e o `relatorio.csv` é do contador, pronto para o Excel em português: cabeçalhos em português, códigos por extenso (situação, tributação e retenção do ISS, tributos aproximados), o ISS retido em reais (o valor apurado na nota, que é o que se soma na planilha), competência `dd/mm/aaaa` e as outras datas `dd/mm/aaaa hh:mm` em Brasília, vírgula decimal, texto sem quebras de linha, a nota que substituiu pelo número, e chave, CPF/CNPJ e código do serviço como texto por fórmula (`="…"`, para o Excel não perder dígitos) — para máquina, use o JSON (nomes técnicos, UTC, ponto decimal). `GET /reports/nfse` devolve o relatório do período na hora; com `formato=csv`, o CSV vem completo, em streaming (o `limite` vale só para a lista do JSON). - **Pacote grande nunca é cortado:** acima de 2.000 notas (1.000 quando os PDFs vão junto) o pacote sai em `volumes` — um por mês, no eixo do recorte (competência, emissão ou evento), e um mês grande em partes, na ordem de numeração. O primeiro item é o resumo: `relatorio.html` do período inteiro, com a tabela dos volumes e a regra da divisão numa frase, e o `relatorio.csv` completo; cada volume traz a sua `listagem.html`, `listagem.csv`, `xml/`, `pdf/` e `eventos/`. Baixe com `download?volume=resumo`, `1`, `2`, … Quem pediu recebe o e-mail com o relatório anexo e os arquivos por links que valem 30 dias, na própria conta (numa empresa compartilhada, a pessoa com acesso; por chave de API, quem criou a chave), se o aviso "Exportação pronta" estiver ligado nas Notificações dela — e, se a exportação falhar, o aviso de que falhou. Para saber **antes** o que vai sair, `GET /nfse/agregado` com o mesmo recorte traz `exportacao`: notas por volume, quantos arquivos, a estimativa em segundos e a contagem mês a mês. - **O que mudou desde a última sincronização:** `GET /nfse/eventos?desde=` lista os cancelamentos e substituições da conta, uma linha por mudança, com a situação atual da nota e se o XML do evento está disponível. O cursor é o campo `cursor` (quando o evento entrou na plataforma), NÃO a hora oficial `dh`: o cancelamento feito pela prefeitura chega na importação do dia seguinte com data anterior, e quem paginasse pela hora oficial nunca o receberia. Com `desde`, a lista vem na ordem de entrada; sem ele, na ordem cronológica oficial. Não precisa guardar cópia das situações para descobrir o que foi cancelado depois de enviado ao contador. Vale qualquer via: o que foi feito aqui, no portal do gov.br ou pela prefeitura (cancelamento deferido por análise fiscal e cancelamento por ofício). Cada evento traz `descricao` com o nome oficial e `muda_situacao`; `todos=true` inclui os que só registram histórico, como a rejeição do tomador e o bloqueio por ofício. A pasta `eventos/` do ZIP continua só com a prova das mudanças de situação. - **Situação com data e prova (16/set):** a nota diz *quando* saiu de ativa — `cancelada_em` e `substituida_em`, na hora oficial do evento (o `dhEvento` do gov.br) — e `substituida_por` aponta a nota que entrou no lugar, também nas importadas. `GET /nfse/{id}/eventos/{evento_id}/xml` baixa o XML do evento. Importante: o XML da nota continua sendo o autorizado, idêntico depois do cancelamento; um sistema contábil que só recebe a nota a importa como válida — mande o evento junto. Para achar o que mudou num período use `periodo_por=evento` (`status=cancelada&periodo_por=evento&de=2026-08&ate=2026-08` = cancelado em agosto), com `ordem=evento_desc` para o mais recente primeiro; cada nota fora de ativa traz `evento_situacao` (qual evento a tirou de ativa) e, na substituída, `substituida_por_numero`. As bordas de `de`/`ate` valem no horário de Brasília. `GET /nfse/agregado` traz `por_status`; o faturamento válido do período é `por_status.ativa`. ## Automações - Uma automação emite sozinha, no dia programado, uma nota com empresa, tomador, serviço e valor fixos (ou com valor variável, que pede confirmação ao dono antes de sair). É o caminho para mensalidades e contratos. - `POST /automations/recorrente` cria uma: tomador (documento), dia do mês (1 a 28), valor (ou sem valor, para confirmar a cada rodada) e, se quiser, o código de serviço e a descrição; sem eles, usa o que a última nota daquele cliente usou — numa conta com mais de uma empresa, mande o `company_id` (na query) para a nota-base ser a daquela empresa. `GET /automations` lista as da conta; `PATCH /automations/{id}` edita e pausa (`"ativo": false`) ou reativa; `DELETE` exclui (o histórico de execuções vai junto; as notas já emitidas ficam); `POST /automations/{id}/run` roda agora, fora da agenda, e emite de verdade; `GET /automations/{id}/runs` traz o histórico com o desfecho de cada rodada e um motivo legível quando falhou. - O **relatório mensal por e-mail** é a outra automação. Agenda-se no painel (Automações → Enviar um relatório por e-mail) ou pelo conector MCP (`nfse_relatorio_agendado`); as rotas que o painel usa — `POST /report-definitions` guarda o recorte (`periodo` = `mes_fechado` ou `mes_atual`, `periodo_por` = `competencia`, `emissao` ou `evento`, `status`, `company_id`, `destinos` e `incluir_zip`) e `POST /automations` agenda o dia — ainda não entram na referência abaixo. No dia, às 08:00 (Brasília), o pacote entra na fila e o e-mail sai quando ele fica pronto: o relatório em HTML (para ler) e em CSV (para o Excel) anexos, com o nome do arquivo trazendo a empresa e o mês; com `incluir_zip`, vai o mesmo pacote da exportação, com os XMLs por situação e a prova de cada cancelamento — anexo até 8 MB, por link de 30 dias acima disso. Um mês grande não é cortado: sai em partes, na ordem de numeração, e o resumo explica a divisão. O e-mail vai para os destinos da definição sempre: é a entrega, não um aviso — nem os avisos da automação nem a preferência "Relatório mensal" da conta o calam (a preferência governa só o cartão do WhatsApp; a falha do relatório é aviso do tipo "Falha de automação"). Em `runs`, a execução nasce `em_fila` e, na entrega, vira o que o provedor de e-mail aceitou: `relatorio_enviado` (todos os destinos), `relatorio_parcial` (parte deles — `erro_msg` diz quem ficou sem) ou `relatorio_nao_entregue` (nenhum: conta como falha e tenta de novo em 1 hora, inclusive no mesmo dia); a mesma definição não gera dois relatórios automáticos no mesmo dia (`repetida`), e `POST /automations/{id}/run` repete de propósito. `periodo_por: "evento"` manda o que foi CANCELADO ou SUBSTITUÍDO no mês — o recorte que o contador usa para refazer o fechamento. Notas de teste nunca entram. - Automações pausadas continuam contando no limite do plano; para liberar vaga, exclua. - Os avisos de cada rodada (emitida, falhou, precisa de valor) chegam por e-mail e WhatsApp a quem o bloco Avisos da automação escolheu — quem criou, as pessoas da conta e, numa empresa compartilhada, o operador que a acessa por outra conta; a integração acompanha por `runs`. - Numa empresa do Simples (ME/EPP) ainda sem alíquota nenhuma, a rodada de emissão sai `pulada`, com `erro_codigo` `ALIQUOTA_NAO_CONFIRMADA`: tenta de novo no dia seguinte, avisa o dono e não conta como falha nem pausa a automação. ## Emitir em lote - Um lote é uma planilha (ou as linhas em JSON) que vira notas propostas, uma por linha. Nada é emitido até a confirmação: a plataforma propõe, e quem emite confere e confirma. A empresa vai no caminho (`/companies/{company_id}/lotes`), e a empresa compartilhada com você funciona igual. - `POST /companies/{company_id}/lotes` recebe a planilha (`multipart/form-data`, campo `file`: XLSX ou CSV, até 8 MB). A leitura é em segundo plano: em alguns segundos o lote passa de `lendo` a `em_revisao`. O modelo do GereNota (baixe no painel, em Emitir nota → Em lote) é lido sempre na hora; a planilha de um formato que a plataforma ainda não conhece passa por `aprendendo`, e a conferência da leitura ("Entendi assim") é feita no painel. Sem arquivo, `POST /companies/{company_id}/lotes/linhas` recebe até 200 linhas com os mesmos campos da planilha (`documento` e `valor` obrigatórios; `nome` obrigatório no CPF; `data`, `descricao`, `codigo_servico`, `email`, `endereco` e `cep` opcionais). - `GET /companies/{company_id}/lotes/{lote_id}/itens` traz as linhas: a nota proposta, a situação (`proposto` = pronta) e o que falta em `pendencias`. Ficam de fora por padrão a linha repetida no arquivo (`repetida`) e a que já tem nota do mesmo cliente, valor e mês (`ja_tem_nota`, contando: três sessões iguais no mês com uma nota emitida marcam só uma linha). O e-mail da linha vai na nota e é para onde ela é enviada; sem ele, vale o do cadastro do cliente. O código do serviço vem da planilha ou das notas anteriores do cliente; sem nenhum dos dois, a linha precisa de dados. - `POST /companies/{company_id}/lotes/{lote_id}/confirmar` põe as linhas prontas na fila, com a data da nota fixada na confirmação (a data de cada linha, por padrão). A fila emite uma nota por vez pelo Sistema Nacional e manda o PDF e o XML ao e-mail do cliente; `GET /companies/{company_id}/lotes/{lote_id}` é o andamento (`emitindo` → `concluido`). A linha recusada traz o motivo em `recusa`; a resposta que não veio do Sistema Nacional é conferida com o mesmo número da DPS, e a nota nunca sai em dobro. O cliente novo entra no cadastro da conta na confirmação. - Confirmam o dono, o operador e a contabilidade com "Pode emitir notas"; a contabilidade sem a opção monta o lote e o envia para quem pode emitir, pelo painel. O plano Free confirma dentro da cota do mês (402 `COTA_DO_LOTE` com `erros[0].restam`). - `POST /companies/{company_id}/lotes/{lote_id}/cancelar` descarta o lote antes da confirmação e, depois dela, tira da fila só o que ainda não saiu: as notas emitidas continuam valendo e se cancelam uma a uma. - O arquivo fica guardado até o lote terminar, por no máximo 7 dias; depois, ficam as notas e a ligação de cada uma com a linha (`lote` em `GET /nfse/{nfse_id}`, e `origem=lote` em `GET /nfse`). ## Limites, cotas e custos - **Por minuto:** buscas de CNPJ/CPF, 10 por minuto por conta, venham de onde vierem; o envio da nota por e-mail (`POST /nfse/{id}/enviar-email`), 10 por minuto por conta; demais rotas sem teto fixo, mas uso abusivo recebe 429 `RATE_LIMIT`. Repita depois de alguns segundos. - **Por dia** (o dia de Brasília, que renova à 0h — o instante que vem em `volta_em`): consultas em tempo real à Receita — Plano Free 3, Plano Individual, Plano Multi e Plano Cortesia 10, Plano Escritório 30 por conta (429 `LIMITE_CONSULTAS_DIA`); o teto técnico de 300 buscas de CNPJ por conta, igual em todos os planos, contra uso automatizado — conta toda busca, do cache ou não, inclusive a do CNPJ que não existe; os links de cadastro ficam fora (429 `LIMITE_CONSULTAS_DIA`, sem `upgrade`); o envio da nota por e-mail, 100 por conta (429 `LIMITE_EMAILS_DO_DIA`). - **Por mês (plano):** consultas em tempo real à Receita — o CPF e o CNPJ que ainda não está no cadastro mensal: Plano Free 5, Plano Individual 20, Plano Multi e Plano Cortesia 60, Plano Escritório 200 —, somando todas as portas da conta: esta API, o painel, os links de cadastro e o WhatsApp; notas — Plano Free 5, planos pagos sem teto; empresas, automações e acessos conforme o plano. O mês é o de Brasília: a contagem recomeça à 0h do dia 1º no horário de Brasília (a nota das 22h do último dia ainda conta no mês dela), e a cota esgotada — 402 `COTA_ESGOTADA` nas notas, 402 `COTA_CONSULTAS_ESGOTADA` nas consultas — traz esse instante em `volta_em`. `GET /me` mostra uso e teto de cada um (e, ao dono da conta, o `upgrade` do limite já no teto); estourar dá 402 com o `code` e a saída no `hint`. - **Links de cadastro** — a página em que um terceiro manda os dados: o link de empresa (o cadastro completo da empresa emissora, que consulta a Receita) e o de cliente (o tomador); o link só do certificado fica fora destes tetos. São criados no painel, no conector MCP (`nfse_link_empresa`, `nfse_link_tomador`) e no WhatsApp. Por dia, os dois tipos somados: Plano Free 3, planos pagos 10 (429 `LIMITE_DE_LINKS_DO_DIA`, com `volta_em`). Abertos ao mesmo tempo: os de cliente, Plano Free 3 e planos pagos 10; os de empresa, Plano Free 1 e planos pagos até 5, nunca mais que as vagas de empresa livres no plano (409 `LINKS_ABERTOS_NO_TETO`, sem `volta_em`: a vaga volta quando um link é usado, cancelado ou vence). - **O plano que resolve:** quando um plano maior resolve o limite batido, o `hint` o nomeia, sem preço, e o dono da conta recebe também o `upgrade`, com o preço e o link para assinar (veja Erros). É o plano mais barato, acima do atual, em que cabem o uso de hoje e o que o pedido traria (num convite para várias empresas, todos os acessos dele) e em que a conta inteira cabe — as empresas, as automações e os acessos que ela já tem —, para a assinatura não ser recusada: - empresas, automações e acessos (`LIMITE_DO_PLANO`): pelo teto — as empresas do Plano Free e do Plano Individual (1 em cada) resolvem no Plano Multi; - notas (`COTA_ESGOTADA`, a cota do Plano Free): o Plano Individual, sem teto de notas; - relatórios automáticos e API/MCP (`RECURSO_FORA_DO_PLANO`): o Plano Individual, o primeiro que os inclui; - consultas à Receita, do mês e do dia, e links de cadastro: só no Plano Free — o Plano Individual, ou o Plano Multi no link de empresa, que acompanha as vagas de empresa; nos planos pagos esses tetos são de segurança, sem plano que resolva; - o Plano Escritório no teto e os planos fora da vitrine (como o Plano Cortesia): nenhum — o `hint` dá o caminho sem plano e o contato, faleaqui@gerenota.com.br. - **O que custa dinheiro ao GereNota (e por isso tem cota):** a consulta em tempo real à Receita — o CPF e o CNPJ que ainda não está no cadastro mensal (os Dados Abertos do CNPJ, que a Receita publica uma vez por mês) —, pela rota de consulta e também quando `POST /tomadores` ou a emissão recebem o cliente só com o CNPJ (com o nome no corpo, nada é consultado). A busca de CNPJ pelo cadastro mensal não custa e não tem cota (a resposta traz `fonte: "gerecnpj"` e o `mes_referencia`); só o teto técnico do dia vale para ela. O mesmo CNPJ no mesmo mês do cadastro, ou consultado em tempo real nos últimos 7 dias, sai do cache sem gastar (a resposta traz `de_cache: true`); o CPF, só com a mesma data de nascimento e pela mesma conta, nas últimas 24 horas. Quando as consultas em tempo real da plataforma param até a virada do dia, a resposta é 503 `CONSULTAS_PAUSADAS` — siga com o cadastro manual. - **Declarações PGDAS-D:** cada consulta ao Integra Contador custa R$ 0,24 ao GereNota e não entra na cota do plano. A plataforma busca sozinha, em segundo plano, o que falta: as 13 declarações da autorização chegam em poucos minutos, e depois entra uma por mês. Pela API, `POST /companies/{id}/pgdas/sync` com `pa` e `forcar=true` consulta um período específico, com teto de 3 consultas pagas por empresa e dia (429 `TETO_DIARIO_PGDAS`, com `volta_em`); sem `forcar`, o que já está no histórico volta sem custo. Quando as consultas pagas da plataforma param até a virada do dia, a resposta é 503 `PGDAS_PAUSADO` — a alíquota do mês não muda. - **Exportações:** sem teto de notas. Acima de 2.000 notas (1.000 com os PDFs) o pacote sai em volumes; os links do e-mail valem 30 dias. - **Tamanho:** upload do certificado A1 até 8 MB (um A1 tem poucos KB); corpo de requisição até 8 MB. - **Paginação:** listagens aceitam `skip` e `limit` (padrão 50, máximo informado em cada rota) e devolvem o total do filtro quando aplicável. ## Versão e changelog - A API é a **v1** (`/api/v1`). Campos novos podem aparecer a qualquer momento nas respostas: ignore o que não conhece. Campos e rotas existentes não mudam de forma nem de significado dentro da v1; uma mudança incompatível só sai como v2, com as duas convivendo por um período anunciado. - Este guia é gerado do código a cada release e verificado no CI; se algo aqui diverge do comportamento real, é um defeito nosso: escreva para faleaqui@gerenota.com.br. - **Changelog** - **Mudanças na superfície, geradas do git** — a partir de 24/09/2026, cada operação que entra ou sai, os parâmetros de cada uma e os campos de primeiro nível dos esquemas aparecem aqui, pelo dia em que mudaram (tirado do histórico de `docs/api/superficie.json`); campo dentro de objeto livre e valor novo de uma lista de valores ficam nas entradas escritas à mão: - 13/10/2026 — campos novos em `CompanyOut`: `pendencia_da_ativacao`; esquemas novos: `CompetenciaPropostaOut`, `LocalPrestacaoOut`; campos novos em `NfseDetalheOut`: `local_prestacao`; campos novos em `SugestaoTomadorOut`: `competencia_proposta`. - 12/10/2026 — campos novos em `DeclaracaoPgdasDetalheOut`: `cpp_declarada`, `efetiva_motivo`, `falhas_leitura`, `fator_r_declarado`, `fator_r_motivo`, `folhas_mensais`, `por_anexo`, `total_geral`; campos novos em `DeclaracaoPgdasOut`: `cpp_declarada`, `efetiva_motivo`, `falhas_leitura`, `fator_r_declarado`, `fator_r_motivo`; campos novos em `gerenota_api__integra_contador__AtividadeOut`: `anexo`, `c_atv_sn`, `classe`, `exterior`, `iss_devido_a`, `retencao_iss`, `tributos`; operações novas: `POST /api/v1/companies/{company_id}/lotes/{lote_id}/entregar`; esquemas novos: `EmailDoCliente`, `EntregaRecusada`, `EntregarIn`, `EntregarOut`; campos novos em `EmailDoCliente`: `itens`. - 11/10/2026 — operações novas: `POST /api/v1/automations/{automation_id}/pular`; esquemas novos: `AutomacaoPuladaOut`, `PularIn`; esquemas novos: `RodarIn`; campos novos em `MeOut`: `plano_escritorio`. - 10/10/2026 — operações novas: `GET /api/v1/companies/{company_id}/lotes/{lote_id}/recibo.csv`, `GET /api/v1/lotes/modelo`, `PATCH /api/v1/companies/{company_id}/lotes/{lote_id}/itens/{item_id}`, `POST /api/v1/companies/{company_id}/lotes/{lote_id}/continuar`, `POST /api/v1/companies/{company_id}/lotes/{lote_id}/itens/acao`, `POST /api/v1/companies/{company_id}/lotes/{lote_id}/pausar`, `POST /api/v1/companies/{company_id}/lotes/{lote_id}/validar`, `PUT /api/v1/companies/{company_id}/lotes/{lote_id}/data`; esquemas novos: `AcaoEmGrupoIn`, `AcaoEmGrupoOut`, `DataIn`, `EditarItemIn`, `EnderecoLinhaIn`, `ValidarIn`; operações novas: `POST /api/v1/companies/{company_id}/certificado/pedidos`; esquemas novos: `PedidoIn`, `PedidoOut`. - 08/10/2026 — operações novas: `GET /api/v1/companies/{company_id}/lotes`, `GET /api/v1/companies/{company_id}/lotes/{lote_id}`, `GET /api/v1/companies/{company_id}/lotes/{lote_id}/itens`, `POST /api/v1/companies/{company_id}/lotes`, `POST /api/v1/companies/{company_id}/lotes/linhas`, `POST /api/v1/companies/{company_id}/lotes/{lote_id}/cancelar`, `POST /api/v1/companies/{company_id}/lotes/{lote_id}/confirmar`; esquemas novos: `ArquivoDoLoteOut`, `ContagensDoLoteOut`, `ItemDoLoteOut`, `ItensDoLoteOut`, `LinhaIn`, `ListaDeLotesOut`, `LoteDaNotaOut`, `LoteDeLinhasIn`, `LoteOut`, `lotes_post`; campos novos em `MinhaEmpresaOut`: `pode_emitir`; campos novos em `NfseDetalheOut`: `lote`; campos novos em `NfseResumoOut`: `lote`. - 07/10/2026 — campos novos em `ConsultaCnpjOut`: `data_extracao`, `mes_referencia`; campos novos em `ReceitaOut`: `atualizando`, `data_extracao`, `fonte`, `mes_referencia`; campos novos em `RegimeSugeridoOut`: `exclusao_marcada`, `fonte`; campos novos em `SocioOut`: `menor`; `GET /api/v1/consultas/cnpj/{documento}` ganhou o parâmetro `confirmar`; esquemas novos: `NaoAchadoNaReceitaOut`, `PendenciaDaReceitaOut`, `ReceitaDoCampoOut`, `SituacaoNaReceitaOut`, `SugestaoDaReceitaOut`; campos novos em `AutomacaoExecucaoOut`: `observacao`; campos novos em `AutomacaoRunOut`: `observacao`; campos novos em `CompanyOut`: `receita_aviso_regime`; campos novos em `SugestaoTomadorOut`: `situacao_na_receita`; campos novos em `TomadorCriadoOut`: `receita_campos`, `receita_mes`, `receita_nao_achado`, `receita_pendente`, `receita_situacao`, `receita_sugestoes`; campos novos em `TomadorDaBuscaOut`: `receita_campos`, `receita_mes`, `receita_nao_achado`, `receita_pendente`, `receita_situacao`, `receita_sugestoes`; campos novos em `TomadorOut`: `receita_campos`, `receita_mes`, `receita_nao_achado`, `receita_pendente`, `receita_situacao`, `receita_sugestoes`. - 06/10/2026 — esquemas novos: `AvisoOut`; campos novos em `CodigoServicoOut`: `tomador_pj_responsavel`; campos novos em `NfseOut`: `avisos`; campos novos em `SugestaoCodigoOut`: `tomador_pj_responsavel`. - 02/10/2026 — esquemas novos: `TomadorDaBuscaOut`; `POST /api/v1/automations/recorrente` ganhou o parâmetro `company_id`; campos novos em `TomadorDaBuscaOut`: `de_outras_empresas`. - 01/10/2026 — esquemas novos: `PlanoQueResolveOut`, `UpgradeOut`; campos novos em `ErroOut`: `upgrade`, `volta_em`; esquemas novos: `CotaDeNotasOut`; campos novos em `PlanoOut`: `upgrade_api_mcp`, `upgrade_relatorios`; campos novos em `UsoTetoOut`: `upgrade`. - 30/09/2026 — esquemas novos: `ReceitaDoCadastroOut`, `TomadorCriadoOut`; campos novos em `SugestaoTomadorOut`: `cadastrado`. - 29/09/2026 — campos novos em `AutomacaoExecucaoOut`: `erro_msg`; campos novos em `DossieAliquotasOut`: `receita_abaixo`, `receita_por_mes`; campos novos em `RegimeTributario`: `receita_abaixo`. - 28/09/2026 — operações novas: `GET /api/v1/exports/{export_id}/link`; esquemas novos: `LinkDoPacoteOut`; `GET /api/v1/consultas/cnpj/{documento}` ganhou o parâmetro `fresco`; campos novos em `CompanyOut`: `emissao_parada`, `fora_do_simples`; campos novos em `MinhaEmpresaOut`: `emissao_parada`; campos novos em `RegimeSugeridoOut`: `nao_optante_explicito`. - 27/09/2026 — `GET /api/v1/nfse` ganhou o parâmetro `com_problema`; `GET /api/v1/nfse/agregado` ganhou o parâmetro `com_problema`; esquemas novos: `AlertaNotaOut`; campos novos em `NfseAgregadoOut`: `com_problema`; campos novos em `NfseDetalheOut`: `alertas`, `fora_depois_da_entrada`; campos novos em `NfseResumoOut`: `alertas`, `fora_depois_da_entrada`, `origem`. - 26/09/2026 — `POST /api/v1/nfse/{nfse_id}/cancelar` ganhou o parâmetro `Idempotency-Key`. - 24/09/2026 — campos novos em `MinhaEmpresaOut`: `aliquota_iss_fora_do_das`. - 2026-10-13 — **O que falta na empresa pendente**: `GET /companies` e `GET /companies/{company_id}/status` trazem `pendencia_da_ativacao` — por que a última validação (`POST /companies/{company_id}/validate`, o link de cadastro ou a saída da lista de espera) não ativou a empresa: `codigo` (o do erro da validação, como `INSCRICAO_MUNICIPAL_OBRIGATORIA`, `CERTIFICADO_AUSENTE` ou `VALIDACAO_REPROVADA`), `mensagem` e `em`, mais `cidade` (Cidade/UF) na inscrição municipal e `checks` (`cnpj_confere`, `dentro_da_validade`, `handshake_govbr`) na validação reprovada. Some quando a empresa é ativada — e quando `PATCH /companies/{company_id}` troca a cidade ou o regime (o motivo era da cidade de antes). Para validar de novo, `POST /companies/{company_id}/validate` usa o certificado já enviado. A empresa inativa não guarda a pendência e continua inativa depois de validada (`status` `inativa`, com o certificado validado): ela volta a emitir pelo `POST /companies/{company_id}/reativar`, que confere o limite do plano. `inscricao_municipal` aceita até 15 caracteres (o limite do leiaute da DPS): acima disso, 422 em `POST /companies` e no `PATCH`. - 2026-10-13 — **A recusa do convênio na automação e no lote**: a partir de 1º/11/2026, a recusa por `E0016`, `E0037`, `E0038` ou `E0039` a uma ME/EPP de cidade sem adesão (a mesma régua da mensagem explicada) deixa de contar como falha da automação: a execução sai `pulada`, com o `erro_codigo` da regra, e a automação tenta de novo no dia seguinte, sem pausar. No lote, a primeira dessas recusas pausa o lote (`estado` `pausado`; `pausado.motivo` com `codigo`, `mensagem` e `convenio`: `regra`, `cidade` e `ate`, o dia e o mês — `DD/MM`, horário de Brasília — em que a guarda de 7 dias do arquivo cancela o que falta), e a linha espera em vez de virar `recusada`; `POST /companies/{company_id}/lotes/{lote_id}/continuar` tenta de novo. A validação no ambiente de teste para do mesmo jeito. **A nota que a automação não emitiu** (a recusa do convênio, a cota, a falta da alíquota ou uma falha) é tentada de novo com a competência da data agendada, mesmo depois da virada do mês, e a agenda segue a partir dessa data: a nota do mês seguinte sai no dia dela, sem repetir a competência. Com uma nota esperando, `POST /automations/{automation_id}/pular` pula essa nota, e a `pulada` da resposta é a data dela. - 2026-10-13 — **O lote com mais de 7 dias**: `GET /companies/{company_id}/lotes/{lote_id}/itens` volta a responder para o lote que passou da guarda de 7 dias do arquivo (respondia 500). Depois da guarda, a linha guarda só a ligação com a nota: a emitida traz em `tomador` o nome e o documento da nota, e do `email` fica a situação da entrega (`status`, `de`, `suprimido`), sem o endereço. `POST /companies/{company_id}/lotes/{lote_id}/entregar` passa a valer também depois da guarda: o cliente de cada linha vem da nota, e o endereço não fica na linha (com `guardar_no_cadastro`, ele vai ao cadastro do cliente; o endereço que voltou vem do alerta da nota). Depois da guarda, `POST …/itens/{item_id}/conferir` responde 410 `LOTE_EXPIRADO` (a linha não tem mais a nota), e o `recibo.csv` traz o cliente e a data pela nota. As respostas do lote (`GET /companies/{company_id}/lotes` e `GET …/lotes/{lote_id}`) deixam de trazer `conversa`, que tinha o número do WhatsApp de quem mandou a planilha. - 2026-10-12 — **A lista de espera da ME/EPP termina em 1º/11/2026** (Resolução CGSN 191/2026): a partir dessa data, 0h de Brasília, `POST /companies` e o link de cadastro não põem mais a ME ou a EPP em `waitlist` pelo município. A que estava na lista sai dela e é validada com o certificado já enviado (passando, fica `ativa`; senão, `pendente`), e `validate` deixa de devolver 409 `MUNICIPIO_NAO_ADERENTE`. A recusa por `E0016`, `E0037`, `E0038` ou `E0039` a uma ME/EPP de cidade sem adesão, com competência a partir de 1º/11/2026, volta com o `code` da regra e a mensagem explicada. Até 31/10/2026, nada muda. - 2026-10-12 — **O e-mail do cliente informado depois da emissão**: `POST /companies/{company_id}/lotes/{lote_id}/entregar` manda, pela fila do lote, o PDF e o XML das notas emitidas que ficaram sem e-mail (`email.status = "sem_email"`) ao e-mail informado de cada cliente — e corrige o e-mail que falhou ou voltou. Valem as travas da revisão (`recusados`); com `guardar_no_cadastro`, o e-mail vai ao cadastro do cliente. Acompanhe em `email.status` (`a_enviar`, `enviando`, `enviado`). - 2026-10-12 — **O lote confere o "já tem nota" de novo na confirmação**: `POST /companies/{company_id}/lotes/{lote_id}/confirmar` marca como `ja_tem_nota` (fora do lote) a linha que ganhou nota depois da leitura do arquivo — a mesma nota emitida por outro lote, pelo painel, pela API ou por uma automação — e devolve 409 `LOTE_COM_NOTA_NOVA`, com as linhas em `erros[0].linhas`: o lote fica na revisão para conferir e confirmar de novo. Na fila, a linha igual (cliente, valor, data e descrição) que já saiu por outro lote vira `ja_tem_nota` e não sai. - 2026-10-08 — **O cadastro mensal da Receita**: a busca de CNPJ (`GET /consultas/cnpj/{documento}`, e o cliente só com o CNPJ em `POST /tomadores` e na emissão) passa a sair do cadastro mensal da Receita — os Dados Abertos do CNPJ, que a Receita publica uma vez por mês e que podem estar algumas semanas atrás do cadastro do dia — e **não gasta mais a cota do plano**: a resposta traz `fonte: "gerecnpj"`, `mes_referencia` e `data_extracao` (também dentro de `receita`, com `receita.fonte` e `receita.atualizando`). O CNPJ que ainda não está no cadastro do mês (aberto depois da extração), o `fresco=true` e o CPF vão à consulta em tempo real (`fonte: "serpro"`), que segue com a cota do mês e o limite do dia do plano; a que vai em tempo real porque o cadastro mensal não respondeu fica por conta da plataforma. Teto técnico novo: 300 buscas de CNPJ por dia por conta, igual em todos os planos, contando também as que saem do cache e o CNPJ que não existe (429 `LIMITE_CONSULTAS_DIA`, sem `upgrade`). O cache passa a ser por fonte: o mesmo mês do cadastro mensal (até 35 dias) ou 7 dias da consulta em tempo real, de qualquer conta. Na empresa compartilhada, `leitor` e `contabilidade` buscam pelo cadastro mensal; a consulta em tempo real continua do `operador`. No `regime_sugerido`, o período do Simples vale pela data: o fim no futuro é a saída já marcada — `exclusao_marcada`, e a empresa segue optante (antes saía como não optante) —, com `fonte`; no cadastro mensal, `periodos_simples` traz só o período mais recente, e ele nunca marca `nao_optante_explicito`: a recusa do cadastro de não optante e a parada da emissão continuam exigindo a consulta em tempo real. O sócio menor vem como "Sócio menor", sem nome nem representante (`menor: true`). `GET /companies` deixa de trazer o quadro societário em `receita.qsa`: fica a contagem, `receita.qsa_total` (os sócios são dado pessoal; a ficha da empresa no painel continua com eles). A conferência do município do MEI (422 `MUNICIPIO_DO_MEI_DIFERENTE_DO_CNPJ`) só barra com o bloco da Receita confirmado em tempo real. Com `completo=true&confirmar=true`, o "não optante" do cadastro mensal é confirmado em tempo real antes de voltar, por conta da plataforma — é o que o cadastro de uma empresa usa. **As fichas dos clientes acompanham a Receita:** em `GET /tomadores`, o cliente CNPJ comparado com o cadastro mensal ganha `receita_campos` (a origem de cada campo: `espelho`, que acompanha a Receita, ou `cliente`), `receita_sugestoes` (o que a Receita tem de diferente; o e-mail e o telefone só quando a ficha não tem), `receita_situacao` (o CNPJ baixado, inapto, suspenso ou nulo — só aviso), `receita_pendente`, `receita_nao_achado` e `receita_mes`; `GET /tomadores/{documento}/sugestao` ganha `situacao_na_receita`; `GET /companies` ganha `receita_aviso_regime` (a reconferência mensal viu a saída do Simples, a saída marcada ou o MEI que virou ME/EPP — só aviso; a emissão para quando a saída se confirma); e as execuções de automação (`GET /automations/{id}/runs` e o "rodar agora") ganham `observacao`, com o município do cliente que mudou pela Receita. Textos: `RATE_LIMIT` passa a "Muitas buscas seguidas; aguarde um minuto", o teto técnico do dia a "Limite de 300 buscas na Receita de hoje atingido", e as dicas de limite dizem quando ele volta — programe pelo `code`. - 2026-10-06 — **MEI, obras e eventos conforme o Anexo I**: a nota de empresa MEI sai sem `pTotTribSN` (vai `indTotTrib` 0) — o Sistema Nacional recusa o percentual para o MEI (E0710) — e, mandado, volta 422 `MEI_NAO_INFORMA_PTOTTRIBSN`; a retenção do ISS numa empresa MEI volta 422 `MEI_NAO_TEM_RETENCAO` (E0583); no cadastro do MEI, `regime.reg_esp_trib` fica `0` e `p_tot_trib_sn` e `p_aliq_iss` ficam nulos; e o MEI não entra mais na lista de espera (`status` `waitlist`) em município que não emite pelo Sistema Nacional — o MEI emite pelo Emissor Nacional em qualquer município. `SERVICO_EXIGE_DADOS_DA_OBRA` passa a valer também para 07.05.01, 07.05.02, 07.06.01, 07.06.02, 07.07.01, 07.08.01, 07.17.01, 14.14.03 e 14.14.04, e `SERVICO_EXIGE_DADOS_DO_EVENTO`, para o 12.13.01 (regras 340 e 357 do Anexo I). - 2026-10-01 — **O plano que resolve e quando o limite volta**: os erros de limite — `LIMITE_DO_PLANO`, `COTA_ESGOTADA`, `RECURSO_FORA_DO_PLANO` (também o 403 do conector MCP), `COTA_CONSULTAS_ESGOTADA`, `LIMITE_CONSULTAS_DIA`, `LIMITE_DE_LINKS_DO_DIA` e `LINKS_ABERTOS_NO_TETO` — ganham `volta_em`, o instante em UTC em que o limite volta sozinho (nas cotas do mês, a 0h de Brasília do dia 1º; nos tetos do dia, a 0h do dia seguinte), e `upgrade`, o plano que resolve, só para o dono da conta (nunca para a chave de API): `upgrade.plano` com `id`, `nome`, `rotulo` ("Plano Individual"), `preco_base` e `preco_anual` (em reais, como texto), `upgrade.limite_no_plano` (`null` = sem limite, ou recurso incluído) e `upgrade.link` (`…/billing?plano=…&motivo=…`, com o `motivo` de uma lista fechada: `empresas`, `automacoes`, `acessos`, `notas`, `consultas`, `consultas_dia`, `links`, `relatorios`, `api`). Os outros tetos do dia — `LIMITE_EMAILS_DO_DIA`, `LIMITE_RODAR_AGORA` e `TETO_DIARIO_PGDAS` — ganham só o `volta_em`. No `GET /me` do dono, o mesmo objeto em `plano.empresas.upgrade`, `plano.automacoes.upgrade`, `plano.acessos.upgrade` e `plano.notas.upgrade` (o limite já no teto: o plano em que o próximo item cabe) e em `plano.upgrade_relatorios` e `plano.upgrade_api_mcp` (o recurso que o plano não inclui). As mensagens e as dicas citam o plano como "Plano Free", "Plano Individual", "Plano Multi" e "Plano Escritório"; a dica nomeia o plano que resolve, sem preço (antes mandava "subir de plano" sem dizer qual), e as empresas do Plano Free e do Plano Individual resolvem no Plano Multi; o Plano Escritório no teto diz como falar com a gente. Programe pelo `code`, não pelo texto. **O mês das cotas vira à 0h de Brasília** — antes virava à 0h UTC, às 21h de Brasília do último dia, e a nota ou a consulta das 21h às 24h contava no mês seguinte: vale para a cota de notas, a de consultas e os `usadas` do `GET /me`. - 2026-09-28 — **Só Simples Nacional e MEI**: a GereNota passa a atender só empresas do Simples Nacional (ME/EPP) e MEI. `POST /companies` recusa o regime `1` (não optante) com 422 `EMPRESA_FORA_DO_SIMPLES`; a criação também recusa o CNPJ que a consulta completa à Receita da própria conta, nos últimos 7 dias, mostrou como não optante (`hint`: "Pelo cadastro na Receita, esta empresa não é optante do Simples."). A empresa que saiu do Simples — sabida pelo "Conferir na Receita" do painel ou pela recusa `E0160` do Sistema Nacional, que dispara a conferência — ganha `fora_do_simples` e `emissao_parada` em `GET /companies`, `GET /companies/{id}/status` e `GET /minhas-empresas`, e toda emissão por ela responde 422 `EMPRESA_FORA_DO_SIMPLES` ("A emissão está parada: a empresa saiu do Simples Nacional"); as automações dela saem `pulada` com esse código e tentam de novo no dia seguinte. MEI e ME/EPP: sem mudança. - 2026-09-28 — **CNPJ com letras** (o formato novo da Receita: letras A–Z nas 12 primeiras posições, os 2 últimos continuam números; ex.: `12.ABC.345/01DE-35`): todo campo de CNPJ — a empresa emissora, o tomador, a identidade de faturamento, as consultas e os caminhos com `{documento}` — aceita e devolve o CNPJ com letras, sem pontuação e em maiúsculas (minúscula vira maiúscula); a conta do dígito verificador é a da Receita, que vale também para o CNPJ só de números. As mensagens de erro passam a falar em caracteres: 422 com "CNPJ inválido: confira os 14 caracteres (letras só nas 12 primeiras posições)" ou "CNPJ inválido: os dois últimos dígitos não batem com o resto"; o documento do tomador na emissão, "precisa ter 11 dígitos (CPF) ou 14 caracteres (CNPJ)". A busca de tomadores (`q`) trata como documento o termo com letras e números juntos, sem espaço (`12.ABC`). **Série da nota:** de 1 a 49999 na criação e na alteração da empresa (422; de 50000 em diante a série é dos emissores do governo e o Sistema Nacional recusaria as notas). Nada muda para quem manda CNPJ só de números. - 2026-09-28 — **Tetos das consultas pagas e dos envios**: as consultas de CNPJ e CPF na Receita ganham teto por dia (Plano Free 3; Plano Individual, Plano Multi e Plano Cortesia 10; Plano Escritório 30 por conta — 429 `LIMITE_CONSULTAS_DIA`, renova à 0h de Brasília), e a cota do mês passa a somar todas as portas da conta — esta API, o painel, os links de cadastro e o WhatsApp —, com os tetos Plano Free 5, Plano Individual 20, Plano Multi e Plano Cortesia 60 e Plano Escritório 200. A consulta que a Receita responde como "não encontrado" conta (ela é cobrada). O CNPJ consultado nos últimos 7 dias sai do cache sem gastar, venha a consulta de qualquer conta (`de_cache: true`); o CPF, só da mesma conta, com a mesma data de nascimento, em 24 horas. Quando as consultas pagas da plataforma param até a virada do dia: 503 `CONSULTAS_PAUSADAS` (Receita) e 503 `PGDAS_PAUSADO` (PGDAS-D); o `POST /companies/{id}/pgdas/sync` com `forcar` passa a 3 consultas pagas por empresa e dia. Envios: até 100 notas por e-mail por dia (429 `LIMITE_EMAILS_DO_DIA`) e 3 "rodar agora" por automação de relatório e dia (429 `LIMITE_RODAR_AGORA`). - 2026-09-28 — **O download de exportação voltou a funcionar**: o link temporário do arquivo — o `Location` do 302 de `GET /exports/{id}/download` e o link que vai no e-mail — passou a ser assinado em SigV4; o de antes era recusado pelo armazenamento (400) desde 22/09, porque o pacote é cifrado com KMS. O arquivo baixa como anexo, com o nome do período (`gerenota-AAAA-MM-a-AAAA-MM.zip`). Rota nova, `GET /exports/{id}/link`: o mesmo link em JSON (`url`, `expira_em`, `arquivo`), para quem não consegue seguir o redirecionamento sem repassar a própria chave — o navegador, por exemplo. - 2026-09-27 — **Notas com problema e notas emitidas fora do GereNota**: a listagem (`GET /nfse`) e a nota (`GET /nfse/{id}`) ganham `origem` na listagem (`plataforma` ou `importada` — a nota emitida fora do GereNota, trazida do Sistema Nacional), `fora_depois_da_entrada` (a de fora emitida depois que a empresa entrou: outro sistema ainda emitindo) e `alertas`, os problemas da nota com o que fazer (`tipo`, `titulo`, `texto`): o último e-mail ao cliente que voltou, foi recusado ou marcado como spam; a retida com o ISS de outro mês; o município que aplicou outra alíquota; o cancelamento por ofício; e a nota que parece ter saído em dobro (a do GereNota e uma de fora, mesmo cliente, competência e valor, as duas ativas). `com_problema=true` em `GET /nfse` e em `GET /nfse/agregado` traz só essas notas, e o agregado passa a contar `com_problema` dentro do mesmo filtro. - 2026-09-27 — **Quem tem recorte vê os clientes das empresas dele**: com a chave, o conector ou o login de quem acessa uma empresa compartilhada (ou de um membro recortado), `GET /tomadores` — a lista, a busca por nome e o prefixo do documento — traz os clientes que já receberam nota dessas empresas e os que a pessoa cadastrou; o CNPJ ou CPF inteiro continua achando qualquer cadastro da conta. O dono e quem não tem recorte: sem mudança. - 2026-09-26 — **O cancelamento aceita `Idempotency-Key`** e o envio da nota por e-mail ganha teto: repetir `POST /nfse/{id}/cancelar` com a mesma chave devolve o mesmo cancelamento (200, `X-Idempotent-Replay: true`) em vez do 409 `NFSE_NAO_ATIVA`; a chamada simultânea recebe 409 `CANCELAMENTO_EM_ANDAMENTO`. `POST /nfse/{id}/enviar-email` aceita até 10 envios por minuto por conta (429 `RATE_LIMIT` acima disso). - 2026-09-26 — **O ISS de outro mês não vai mais à nota**: numa ME/EPP no DAS, a nota retida sem `pAliq` de um mês que a plataforma não tem (modo manual sem aquele mês confirmado — inclusive o corrente, antes da confirmação —, ou quando a conta pelas declarações PGDAS-D não fecha para o período) passa a responder 422 `ALIQUOTA_ISS_DO_MES_AUSENTE`, em vez de sair com o ISS em uso — que é de outro mês, e com alíquota menor que a devida a diferença cai no DAS do prestador (LC 123, art. 21, § 4º, VI). Quem integra manda a `pAliq` daquele mês. Na nota de um mês que já virou, a dica do erro não manda confirmar a alíquota (a confirmação vale para o mês corrente). A automação com retenção segue a mesma regra: usa a `pAliq` gravada nela e, sem ela, sai `pulada` e tenta de novo no dia seguinte; completar uma pendência nessa situação responde 422 com a dica de informar a alíquota na automação. A automação criada pelo histórico (`POST /automations/recorrente` sem `tributacao`) numa ME/EPP no DAS deixa de copiar a `pAliq` da última nota retida — era o ISS de outro mês. - 2026-09-25 — **O ISS do mês fora do histórico**: numa ME/EPP no DAS em modo automático, a retenção sem `pAliq` de um mês que o histórico mensal não tem passa a levar o ISS daquele mês pela conta das declarações PGDAS-D arquivadas (o anexo e o impedimento daquele período, só com os 12 meses declarados), em vez do ISS em uso — o histórico começava na primeira alíquota registrada, e a nota tardia de antes dele saía com o número de outro mês. O mês calculado passa a constar do `historico` do dossiê quando uma nota retida sai com esse número. O cadastro com `reg_ap_trib_sn` 2 ou 3 tira o ISS do DAS também na nota de um mês do histórico. Sem o mês, veja a entrada de 26/09. - 2026-09-25 — **Retenção do ISS no Simples**: numa ME/EPP no DAS, a retenção sem `pAliq` passa a ser preenchida pela API com o ISS do mês da prestação (o da competência): o do mês corrente, ou o de um mês anterior quando ele está no histórico mensal da empresa — fora dele, o ISS em uso (até 26/09: veja a entrada desse dia). Sem ISS no mês resolvido, 422 `ALIQUOTA_ISS_DO_MES_AUSENTE` (antes a nota saía sem a alíquota que a lei manda informar). Com o ISS fora do DAS (o sublimite pela declaração, ou `reg_ap_trib_sn` 2 ou 3), a nota vai sem `pAliq`, como antes. **Automação com retenção**: criada por `POST /automations/recorrente` ou pelo aceite de uma sugestão, passa a exigir o endereço completo do tomador (422 `RETENCAO_SEM_TOMADOR`) e a `pAliq` (422 `ALIQUOTA_OBRIGATORIA`), como o assistente já exigia; em todas as rotas da automação, a ME/EPP no DAS que tem o ISS do mês fica dispensada da `pAliq` — o disparo usa o ISS do mês da prestação, e a `pAliq` gravada só vale quando a empresa não tem ISS naquele mês (com o ISS fora do DAS, ela é a alíquota do município). Sem número nenhum, o disparo sai `pulada` com `ALIQUOTA_ISS_DO_MES_AUSENTE` e tenta de novo no dia seguinte. - 2026-09-24 — **Avisos**: a execução da automação de relatório diz o que o e-mail teve — além de `relatorio_enviado`, os valores novos `relatorio_parcial` e `relatorio_nao_entregue` — e a automação de relatório pausa sozinha, com `pausada_por: sem_destinos`, quando o último destino sai da lista pelo link do e-mail. - 2026-09-22 — **Alíquotas do Simples** (47 operações): a tag `aliquotas`, com o dossiê (`GET /companies/{id}/aliquotas`: a alíquota do mês com a conta, a próxima, a conferência, os casos e o regime de apuração consultado na Receita Federal), as declarações PGDAS-D como dado (a lista, uma por período, o PDF) e a consulta paga (`POST …/pgdas/sync` com `pa` e `forcar`; 429 `TETO_DIARIO_PGDAS`; 403 `ACEITE_SO_DO_DONO`). A conferência da receita traz frases prontas para o cliente (`frase_titulo`, `frase`, `detalhes`) e a dos 12 meses (`doze_meses`). Empresa ME/EPP sem alíquota nenhuma recebe 422 `ALIQUOTA_NAO_CONFIRMADA` (antes a nota saía com um padrão de 13,99 %), e a automação nessa situação sai `pulada`. **Exportação sem corte:** fila justa, `volumes` e `download?volume=`, download por redirecionamento 302, links de 30 dias no e-mail, `total_no_recorte` sempre igual a `total_notas`; `GET /nfse/agregado` ganha `exportacao` (o que o pacote vai ter antes de pedir); o CSV de `GET /reports/nfse` vem completo; o relatório mensal sai pela fila (`em_fila`, `repetida`). As notas ganham `vBC` e `pAliqAplic` (a base e a alíquota que o município aplicou). - 2026-09-16 a 18 — **Contabilidade** (42 operações): `POST /servicos/sugerir` e `GET /servicos/codigo/{codigo}`; a situação com data e prova (`cancelada_em`, `substituida_em`, `substituida_por`, `evento_situacao`, `substituida_por_numero`), `periodo_por=evento` com bordas em Brasília, `GET /nfse/eventos` (cursor `desde`) e `GET /nfse/{id}/eventos/{evento_id}/xml`; `por_status` no agregado; o CSV do contador em português, `relatorio.html` e `eventos/` no ZIP; `vISSQN` na listagem e a coluna "ISS retido (R$)" no CSV. - 2026-09-16 — primeira versão documentada da superfície pública (38 operações); cota mensal e cache nas consultas de CNPJ/CPF; `Idempotency-Key` passa a barrar emissões simultâneas com 409. ## Para assistentes conversacionais: o MCP Se a integração é uma conversa (Claude, ou qualquer cliente compatível com MCP) e não um sistema, não use chave de API: conecte o assistente ao GereNota pelo conector remoto em `https://api.gerenota.com.br/mcp`. O login é por código enviado ao e-mail da conta, e o assistente ganha as ferramentas do produto (emitir com prévia e confirmação explícita, listar, cancelar, exportar, automações), com o papel da pessoa respeitado. O guia das ferramentas está dentro do próprio conector (`nfse_help`). Para a contabilidade, o conector tem o mesmo que a API: `nfse_alteracoes` (o que mudou de situação, com `desde` como cursor), `nfse_evento_xml` (o XML do evento, a prova), `nfse_listar` com `periodo_por=evento` e `nfse_exportar` (o ZIP). Para as alíquotas do Simples, `nfse_aliquotas` devolve o mesmo dossiê da API (a alíquota do mês com a conta, a próxima, a conferência e as declarações). A API REST deste documento é para sistemas que programam a integração. ## Referência Todas as rotas abaixo ficam sob `https://api.gerenota.com.br` e exigem `Authorization: Bearer gnk_live_…`, salvo `/health`. ## Conta Quem sou eu: identidade, plano e cotas da chave em uso. ### Ver a conta, o papel e o plano da chave `GET /api/v1/me` Diz de quem é a chave em uso — conta, usuário e papel efetivo — e como está o plano. Vale como primeira chamada de uma integração nova: confirma que a chave é válida e mostra o que ela pode fazer. `role` é `operador` para chave de escopo `emissao` e `leitor` para escopo `leitura`; o papel efetivo nunca passa do papel de quem criou a chave. `empresas` conta as empresas próprias da conta e `compartilhadas`, as de outras contas a que este usuário tem acesso; `empresa_padrao` traz o `company_id` que o painel abre por padrão — bom palpite quando a sua integração não recebeu a empresa de outro jeito. O bloco `plano` traz o consumo do mês (`notas.usadas` × `notas.cota`, `consultas.usadas` × `consultas.cota`) e os tetos de empresas, automações e acessos, com a mesma régua que a API usa para barrar; `teto`/`cota` em `null` significa sem limite, e o bloco inteiro pode vir `null` sem que haja erro (nesse caso, siga e trate o 402 quando ele vier). Para o dono da conta (no painel ou no conector; a chave de API nunca é do dono), o limite já no teto traz `upgrade`, o plano em que o próximo item cabe, com o preço e o link para assinar, e o recurso que o plano não inclui traz `upgrade_relatorios` ou `upgrade_api_mcp`. `billing.bloqueada` em `true` quer dizer renovação vencida: as outras rotas respondem 402 `CONTA_BLOQUEADA` até o pagamento, e só esta continua respondendo. `escopo` diz o escopo da própria chave (`emissao` ou `leitura`) antes de qualquer chamada de escrita; é nulo na sessão de login do painel. **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/me" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Identidade da chave, com plano e sinais de cobrança | Campo | Tipo | Descrição | |---|---|---| | `account_id` | string **(obrigatório)** | Conta (tenant) a que a chave pertence | | `user_id` | string **(obrigatório)** | Usuário dono da chave | | `role` | string **(obrigatório)** | Papel efetivo: `owner`, `operador`, `contabilidade` ou `leitor` | | `escopo` | string, ou null | Escopo da chave de API em uso: `emissao` (emite, cancela, substitui) ou `leitura` (só consulta); nulo quando a sessão é de login no painel | | `nome` | string, ou null | Nome do usuário, quando cadastrado | | `email` | string, ou null | E-mail do usuário, quando cadastrado | | `telefone` | string, ou null | Telefone do usuário, só dígitos, quando cadastrado | | `telefone_verificado` | boolean **(obrigatório)** | Se o telefone já foi confirmado por código | | `empresas` | integer, ou null | Quantas empresas próprias a conta tem | | `compartilhadas` | integer, ou null | Quantas empresas de outras contas foram compartilhadas com este usuário | | `plano_escritorio` | boolean | `true` quando a conta está no Plano Escritório (o painel abre a Carteira para quem cuida de muitas empresas) Padrão: `false`. | | `empresa_padrao` | string, ou null | `company_id` da empresa que o painel abre por padrão, quando há uma | | `billing` | objeto BillingFlagsOut, ou null | Sinais de cobrança da conta | | `plano` | objeto PlanoOut, ou null | Plano com uso × teto; `null` quando não foi possível apurar (não é erro) | | `importacao_auto` | boolean, ou null | Se a importação automática de notas do Sistema Nacional está ligada no serviço | **Exemplo de resposta** ```json { "account_id": "acc_it", "billing": { "bloqueada": false, "vence_hoje": false }, "compartilhadas": 0, "email": "it@gerenota.test", "empresa_padrao": null, "empresas": 0, "escopo": null, "importacao_auto": false, "nome": null, "plano": { "acessos": { "teto": 999, "uso": 0 }, "api_mcp": true, "automacoes": { "teto": null, "uso": 0 }, "consultas": { "cota": null, "usadas": 0 }, "empresas": { "teto": null, "uso": 0 }, "nome": "Dev (interno)", "notas": { "cota": null, "usadas": 0 }, "relatorios": true }, "role": "owner", "telefone": null, "telefone_verificado": false, "user_id": "it@gerenota.test" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | ## Empresas As empresas emissoras da conta: listar, cadastrar, enviar o certificado A1 e validar. ### Listar as empresas que a chave pode usar `GET /api/v1/minhas-empresas` Lista as empresas em que você pode operar: as da própria conta e as que outras contas compartilharam com você, cada uma com o seu papel efetivo. É o ponto de partida de qualquer integração: escolha aqui o `id` e use-o como `company_id` nas demais rotas. Para uma empresa compartilhada, acrescente `?company_id=` às chamadas: elas rodam na conta dona, com o seu papel. `GET /companies` lista só as empresas próprias, com mais detalhes. **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/minhas-empresas" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Empresas próprias e compartilhadas, com o papel em cada uma | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Id da empresa: é o `company_id` das outras rotas | | `razao_social` | string, ou null | Razão social | | `nome_fantasia` | string, ou null | Nome fantasia, quando cadastrado | | `cnpj` | string, ou null | CNPJ, sem pontuação (pode ter letras nas 12 primeiras posições) | | `status` | string, ou null | `ativa` (pode emitir), `cadastrada` (sem certificado validado) ou `inativa` | | `propria` | boolean | True = da sua conta; False = compartilhada por outra conta (aí vem `account_id` da dona) Padrão: `true`. | | `papel` | string, ou null | Seu papel efetivo nesta empresa: `owner`, `operador`, `contabilidade` ou `leitor` | | `pode_emitir` | boolean, ou null | `true` quando você emite nota por esta empresa: o dono, o operador e a contabilidade com a opção "Pode emitir notas" que o dono liga no compartilhamento | | `municipio` | string, ou null | Município/UF da sede, como `Natal/RN` | | `cert_bloqueado` | boolean, ou null | True quando não há certificado válido: a emissão está bloqueada | | `emissao_parada` | string, ou null | A frase pronta quando a emissão está parada porque a empresa saiu do Simples Nacional; `null` quando ela emite | | `estado_aliquotas` | string, ou null | Situação das alíquotas do Simples: confirmadas para a competência ou pendentes | | `aliquota_atual` | string, ou null | Percentual total de tributos do Simples em uso (pTotTribSN) | | `aliquota_iss` | string, ou null | Alíquota de ISS em uso, quando informada | | `aliquota_iss_fora_do_das` | boolean | A empresa está impedida de recolher o ISS no Simples (sublimite) — pela declaração PGDAS-D ou pelo cadastro (`regime.reg_ap_trib_sn` 2 ou 3): sem `aliquota_iss`, e nas notas com retenção vale a alíquota do município Padrão: `false`. | | `aliquota_competencia` | string, ou null | Competência (AAAA-MM) para a qual as alíquotas foram confirmadas | | `tributacao_modo` | string, ou null | `auto` (do PGDAS) ou `manual` | | `receita_resumo` | objeto, ou null | Resumo dos dados da Receita: `cnae_principal`, `porte`, `consultado_em`; nulo se nunca consultada | | `account_id` | string, ou null | Conta dona, presente nas empresas compartilhadas | **Exemplo de resposta** ```json [ { "aliquota_atual": null, "aliquota_competencia": null, "aliquota_iss": null, "cert_bloqueado": false, "cnpj": "12345678000195", "estado_aliquotas": "nunca", "id": "cmp_9b958e240b9f983f", "municipio": "Natal/RN", "nome_fantasia": null, "papel": "operador", "propria": true, "razao_social": "EMPRESA COMPARTILHADA LTDA", "receita_resumo": null, "status": "ativa", "tributacao_modo": "auto" } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | ### Listar as empresas da conta `GET /api/v1/companies` Lista as empresas emissoras da conta, cada uma com cadastro, regime tributário e situação. É por aqui que se descobre o `company_id` das demais rotas: é o campo `id` de cada item, no formato `cmp_…`. Só emite nota a empresa com `status` igual a `ativa` — `pendente` ainda não validou o certificado A1 e `waitlist` está em município que não emite pelo Sistema Nacional. A lista já vem recortada pelo acesso de quem criou a chave; empresas de outra conta compartilhadas com este usuário **não** aparecem aqui, mas podem ser usadas nas demais rotas pelo `company_id` que o dono informou. Devolve no máximo 200 empresas, sem paginação nem filtro, e basta escopo `leitura`. **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da empresa (`cmp_…`) — é o `company_id` das demais rotas | | `cnpj` | string **(obrigatório)** | CNPJ da empresa, sem pontuação (14 caracteres; pode ter letras nas 12 primeiras) | | `inscricao_municipal` | string, ou null | Inscrição municipal, quando cadastrada | | `razao_social` | string **(obrigatório)** | Razão social da empresa | | `nome_fantasia` | string, ou null | Nome fantasia, quando cadastrado | | `status` | string **(obrigatório)** | `pendente` (cadastrada, sem certificado validado), `ativa` (pode emitir), `inativa` (pausada pelo dono), `waitlist` (lista de espera: a ME ou a EPP de município que ainda não emite pelo Sistema Nacional, até 31/10/2026) ou `suspensa` | | `serie_padrao` | string **(obrigatório)** | Série usada na numeração das notas desta empresa | | `criado_em` | string (date-time) **(obrigatório)** | Data e hora do cadastro (ISO 8601, UTC) | | `endereco` | objeto Endereco, ou null | Endereço da empresa; `cMun` é o código IBGE | | `regime` | objeto RegimeTributario, ou null | Regime tributário usado na emissão (Simples Nacional, regime especial, alíquotas) | | `telefone` | string, ou null | Telefone de contato, só dígitos | | `email` | string, ou null | E-mail de contato da empresa | | `pgdas` | objeto, ou null | Último retrato do PGDAS-D que alimentou as alíquotas, quando houver | | `tributacao_modo` | string | `auto` (alíquotas renovadas pelo PGDAS-D) ou `manual` (o dono informa) Padrão: `"auto"`. | | `aviso` | string, ou null | Recado sobre o que acabou de acontecer — ex.: município em lista de espera | | `sync_opcoes` | objeto, ou null | Preferências da importação automática de notas — hoje só `importar_legado_convertido` (bool) | | `receita` | objeto, ou null | Dados cadastrais trazidos da Receita (CNAEs, natureza, porte, capital, Simples), quando consultados, com a fonte (`fonte`: `gerecnpj`, o cadastro mensal, com `mes_referencia`; ou `serpro`, em tempo real). O quadro societário não vem nas listas: só a contagem (`qsa_total`); os sócios estão em `GET /companies/{id}/receita` | | `receita_consultado_em` | string (date-time), ou null | Quando os dados da Receita foram consultados (ISO 8601, UTC) | | `fora_do_simples` | objeto, ou null | Preenchido quando a Receita mostrou que a empresa saiu do Simples Nacional (`desde`, `conferido_em`, `fonte`): a emissão fica parada (422 `EMPRESA_FORA_DO_SIMPLES`) até o "Conferir na Receita" mostrar que ela voltou | | `emissao_parada` | string, ou null | A frase pronta quando a emissão está parada por regime; `null` quando emite | | `pendencia_da_ativacao` | objeto, ou null | Por que a última validação não ativou a empresa: `codigo` (o do erro de `POST /companies/{id}/validate` — `INSCRICAO_MUNICIPAL_OBRIGATORIA`, `CERTIFICADO_AUSENTE`, `VALIDACAO_REPROVADA`…), `mensagem`, `em`, `cidade` (Cidade/UF, na inscrição municipal) e `checks` (`cnpj_confere`, `dentro_da_validade`, `handshake_govbr`, na validação reprovada). Some quando a empresa é ativada; `null` quando nunca reprovou | | `receita_aviso_regime` | objeto, ou null | A reconferência mensal viu no cadastro da Receita uma mudança de regime que ainda não parou nada: `tipo` (`saiu`, a empresa não é mais optante do Simples; `saida_marcada`, a saída marcada para uma data futura; `deixou_mei`, o MEI que virou ME/EPP), `data` (a da saída, `AAAA-MM-DD`) e `mes` (o do cadastro, `AAAA-MM`). Só avisa: a emissão para quando a saída se confirma na Receita do dia. Some quando a conferência não mostra mais a mudança; `null` quando não há | **Exemplo de resposta** ```json [ { "aviso": null, "cnpj": "12345678000195", "criado_em": "2026-09-16T18:39:30.506000Z", "email": null, "endereco": { "CEP": "59064902", "cMun": "2408102", "nro": "1", "xBairro": "CENTRO", "xCpl": null, "xLgr": "AV X" }, "id": "cmp_157c9bd26b9e0b22", "inscricao_municipal": "1234567", "nome_fantasia": null, "pgdas": null, "razao_social": "EMPRESA TESTE ALIQUOTAS LTDA", "receita": null, "receita_consultado_em": null, "regime": { "aliquota_confirmada_para": "2026-09", "aliquota_detectada": null, "aliquota_fonte": "manual", "op_simp_nac": "3", "p_aliq_iss": null, "p_tot_trib_sn": "12.34", "reg_ap_trib_sn": "1", "reg_esp_trib": "0" }, "serie_padrao": "1", "status": "ativa", "sync_opcoes": null, "telefone": null, "tributacao_modo": "manual" } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | ### Ver a situação de uma empresa e do certificado `GET /api/v1/companies/{company_id}/status` Devolve a ficha operacional de uma empresa: o cadastro (`company`), o certificado A1 mais recente (`certificate`) e o estado da importação automática de notas (`importacao`). Use antes de emitir para saber se a empresa está de pé: `company.status` precisa ser `ativa` e `certificate.status`, `validado` — e olhe `certificate.dias_para_vencer`, que fica negativo quando o certificado já venceu (nesse caso a emissão passa a falhar). `certificate` vem `null` enquanto nenhum arquivo .pfx foi enviado. O bloco `importacao` é informativo e best-effort: diz se a rodada automática está ligada, quando foi a última e quantas notas antigas ainda faltam entrar; pode vir com `indisponivel: true` sem que a empresa tenha problema algum. Responde 404 quando o `company_id` não existe nesta conta e 403 `EMPRESA_FORA_DO_RECORTE` quando a empresa está fora do acesso da chave. Basta escopo `leitura`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/status" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `company` | objeto CompanyOut **(obrigatório)** | O cadastro da empresa | | `company.id` | string **(obrigatório)** | Identificador da empresa (`cmp_…`) — é o `company_id` das demais rotas | | `company.cnpj` | string **(obrigatório)** | CNPJ da empresa, sem pontuação (14 caracteres; pode ter letras nas 12 primeiras) | | `company.inscricao_municipal` | string, ou null | Inscrição municipal, quando cadastrada | | `company.razao_social` | string **(obrigatório)** | Razão social da empresa | | `company.nome_fantasia` | string, ou null | Nome fantasia, quando cadastrado | | `company.status` | string **(obrigatório)** | `pendente` (cadastrada, sem certificado validado), `ativa` (pode emitir), `inativa` (pausada pelo dono), `waitlist` (lista de espera: a ME ou a EPP de município que ainda não emite pelo Sistema Nacional, até 31/10/2026) ou `suspensa` | | `company.serie_padrao` | string **(obrigatório)** | Série usada na numeração das notas desta empresa | | `company.criado_em` | string (date-time) **(obrigatório)** | Data e hora do cadastro (ISO 8601, UTC) | | `company.endereco` | objeto Endereco, ou null | Endereço da empresa; `cMun` é o código IBGE | | `company.regime` | objeto RegimeTributario, ou null | Regime tributário usado na emissão (Simples Nacional, regime especial, alíquotas) | | `company.telefone` | string, ou null | Telefone de contato, só dígitos | | `company.email` | string, ou null | E-mail de contato da empresa | | `company.pgdas` | objeto, ou null | Último retrato do PGDAS-D que alimentou as alíquotas, quando houver | | `company.tributacao_modo` | string | `auto` (alíquotas renovadas pelo PGDAS-D) ou `manual` (o dono informa) Padrão: `"auto"`. | | `company.aviso` | string, ou null | Recado sobre o que acabou de acontecer — ex.: município em lista de espera | | `company.sync_opcoes` | objeto, ou null | Preferências da importação automática de notas — hoje só `importar_legado_convertido` (bool) | | `company.receita` | objeto, ou null | Dados cadastrais trazidos da Receita (CNAEs, natureza, porte, capital, Simples), quando consultados, com a fonte (`fonte`: `gerecnpj`, o cadastro mensal, com `mes_referencia`; ou `serpro`, em tempo real). O quadro societário não vem nas listas: só a contagem (`qsa_total`); os sócios estão em `GET /companies/{id}/receita` | | `company.receita_consultado_em` | string (date-time), ou null | Quando os dados da Receita foram consultados (ISO 8601, UTC) | | `company.fora_do_simples` | objeto, ou null | Preenchido quando a Receita mostrou que a empresa saiu do Simples Nacional (`desde`, `conferido_em`, `fonte`): a emissão fica parada (422 `EMPRESA_FORA_DO_SIMPLES`) até o "Conferir na Receita" mostrar que ela voltou | | `company.emissao_parada` | string, ou null | A frase pronta quando a emissão está parada por regime; `null` quando emite | | `company.pendencia_da_ativacao` | objeto, ou null | Por que a última validação não ativou a empresa: `codigo` (o do erro de `POST /companies/{id}/validate` — `INSCRICAO_MUNICIPAL_OBRIGATORIA`, `CERTIFICADO_AUSENTE`, `VALIDACAO_REPROVADA`…), `mensagem`, `em`, `cidade` (Cidade/UF, na inscrição municipal) e `checks` (`cnpj_confere`, `dentro_da_validade`, `handshake_govbr`, na validação reprovada). Some quando a empresa é ativada; `null` quando nunca reprovou | | `company.receita_aviso_regime` | objeto, ou null | A reconferência mensal viu no cadastro da Receita uma mudança de regime que ainda não parou nada: `tipo` (`saiu`, a empresa não é mais optante do Simples; `saida_marcada`, a saída marcada para uma data futura; `deixou_mei`, o MEI que virou ME/EPP), `data` (a da saída, `AAAA-MM-DD`) e `mes` (o do cadastro, `AAAA-MM`). Só avisa: a emissão para quando a saída se confirma na Receita do dia. Some quando a conferência não mostra mais a mudança; `null` quando não há | | `certificate` | objeto CertificateOut, ou null | O certificado A1 mais recente da empresa; `null` quando nenhum foi enviado | | `importacao` | objeto, ou null | Estado da importação automática das notas do Sistema Nacional: `ultima` (a última rodada, com `em`, `status` e contagens), `em_andamento` e `progresso`, `pode_importar` e `motivo` (por que não dá), `automatica` (se a rodada diária está ligada e quando volta) e `legado` (notas do sistema antigo do município: `disponiveis` × `no_painel`). Vem com `indisponivel: true` quando não deu para apurar | **Exemplo de resposta** ```json { "certificate": { "company_id": "cmp_2c15d6b44e32ffd3", "dias_para_vencer": 299, "id": "crt_35b722208a116264", "not_after": "2027-07-13T18:46:13Z", "status": "recebido", "subject_cn": "EMPRESA TESTE:12345678000195", "subject_cnpj": "12345678000195" }, "company": { "aviso": null, "cnpj": "12345678000195", "criado_em": "2026-09-16T18:46:13.336000Z", "email": null, "endereco": { "CEP": "59064902", "cMun": "2408102", "nro": "1", "xBairro": "CENTRO", "xCpl": null, "xLgr": "AV X" }, "id": "cmp_2c15d6b44e32ffd3", "inscricao_municipal": "1234567", "nome_fantasia": null, "pgdas": null, "razao_social": "EMPRESA TESTE INTEGRACAO LTDA", "receita": null, "receita_consultado_em": null, "regime": { "aliquota_confirmada_para": null, "aliquota_detectada": null, "aliquota_fonte": null, "op_simp_nac": "3", "p_aliq_iss": null, "p_tot_trib_sn": null, "reg_ap_trib_sn": "1", "reg_esp_trib": "0" }, "serie_padrao": "1", "status": "pendente", "sync_opcoes": null, "telefone": null, "tributacao_modo": "auto" }, "importacao": { "automatica": { "ligada": false, "motivo_pausa": "desligada", "proxima_em": null, "ultima_em": null, "vencido_em": null }, "em_andamento": false, "em_andamento_origem": null, "indisponivel": false, "legado": { "disponiveis": 0, "ligado": false, "no_painel": 0 }, "motivo": "certificado_aguardando_validacao", "opcoes": { "importar_legado_convertido": false }, "pode_importar": false, "progresso": null, "ultima": null } } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Cadastrar uma empresa emissora `POST /api/v1/companies` Cadastra uma empresa emissora na conta e devolve a ficha criada, com o `id` (`cmp_…`) que as outras rotas pedem como `company_id`. A empresa nasce com `status` `pendente` e ainda **não emite**: o caminho até a primeira nota é enviar o certificado A1 (`POST /companies/{company_id}/certificate`) e validar (`POST /companies/{company_id}/validate`). Mande `cnpj` sem pontuação (ela é aceita e normalizada; o CNPJ pode ter letras nas 12 primeiras posições) e, em `endereco.cMun`, o código IBGE de 7 dígitos do município da empresa — confirme pelo CEP em `GET /consultas/cep/{cep}` em vez de adivinhar, porque o código errado só aparece na rejeição da nota. Até 31/10/2026, a ME ou a EPP de município que ainda não emite pelo Sistema Nacional é aceita com `status` `waitlist`, e o campo `aviso` explica: ela não emite até sair da lista. Em 1º/11/2026 ela sai (a partir dessa data, a ME e a EPP emitem pelo Emissor Nacional em qualquer cidade). O MEI não entra na lista. Erros: 409 quando o CNPJ já está cadastrado nesta conta ou já chega compartilhado por outra (`CNPJ_JA_COMPARTILHADO`), 402 `LIMITE_DO_PLANO` quando o plano não comporta mais uma empresa e 503 `ADN_INDISPONIVEL` quando o serviço do gov.br que informa a adesão do município não responde. Com o `company_id` de uma empresa compartilhada por outra conta, 403 `PERMISSAO_NEGADA`: a empresa nova nasce na sua conta, nunca na conta que compartilhou. Exige chave de escopo `emissao`. **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `cnpj` | string **(obrigatório)** | CNPJ da empresa emissora: 14 caracteres (letras A–Z ou números nas 12 primeiras posições; os 2 últimos, números); pontuação é aceita e normalizada; letra minúscula vira maiúscula | | `inscricao_municipal` | string, ou null | Inscrição municipal, até 15 caracteres. Na maioria das cidades, o Sistema Nacional identifica a empresa pelo CNPJ; onde a prefeitura exige a inscrição na nota (como São Paulo e Recife), a ME e a EPP só ativam e emitem com ela | | `razao_social` | string **(obrigatório)** | Razão social exatamente como está no cadastro da Receita | | `nome_fantasia` | string, ou null | Nome fantasia, só para exibição no painel | | `regime` | objeto RegimeTributarioIn | O que o dono informa do regime: a opção pelo Simples, o regime especial e, se quiser, os percentuais. Os campos que a plataforma calcula (a conta da alíquota, a próxima, a conferência) só aparecem na leitura e nunca são aceitos na entrada. O Sistema Nacional confere a opção pelo Simples contra o cadastro do Simples mês a mês: valor fora da tabela devolve 422, e divergência com o cadastro real volta como erro explicado. Padrão: `{"op_simp_nac": "3", "reg_ap_trib_sn": "1", "reg_esp_trib": "0"}`. | | `regime.op_simp_nac` | um de: `"1"`, `"2"`, `"3"` | Opção pelo Simples Nacional: 2 = MEI · 3 = ME/EPP. A GereNota atende só Simples Nacional e MEI: 1 (não optante) volta 422 `EMPRESA_FORA_DO_SIMPLES` (o SEFIN valida o regime contra o cadastro do Simples por competência — E0160) Padrão: `"3"`. | | `regime.reg_ap_trib_sn` | um de: `"1"`, `"2"`, `"3"`, ou null | Só ME/EPP (op_simp_nac=3): 1 = tudo no DAS · 2 = ISS por fora (sublimite estourado) · 3 = ISS e ICMS por fora Padrão: `"1"`. | | `regime.reg_esp_trib` | um de: `"0"`, `"1"`, `"2"`, `"3"`, `"4"`, `"5"`, `"6"`, `"9"` | Regime especial de tributação: 0 = nenhum · 1 = cooperativa · 2 = estimativa · 3 = ME municipal · 4 = notário · 5 = autônomo · 6 = sociedade de profissionais · 9 = outros Padrão: `"0"`. | | `regime.p_tot_trib_sn` | string, ou null | Efetiva total do Simples (%) — o `pTotTribSN` das notas. Informado aqui é alíquota MANUAL do dono; no modo automático vem do PGDAS-D mês a mês. ME/EPP sem valor não emite (422 ALIQUOTA_NAO_CONFIRMADA) | | `regime.p_aliq_iss` | string, ou null | ISS efetivo (%) — a `pAliq` das notas COM retenção. Mesma regra do p_tot_trib_sn | | `regime.ibs_cbs_no_das` | um de: `"dentro"`, `"fora"`, ou null | 2027: IBS/CBS recolhidos DENTRO do DAS ou por fora (regime híbrido) — a opção de setembro/2026. Registro; a composição do DAS de 2027 é modelagem futura | | `endereco` | objeto Endereco **(obrigatório)** | Endereço da empresa; `cMun` (código IBGE de 7 dígitos) define o município de emissão | | `endereco.cMun` | string **(obrigatório)** | | | `endereco.CEP` | string **(obrigatório)** | | | `endereco.xLgr` | string **(obrigatório)** | | | `endereco.nro` | string **(obrigatório)** | | | `endereco.xBairro` | string **(obrigatório)** | | | `endereco.xCpl` | string, ou null | | | `telefone` | string, ou null | Telefone com DDD, só dígitos (o nono dígito é completado quando falta) | | `email` | string, ou null | E-mail de contato da empresa | | `serie_padrao` | string | Série da numeração das notas — número de 1 a 49999, sem zeros à esquerda (de 50000 em diante a série é reservada aos emissores do governo) Padrão: `"1"`. | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"cnpj": "12345678000195", "endereco": {"CEP": "59064902", "cMun": "2408102", "nro": "1", "xBairro": "CENTRO", "xLgr": "AV X"}, "inscricao_municipal": "1234567", "razao_social": "EMPRESA TESTE ALIQUOTAS LTDA"}' ``` **Resposta 201** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da empresa (`cmp_…`) — é o `company_id` das demais rotas | | `cnpj` | string **(obrigatório)** | CNPJ da empresa, sem pontuação (14 caracteres; pode ter letras nas 12 primeiras) | | `inscricao_municipal` | string, ou null | Inscrição municipal, quando cadastrada | | `razao_social` | string **(obrigatório)** | Razão social da empresa | | `nome_fantasia` | string, ou null | Nome fantasia, quando cadastrado | | `status` | string **(obrigatório)** | `pendente` (cadastrada, sem certificado validado), `ativa` (pode emitir), `inativa` (pausada pelo dono), `waitlist` (lista de espera: a ME ou a EPP de município que ainda não emite pelo Sistema Nacional, até 31/10/2026) ou `suspensa` | | `serie_padrao` | string **(obrigatório)** | Série usada na numeração das notas desta empresa | | `criado_em` | string (date-time) **(obrigatório)** | Data e hora do cadastro (ISO 8601, UTC) | | `endereco` | objeto Endereco, ou null | Endereço da empresa; `cMun` é o código IBGE | | `regime` | objeto RegimeTributario, ou null | Regime tributário usado na emissão (Simples Nacional, regime especial, alíquotas) | | `telefone` | string, ou null | Telefone de contato, só dígitos | | `email` | string, ou null | E-mail de contato da empresa | | `pgdas` | objeto, ou null | Último retrato do PGDAS-D que alimentou as alíquotas, quando houver | | `tributacao_modo` | string | `auto` (alíquotas renovadas pelo PGDAS-D) ou `manual` (o dono informa) Padrão: `"auto"`. | | `aviso` | string, ou null | Recado sobre o que acabou de acontecer — ex.: município em lista de espera | | `sync_opcoes` | objeto, ou null | Preferências da importação automática de notas — hoje só `importar_legado_convertido` (bool) | | `receita` | objeto, ou null | Dados cadastrais trazidos da Receita (CNAEs, natureza, porte, capital, Simples), quando consultados, com a fonte (`fonte`: `gerecnpj`, o cadastro mensal, com `mes_referencia`; ou `serpro`, em tempo real). O quadro societário não vem nas listas: só a contagem (`qsa_total`); os sócios estão em `GET /companies/{id}/receita` | | `receita_consultado_em` | string (date-time), ou null | Quando os dados da Receita foram consultados (ISO 8601, UTC) | | `fora_do_simples` | objeto, ou null | Preenchido quando a Receita mostrou que a empresa saiu do Simples Nacional (`desde`, `conferido_em`, `fonte`): a emissão fica parada (422 `EMPRESA_FORA_DO_SIMPLES`) até o "Conferir na Receita" mostrar que ela voltou | | `emissao_parada` | string, ou null | A frase pronta quando a emissão está parada por regime; `null` quando emite | | `pendencia_da_ativacao` | objeto, ou null | Por que a última validação não ativou a empresa: `codigo` (o do erro de `POST /companies/{id}/validate` — `INSCRICAO_MUNICIPAL_OBRIGATORIA`, `CERTIFICADO_AUSENTE`, `VALIDACAO_REPROVADA`…), `mensagem`, `em`, `cidade` (Cidade/UF, na inscrição municipal) e `checks` (`cnpj_confere`, `dentro_da_validade`, `handshake_govbr`, na validação reprovada). Some quando a empresa é ativada; `null` quando nunca reprovou | | `receita_aviso_regime` | objeto, ou null | A reconferência mensal viu no cadastro da Receita uma mudança de regime que ainda não parou nada: `tipo` (`saiu`, a empresa não é mais optante do Simples; `saida_marcada`, a saída marcada para uma data futura; `deixou_mei`, o MEI que virou ME/EPP), `data` (a da saída, `AAAA-MM-DD`) e `mes` (o do cadastro, `AAAA-MM`). Só avisa: a emissão para quando a saída se confirma na Receita do dia. Some quando a conferência não mostra mais a mudança; `null` quando não há | **Exemplo de resposta** ```json { "aviso": null, "cnpj": "12345678000195", "criado_em": "2026-09-16T18:39:18.763504Z", "email": null, "endereco": { "CEP": "59064902", "cMun": "2408102", "nro": "1", "xBairro": "CENTRO", "xCpl": null, "xLgr": "AV X" }, "id": "cmp_a7ee8f7a44edd30e", "inscricao_municipal": "1234567", "nome_fantasia": null, "pgdas": null, "razao_social": "EMPRESA TESTE ALIQUOTAS LTDA", "receita": null, "receita_consultado_em": null, "regime": { "aliquota_confirmada_para": null, "aliquota_detectada": null, "aliquota_fonte": null, "op_simp_nac": "3", "p_aliq_iss": null, "p_tot_trib_sn": null, "reg_ap_trib_sn": "1", "reg_esp_trib": "0" }, "serie_padrao": "1", "status": "pendente", "sync_opcoes": null, "telefone": null, "tributacao_modo": "auto" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 503 | Serviço externo indisponível ou não configurado | ### Pedir o certificado digital a quem é dono `POST /api/v1/companies/{company_id}/certificado/pedidos` Pede o certificado digital A1 da empresa a quem é dono dela — para a contabilidade e o operador; quem é dono libera direto, pelo painel. O pedido não libera nada: quem é dono recebe o aviso por e-mail e WhatsApp e decide, com o código que chega no e-mail de quem é dono; se liberar, o link vai para o e-mail do acesso de quem pediu. O pedido vence em 7 dias. Com um pedido da mesma pessoa para a mesma empresa ainda aberto, devolve esse pedido, sem aviso novo. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `recado` | string, ou null | O recado a quem é dono (até 500 caracteres; no WhatsApp, até 200 e sem link) | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/certificado/pedidos" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 201** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | O id do pedido (`cpd_…`) | | `company_id` | string **(obrigatório)** | | | `empresa` | string **(obrigatório)** | O nome da empresa | | `email` | string **(obrigatório)** | O e-mail do acesso de quem pediu: se quem é dono liberar, o link vai para ele | | `estado` | um de: `"aberto"`, `"liberado"`, `"recusado"`, `"vencido"` **(obrigatório)** | | | `recado` | string, ou null | | | `criado_em` | string (date-time) **(obrigatório)** | | | `vence_em` | string (date-time) **(obrigatório)** | O pedido vence 7 dias depois de criado | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ## Alíquotas Alíquotas do Simples (ME/EPP): o dossiê da empresa (a alíquota do mês com a conta e a explicação, a próxima, a conferência, os casos relevantes), as declarações PGDAS-D arquivadas como dado (13 PAs na entrada, uma por mês depois, versões) e a consulta paga ao Integra Contador. ### Ver o dossiê das alíquotas do Simples da empresa `GET /api/v1/companies/{company_id}/aliquotas` O dossiê das alíquotas do Simples da empresa: `empresa` (o modo, a autorização e o regime de apuração do ano, com a fonte), `mes` (a alíquota em vigor, a fonte — `pgdas`, `estimada`, `proporcionalizada`, `inicio_atividade` ou `manual` — a conta aberta e a `explicacao` em português, com a base legal), `proxima` (a do mês seguinte, quando o PGDAS-D já permite), `conferencia` (a última: alíquota declarada × aplicada, receita declarada × notas — com as frases prontas para mostrar ao cliente em `receita.frase_titulo`, `frase` e `detalhes` —, retificações, notas com retenção afetadas por uma correção), `payload_divergencia` (notas que chegaram com alíquota própria), `casos` (os casos relevantes, cada um com gravidade `acao` | `atencao` | `info`, título e texto — o que dizer ao cliente), `historico` (mês a mês, mais novo primeiro) e `declaracoes` (as PGDAS-D consultadas; o PDF de cada uma em `/pgdas/declaracoes/{pa}/pdf`). Só leitura — nada aqui consulta o Integra Contador. Vale para empresa compartilhada em qualquer papel. Qualquer papel com acesso à empresa lê, inclusive o leitor e a chave de API de `leitura`: quem vê as notas já vê a receita delas. Confirmar ou editar a alíquota segue com dono, operador e contabilidade. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/aliquotas" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `empresa` | objeto **(obrigatório)** | id, nome, op_simp_nac, tributacao_modo (auto \| manual), pgdas_autorizado, regime_apuracao (caixa \| competencia) com regime_apuracao_fonte (rfb = opção registrada na Receita Federal, consultada no Integra Contador; pgdas = item 1 da declaração do próprio ano; lei = a partir de 2027 só há competência; padrao = nenhuma opção registrada no ano, vale a regra geral, competência), regimes_apuracao (ano → regime, todas as opções efetivadas), regime_consultado_em, regime_apuracao_divergencia (quando a declaração e a opção registrada discordam) e regime_apuracao_ate | | `mes` | objeto **(obrigatório)** | A alíquota em vigor: mes, defasada, p_tot_trib_sn, p_aliq_iss, iss_fora_do_das, fonte (pgdas \| estimada \| proporcionalizada \| inicio_atividade \| manual), conta, rbt12, anexo, faixa, janela, meses_estimados, tabela, explicacao | | `proxima` | objeto, ou null | A do mês seguinte (a_partir_de, p_tot_trib_sn, p_aliq_iss, conta, explicacao) | | `pelo_pgdas_seria` | objeto, ou null | Modo manual: o que a conta pelo PGDAS-D daria para o mês | | `pelo_pgdas` | objeto, ou null | Modo manual: o registro da última conta (mes, atual, proxima, calculada_em) | | `conferencia` | objeto, ou null | A última conferência: pa, mes, aliquota (veredito, declarada, aplicada, hipotese), receita (veredito, declarada, notas, diferenca, pct, avisar — qualquer diferença acima de R$ 1 é alerta —, notas_apos_transmissao, regime_apuracao, rpa_caixa, transmitida_em, frase_titulo + frase + detalhes = o texto pronto para o cliente, doze_meses = notas × RBT12 dos 12 meses quando o histórico de notas cobre a janela), retificados, corrigida, nova, notas_afetadas, explicacao | | `payload_divergencia` | objeto, ou null | Notas do mês que vieram com alíquota própria diferente da calculada | | `casos` | lista de objeto | Os casos relevantes: tipo, gravidade (acao \| atencao \| info), titulo, texto | | `historico` | lista de objeto | A alíquota que valeu em cada mês, com a conta e a conferência (até 24 meses) | | `receita_por_mes` | lista de objeto | O faturamento declarado × as notas, mês a mês (mais novo primeiro; os 13 PAs mais recentes e os meses ainda sem declaração): mes, pa, notas (as ativas) e quantidade, declarada, rpa_caixa, transmitida_em, versao, rbt12, p_tot_trib_sn e p_aliq_iss da declaração, corrigida_na / informada_na (o PA da declaração mais nova de onde veio o valor, quando a do próprio mês foi corrigida depois ou não o trouxe), grupos (no_mes, seguinte e depois — as notas emitidas até o fim do mês, no mês seguinte até a transmissão e depois dela: soma, quantidade, ativas, de, ate), situacao (em_aberto \| sem_notas \| sem_rpa \| bateu \| depois \| abaixo \| acima), atencao (a diferença é 10 % ou mais das notas, nas duas leituras: as do dia da declaração e as ativas de hoje), faltam e pct, fecha + entraram (a combinação de grupos que dá o declarado no centavo; null quando nenhuma dá) e nao_entraram (soma e quantidade) | | `receita_abaixo` | objeto, ou null | Os meses que pedem atenção (meses: mes, pa, notas, declarada, faltam, pct, fecha, nao_entraram), quanto falta neles (faltam) e a alíquota se eles fossem declarados pelas notas (corrigida: mes, meses, p_tot_trib_sn, p_aliq_iss, rbt12 e a atual) — null quando nada muda | | `declaracoes` | lista de objeto | As declarações PGDAS-D arquivadas (resumo; o detalhe está em …/pgdas/declaracoes/{pa}): por PA, a receita do mês por competência (`rpa_competencia`, o faturado — forma a RBT12 e a alíquota) e, no regime de caixa, por caixa (`rpa_caixa`, o recebido — base do DAS) | | `base_legal` | string **(obrigatório)** | A regra da alíquota da nota (Res. CGSN 140/2018, art. 27) | | `meses` | lista de string | Abreviaturas dos meses, para montar rótulos | **Exemplo de resposta** ```json { "base_legal": "Res. CGSN 140/2018, art. 27, I, a: a alíquota de ISS da nota é a efetiva da faixa a que a empresa está sujeita no mês anterior — a receita acumulada nos 12 meses que antecedem o mês anterior", "casos": [ { "gravidade": "atencao", "texto": "Agosto: a receita declarada bate com as notas (R$ (valor)). A empresa é do caixa: o imposto do mês sai do que foi recebido (R$ (valor) declarados); a alíquota vem do que foi faturado nos últimos 12 meses. Últimos 12 meses (08/2025 a 07/2026): as notas somam R$ (valor) e as declarações somam R$ (valor): R$ (valor) a menos (menos de 1 %). É desse total que sai a alíquota; vale perguntar ao contador. O mês que não bate: janeiro/2026 (R$ (valor) a menos).", "tipo": "receita_abaixo", "titulo": "A receita dos últimos 12 meses não bate com as notas" }, { "gravidade": "info", "texto": "A tabela de receitas da declaração mais nova mudou em 08/2025 (R$ (valor) → R$ (valor)), 09/2025 (R$ (valor) → R$ (valor)), 10/2025 (R$ (valor) → R$ (valor)), 11/2025 (R$ (valor) → R$ (valor)), 12/2025 (R$ (valor) → R$ (valor)), 01/2026 (R$ (valor) → R$ (valor)), 02/2026 (R$ (valor) → R$ (valor)), 03/2026 (R$ (valor) → R$ (valor)), 04/2026 (R$ (valor) → R$ (valor)), 05/2026 (R$ (valor) → R$ (valor)), 06/2026 (R$ (valor) → R$ (valor)), 07/2026 (R$ (valor) → R$ (valor)). A RBT12 e a alíquota foram refeitas com a tabela nova.", "tipo": "retificacao", "titulo": "Declaração retificada pelo contador" }, { "gravidade": "info", "texto": "A partir de 1º/10/2026: 13,80 % (ISS 4,48 %). 13,80 % (ISS 4,48 %): RBT12 R$ (valor) = Σ set/25..ago/26 do PGDAS 202608 — Anexo III, 4ª faixa Nada muda nas notas deste mês.", "tipo": "proxima_muda", "titulo": "A alíquota muda em outubro/2026" }, { "gravidade": "info", "texto": "A empresa é do caixa: o imposto do mês sai do que foi recebido. A alíquota, porém, vem do que foi faturado nos últimos 12 meses, nos dois regimes. Vale até dezembro de 2026: em 2027 toda empresa passa para competência.", "tipo": "caixa_ate_dez26", "titulo": "Regime de caixa até dezembro/2026" } ], "conferencia": { "aliquota": { "aplicada": { "p_aliq_iss": "4.50", "p_tot_trib_sn": "13.86" }, "declarada": { "p_aliq_iss": "4.51", "p_tot_trib_sn": "13.87" }, "diferenca_pp": "0.01", "mes_fechado": false, "veredito": "bateu" }, "em": "2026-09-23T01:42:23.682000Z", "explicacao": "A declaração PGDAS-D de 08/2026 confirmou a alíquota de 09/2026: declarada 13,87 % × aplicada 13,86 % (tolerância de 0,01 pp). Agosto: a receita declarada bate com as notas (R$ (valor)). A empresa é do caixa: o imposto do mês sai do que foi recebido (R$ (valor) declarados); a alíquota vem do que foi faturado nos últimos 12 meses. Últimos 12 meses (08/2025 a 07/2026): as notas somam R$ (valor) e as declarações somam R$ (valor): R$ (valor) a menos (menos de 1 %). É desse total que sai a alíquota; vale perguntar ao contador. O mês que não bate: janeiro/2026 (R$ (valor) a menos). PA retificado: 08/2025, 09/2025, 10/2025, 11/2025, 12/2025, 01/2026, 02/2026, 03/2026, 04/2026, 05/2026, 06/2026, 07/2026 — a receita mudou na declaração e a conta foi refeita com a tabela nova.", "mes": "2026-09", "pa": "202608", "receita": { "avisar": true, "base_comparada": "notas_por_competencia", "campo_origem": "rpa_competencia", "canceladas_apos_transmissao": null, "declarada": "34394.37", "detalhes": [ "A empresa é do caixa: o imposto do mês sai do que foi recebido (R$ (valor) declarados); a alíquota vem do que foi faturado nos últimos 12 meses." ], "diferenca": "0.00", "doze_meses": { "assinatura": "2026-01:1000.00", "cobertura": true, "declarada": "618794.01", "diferenca": "370.00", "frase": "Últimos 12 meses (08/2025 a 07/2026): as notas somam R$ (valor) e as declarações somam R$ (valor): R$ (valor) a menos (menos de 1 %). É desse total que sai a alíquota; vale perguntar ao contador. O mês que não bate: janeiro/2026 (R$ (valor) a menos).", "janela": [ "2025-08", "2026-07" ], "meses_divergentes": [ { "declarada": "51566.16", "diferenca": "370.00", "mes": "2026-01", "notas": "51936.16" } ], "notas": "619164.01", "novo": true, "pct": "0", "veredito": "declarada_abaixo_das_notas" }, "frase": "", "frase_titulo": "Agosto: a receita declarada bate com as notas (R$ (valor)).", "mes": "2026-08", "notas": "34394.37", "notas_apos_transmissao": { "quantidade": 0, "soma": "0.00" }, "pa": "202608", "pct": "0", "regime_apuracao": "caixa", "rotulo": "a receita declarada bate com as notas", "rpa_caixa": "64243.51", "transmitida_em": "2026-09-17T19:18:56Z", "veredito": "bateu" }, "retificados": { "2025-08": { "antes": "55239.42", "depois": "51566.16" }, "2025-09": { "antes": "59121.09", "depois": "51566.16" }, "2025-10": { "antes": "49775.79", "depois": "51566.16" }, "2025-11": { "antes": "56314.34", "depois": "51566.16" }, "2025-12": { "antes": "48511.11", "depois": "51566.16" }, "2026-01": { "antes": "45810.35", "depois": "51566.16" }, "2026-02": { "antes": "45257.35", "depois": "51566.16" }, "2026-03": { "antes": "75066.57", "depois": "51566.16" }, "2026-04": { "antes": "49844.95", "depois": "51566.16" }, "2026-05": { "antes": "54580.89", "depois": "51566.16" }, "2026-06": { "antes": "46538.89", "depois": "51566.16" }, "2026-07": { "antes": "32733.26", "depois": "51566.25" } } }, "declaracoes": [ { "anexo": "III", "anexo_confere": true, "consultado_em": "2026-09-23T01:42:23.670000Z", "faixa": 4, "fonte": "sync", "impedido_iss_no_das": false, "meses_retificados": { "2025-08": { "antes": "55239.42", "depois": "51566.16" }, "2025-09": { "antes": "59121.09", "depois": "51566.16" }, "2025-10": { "antes": "49775.79", "depois": "51566.16" }, "2025-11": { "antes": "56314.34", "depois": "51566.16" }, "2025-12": { "antes": "48511.11", "depois": "51566.16" }, "2026-01": { "antes": "45810.35", "depois": "51566.16" }, "2026-02": { "antes": "45257.35", "depois": "51566.16" }, "2026-03": { "antes": "75066.57", "depois": "51566.16" }, "2026-04": { "antes": "49844.95", "depois": "51566.16" }, "2026-05": { "antes": "54580.89", "depois": "51566.16" }, "2026-06": { "antes": "46538.89", "depois": "51566.16" }, "2026-07": { "antes": "32733.26", "depois": "51566.25" } }, "p_aliq_iss": "4.51", "p_tot_trib_sn": "13.87", "pa": "202608", "rbt12": "618794.01", "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "34394.37", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": "III", "anexo_confere": true, "consultado_em": "2026-08-21T00:00:00Z", "faixa": 4, "fonte": "sync", "impedido_iss_no_das": null, "meses_retificados": {}, "p_aliq_iss": null, "p_tot_trib_sn": null, "pa": "202607", "rbt12": "642686.65", "regime_apuracao": "caixa", "retificadora": null, "rpa_caixa": null, "rpa_competencia": "32733.26", "tem_pdf": false, "transmitida_em": null, "versao": "001" } ], "empresa": { "ibs_cbs_no_das": null, "id": "cmp_c71a919fd06d9695", "nome": "EMPRESA TESTE EMISSAO LTDA", "op_simp_nac": "3", "pgdas_autorizado": true, "regime_apuracao": "caixa", "regime_apuracao_ate": "2026-12", "regime_apuracao_divergencia": null, "regime_apuracao_fonte": "pgdas", "regime_consultado_em": "2026-09-23T01:42:23.511000Z", "regimes_apuracao": {}, "tributacao_modo": "auto" }, "historico": [ { "anexo": "III", "anterior": null, "calculada_em": "2026-09-23T01:42:23.521000Z", "conferencia": { "aliquota": "bateu", "corrigida": false, "em": "2026-09-23T01:42:23.682000Z", "pa": "202608", "receita": "bateu", "receita_pct": "0", "retificados": [ "2025-08", "2025-09", "2025-10", "2025-11", "2025-12", "2026-01", "2026-02", "2026-03", "2026-04", "2026-05", "2026-06", "2026-07" ] }, "conta": "13,86 % (ISS 4,50 %): RBT12 R$ (valor) = Σ ago/25..jul/26 do PGDAS 202607 — Anexo III, 4ª faixa", "corrigida": false, "faixa": 4, "fonte": "pgdas", "iss_fora_do_das": false, "janela": [ "2025-08", "2026-07" ], "mes": "2026-09", "meses_estimados": [], "p_aliq_iss": "4.50", "p_tot_trib_sn": "13.86", "rbt12": "618794.01", "tabela": "2018" } ], "mes": { "anexo": "III", "calculada_em": "2026-09-23T01:42:23.521000Z", "conta": "13,86 % (ISS 4,50 %): RBT12 R$ (valor) = Σ ago/25..jul/26 do PGDAS 202607 — Anexo III, 4ª faixa", "defasada": false, "explicacao": "A alíquota de setembro/2026 é 13,86 % (ISS 4,50 %) porque a receita acumulada de ago/25 a jul/26, por competência, foi R$ (valor) — 4ª faixa do Anexo III: (16.00 % × RBT12 − R$ (valor)) ÷ RBT12, truncada a duas casas. Res. CGSN 140/2018, art. 27, I, a: a alíquota de ISS da nota é a efetiva da faixa a que a empresa está sujeita no mês anterior — a receita acumulada nos 12 meses que antecedem o mês anterior.", "faixa": 4, "fonte": "pgdas", "iss_fora_do_das": false, "janela": [ "2025-08", "2026-07" ], "mes": "2026-09", "meses_estimados": [], "p_aliq_iss": "4.50", "p_tot_trib_sn": "13.86", "rbt12": "618794.01", "tabela": "2018" }, "meses": [ "jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez" ], "payload_divergencia": null, "pelo_pgdas": null, "pelo_pgdas_seria": null, "proxima": { "a_partir_de": "2026-10", "anexo": "III", "calculada_em": "2026-09-23T01:42:23.682000Z", "conta": "13,80 % (ISS 4,48 %): RBT12 R$ (valor) = Σ set/25..ago/26 do PGDAS 202608 — Anexo III, 4ª faixa", "explicacao": "A partir de 1º/10/2026: 13,80 % (ISS 4,48 %). 13,80 % (ISS 4,48 %): RBT12 R$ (valor) = Σ set/25..ago/26 do PGDAS 202608 — Anexo III, 4ª faixa Nada muda nas notas deste mês.", "faixa": 4, "fonte": "pgdas", "iss_fora_do_das": false, "janela": [ "2025-09", "2026-08" ], "mes": "2026-10", "meses_estimados": [], "p_aliq_iss": "4.48", "p_tot_trib_sn": "13.80", "proporcional": false, "rbt12": "601622.22", "tabela": "2018" } } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Listar as declarações PGDAS-D arquivadas `GET /api/v1/companies/{company_id}/pgdas/declaracoes` As declarações PGDAS-D arquivadas da empresa — TODAS as versões, da mais nova para a mais antiga (o histórico de entrada traz 13 PAs; cada mês novo entra pelo dia 21; retificadora = versão nova do mesmo PA, a anterior fica). Cada item: PA, versão (001 = original), nº da declaração, regime de apuração, receita do PA por competência e por caixa, RBT12 (e RBT12p/RBA/RBAA), efetiva total e ISS declaradas, anexo/faixa inferidos, meses retificados apontados pela tabela 2.2, transmissão, se o PDF está arquivado. O detalhe de cada uma (tabela mensal de receitas, atividades) sai em `…/declaracoes/{pa}`. Qualquer papel com acesso à empresa lê, inclusive o leitor e a chave de API de `leitura`: quem vê as notas já vê a receita delas. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/pgdas/declaracoes" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `pa` | string **(obrigatório)** | Período de apuração, `AAAAMM` | | `versao` | string **(obrigatório)** | `001` = original; `002`+ = retificadora (os 3 últimos dígitos do nº da declaração) | | `numero_declaracao` | string, ou null | Nº da declaração no PGDAS-D | | `retificadora` | boolean, ou null | True quando a declaração se diz retificadora | | `regime_apuracao` | string, ou null | `caixa` ou `competencia` (seção 1 do PDF) | | `data_abertura` | string, ou null | Data de abertura no CNPJ (`AAAA-MM-DD`) | | `impedido_iss_no_das` | boolean, ou null | Impedida de recolher ICMS/ISS no DAS (sublimite estourado — seção 2.7) | | `rpa_competencia` | string, ou null | Receita bruta do PA por competência (R$) — o faturado no mês; é ela que forma a RBT12 e a alíquota, nos dois regimes | | `rpa_caixa` | string, ou null | Receita bruta do PA por caixa (R$) — o recebido no mês, base do DAS no regime de caixa; `null` na empresa de competência | | `rbt12` | string, ou null | Receita bruta dos 12 meses anteriores ao PA, do mercado interno (R$) | | `rbt12p` | string, ou null | RBT12 proporcionalizada (início de atividade), do mercado interno, quando houver | | `rba` | string, ou null | Receita bruta acumulada no ano corrente, do mercado interno (R$) | | `rbaa` | string, ou null | Receita bruta acumulada no ano anterior, do mercado interno (R$) | | `p_tot_trib_sn` | string, ou null | Efetiva total declarada (%) — débito ÷ base da seção 2.7 | | `p_aliq_iss` | string, ou null | ISS efetivo declarado (%) | | `iss_retido_no_pa` | boolean, ou null | Toda a receita do PA teve ISS retido (ISS zerado no DAS) | | `anexo` | string, ou null | Anexo do Simples que reproduz a efetiva declarada (III, IV ou V) | | `faixa` | integer, ou null | Faixa (1–6) da RBT12 nesse anexo | | `anexo_confere` | boolean, ou null | A efetiva total E o ISS declarados saem da tabela com a RBT12 declarada | | `anexo_ambiguo` | boolean, ou null | III e V empatam (6ª faixa) — anexo indeterminado por este PDF | | `efetiva_motivo` | string, ou null | Por que a efetiva total não saiu desta declaração: `mais_de_um_anexo` (atividades de anexos diferentes — a soma não bate com anexo nenhum; a de cada anexo está em `por_anexo`, no detalhe) ou `leiaute` (a seção 2.7 não foi lida, ver `falhas_leitura`) | | `fator_r_declarado` | string, ou null | Seção 2.4: o fator r que a declaração traz (`0.31` = 31 %), só quando há atividade sujeita ao fator r declarada; com 0,28 ou mais, essa atividade fica no Anexo III, abaixo, no V | | `fator_r_motivo` | string, ou null | Por que `fator_r_declarado` é nulo: `nao_se_aplica` (a 2.4 diz "Não se aplica" — nenhuma atividade sujeita ao fator r declarada), `ilegivel` (formato desconhecido: o número não é lido) ou `ausente` | | `cpp_declarada` | string, ou null | Seção 2.8 (Total Geral da Empresa, Total do Débito Declarado), coluna INSS/CPP: a contribuição patronal paga dentro do DAS no PA (R$) — conta como folha no fator r | | `falhas_leitura` | lista de string | Seções que a leitura não reconheceu, por código (`identificacao` = 1 (o período de apuração); `receitas_2_1` = 2.1 (o discriminativo de receitas: RPA, RBT12, RBA); `receitas_2_2` = 2.2 (as receitas brutas anteriores, mês a mês); `folha_2_3` = 2.3 (a folha de salários, mês a mês); `fator_r_2_4` = 2.4 (o fator r); `impedimento_2_7` = 2.7 (o impedimento de recolher o ISS no DAS); `atividades_2_7` = 2.7 (as atividades e os débitos por tributo); `total_2_8` = 2.8 (o total geral da empresa: a CPP); `leitura` = a leitura parou no meio (erro do leitor)). O número dessas seções fica nulo, nunca errado, e a operação do GereNota é avisada; com uma seção da conta (1, 2.1, 2.2, o impedimento ou as atividades da 2.7), esta declaração não muda a alíquota | | `meses_retificados` | objeto | Meses cuja receita mudou em relação ao histórico anterior (`AAAA-MM` → {antes, depois}) — PA retificado | | `transmitida_em` | string (date-time), ou null | Data e hora da transmissão (seção 3), em UTC | | `consultado_em` | string (date-time), ou null | Quando a plataforma consultou/arquivou | | `fonte` | string, ou null | `sync` (consulta) · `backfill_s3` / `historico_s3` (texto já arquivado) | | `tem_pdf` | boolean | O PDF está arquivado (`…/declaracoes/{pa}/pdf`) Padrão: `false`. | **Exemplo de resposta** ```json [ { "anexo": "III", "anexo_ambiguo": null, "anexo_confere": true, "consultado_em": "2026-08-21T00:00:00Z", "data_abertura": "2019-05-20", "faixa": 4, "fonte": "sync", "impedido_iss_no_das": null, "iss_retido_no_pa": null, "meses_retificados": {}, "numero_declaracao": null, "p_aliq_iss": null, "p_tot_trib_sn": null, "pa": "202608", "rba": null, "rbaa": null, "rbt12": "618794.01", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": null, "rpa_caixa": null, "rpa_competencia": "34394.37", "tem_pdf": false, "transmitida_em": null, "versao": "001" }, { "anexo": "III", "anexo_ambiguo": false, "anexo_confere": true, "consultado_em": "2026-09-22T19:14:53.449000Z", "data_abertura": "2019-05-20", "faixa": 4, "fonte": "historico_s3", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202607001", "p_aliq_iss": "4.51", "p_tot_trib_sn": "13.87", "pa": "202607", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "618794.01", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "32733.26", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": "III", "anexo_ambiguo": false, "anexo_confere": true, "consultado_em": "2026-09-22T19:14:53.463000Z", "data_abertura": "2019-05-20", "faixa": 4, "fonte": "historico_s3", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202606001", "p_aliq_iss": "4.51", "p_tot_trib_sn": "13.87", "pa": "202606", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "618794.01", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "46538.89", "tem_pdf": false, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:53.567000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202605001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202605", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:53.686000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202604001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202604", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:53.913000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202602001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202602", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:54.030000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202601001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202601", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:54.169000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202512001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202512", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:54.287000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202511001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202511", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:54.409000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202510001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202510", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:54.526000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202509001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202509", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, { "anexo": null, "anexo_ambiguo": false, "anexo_confere": null, "consultado_em": "2026-09-22T19:14:54.647000Z", "data_abertura": "2019-05-20", "faixa": null, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202508001", "p_aliq_iss": "4.20", "p_tot_trib_sn": "13.00", "pa": "202508", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "370000.00", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "3700.00", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Ver uma declaração PGDAS-D como dado `GET /api/v1/companies/{company_id}/pgdas/declaracoes/{pa}` UMA declaração PGDAS-D como dado (`pa` = `AAAAMM`; `versao` omitida = a mais recente): tudo da lista mais `receitas_mensais` (a tabela 2.2 — receita por competência de cada mês desde janeiro do ano anterior; é dela que sai a RBT12 de qualquer mês), `atividades` (seção 2.7: receita e débitos por atividade, o que dá a efetiva), `versoes` (todas as versões do PA) e `pdf` (o caminho do PDF arquivado). 404 `DECLARACAO_NAO_ENCONTRADA` quando o PA não está no histórico — `POST …/pgdas/sync` com `pa` e `forcar=true` consulta esse PA (R$ 0,24). Qualquer papel com acesso à empresa lê, inclusive o leitor e a chave de API de `leitura`: quem vê as notas já vê a receita delas. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `pa` | path | string **(obrigatório)** | Período de apuração, `AAAAMM` | | `versao` | query | string, ou null | Versão (`001`, `002`…); omitida = a mais recente | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/pgdas/declaracoes/{pa}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `pa` | string **(obrigatório)** | Período de apuração, `AAAAMM` | | `versao` | string **(obrigatório)** | `001` = original; `002`+ = retificadora (os 3 últimos dígitos do nº da declaração) | | `numero_declaracao` | string, ou null | Nº da declaração no PGDAS-D | | `retificadora` | boolean, ou null | True quando a declaração se diz retificadora | | `regime_apuracao` | string, ou null | `caixa` ou `competencia` (seção 1 do PDF) | | `data_abertura` | string, ou null | Data de abertura no CNPJ (`AAAA-MM-DD`) | | `impedido_iss_no_das` | boolean, ou null | Impedida de recolher ICMS/ISS no DAS (sublimite estourado — seção 2.7) | | `rpa_competencia` | string, ou null | Receita bruta do PA por competência (R$) — o faturado no mês; é ela que forma a RBT12 e a alíquota, nos dois regimes | | `rpa_caixa` | string, ou null | Receita bruta do PA por caixa (R$) — o recebido no mês, base do DAS no regime de caixa; `null` na empresa de competência | | `rbt12` | string, ou null | Receita bruta dos 12 meses anteriores ao PA, do mercado interno (R$) | | `rbt12p` | string, ou null | RBT12 proporcionalizada (início de atividade), do mercado interno, quando houver | | `rba` | string, ou null | Receita bruta acumulada no ano corrente, do mercado interno (R$) | | `rbaa` | string, ou null | Receita bruta acumulada no ano anterior, do mercado interno (R$) | | `p_tot_trib_sn` | string, ou null | Efetiva total declarada (%) — débito ÷ base da seção 2.7 | | `p_aliq_iss` | string, ou null | ISS efetivo declarado (%) | | `iss_retido_no_pa` | boolean, ou null | Toda a receita do PA teve ISS retido (ISS zerado no DAS) | | `anexo` | string, ou null | Anexo do Simples que reproduz a efetiva declarada (III, IV ou V) | | `faixa` | integer, ou null | Faixa (1–6) da RBT12 nesse anexo | | `anexo_confere` | boolean, ou null | A efetiva total E o ISS declarados saem da tabela com a RBT12 declarada | | `anexo_ambiguo` | boolean, ou null | III e V empatam (6ª faixa) — anexo indeterminado por este PDF | | `efetiva_motivo` | string, ou null | Por que a efetiva total não saiu desta declaração: `mais_de_um_anexo` (atividades de anexos diferentes — a soma não bate com anexo nenhum; a de cada anexo está em `por_anexo`, no detalhe) ou `leiaute` (a seção 2.7 não foi lida, ver `falhas_leitura`) | | `fator_r_declarado` | string, ou null | Seção 2.4: o fator r que a declaração traz (`0.31` = 31 %), só quando há atividade sujeita ao fator r declarada; com 0,28 ou mais, essa atividade fica no Anexo III, abaixo, no V | | `fator_r_motivo` | string, ou null | Por que `fator_r_declarado` é nulo: `nao_se_aplica` (a 2.4 diz "Não se aplica" — nenhuma atividade sujeita ao fator r declarada), `ilegivel` (formato desconhecido: o número não é lido) ou `ausente` | | `cpp_declarada` | string, ou null | Seção 2.8 (Total Geral da Empresa, Total do Débito Declarado), coluna INSS/CPP: a contribuição patronal paga dentro do DAS no PA (R$) — conta como folha no fator r | | `falhas_leitura` | lista de string | Seções que a leitura não reconheceu, por código (`identificacao` = 1 (o período de apuração); `receitas_2_1` = 2.1 (o discriminativo de receitas: RPA, RBT12, RBA); `receitas_2_2` = 2.2 (as receitas brutas anteriores, mês a mês); `folha_2_3` = 2.3 (a folha de salários, mês a mês); `fator_r_2_4` = 2.4 (o fator r); `impedimento_2_7` = 2.7 (o impedimento de recolher o ISS no DAS); `atividades_2_7` = 2.7 (as atividades e os débitos por tributo); `total_2_8` = 2.8 (o total geral da empresa: a CPP); `leitura` = a leitura parou no meio (erro do leitor)). O número dessas seções fica nulo, nunca errado, e a operação do GereNota é avisada; com uma seção da conta (1, 2.1, 2.2, o impedimento ou as atividades da 2.7), esta declaração não muda a alíquota | | `meses_retificados` | objeto | Meses cuja receita mudou em relação ao histórico anterior (`AAAA-MM` → {antes, depois}) — PA retificado | | `transmitida_em` | string (date-time), ou null | Data e hora da transmissão (seção 3), em UTC | | `consultado_em` | string (date-time), ou null | Quando a plataforma consultou/arquivou | | `fonte` | string, ou null | `sync` (consulta) · `backfill_s3` / `historico_s3` (texto já arquivado) | | `tem_pdf` | boolean | O PDF está arquivado (`…/declaracoes/{pa}/pdf`) Padrão: `false`. | | `receitas_mensais` | objeto | Seção 2.2: receita por competência de cada mês desde janeiro do ano anterior até M−1 (`AAAA-MM` → R$) | | `folhas_mensais` | objeto | Seção 2.3: a folha de salários de cada mês dos 12 anteriores ao PA (`AAAA-MM` → R$), só quando há atividade sujeita ao fator r declarada (senão a declaração diz "Nenhuma" e vem vazio) | | `total_geral` | objeto | Seção 2.8: o total do débito declarado da empresa por tributo (R$), pelo nome da coluna, como em `atividades[].tributos` | | `por_anexo` | objeto | As atividades da 2.7 separadas por anexo (`III`, `IV`, `V`): `atividades` (quantas), `receita`, `debitos` por tributo, `p_tot_trib_sn` e `p_aliq_iss` do grupo, `iss_retido_no_pa`, `faixa` e `confere` (a efetiva do grupo sai da tabela desse anexo com a RBT12 declarada) | | `atividades` | lista de objeto AtividadeOut | Seção 2.7: por atividade, a receita informada, os débitos por tributo e a classe | | `atividades.descricao` | string **(obrigatório)** | A atividade como o PGDAS-D a descreve | | `atividades.receita` | string **(obrigatório)** | Receita informada na atividade (R$) | | `atividades.iss` | string, ou null | ISS devido na atividade (R$); nulo quando a tabela de débitos não foi lida | | `atividades.total` | string, ou null | Total dos débitos da atividade (R$); nulo quando a tabela de débitos não foi lida | | `atividades.tributos` | objeto | Os débitos da atividade por tributo (R$), pelo nome da coluna do PGDAS-D: `irpj`, `csll`, `cofins`, `pis`, `cpp` (INSS/CPP), `icms`, `ipi`, `iss` e `total`; a partir de 2027, `cbs` e `ibs` no lugar de `cofins` e `pis`. Vazio nas declarações lidas antes de 12/10/2026 | | `atividades.classe` | string, ou null | A atividade pela descrição do PGDAS-D: `fator_r` (sujeita ao fator r — Anexo III ou V), `anexo_iii` (não sujeita, tributada pelo Anexo III), `anexo_iv`, `contabil_iss_fixo` (escritório contábil com ISS em valor fixo), `construcao_anexo_iii`/`construcao_anexo_iv` (7.02 e 7.05), `transporte_municipal` (16.01), `locacao_bens_moveis`; nulo para as demais (comércio, indústria) e nas declarações lidas antes de 12/10/2026 | | `atividades.c_atv_sn` | string, ou null | O código da atividade no catálogo do Simples de 2027 (`cAtvSN` da NT 009): `07` só Anexo III, `08` contábil com ISS fixo, `09` sujeita ao fator r, `10` transporte municipal, `11` locação de bens móveis, `12`/`13` construção (III/IV), `14` Anexo IV; nulo para o exterior e para as classes sem código | | `atividades.anexo` | string, ou null | O anexo da atividade (III, IV ou V); na sujeita ao fator r, pelo fator r da 2.4 (0,28 ou mais, III); nulo quando não dá para saber | | `atividades.retencao_iss` | boolean, ou null | Com (true) ou sem (false) retenção/substituição tributária de ISS | | `atividades.iss_devido_a` | string, ou null | Sem retenção, a quem o ISS é devido: `proprio` (o município do estabelecimento) ou `outro` (outro município) | | `atividades.exterior` | boolean, ou null | Prestação de serviços para o exterior (exportação) | | `versoes` | lista de objeto VersaoDeclaracaoOut | Todas as versões deste PA, da mais nova para a mais antiga | | `versoes.versao` | string, ou null | `001` = original; `002`+ = retificadora | | `versoes.numero_declaracao` | string, ou null | Nº da declaração no PGDAS-D | | `versoes.retificadora` | boolean, ou null | True quando a declaração se diz retificadora | | `versoes.transmitida_em` | string (date-time), ou null | Transmissão (seção 3), em UTC | | `versoes.consultado_em` | string (date-time), ou null | Quando a plataforma a arquivou | | `versoes.tem_pdf` | boolean | O PDF desta versão está arquivado Padrão: `false`. | | `pdf` | string, ou null | Caminho do PDF arquivado desta versão, quando houver | **Exemplo de resposta** ```json { "anexo": "III", "anexo_ambiguo": false, "anexo_confere": true, "atividades": [ { "descricao": "Prestação de Serviços, exceto para o exterior - Não sujeitos ao fator “r” e tributados pelo Anexo III, sem retenção/substituição tributária de ISS, com ISS devido ao próprio Município do estabelecimento", "iss": "2062.43", "receita": "45756.47", "total": "6345.94" }, { "descricao": "Prestação de Serviços, exceto para o exterior - Não sujeitos ao fator “r” e tributados pelo Anexo III, com retenção/substituição tributária de ISS", "iss": "0.00", "receita": "18487.04", "total": "1730.67" } ], "consultado_em": "2026-09-22T19:14:53.449000Z", "data_abertura": "2019-05-20", "faixa": 4, "fonte": "historico_s3", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202607001", "p_aliq_iss": "4.51", "p_tot_trib_sn": "13.87", "pa": "202607", "pdf": "/api/v1/companies/cmp_3b50e1e07a2e1cbe/pgdas/declaracoes/202607/pdf?versao=001", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "618794.01", "rbt12p": null, "receitas_mensais": { "2025-01": "49272.72", "2025-02": "57480.75", "2025-03": "60995.57", "2025-04": "54043.34", "2025-05": "53693.34", "2025-06": "57932.91", "2025-07": "56625.90", "2025-08": "55239.42", "2025-09": "59121.09", "2025-10": "49775.79", "2025-11": "56314.34", "2025-12": "48511.11", "2026-01": "45810.35", "2026-02": "45257.35", "2026-03": "75066.57", "2026-04": "49844.95", "2026-05": "54580.89", "2026-06": "46538.89" }, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "32733.26", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001", "versoes": [ { "consultado_em": "2026-09-22T19:14:53.449000Z", "numero_declaracao": "11111111202607001", "retificadora": false, "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" } ] } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Baixar o PDF arquivado de uma declaração PGDAS-D `GET /api/v1/companies/{company_id}/pgdas/declaracoes/{pa}/pdf` O PDF arquivado da declaração PGDAS-D do PA (`AAAAMM`; `versao` omitida = a mais recente), servido pela própria API (`application/pdf`, `Content-Disposition: inline`) — como o DANFSE, sem link do S3: o painel baixa com o token. 404 quando a declaração não foi consultada ou não tem PDF (consultas anteriores ao arquivamento). A empresa precisa estar no recorte de quem chama. Qualquer papel com acesso à empresa lê, inclusive o leitor e a chave de API de `leitura`: quem vê as notas já vê a receita delas. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `pa` | path | string **(obrigatório)** | Período de apuração, `AAAAMM` | | `versao` | query | string, ou null | Versão (`001`, `002`…); omitida = a mais recente | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/pgdas/declaracoes/{pa}/pdf" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -o declaracao.pdf ``` **Resposta 200** — O PDF da declaração (`application/pdf`) **Exemplo de resposta** ```json { "_binario": "application/pdf", "_bytes": 11 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | | 503 | Serviço externo indisponível ou não configurado | ### Consultar a declaração PGDAS-D no Integra Contador (paga) `POST /api/v1/companies/{company_id}/pgdas/sync` Consulta a declaração PGDAS-D no Integra Contador (paga) e absorve o resultado: a declaração inteira (regime de apuração, receita do PA por competência e por caixa, RBT12, RBA, a tabela de receitas mensais, a data de transmissão) entra no histórico da empresa com o PDF arquivado; a alíquota do mês é recalculada (só entra se o mês ainda não tinha) e a `proxima` anunciada; a declaração é conferida contra o mês que ela prova. `pa` pede um PA só (uma consulta); sem ele, a ordem do calendário. **PAs antigos:** cada declaração consultada fica no histórico (`GET …/pgdas/declaracoes`). Na autorização a plataforma busca sozinha, em segundo plano (poucos minutos), os 13 PAs a partir da declaração mais recente (ela + os 12 meses que formam a RBT12 dela; empresa mais nova, desde a abertura) — uma consulta paga por PA, R$ 0,24, contada e não repassada. Para um PA específico fora disso, chame com `pa` (`AAAAMM`) e `forcar=true`: uma consulta, a declaração entra no histórico e, se for mais antiga que a atual, a alíquota e a ficha da empresa não mudam. O `aceite` (termo assinado em nome da empresa) é ato do dono — 403 `ACEITE_SO_DO_DONO` para os demais papéis; a empresa precisa estar no recorte de quem chama (403 `EMPRESA_FORA_DO_RECORTE`). Chave de API com escopo `emissao` (papel operador/contabilidade); a de `leitura` recebe 403 — consultar é operação fiscal (e paga). Custo: cada PA consultado é uma requisição paga; pela API há um teto diário por empresa (429 `TETO_DIARIO_PGDAS`, 3 consultas) — o histórico entra sozinho, em segundo plano. Quando as consultas pagas da plataforma param até a virada do dia, a resposta é 503 `PGDAS_PAUSADO`; a alíquota do mês não muda. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `aceite` | boolean | Consentimento explícito na 1ª sincronização — o termo assinado é o instrumento. Só o dono da conta. Padrão: `false`. | | `forcar` | boolean | Ignora o cache mensal (a consulta é PAGA — R$ 0,24 por PA pedido) Padrão: `false`. | | `pa` | string, ou null | Só este PA (`AAAAMM`) — uma consulta paga. Omitido: M−1, M−2 e M−3 na ordem do calendário (antes do dia 21, M−2 primeiro), parando na primeira declaração encontrada | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/pgdas/sync" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"aceite": true}' ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `periodo_apuracao` | string, ou null | PA (período de apuração, `AAAAMM`) da declaração mais recente da empresa | | `p_tot_trib_sn` | string, ou null | Efetiva total declarada nesse PA (%) | | `p_aliq_iss` | string, ou null | ISS efetivo declarado nesse PA (%) | | `regime_apuracao` | string, ou null | `caixa` ou `competencia` — o regime do ANO CORRENTE (o de cada declaração está em `declaracao.regime_apuracao`); ver `regime_apuracao_fonte` | | `regime_apuracao_fonte` | string, ou null | De onde vem `regime_apuracao`: `rfb` = opção registrada na Receita Federal (Integra Contador, REGIMEAPURACAO); `pgdas` = item 1 da última declaração, do próprio ano; `padrao` = consultado e sem opção registrada (competência, a regra geral); `lei` = a partir de 2027 só há competência | | `regimes_apuracao` | objeto, ou null | Opções registradas na Receita Federal, ano → `caixa` \| `competencia` | | `regime_consultado_em` | string (date-time), ou null | Última consulta à Receita (REGIMEAPURACAO) | | `regime_apuracao_divergencia` | objeto, ou null | Quando a declaração e a opção registrada discordam no mesmo ano: {ano, pa, rfb, declaracao} | | `rbt12` | string, ou null | RBT12 declarada nesse PA (R$) | | `consultado_em` | string (date-time), ou null | Quando a consulta foi feita | | `fonte` | string **(obrigatório)** | `pgdas` (consultou agora) ou `cache` (já consultado neste mês, sem nova consulta) | | `aliquota` | objeto, ou null | O que a conta deu: `atual` (a alíquota do mês, aplicada ou não), `proxima`, `aplicada`, `mudou_atual` | | `conferencia` | objeto, ou null | A conferência da declaração contra o mês que ela prova: aliquota (veredito), receita (veredito, declarada, notas, diferenca, avisar e as frases prontas frase_titulo + frase + detalhes; doze_meses quando o histórico de notas cobre a janela), retificados | | `principal` | boolean, ou null | False quando a declaração consultada é mais antiga que a atual (só histórico) | | `pa_consultado` | string, ou null | O PA que esta chamada consultou ou devolveu (`AAAAMM`) | | `declaracao` | objeto DeclaracaoPgdasOut, ou null | A declaração do PA consultado, como no histórico; se for mais antiga que a mais recente da empresa, a ficha e a alíquota não mudam | **Exemplo de resposta** ```json { "aliquota": { "aplicada": true, "atual": { "anexo": "III", "conta": "13,86 % (ISS 4,50 %): RBT12 R$ (valor) = Σ ago/25..jul/26 do PGDAS 202608 — Anexo III, 4ª faixa", "faixa": 4, "fonte": "pgdas", "iss_fora_do_das": false, "janela": [ "2025-08", "2026-07" ], "mes": "2026-09", "meses_estimados": [], "p_aliq_iss": "4.50", "p_tot_trib_sn": "13.86", "proporcional": false, "rbt12": "618794.01", "tabela": "2018" }, "legado": false, "manual": false, "mudou_atual": true, "mudou_proxima": true, "proxima": { "anexo": "III", "conta": "13,79 % (ISS 4,48 %): RBT12 R$ (valor) = Σ set/25..ago/26 do PGDAS 202608 — Anexo III, 4ª faixa", "faixa": 4, "fonte": "pgdas", "iss_fora_do_das": false, "janela": [ "2025-09", "2026-08" ], "mes": "2026-10", "meses_estimados": [], "p_aliq_iss": "4.48", "p_tot_trib_sn": "13.79", "proporcional": false, "rbt12": "597948.96", "tabela": "2018" } }, "anexo": "III", "anexo_confere": true, "autorizado_em": "2026-09-23T01:42:26.679000Z", "conferencia": { "aliquota": { "veredito": "sem_aliquota" }, "em": "2026-09-23T01:42:26.801972Z", "mes": "2026-09", "pa": "202608", "receita": { "avisar": false, "base_comparada": "notas_por_competencia", "campo_origem": "rpa_competencia", "declarada": "34394.37", "detalhes": [], "doze_meses": { "cobertura": false, "janela": [ "2025-08", "2026-07" ], "sem_notas": [ "2025-08", "2025-09", "2025-10", "2025-11", "2025-12", "2026-01", "2026-02", "2026-03", "2026-04", "2026-05", "2026-06", "2026-07" ] }, "frase": "O PGDAS-D declarou R$ (valor)", "frase_titulo": "Agosto: não há nota desse mês no GereNota para comparar.", "mes": "2026-08", "motivo": "nenhuma nota ativa do mês no GereNota — nada a comparar", "notas": "0.00", "notas_apos_transmissao": { "quantidade": 0, "soma": "0.00" }, "pa": "202608", "regime_apuracao": "caixa", "rotulo": "sem nota no GereNota para comparar", "rpa_caixa": "64243.51", "transmitida_em": "2026-09-17T19:18:56Z", "veredito": "sem_notas" }, "retificados": {} }, "consultado_em": "2026-09-23T01:42:26.821000Z", "declaracao": { "anexo": "III", "anexo_ambiguo": false, "anexo_confere": true, "consultado_em": "2026-09-23T01:42:26.790881Z", "data_abertura": "2019-05-20", "faixa": 4, "fonte": "sync", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "meses_retificados": {}, "numero_declaracao": "11111111202608001", "p_aliq_iss": "4.51", "p_tot_trib_sn": "13.87", "pa": "202608", "rba": "384226.63", "rbaa": "659006.28", "rbt12": "618794.01", "rbt12p": null, "regime_apuracao": "caixa", "retificadora": false, "rpa_caixa": "64243.51", "rpa_competencia": "34394.37", "tem_pdf": true, "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" }, "faixa": 4, "fonte": "pgdas", "impedido_iss_no_das": false, "iss_retido_no_pa": false, "numero_declaracao": "11111111202608001", "p_aliq_iss": "4.51", "p_tot_trib_sn": "13.87", "pa_consultado": "202608", "periodo_apuracao": "202608", "principal": true, "rba": "384226.63", "rbaa": "659006.28", "rbt12": "618794.01", "rbt12p": null, "regime_apuracao": "caixa", "regime_apuracao_divergencia": null, "regime_apuracao_fonte": "rfb", "regime_consultado_em": "2026-09-23T01:42:26.848000Z", "regimes_apuracao": { "2021": "competencia", "2025": "caixa", "2026": "caixa" }, "rpa_caixa": "64243.51", "rpa_competencia": "34394.37", "transmitida_em": "2026-09-17T19:18:56Z", "versao": "001" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | | 503 | Serviço externo indisponível ou não configurado | ## Notas Emitir (teste ou valendo), listar, consultar, XML, PDF (DANFSE) e envio por e-mail. ### Emitir uma nota (teste ou valendo) `POST /api/v1/companies/{company_id}/nfse` Emite uma NFS-e pelo Sistema Nacional (gov.br) em nome da empresa `company_id`. O corpo é a DPS: a competência (`dCompet`, AAAA-MM-DD, nunca futura), o serviço (`servico.cTribNac` com 6 dígitos e a descrição) e os valores como **string decimal** (`valores.vServ`, ex.: `"1500.00"`). O tomador é opcional. Não mande série, número, alíquota nem regime: tudo isso sai do cadastro da empresa. Com `"ambiente": "teste"` a nota é validada no ambiente restrito do gov.br sem efeito fiscal — não consome cota, não aparece nas listagens e é descartada em 24 h. **Tomador só com o CNPJ** (`{"tipo": "CNPJ", "documento": "…"}`, sem `nome`): a emissão usa o cadastro da conta; se o CNPJ é novo, busca na Receita — pelo cadastro mensal (os Dados Abertos do CNPJ), sem custo e sem cota, ou, quando o CNPJ ainda não está nele, pela consulta em tempo real, que gasta uma unidade da cota mensal do plano —, cadastra o cliente com a razão social e o endereço e emite com eles. O e-mail da Receita não vira o de entrega. Com acesso a só algumas empresas (membro recortado ou empresa compartilhada), o cliente cadastrado fora do seu acesso também sai pela Receita, com a mesma regra de custo: a nota leva a razão social e o endereço da Receita e o que vier no pedido — nunca o e-mail, o telefone, a inscrição ou o endereço do cadastro —, e o pedido não altera o cadastro. Quando a busca não sai (402 `COTA_CONSULTAS_ESGOTADA`, 429, 503) ou a Receita não conhece o CNPJ (422 `CNPJ_NAO_ENCONTRADO_NA_RECEITA`), nada é emitido: mande o `nome` do tomador. Mande sempre um `Idempotency-Key` (um texto único seu por pedido): repetir a chamada com a mesma chave devolve a MESMA nota (cabeçalho `X-Idempotent-Replay: true`), e uma segunda chamada enquanto a primeira ainda corre recebe 409 `EMISSAO_EM_ANDAMENTO`. Se o gov.br não responder a tempo e a nota não puder ser confirmada, a resposta é 503 `EMISSAO_INCERTA` e a chave fica guardada: repita com ela — a repetição confere a nota antes de emitir e nunca gera duas. Exige chave com escopo `emissao`. **Avisos que não impedem a nota** (`avisos` na resposta): a nota sai, e o aviso diz o que conferir. Hoje, `RETENCAO_COM_TOMADOR_DE_OUTRO_MUNICIPIO`: o ISS retido por um tomador de fora do município em que o ISS é devido — a retenção só vale com o tomador no município do ISS (LC 116, arts. 3º e 6º; LC 123, art. 21, § 4º), salvo nos subitens em que a LC 116 faz a pessoa jurídica tomadora responsável onde quer que ela esteja (art. 6º, § 2º, II). Quando o gov.br rejeita, a resposta é 422 com o `code` do erro oficial (`E0160`, `E0625`…) e o detalhe em `erros`; as validações da plataforma chegam antes, com códigos próprios: a competência e os valores (`COMPETENCIA_FUTURA`, `VALOR_OBRIGATORIO`, `DESCONTO_MAIOR_QUE_O_SERVICO`, `DPS_XSD_INVALIDA`), a alíquota (`ALIQUOTA_NAO_CONFIRMADA`, `ALIQUOTA_SEM_RETENCAO`, `ALIQUOTA_ISS_DO_MES_AUSENTE`), a retenção (`RETENCAO_SEM_TOMADOR`, `INTERMEDIARIO_NAO_SUPORTADO`, `TRIBUTACAO_NAO_SUPORTADA`, `RETENCAO_NAO_PERMITIDA_NO_SERVICO`), o tomador (`TOMADOR_DO_EXTERIOR_NAO_SUPORTADO`, `TOMADOR_E_O_PROPRIO_PRESTADOR`), o MEI (`MEI_NAO_INFORMA_PTOTTRIBSN`, `MEI_NAO_TEM_RETENCAO`, `MUNICIPIO_DO_MEI_DIFERENTE_DO_CNPJ`), a inscrição municipal no município que a exige (`INSCRICAO_MUNICIPAL_OBRIGATORIA`), o local e o serviço (`LOCAL_PRESTACAO_OBRIGATORIO`, `MUNICIPIO_DA_PRESTACAO_NAO_ADERENTE`, `SERVICO_EXIGE_ENDERECO_DO_TOMADOR`, `SERVICO_EXIGE_DADOS_DA_OBRA`, `SERVICO_EXIGE_DADOS_DO_EVENTO`, `SERVICO_SEM_INCIDENCIA_NAO_SUPORTADO`). 402 é cota ou conta (`COTA_ESGOTADA`, `CONTA_BLOQUEADA`), 409 é estado (`EMPRESA_NAO_ATIVA`, `CERTIFICADO_NAO_VALIDADO`, `NDPS_DISPUTADO`) e 502 é o Sistema Nacional fora do ar. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `Idempotency-Key` | header | string, ou null | Texto único por intenção (um UUID serve); veja a seção Idempotência | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `dCompet` | string **(obrigatório)** | Competência no formato AAAA-MM-DD: a data da prestação do serviço. Não pode ser futura | | `servico` | objeto ServicoIn **(obrigatório)** | O serviço prestado: o código nacional, o texto que sai na nota e o detalhamento opcional. | | `servico.cMunPrestacao` | string, ou null | Código IBGE do município onde o serviço foi prestado. Omita para usar o município da empresa emissora — só informe quando prestou em outra cidade | | `servico.cTribNac` | string **(obrigatório)** | Código de tributação nacional do serviço, 6 dígitos (ex.: 010501). É o item da lista nacional; sem pontos | | `servico.descricao` | string **(obrigatório)** | Descrição do serviço que sai impressa na nota | | `servico.cNBS` | string, ou null | Código NBS (9 dígitos), quando o município o exigir | | `servico.informacoes_complementares` | string, ou null | Texto livre impresso no campo de informações complementares da nota | | `servico.itens` | lista de objeto ItemIn, ou null | Detalhamento opcional. Com itens, o valor do serviço pode ser omitido: o total é a soma de quantidade × valor unitário e o detalhe vai nas informações complementares | | `valores` | objeto ValoresIn **(obrigatório)** | Os valores da nota, sempre como string decimal com ponto (`"1500.00"`) — nunca número. | | `valores.vServ` | string, ou null | Valor do serviço em reais (ex.: "1500.00"). Obrigatório, salvo quando servico.itens traz o detalhamento — aí o total é calculado | | `valores.vDescIncond` | string, ou null | Desconto incondicionado — abate a base de cálculo do ISSQN | | `valores.vDescCond` | string, ou null | Desconto condicionado — não abate a base de cálculo | | `valores.pTotTribSN` | string, ou null | Percentual aproximado de tributos (Lei 12.741) para optante do Simples. Omita: ME/EPP usa a alíquota da empresa (a do mês pelo PGDAS-D, ou a confirmada no painel) — sem alíquota nenhuma a emissão para em 422 ALIQUOTA_NAO_CONFIRMADA. O MEI não leva o percentual (o Sistema Nacional o recusa para o MEI, E0710): a nota sai com indTotTrib 0, e mandado volta 422 MEI_NAO_INFORMA_PTOTTRIBSN. Mandado diferente da calculada, a nota da ME/EPP sai como veio e o dono é avisado uma vez por mês | | `tributacao` | objeto TributacaoIn | Tributação do ISSQN. Os defaults cobrem o caso comum: serviço tributado no município, sem retenção. Padrão: `{"tribISSQN": "1", "tpRetISSQN": "1"}`. | | `tributacao.tribISSQN` | um de: `"1"`, `"2"`, `"3"`, `"4"` | 1 = tributável no município (único aceito hoje) · 2 = imunidade · 3 = exportação · 4 = não incidência Padrão: `"1"`. | | `tributacao.tpRetISSQN` | um de: `"1"`, `"2"`, `"3"` | Retenção do ISSQN: 1 = não retido (padrão) · 2 = retido pelo tomador · 3 = retido pelo intermediário (ainda não suportado) Padrão: `"1"`. | | `tributacao.pAliq` | string, ou null | Alíquota do ISSQN em %, string decimal até 5.00 (ex.: "4.53"). Informe SOMENTE quando há retenção (tpRetISSQN=2); sem retenção, a alíquota parametrizada do município é aplicada pelo sistema | | `tomador` | objeto TomadorIn, ou null | O cliente. Opcional: a nota pode sair sem tomador identificado | | `ambiente` | um de: `"producao"`, `"teste"` | "producao" (padrão) emite a nota valendo. "teste" valida tudo no ambiente restrito do gov.br sem efeito fiscal: não consome cota, não aparece nas listagens e é descartada em 24 h Padrão: `"producao"`. | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/nfse" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"ambiente": "teste", "dCompet": "2026-07-01", "servico": {"cMunPrestacao": "2408102", "cNBS": "111032200", "cTribNac": "010501", "descricao": "LICENCA DE USO DE SOFTWARE - TESTE"}, "tributacao": {"tpRetISSQN": "1", "tribISSQN": "1"}, "valores": {"vServ": "500.00"}}' ``` **Resposta 201** — A nota autorizada pelo Sistema Nacional | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da nota nesta API (nfse_…) — use nas rotas /nfse/{nfse_id} | | `chave_acesso` | string **(obrigatório)** | Chave de acesso da NFS-e no Sistema Nacional, 50 dígitos | | `serie` | string **(obrigatório)** | Série da DPS, do cadastro da empresa | | `nDPS` | string **(obrigatório)** | Número sequencial da DPS dentro da série | | `numero` | string, ou null | Número oficial da NFS-e (nNFSe) atribuído pelo gov.br — é este que sai no DANFSE e o que o cliente enxerga | | `dps_id` | string **(obrigatório)** | Identificador da DPS assinada que gerou a nota | | `valor_servico` | string, ou null **(obrigatório)** | Valor do serviço em reais, string decimal (ex.: "1500.00") | | `status` | string **(obrigatório)** | Situação da nota: "ativa" logo após a emissão | | `ndps_ressincronizado` | boolean | true quando o número da DPS foi realinhado com o servidor porque outro emissor usava a série Padrão: `false`. | | `elapsed_ms` | integer **(obrigatório)** | Tempo da conversa com o Sistema Nacional, em milissegundos | | `substitui_chave` | string, ou null | Chave da nota substituída, quando esta nota saiu de uma substituição | | `avisos` | lista de objeto AvisoOut, ou null | O que vale conferir numa nota que saiu — hoje, o ISS retido por um tomador de fora do município do ISS (`RETENCAO_COM_TOMADOR_DE_OUTRO_MUNICIPIO`); nulo quando não há nada | **Exemplo de resposta** ```json { "chave_acesso": "33333333333333333333333333333333333333330000000001", "dps_id": "DPS000000000000000000000000000000000000000001", "elapsed_ms": 7, "id": "nfse_5f7cb5569c7fe36e", "nDPS": "1", "ndps_ressincronizado": false, "numero": "101", "serie": "1", "status": "ativa", "substitui_chave": null, "valor_servico": "500.00" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | | 502 | O Sistema Nacional ou a Receita respondeu com erro | | 503 | Serviço externo indisponível ou não configurado | ### Ver o rascunho da nota em PDF `POST /api/v1/companies/{company_id}/nfse/rascunho-pdf` Desenha, em PDF, a nota que sairia com este corpo — sem emitir nada. O corpo é exatamente o de `POST /companies/{company_id}/nfse`, e as validações são as mesmas: o que passa aqui passa na emissão, e o que seria recusado volta no mesmo 422, com o mesmo `code`. Use para mostrar a nota a quem vai aprová-la antes de gerar o documento fiscal, ou para conferir valores e textos sem gastar nada. Nada é gravado: não há chave de acesso, não anda a numeração, não consome cota e a nota não passa a existir no gov.br (o `ambiente` do corpo é ignorado). O PDF sai com marca d'água de rascunho, sem número e sem QR Code, e os tributos são o cálculo da plataforma — o gov.br pode ajustá-los na emissão. Exige chave com escopo `emissao`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `dCompet` | string **(obrigatório)** | Competência no formato AAAA-MM-DD: a data da prestação do serviço. Não pode ser futura | | `servico` | objeto ServicoIn **(obrigatório)** | O serviço prestado: o código nacional, o texto que sai na nota e o detalhamento opcional. | | `servico.cMunPrestacao` | string, ou null | Código IBGE do município onde o serviço foi prestado. Omita para usar o município da empresa emissora — só informe quando prestou em outra cidade | | `servico.cTribNac` | string **(obrigatório)** | Código de tributação nacional do serviço, 6 dígitos (ex.: 010501). É o item da lista nacional; sem pontos | | `servico.descricao` | string **(obrigatório)** | Descrição do serviço que sai impressa na nota | | `servico.cNBS` | string, ou null | Código NBS (9 dígitos), quando o município o exigir | | `servico.informacoes_complementares` | string, ou null | Texto livre impresso no campo de informações complementares da nota | | `servico.itens` | lista de objeto ItemIn, ou null | Detalhamento opcional. Com itens, o valor do serviço pode ser omitido: o total é a soma de quantidade × valor unitário e o detalhe vai nas informações complementares | | `valores` | objeto ValoresIn **(obrigatório)** | Os valores da nota, sempre como string decimal com ponto (`"1500.00"`) — nunca número. | | `valores.vServ` | string, ou null | Valor do serviço em reais (ex.: "1500.00"). Obrigatório, salvo quando servico.itens traz o detalhamento — aí o total é calculado | | `valores.vDescIncond` | string, ou null | Desconto incondicionado — abate a base de cálculo do ISSQN | | `valores.vDescCond` | string, ou null | Desconto condicionado — não abate a base de cálculo | | `valores.pTotTribSN` | string, ou null | Percentual aproximado de tributos (Lei 12.741) para optante do Simples. Omita: ME/EPP usa a alíquota da empresa (a do mês pelo PGDAS-D, ou a confirmada no painel) — sem alíquota nenhuma a emissão para em 422 ALIQUOTA_NAO_CONFIRMADA. O MEI não leva o percentual (o Sistema Nacional o recusa para o MEI, E0710): a nota sai com indTotTrib 0, e mandado volta 422 MEI_NAO_INFORMA_PTOTTRIBSN. Mandado diferente da calculada, a nota da ME/EPP sai como veio e o dono é avisado uma vez por mês | | `tributacao` | objeto TributacaoIn | Tributação do ISSQN. Os defaults cobrem o caso comum: serviço tributado no município, sem retenção. Padrão: `{"tribISSQN": "1", "tpRetISSQN": "1"}`. | | `tributacao.tribISSQN` | um de: `"1"`, `"2"`, `"3"`, `"4"` | 1 = tributável no município (único aceito hoje) · 2 = imunidade · 3 = exportação · 4 = não incidência Padrão: `"1"`. | | `tributacao.tpRetISSQN` | um de: `"1"`, `"2"`, `"3"` | Retenção do ISSQN: 1 = não retido (padrão) · 2 = retido pelo tomador · 3 = retido pelo intermediário (ainda não suportado) Padrão: `"1"`. | | `tributacao.pAliq` | string, ou null | Alíquota do ISSQN em %, string decimal até 5.00 (ex.: "4.53"). Informe SOMENTE quando há retenção (tpRetISSQN=2); sem retenção, a alíquota parametrizada do município é aplicada pelo sistema | | `tomador` | objeto TomadorIn, ou null | O cliente. Opcional: a nota pode sair sem tomador identificado | | `ambiente` | um de: `"producao"`, `"teste"` | "producao" (padrão) emite a nota valendo. "teste" valida tudo no ambiente restrito do gov.br sem efeito fiscal: não consome cota, não aparece nas listagens e é descartada em 24 h Padrão: `"producao"`. | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/nfse/rascunho-pdf" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -o rascunho.pdf \ -H "Content-Type: application/json" \ -d '{"dCompet": "2026-07-01", "servico": {"cNBS": "111032200", "cTribNac": "010501", "descricao": "LICENCA DE USO DE SOFTWARE - TESTE"}, "tributacao": {"tpRetISSQN": "1", "tribISSQN": "1"}, "valores": {"vServ": "500.00"}}' ``` **Resposta 200** — O rascunho do DANFSE em PDF (`application/pdf`) **Exemplo de resposta** ```json { "_binario": "application/pdf", "_bytes": 45199 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Listar as notas por período e filtros `GET /api/v1/nfse` Lista as notas da conta, das mais recentes para as mais antigas. O período vai em `de` e `ate`, e cada um aceita mês (`2026-08`) ou dia exato (`2026-08-14`); `periodo_por` escolhe o campo da faixa: `competencia` (padrão, a do fechamento fiscal) ou `emissao`. Dá para filtrar por `status` (`ativa`, `cancelada`, `substituida`), por `company_id`, por `origem` (`plataforma`, `importada` ou `lote` — as que saíram de um lote), pelo número da nota (`numero`, que casa com o número oficial ou com o da DPS) e por texto livre em `q` (nome do cliente, documento ou descrição do serviço). `ordem` aceita `emissao_desc` (padrão), `emissao_asc`, `competencia_desc`, `competencia_asc`, `valor_desc`, `valor_asc`, `numero_desc`, `numero_asc`, `evento_desc` e `evento_asc` (a data em que a nota saiu de ativa — a ordem natural de `periodo_por=evento`). A paginação é `skip` e `limit` (máximo 100 por página); para saber o tamanho total e a soma do mesmo filtro, chame `GET /nfse/agregado`. Notas emitidas em ambiente de teste nunca aparecem aqui. Basta uma chave com escopo `leitura`. Situação com data: `cancelada_em` e `substituida_em` dizem quando a nota saiu de ativa, na hora oficial do evento, e `periodo_por=evento` filtra por essa data — `status=cancelada&periodo_por=evento&de=2026-08&ate=2026-08` é "o que foi cancelado em agosto". Nas notas fora de ativa, `evento_situacao` diz qual evento a tirou de ativa (cancelamento, substituição, cancelamento deferido por análise fiscal ou por ofício) e `substituida_por_numero` traz o número da nota que entrou no lugar. As bordas de `de`/`ate` valem no horário de Brasília, para qualquer `periodo_por`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `status` | query | string, ou null | | | `company_id` | query | string, ou null | Id da empresa (de `GET /companies`) | | `periodo_por` | query | string | | | `de` | query | string, ou null | | | `ate` | query | string, ou null | | | `origem` | query | string, ou null | | | `q` | query | string, ou null | | | `numero` | query | string, ou null | | | `com_problema` | query | boolean | true traz só as notas com algum problema (ver `alertas` em cada uma) | | `ordem` | query | um de: `"emissao_desc"`, `"emissao_asc"`, `"competencia_desc"`, `"competencia_asc"`, `"valor_desc"`, `"valor_asc"`, `"numero_desc"`, `"numero_asc"`, `"evento_desc"`, `"evento_asc"` | | | `skip` | query | integer | Quantas notas pular — a paginação: 0, depois 100, 200… | | `limit` | query | integer | Quantas notas por página: padrão 50, MÁXIMO 100 (acima disso a API devolve 100 sem avisar). Se a página voltar cheia, há mais: repita com `skip` somado; `GET /nfse/agregado` diz o total | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — As notas que casam com o filtro, em resumo | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da nota nesta API (nfse_…) | | `numero` | string, ou null | Número oficial da NFS-e (nNFSe), o do DANFSE | | `nDPS` | integer, ou null | Número sequencial da DPS dentro da série | | `serie` | string, ou null | Série da DPS | | `chave` | string, ou null | Chave de acesso da NFS-e, 50 dígitos | | `dCompet` | string, ou null | Competência (AAAA-MM-DD) | | `valor_servico` | string, ou null | Valor do serviço em reais, string decimal | | `descricao_servico` | string, ou null | Descrição do serviço impressa na nota | | `cTribNac` | string, ou null | Código de tributação nacional do serviço (6 dígitos) | | `tomador_nome` | string, ou null | Nome do cliente, quando a nota tem tomador | | `tomador_documento` | string, ou null | CNPJ ou CPF do cliente, sem pontuação: o CPF com 11 números; o CNPJ com 14 caracteres (letras A–Z só nas 12 primeiras posições, em maiúsculas) | | `status` | string, ou null | "ativa", "cancelada" ou "substituida" | | `cancelada_em` | string (date-time), ou null | Quando a nota foi cancelada (UTC, hora oficial do evento); só em status cancelada | | `substituida_em` | string (date-time), ou null | Quando a nota foi substituída (UTC): o dhEvento do e105102 ou a autorização da substituta, o que vier primeiro; só em status substituida | | `substituida_por` | string, ou null | Id da nota que substituiu esta, se for o caso | | `substituida_por_numero` | string, ou null | Número oficial da nota que substituiu esta, para citar sem outra chamada | | `evento_situacao` | objeto, ou null | O evento que tirou a nota de ativa, `{"codigo", "descricao"}`: 101101 cancelamento, 105102 substituição, 105104 cancelamento deferido por análise fiscal ou 305101 cancelamento por ofício; `null` nas ativas | | `substitui_chave` | string, ou null | Chave da nota que esta substituiu, se for o caso | | `company_id` | string, ou null | Empresa emissora da nota (cmp_…) | | `emitida_em` | string (date-time), ou null | Data/hora (UTC) da autorização da nota | | `tpRetISSQN` | string, ou null | Retenção do ISSQN aplicada: 1, 2 ou 3 | | `pAliq` | string, ou null | Alíquota do ISSQN DECLARADA na emissão, em %, quando houve retenção | | `vISSQN` | string, ou null | ISSQN apurado na nota pelo Sistema Nacional, em reais; `null` em notas antigas | | `vBC` | string, ou null | Base de cálculo do ISSQN que o município usou, em reais; `null` em notas sem retenção e nas gravadas antes do campo existir | | `pAliqAplic` | string, ou null | Alíquota que o município APLICOU, em %. Compare com `pAliq` (a declarada): diferente quer dizer que o município calculou por outra régua, e quem manda é esta | | `tot_trib_tipo` | string, ou null | Como os tributos foram informados: "pTotTribSN" ou "indTotTrib" | | `tot_trib_valor` | string, ou null | Percentual aproximado de tributos, quando pTotTribSN | | `vDescIncond` | string, ou null | Desconto incondicionado | | `vDescCond` | string, ou null | Desconto condicionado | | `origem` | string, ou null | "plataforma" (emitida pelo GereNota) ou "importada" (emitida fora do GereNota — pelo portal do Emissor Nacional, por outro sistema ou pela prefeitura — e trazida do Sistema Nacional) | | `lote` | objeto LoteDaNotaOut, ou null | A nota saiu de um lote: o arquivo e a linha dele | | `fora_depois_da_entrada` | boolean | true na nota emitida FORA do GereNota (`origem` importada) depois que a empresa entrou — outro sistema ainda emitindo pela empresa; false no histórico da entrada e nas notas do GereNota Padrão: `false`. | | `alertas` | lista de objeto AlertaNotaOut | Os problemas da nota, cada um com o que fazer — o último e-mail ao cliente que voltou, foi recusado ou marcado como spam; a retida com o ISS de outro mês; o município que aplicou outra alíquota; o cancelamento por ofício; e a nota que parece ter saído em dobro (a do GereNota e uma de fora, mesmo cliente, competência e valor, as duas ativas). Vazio na nota sem problema. Revistos quando o fato acontece e uma vez por dia | | `alertas.tipo` | string **(obrigatório)** | "email_nao_chegou", "iss_de_outro_mes", "aliquota_aplicada_diferente", "cancelada_pela_prefeitura" ou "em_dobro" | | `alertas.titulo` | string **(obrigatório)** | O nome curto do problema, o do selo na tela (ex.: "E-mail não chegou") | | `alertas.texto` | string **(obrigatório)** | O que aconteceu e o que fazer, em uma ou duas frases | | `alertas.para` | string, ou null | No e-mail que não chegou: o endereço do último envio | | `alertas.situacao` | string, ou null | No e-mail que não chegou: "devolvido" (o destino recusou), "spam" ou "falhou" (o provedor recusou) | | `alertas.em` | string (date-time), ou null | Quando: a notícia do e-mail (devolução, spam, recusa) ou o cancelamento por ofício (UTC) | | `alertas.nota_id` | string, ou null | No em dobro: a outra nota (nfse_…) | | `alertas.numero` | string, ou null | No em dobro: o número oficial da outra nota | **Exemplo de resposta** ```json [ { "cTribNac": "010501", "cancelada_em": null, "chave": "99999999999999999999999999999999999999999999999991", "company_id": "cmp_bb869705b43528e3", "dCompet": "2026-06-02", "descricao_servico": "Servico historico 3", "emitida_em": "2026-09-02T12:00:00Z", "evento_situacao": null, "id": "nfse_e42dced4c5ae5cfd", "nDPS": 3, "numero": "3", "pAliq": null, "serie": "1", "status": "ativa", "substitui_chave": "88888888888888888888888888888888888888888888888888", "substituida_em": null, "substituida_por": null, "substituida_por_numero": null, "tomador_documento": "03635323000140", "tomador_nome": "CONSELHO X", "tot_trib_tipo": null, "tot_trib_valor": null, "tpRetISSQN": null, "vDescCond": null, "vDescIncond": null, "valor_servico": "210.00" }, { "cTribNac": "010501", "cancelada_em": "2026-09-01T01:30:00Z", "chave": "77777777777777777777777777777777777777777777777777", "company_id": "cmp_bb869705b43528e3", "dCompet": "2026-05-02", "descricao_servico": "Servico historico 1", "emitida_em": "2026-06-01T13:00:00Z", "evento_situacao": { "codigo": "101101", "descricao": "Cancelamento" }, "id": "nfse_01ca80310a4377f7", "nDPS": 1, "numero": "1", "pAliq": null, "serie": "1", "status": "cancelada", "substitui_chave": null, "substituida_em": null, "substituida_por": null, "substituida_por_numero": null, "tomador_documento": "03635323000140", "tomador_nome": "CONSELHO X", "tot_trib_tipo": null, "tot_trib_valor": null, "tpRetISSQN": null, "vDescCond": null, "vDescIncond": null, "valor_servico": "100.00" }, { "cTribNac": "010501", "cancelada_em": null, "chave": "88888888888888888888888888888888888888888888888888", "company_id": "cmp_bb869705b43528e3", "dCompet": "2026-06-02", "descricao_servico": "Servico historico 2", "emitida_em": "2026-06-01T13:00:00Z", "evento_situacao": { "codigo": "105102", "descricao": "Cancelamento por substituição" }, "id": "nfse_c28699256a8fbb87", "nDPS": 2, "numero": "2", "pAliq": null, "serie": "1", "status": "substituida", "substitui_chave": null, "substituida_em": "2026-09-02T12:00:00Z", "substituida_por": "nfse_e42dced4c5ae5cfd", "substituida_por_numero": "3", "tomador_documento": "03635323000140", "tomador_nome": "CONSELHO X", "tot_trib_tipo": null, "tot_trib_valor": null, "tpRetISSQN": null, "vDescCond": null, "vDescIncond": null, "valor_servico": "200.00" } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ### Somar e contar as notas do filtro `GET /api/v1/nfse/agregado` Devolve quantas notas casam com o filtro e quanto elas somam. Aceita exatamente os mesmos filtros de `GET /nfse` (`status`, `company_id`, `periodo_por`, `de`, `ate`, `origem`, `q`, `com_problema`), sem paginação: é a resposta para "quantas notas e qual o faturamento deste mês". Use junto com a listagem para saber o total de páginas e para conferir o fechamento de uma competência. `valor_total` vem como string decimal com duas casas. Notas de teste ficam de fora, como em toda listagem. Basta uma chave com escopo `leitura`. `por_status` separa as situações: `valor_total` soma tudo o que passou no filtro (como o painel mostra), e o faturamento válido do período é `por_status.ativa.valor_total`. Aceita também `periodo_por=evento`, para somar o que foi cancelado ou substituído num período. `com_problema` conta, dentro do mesmo filtro, as notas com algum problema (`alertas`). `exportacao` diz o que `POST /exports` faria com este mesmo recorte, ANTES de pedir: `por_volume` (quantas notas cabem num arquivo — 1.000 com os PDFs, 2.000 só XML), `arquivos` (quantos sairiam: 1 quando cabe; volumes + resumo quando não), `estimativa_s` (segundos de montagem), `por_mes` (a contagem mês a mês no eixo de `periodo_por`, para estreitar o recorte) e `ultimo_mes_quinzenas` (só quando o último mês sozinho passa do volume). O bloco pode faltar se a conta por mês não puder ser feita — a contagem principal nunca depende dele. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `status` | query | string, ou null | | | `company_id` | query | string, ou null | Id da empresa (de `GET /companies`) | | `periodo_por` | query | string | | | `de` | query | string, ou null | | | `ate` | query | string, ou null | | | `origem` | query | string, ou null | | | `q` | query | string, ou null | | | `com_problema` | query | boolean | true soma e conta só as notas com algum problema | | `incluir_pdf` | query | boolean | Para o bloco `exportacao`: com os PDFs o volume é de 1.000 notas; só XML, 2.000 | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse/agregado" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Quantidade e soma das notas que casam com o filtro | Campo | Tipo | Descrição | |---|---|---| | `total` | integer **(obrigatório)** | Quantidade de notas que casam com o filtro | | `valor_total` | string **(obrigatório)** | Soma dos valores de serviço de TODAS as notas do filtro, string decimal com 2 casas (ex.: "6821.40") — inclui canceladas e substituídas; o faturamento válido é `por_status.ativa` | | `por_status` | objeto | Detalhe por situação ("ativa", "cancelada", "substituida"), só as que aparecem no filtro | | `com_problema` | objeto NfseAgregadoSituacaoOut, ou null | Quantas notas do filtro têm algum problema (`alertas`) e quanto somam — o número da aba "Com problema" da tela Notas; para listá-las, `com_problema=true` em `GET /nfse` | **Exemplo de resposta** ```json { "por_status": { "cancelada": { "total": 1, "valor_total": "100.00" }, "substituida": { "total": 1, "valor_total": "200.00" } }, "total": 2, "valor_total": "300.00" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ### Consultar uma nota pelo id `GET /api/v1/nfse/{nfse_id}` Devolve uma nota inteira pelo `nfse_id` que a emissão retornou. Traz a identificação (chave de acesso, número oficial, série, número da DPS), a competência, os valores, o tomador, a tributação aplicada e a situação (`ativa`, `cancelada` ou `substituida`). É a rota para conferir o estado atual de uma nota depois de um cancelamento ou de uma substituição — aí `substituida_por` aponta a nota que a substituiu. Diferente da listagem, aqui a nota de teste também pode ser consultada, pelo id. `local_prestacao` diz onde o serviço foi prestado, como a nota declarou — o local que a substituição mantém. Para o documento em si, use `/nfse/{nfse_id}/pdf` (DANFSE) ou `/nfse/{nfse_id}/xml`. Basta uma chave com escopo `leitura`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — A nota com todos os dados guardados | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da nota nesta API (nfse_…) | | `company_id` | string, ou null | Empresa emissora da nota (cmp_…) | | `chave` | string, ou null | Chave de acesso da NFS-e, 50 dígitos | | `dps_id` | string, ou null | Identificador da DPS assinada; vazio em nota importada | | `serie` | string, ou null | Série da DPS | | `ndps` | integer, ou null | Número sequencial da DPS (na listagem este mesmo dado se chama nDPS) | | `numero` | string, ou null | Número oficial da NFS-e (nNFSe), o do DANFSE | | `dCompet` | string, ou null | Competência (AAAA-MM-DD) | | `valor_servico` | string, ou null | Valor do serviço em reais, string decimal | | `descricao_servico` | string, ou null | Descrição do serviço impressa na nota | | `informacoes_complementares` | string, ou null | Informações complementares da nota | | `tomador_nome` | string, ou null | Nome do cliente, quando a nota tem tomador | | `tomador_documento` | string, ou null | CNPJ ou CPF do cliente, sem pontuação: o CPF com 11 números; o CNPJ com 14 caracteres (letras A–Z só nas 12 primeiras posições, em maiúsculas) | | `cTribNac` | string, ou null | Código de tributação nacional do serviço (6 dígitos) | | `cNBS` | string, ou null | Código NBS do serviço, quando informado | | `tribISSQN` | string, ou null | Tributação do ISSQN declarada (1 a 4) | | `tpRetISSQN` | string, ou null | Retenção do ISSQN aplicada: 1, 2 ou 3 | | `pAliq` | string, ou null | Alíquota do ISSQN DECLARADA na emissão, em %, quando houve retenção | | `vISSQN` | string, ou null | ISSQN apurado na nota pelo Sistema Nacional, em reais; `null` em notas antigas | | `vBC` | string, ou null | Base de cálculo do ISSQN que o município usou, em reais; `null` em notas sem retenção e nas gravadas antes do campo existir | | `pAliqAplic` | string, ou null | Alíquota que o município APLICOU, em %. Compare com `pAliq` (a declarada): diferente quer dizer que o município calculou por outra régua, e quem manda é esta | | `tot_trib_tipo` | string, ou null | "pTotTribSN" ou "indTotTrib" | | `tot_trib_valor` | string, ou null | Percentual aproximado de tributos, quando pTotTribSN | | `vDescIncond` | string, ou null | Desconto incondicionado | | `vDescCond` | string, ou null | Desconto condicionado | | `status` | string, ou null | "ativa", "cancelada" ou "substituida" | | `origem` | string, ou null | "plataforma" (emitida pelo GereNota) ou "importada" (emitida fora do GereNota e trazida do Sistema Nacional) | | `lote` | objeto LoteDaNotaOut, ou null | A nota saiu de um lote: o arquivo e a linha dele | | `fora_depois_da_entrada` | boolean | true na nota emitida FORA do GereNota (`origem` importada) depois que a empresa entrou — outro sistema ainda emitindo pela empresa; false no histórico da entrada e nas notas do GereNota Padrão: `false`. | | `alertas` | lista de objeto AlertaNotaOut | Os problemas da nota, cada um com o que fazer — o último e-mail ao cliente que voltou, foi recusado ou marcado como spam; a retida com o ISS de outro mês; o município que aplicou outra alíquota; o cancelamento por ofício; e a nota que parece ter saído em dobro (a do GereNota e uma de fora, mesmo cliente, competência e valor, as duas ativas). Vazio na nota sem problema. Revistos quando o fato acontece e uma vez por dia | | `alertas.tipo` | string **(obrigatório)** | "email_nao_chegou", "iss_de_outro_mes", "aliquota_aplicada_diferente", "cancelada_pela_prefeitura" ou "em_dobro" | | `alertas.titulo` | string **(obrigatório)** | O nome curto do problema, o do selo na tela (ex.: "E-mail não chegou") | | `alertas.texto` | string **(obrigatório)** | O que aconteceu e o que fazer, em uma ou duas frases | | `alertas.para` | string, ou null | No e-mail que não chegou: o endereço do último envio | | `alertas.situacao` | string, ou null | No e-mail que não chegou: "devolvido" (o destino recusou), "spam" ou "falhou" (o provedor recusou) | | `alertas.em` | string (date-time), ou null | Quando: a notícia do e-mail (devolução, spam, recusa) ou o cancelamento por ofício (UTC) | | `alertas.nota_id` | string, ou null | No em dobro: a outra nota (nfse_…) | | `alertas.numero` | string, ou null | No em dobro: o número oficial da outra nota | | `local_prestacao` | objeto LocalPrestacaoOut, ou null | Onde o serviço foi prestado, como a nota declarou — é o local que a substituição mantém quando o pedido não traz `servico.cMunPrestacao`. `null` quando não foi possível ler o local agora (na nota antiga, ele vem do XML autorizado) | | `ambiente` | string, ou null | "producao" ou "teste" | | `substitui_chave` | string, ou null | Chave da nota que esta substituiu, se for o caso | | `substituida_por` | string, ou null | Id da nota que substituiu esta, se for o caso | | `cancelada_em` | string (date-time), ou null | Quando a nota foi cancelada (UTC, hora oficial do evento); só em status cancelada | | `substituida_em` | string (date-time), ou null | Quando a nota foi substituída (UTC): o dhEvento do e105102 ou a autorização da substituta, o que vier primeiro; só em status substituida | | `emitida_em` | string (date-time), ou null | Data/hora (UTC) da autorização da nota | **Exemplo de resposta** ```json { "ambiente": "producao", "cNBS": "111032200", "cTribNac": "010501", "cancelada_em": "2026-09-16T21:47:06.443000Z", "chave": "33333333333333333333333333333333333333330000000001", "company_id": "cmp_aa60e591871fbfcd", "dCompet": "2026-07-01", "descricao_servico": "LICENCA DE USO DE SOFTWARE - TESTE", "dps_id": "DPS000000000000000000000000000000000000000001", "emitida_em": "2026-09-16T21:47:06.319000Z", "id": "nfse_f7f56218c87b66fa", "informacoes_complementares": null, "ndps": 1, "numero": "101", "origem": "plataforma", "pAliq": null, "serie": "1", "status": "cancelada", "substitui_chave": null, "substituida_em": null, "substituida_por": null, "tomador_documento": null, "tomador_nome": null, "tot_trib_tipo": "pTotTribSN", "tot_trib_valor": "13.99", "tpRetISSQN": "1", "tribISSQN": "1", "vDescCond": null, "vDescIncond": null, "valor_servico": "500.00" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Baixar o XML autorizado da nota `GET /api/v1/nfse/{nfse_id}/xml` Devolve o XML da NFS-e autorizada — os bytes do arquivo, não JSON. É o documento fiscal que o Sistema Nacional assinou: guarde-o, é ele que vale para a contabilidade e para o cliente. O `Content-Type` é `application/xml` e o `Content-Disposition` já traz um nome de arquivo pronto ("NFS-e 8 (serie 2) - Empresa.xml"), que forma par com o nome do PDF da mesma nota. Se o arquivo ainda não estiver disponível no armazenamento, a resposta é 409 `ARQUIVO_INDISPONIVEL` — tente de novo mais tarde. Basta uma chave com escopo `leitura`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}/xml" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -o nota.xml ``` **Resposta 200** — O XML da NFS-e autorizada pelo gov.br (`application/xml`) **Exemplo de resposta** ```json { "_binario": "application/xml", "_bytes": 39 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Baixar o DANFSE (PDF) da nota `GET /api/v1/nfse/{nfse_id}/pdf` Devolve o DANFSE da nota em PDF — os bytes do arquivo, não JSON. É o documento que se manda ao cliente e se imprime, no leiaute obrigatório da NT 008/2026, com QR Code e chave de acesso. O `Content-Type` é `application/pdf` e o `Content-Disposition` traz um nome de arquivo pronto, que forma par com o do XML da mesma nota. Nota cancelada ou substituída sai com a marca d'água correspondente, e nota emitida em ambiente de teste sai marcada como sem validade jurídica. O PDF é gerado na primeira chamada e reaproveitado nas seguintes, então a primeira pode demorar alguns segundos. Se o XML autorizado não estiver acessível no momento, a resposta é 502 `DANFSE_INDISPONIVEL` e vale repetir. Basta uma chave com escopo `leitura`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}/pdf" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -o nota.pdf ``` **Resposta 200** — O DANFSE em PDF (`application/pdf`) **Exemplo de resposta** ```json { "_binario": "application/pdf", "_bytes": 20 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 502 | O Sistema Nacional ou a Receita respondeu com erro | ### Enviar a nota ao tomador por e-mail `POST /api/v1/nfse/{nfse_id}/enviar-email` Manda a nota para o cliente por e-mail, em nome da empresa emissora. O e-mail leva o DANFSE em PDF e o XML autorizado como anexos, com o número da nota, o valor e a chave de acesso no corpo. Sem `para`, o destino é o e-mail do cadastro do tomador; quando ele não tem nenhum, a resposta é 422 `EMAIL_OBRIGATORIO`. Com `"salvar_no_tomador": true`, o endereço usado passa a constar no cadastro do cliente (só se ele ainda não tinha um). Não há reenvio automático: cada chamada manda um e-mail, então trate a repetição com cuidado. Nota emitida em ambiente de teste nunca é entregue (409 `NOTA_DE_TESTE`), e falha do provedor de e-mail volta como 502 `ENVIO_FALHOU`. Exige chave com escopo `emissao`. São até 10 envios por minuto (429 `RATE_LIMIT`) e 100 por dia (429 `LIMITE_EMAILS_DO_DIA`, renova à 0h de Brasília) por conta. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `para` | string (email), ou null | E-mail do destinatário. Omita para usar o e-mail cadastrado do tomador da nota — se não houver nenhum, a resposta é 422 EMAIL_OBRIGATORIO | | `salvar_no_tomador` | boolean | true grava este endereço no cadastro do cliente quando ele ainda não tem e-mail (nunca sobrescreve um e-mail já cadastrado) Padrão: `false`. | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}/enviar-email" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"para": "cliente@teste.com"}' ``` **Resposta 200** — Para onde a nota foi enviada e quando | Campo | Tipo | Descrição | |---|---|---| | `para` | string **(obrigatório)** | Endereço para onde o e-mail foi enviado | | `enviado_em` | string (date-time) **(obrigatório)** | Data/hora (UTC) do envio | | `danfse_source` | string **(obrigatório)** | De onde veio o PDF anexado | | `suprimido` | boolean | true quando o ambiente não entrega e-mail de verdade (chaves de teste) Padrão: `false`. | **Exemplo de resposta** ```json { "danfse_source": "local", "enviado_em": "2026-09-16T18:47:31.975778Z", "para": "cliente@teste.com", "suprimido": false } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | | 502 | O Sistema Nacional ou a Receita respondeu com erro | ## Lotes Emitir em lote: uma planilha (XLSX ou CSV) ou as linhas em JSON viram notas propostas, uma por linha; você confere e confirma, e a fila emite uma nota por vez pelo Sistema Nacional. ### Criar um lote a partir de uma planilha `POST /api/v1/companies/{company_id}/lotes` Recebe a planilha (`multipart/form-data`, campo `file`: XLSX ou CSV, até 8 MB) e cria um lote no estado `lendo`. A leitura é feita em segundo plano: em alguns segundos o lote passa a `em_revisao`, com uma linha proposta por linha da planilha (`GET …/lotes/{lote_id}/itens`); o formato que a plataforma ainda não conhece passa por `aprendendo` e é conferido no painel. O modelo do GereNota (baixe no painel) é lido sempre na hora. Mais de 200 notas: o lote fica `acima_do_limite`, e o painel divide. O mesmo arquivo já enviado à empresa nos últimos 90 dias volta 409 `LOTE_ARQUIVO_REPETIDO` com o lote anterior em `erros[0].lote_id`; mande `forcar=true` para criar outro (a linha COM DATA que já tem nota no mesmo mês, para o mesmo cliente e valor, aparece como `ja_tem_nota`; a linha sem data não passa por essa conferência). PDF e imagem: 415. Montam lotes o dono, o operador e a contabilidade; nada é emitido até a confirmação. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Corpo:** `multipart/form-data` **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes" \ -H "Authorization: Bearer $GERENOTA_KEY" \ # corpo: multipart/form-data ``` **Resposta 201** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Exemplo de resposta** ```json { "arquivo": { "nome": "atendimentos.xlsx", "tamanho": 8542, "tipo": "xlsx" }, "arquivo_expira_em": "2026-10-16T01:56:50.658227Z", "atualizado_em": "2026-10-09T01:56:50.658227Z", "company_id": "cmp_d478c9ec6faeac5c", "contagens": {}, "criado_em": "2026-10-09T01:56:50.658227Z", "data_prestacao": null, "em_confirmacao": false, "estado": "lendo", "expira_em": "2027-01-07T01:56:50.658227Z", "id": "lot_90a455ed9622364b", "montado_por": { "papel": "owner", "por": "it@gerenota.test" }, "origem": "painel" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 413 | Arquivo acima do limite | | 415 | O arquivo não é do tipo aceito (a planilha do lote é XLSX ou CSV) | | 422 | Dados inválidos — `erros` aponta o campo | ### Criar um lote com as linhas em JSON `POST /api/v1/companies/{company_id}/lotes/linhas` O lote sem arquivo: até 200 linhas, cada uma com os campos da planilha (o documento e o valor obrigatórios; o nome, obrigatório no CPF). Os valores passam pelas mesmas conversões do arquivo ("1.234,56", "05/09/2026", "04.16.01"). O lote nasce `lendo` e, em segundos, passa a `em_revisao`: confira as linhas em `GET …/lotes/{lote_id}/itens` e confirme com `POST …/lotes/{lote_id}/confirmar`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `linhas` | lista de objeto LinhaIn **(obrigatório)** | | | `linhas.documento` | string **(obrigatório)** | CPF ou CNPJ do cliente, com ou sem pontuação | | `linhas.valor` | string **(obrigatório)** | Valor da nota ("180,00", "1.234,56" ou "1234.56") | | `linhas.nome` | string, ou null | Nome do cliente — obrigatório no CPF | | `linhas.data` | string, ou null | Data da prestação (dd/mm/aaaa ou aaaa-mm-dd) | | `linhas.descricao` | string, ou null | O texto do serviço na nota | | `linhas.codigo_servico` | string, ou null | Código de tributação nacional (04.16.01 ou 041601) | | `linhas.nbs` | string, ou null | Código NBS, quando o município exige | | `linhas.email` | string, ou null | E-mail do cliente: a nota vai para ele | | `linhas.endereco` | string, ou null | Endereço em texto (rua, número, bairro) | | `linhas.cep` | string, ou null | CEP do endereço | | `nome` | string, ou null | Um nome para reconhecer o lote | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/linhas" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"linhas": [{"codigo_servico": "041601", "descricao": "Consulta", "documento": "12345678909", "nome": "Ana", "valor": "200"}]}' ``` **Resposta 201** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Exemplo de resposta** ```json { "arquivo": { "nome": "linhas da API", "tamanho": null, "tipo": "json" }, "arquivo_expira_em": "2026-10-16T01:57:08.233735Z", "atualizado_em": "2026-10-09T01:57:08.233735Z", "company_id": "cmp_3dcac10147c2d2ae", "contagens": {}, "criado_em": "2026-10-09T01:57:08.233735Z", "data_prestacao": null, "em_confirmacao": false, "estado": "lendo", "expira_em": "2027-01-07T01:57:08.233735Z", "id": "lot_f8c08326e7b7d53a", "leitura": { "amostra": [ { "avisos": [], "brutos": {}, "campos": { "codigo_servico": "041601", "descricao": "Consulta", "documento": "12345678909", "nome": "Ana", "tipo_documento": "CPF", "valor": "200.00" }, "linha": 1 } ], "clientes": 1, "datas_separadoras": [], "linha_cabecalho": 0, "linhas": 1, "parte": null, "percebi": {}, "periodo": null, "puladas": [], "rotulos": [ "nome", "documento", "valor", "data", "descricao", "codigo_servico", "nbs", "endereco", "cep", "email" ], "total": "200.00", "total_arquivo": null }, "montado_por": { "papel": "owner", "por": "it@gerenota.test" }, "origem": "api" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Listar os lotes da empresa `GET /api/v1/companies/{company_id}/lotes` Os lotes da empresa nos últimos 90 dias, do mais novo para o mais antigo, com as contagens das linhas. Filtre por `estado` (ex.: `pronto_para_confirmar`). `pode_emitir` diz se o acesso em uso confirma lotes. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `estado` | query | string, ou null | | | `limite` | query | integer | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `lotes` | lista de objeto LoteOut **(obrigatório)** | Os lotes da empresa, do mais novo para o mais antigo (90 dias) | | `lotes.id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `lotes.company_id` | string **(obrigatório)** | A empresa emissora do lote | | `lotes.origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `lotes.arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `lotes.arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `lotes.arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `lotes.arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `lotes.estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `lotes.contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `lotes.criado_em` | string (date-time) **(obrigatório)** | | | `lotes.atualizado_em` | string (date-time) **(obrigatório)** | | | `pode_montar` | boolean **(obrigatório)** | O acesso em uso monta lotes (o dono, o operador e a contabilidade) | | `pode_emitir` | boolean **(obrigatório)** | O acesso em uso confirma lotes: o dono, o operador e a contabilidade com "Pode emitir notas" | **Exemplo de resposta** ```json { "lotes": [ { "arquivo": { "nome": "atendimentos.xlsx", "tamanho": 8423, "tipo": "xlsx" }, "arquivo_expira_em": "2026-10-16T01:57:01.804000Z", "atualizado_em": "2026-10-09T01:57:01.804000Z", "company_id": "cmp_99b92c3b9d8ea518", "contagens": {}, "criado_em": "2026-10-09T01:57:01.804000Z", "data_prestacao": null, "em_confirmacao": false, "estado": "lendo", "expira_em": "2027-01-07T01:57:01.804000Z", "id": "lot_ecb7a2d6ba42a40f", "montado_por": { "papel": "owner", "por": "it@gerenota.test" }, "origem": "painel" }, { "arquivo": { "nome": "atendimentos.xlsx", "tamanho": 8423, "tipo": "xlsx" }, "arquivo_expira_em": "2026-10-16T01:57:01.787000Z", "atualizado_em": "2026-10-09T01:57:01.787000Z", "company_id": "cmp_99b92c3b9d8ea518", "contagens": {}, "criado_em": "2026-10-09T01:57:01.787000Z", "data_prestacao": null, "em_confirmacao": false, "estado": "lendo", "expira_em": "2027-01-07T01:57:01.787000Z", "id": "lot_025096fc00bd6a9b", "montado_por": { "papel": "owner", "por": "it@gerenota.test" }, "origem": "painel" } ], "pode_emitir": true, "pode_montar": true } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Consultar um lote `GET /api/v1/companies/{company_id}/lotes/{lote_id}` O lote com o estado e as contagens — é o andamento: depois da confirmação, `contagens.por_estado` mostra as linhas na fila (`pronto`), a que está saindo (`emitindo`), as emitidas e as recusadas. Consulte de alguns em alguns segundos enquanto o estado for `lendo`, `confirmado` ou `emitindo`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Exemplo de resposta** ```json { "arquivo": { "nome": "atendimentos.xlsx", "tamanho": 8542, "tipo": "xlsx" }, "arquivo_expira_em": "2026-10-16T01:56:50.658000Z", "atualizado_em": "2026-10-09T01:56:50.701000Z", "company_id": "cmp_d478c9ec6faeac5c", "conferencia": { "avisos": [], "confianca": "alta", "contagens": { "documentos": { "CPF": 3 }, "linha_do_cabecalho": 1, "linhas_lidas": 3, "linhas_no_arquivo": 4, "periodo": { "ate": "2026-09-05", "de": "2026-09-05" }, "puladas": {}, "total_arquivo": null, "total_lido": "540.00" }, "problemas": [] }, "contagens": { "itens": 3, "por_estado": { "precisa_dados": 2, "proposto": 1 }, "total_incluido": "180.00" }, "criado_em": "2026-10-09T01:56:50.658000Z", "data_prestacao": null, "em_confirmacao": false, "estado": "em_revisao", "expira_em": "2027-01-07T01:56:50.658000Z", "formato": "Modelo do GereNota", "id": "lot_90a455ed9622364b", "leitura": { "amostra": [ { "avisos": [], "brutos": { "codigo_servico": "04.16.01", "data": "05/09/2026", "valor": "180,00" }, "campos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "12345678909", "email": "ana@gmial.com", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 2 }, { "avisos": [], "brutos": { "codigo_servico": "04.16.01", "data": "05/09/2026", "valor": "180,00" }, "campos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "98765432100", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 3 }, { "avisos": [], "brutos": { "cep": "59020-300", "codigo_servico": "04.16.01", "data": "05/09/2026", "valor": "180,00" }, "campos": { "cep": "59020300", "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "11144477735", "endereco": "Rua das Flores, 120, Tirol", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 4 } ], "clientes": 3, "datas_separadoras": [], "linha_cabecalho": 1, "linhas": 3, "parte": null, "percebi": { "cep_no_texto": 1, "valores_em_texto": 3 }, "periodo": { "ate": "2026-09-05", "de": "2026-09-05" }, "puladas": [], "rotulos": [ "Nome do cliente", "CPF ou CNPJ", "Valor", "Data da prestação", "Descrição do serviço", "Código do serviço", "E-mail do cliente", "Endereço", "CEP" ], "total": "540.00", "total_arquivo": null }, "meses_declarados": {}, "modo_padrao": "linha", "montado_por": { "papel": "owner", "por": "it@gerenota.test" }, "origem": "painel", "pode_emitir": true } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### As linhas de um lote `GET /api/v1/companies/{company_id}/lotes/{lote_id}/itens` As linhas do lote, na ordem do arquivo: o cliente, o serviço, o valor, a situação e o que falta (`pendencias`). Filtre por `estado` (pode repetir: `estado=precisa_dados&estado=proposto`). A linha recusada traz `recusa` com o motivo do Sistema Nacional; a emitida, `nfse_id` e `numero`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | | `estado` | query | lista de string, ou null | | | `pagina` | query | integer | | | `por_pagina` | query | integer | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/itens" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `itens` | lista de objeto ItemDoLoteOut **(obrigatório)** | | | `itens.id` | string **(obrigatório)** | Identificador da linha (lti_…) | | `itens.linha` | integer **(obrigatório)** | A linha no arquivo (1 é a primeira) | | `itens.estado` | string **(obrigatório)** | A situação da linha (veja `contagens.por_estado` no lote) | | `itens.incluir` | boolean **(obrigatório)** | A linha entra no lote (as repetidas e as que já têm nota ficam fora) | | `itens.tomador` | objeto **(obrigatório)** | O cliente da nota: `tipo`, `documento`, `nome`, `email` e `endereco` | | `itens.servico` | objeto **(obrigatório)** | O serviço: `cTribNac`, `descricao` e de onde veio o código | | `itens.valor` | string, ou null | O valor da nota, em reais | | `itens.pendencias` | lista de objeto **(obrigatório)** | O que falta para a linha seguir: `campo` e `motivo` | | `itens.nfse_id` | string, ou null | A nota emitida pela linha (nfse_…), quando saiu | | `total` | integer **(obrigatório)** | Quantas linhas casam com o filtro | | `pagina` | integer **(obrigatório)** | | **Exemplo de resposta** ```json { "itens": [ { "avisos": [], "cadastro": { "atualizar": false, "diferencas": {}, "existe": false, "tomador_id": null, "travado": false }, "data_linha": "2026-09-05", "estado": "precisa_dados", "id": "lti_24ef8fb2bb238b08", "incluir": true, "lidos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "12345678909", "email": "ana@gmial.com", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 2, "nfse_id": null, "pendencias": [ { "campo": "email", "motivo": "email_para_conferir", "sugestao": "ana@gmail.com" } ], "servico": { "cNBS": null, "cTribNac": "041601", "descricao": "Sessão de psicoterapia", "origem_codigo": "planilha", "origem_descricao": "planilha", "tpRetISSQN": "1" }, "tentativas": 0, "tomador": { "documento": "12345678909", "email": "ana@gmial.com", "endereco": null, "nome": "Cliente Teste", "tipo": "CPF" }, "valor": "180.00" }, { "avisos": [], "cadastro": { "atualizar": false, "diferencas": {}, "existe": false, "tomador_id": null, "travado": false }, "data_linha": "2026-09-05", "estado": "precisa_dados", "id": "lti_e7dde9f44a22066d", "incluir": true, "lidos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "98765432100", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 3, "nfse_id": null, "pendencias": [ { "campo": "nome", "motivo": "falta o nome do cliente" } ], "servico": { "cNBS": null, "cTribNac": "041601", "descricao": "Sessão de psicoterapia", "origem_codigo": "planilha", "origem_descricao": "planilha", "tpRetISSQN": "1" }, "tentativas": 0, "tomador": { "documento": "98765432100", "email": null, "endereco": null, "nome": null, "tipo": "CPF" }, "valor": "180.00" }, { "avisos": [], "cadastro": { "atualizar": false, "diferencas": {}, "existe": false, "tomador_id": null, "travado": false }, "data_linha": "2026-09-05", "estado": "proposto", "id": "lti_88612f62978b41d9", "incluir": true, "lidos": { "cep": "59020300", "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "11144477735", "endereco": "Rua das Flores, 120, Tirol", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 4, "nfse_id": null, "pendencias": [], "servico": { "cNBS": null, "cTribNac": "041601", "descricao": "Sessão de psicoterapia", "origem_codigo": "planilha", "origem_descricao": "planilha", "tpRetISSQN": "1" }, "tentativas": 0, "tomador": { "documento": "11144477735", "email": null, "endereco": { "CEP": "59020300", "cMun": "2408102", "municipio_nome": "Natal", "nro": "120", "uf": "RN", "xBairro": "Tirol", "xCpl": null, "xLgr": "Rua das Flores" }, "nome": "Cliente Teste", "tipo": "CPF" }, "valor": "180.00" } ], "pagina": 1, "total": 3 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Confirmar o lote: as notas vão para a fila de emissão `POST /api/v1/companies/{company_id}/lotes/{lote_id}/confirmar` O único passo que emite. As linhas prontas (`proposto`) vão para a fila, com a data da nota fixada agora; as que precisam de dados ficam de fora. A fila emite uma nota por vez pelo Sistema Nacional — acompanhe em `GET …/lotes/{lote_id}`. Antes, confere o que pode ter mudado desde a revisão: 403 `LOTE_SEM_PERMISSAO_DE_EMITIR` (o acesso não emite — confirmam o dono, o operador e a contabilidade com "Pode emitir notas"), 422 `CERTIFICADO_VENCIDO`, 402 `COTA_DO_LOTE` (o lote passa da cota do mês: `erros[0].restam`) e 409 `LOTE_EM_OUTRO_ESTADO`. O cliente novo entra no cadastro, e a nota nunca sai em dobro. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/confirmar" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Exemplo de resposta** ```json { "arquivo": { "nome": "atendimentos.xlsx", "tamanho": 8477, "tipo": "xlsx" }, "arquivo_expira_em": "2026-10-16T01:56:55.103000Z", "atualizado_em": "2026-10-09T01:56:55.178000Z", "cadastro_aplicado": { "atualizados": 0, "criados": 1 }, "company_id": "cmp_40c6588c9d9f1495", "conferencia": { "avisos": [ { "codigo": "data_futura", "detalhe": "1 linhas", "linhas": [ 3 ] } ], "confianca": "alta", "contagens": { "documentos": { "CPF": 2 }, "linha_do_cabecalho": 1, "linhas_lidas": 2, "linhas_no_arquivo": 3, "periodo": { "ate": "2026-11-18", "de": "2026-09-05" }, "puladas": {}, "total_arquivo": null, "total_lido": "360.00" }, "problemas": [] }, "confirmado": { "em": "2026-10-09T01:56:55.158000Z", "papel": "owner", "por": "it@gerenota.test" }, "contagens": { "itens": 2, "por_estado": { "precisa_dados": 1, "pronto": 1 }, "total_incluido": "180.00" }, "criado_em": "2026-10-09T01:56:55.103000Z", "data_prestacao": { "fixada_em": "2026-10-08", "modo": "linha", "outra": null }, "em_confirmacao": false, "estado": "confirmado", "expira_em": "2027-01-07T01:56:55.103000Z", "id": "lot_f4c1c872ae575985", "leitura": { "amostra": [ { "avisos": [], "brutos": { "codigo_servico": "04.16.01", "data": "05/09/2026", "valor": "180,00" }, "campos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "12345678909", "email": "ana@gmial.com", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 2 }, { "avisos": [ "data:futura" ], "brutos": { "codigo_servico": "04.16.01", "data": "18/11/2026", "valor": "180,00" }, "campos": { "codigo_servico": "041601", "data": "2026-11-18", "descricao": "Sessão de psicoterapia", "documento": "98765432100", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 3 } ], "clientes": 2, "datas_separadoras": [], "linha_cabecalho": 1, "linhas": 2, "parte": null, "percebi": { "valores_em_texto": 2 }, "periodo": { "ate": "2026-11-18", "de": "2026-09-05" }, "puladas": [], "rotulos": [ "Nome do cliente", "CPF ou CNPJ", "Valor", "Data da prestação", "Descrição do serviço", "Código do serviço", "E-mail do cliente", "Endereço", "CEP" ], "total": "360.00", "total_arquivo": null }, "modo_padrao": "linha", "montado_por": { "papel": "owner", "por": "it@gerenota.test" }, "origem": "painel" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Cancelar o lote (só o que ainda não saiu) `POST /api/v1/companies/{company_id}/lotes/{lote_id}/cancelar` Antes da confirmação, o lote é descartado. Depois, sai da fila só o que ainda não foi emitido: a nota que está saindo termina, e a nota emitida continua valendo (cancele-a em `POST /nfse/{nfse_id}/cancelar`). Com alguma nota emitida, o lote termina `parcial`; sem nenhuma, `cancelado`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/cancelar" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Exemplo de resposta** ```json { "arquivo": { "nome": "atendimentos.xlsx", "tamanho": 8489, "tipo": "xlsx" }, "arquivo_expira_em": "2026-10-16T01:57:33.431000Z", "atualizado_em": "2026-10-09T01:57:33.709000Z", "cadastro_aplicado": { "atualizados": 0, "criados": 3 }, "canceladas": 2, "cancelado": { "em": "2026-10-09T01:57:33.699000Z", "por": "it@gerenota.test" }, "company_id": "cmp_cf8555bf2bf8e866", "conferencia": { "avisos": [], "confianca": "alta", "contagens": { "documentos": { "CPF": 3 }, "linha_do_cabecalho": 1, "linhas_lidas": 3, "linhas_no_arquivo": 4, "periodo": { "ate": "2026-09-05", "de": "2026-09-05" }, "puladas": {}, "total_arquivo": null, "total_lido": "540.00" }, "problemas": [] }, "confirmado": { "em": "2026-10-09T01:57:33.475000Z", "papel": "owner", "por": "it@gerenota.test" }, "contagens": { "itens": 3, "por_estado": { "cancelada": 2, "emitida": 1 }, "total_incluido": "180.00" }, "criado_em": "2026-10-09T01:57:33.431000Z", "data_prestacao": { "fixada_em": "2026-10-08", "modo": "linha", "outra": null }, "em_confirmacao": false, "emitindo_desde": "2026-10-09T01:57:33.517000Z", "estado": "parcial", "expira_em": "2027-01-07T01:57:33.431000Z", "id": "lot_9489ddb3861b2a6a", "leitura": { "amostra": [ { "avisos": [], "brutos": { "codigo_servico": "04.16.01", "data": "05/09/2026", "valor": "180,00" }, "campos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "12345678909", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 2 }, { "avisos": [], "brutos": { "codigo_servico": "04.16.01", "data": "05/09/2026", "valor": "180,00" }, "campos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "98765432100", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 3 }, { "avisos": [], "brutos": { "codigo_servico": "04.16.01", "data": "05/09/2026", "valor": "180,00" }, "campos": { "codigo_servico": "041601", "data": "2026-09-05", "descricao": "Sessão de psicoterapia", "documento": "11144477735", "nome": "Cliente Teste", "tipo_documento": "CPF", "valor": "180.00" }, "linha": 4 } ], "clientes": 3, "datas_separadoras": [], "linha_cabecalho": 1, "linhas": 3, "parte": null, "percebi": { "valores_em_texto": 3 }, "periodo": { "ate": "2026-09-05", "de": "2026-09-05" }, "puladas": [], "rotulos": [ "Nome do cliente", "CPF ou CNPJ", "Valor", "Data da prestação", "Descrição do serviço", "Código do serviço", "E-mail do cliente", "Endereço", "CEP" ], "total": "540.00", "total_arquivo": null }, "modo_padrao": "linha", "montado_por": { "papel": "owner", "por": "it@gerenota.test" }, "origem": "painel" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### A data da prestação do lote `PUT /api/v1/companies/{company_id}/lotes/{lote_id}/data` S-CN (D-CN7, D-LT4): qual data vai nas notas — `linha` (a coluna de data de cada linha), `emissao` (o dia em que o lote for confirmado) ou `outra` (uma data para o lote todo, em `outra`, AAAA-MM-DD). Data futura não passa. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `modo` | um de: `"linha"`, `"emissao"`, `"outra"` **(obrigatório)** | | | `outra` | string, ou null | | **Exemplo de chamada** ```bash curl -X PUT "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/data" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Editar uma linha da revisão `PATCH /api/v1/companies/{company_id}/lotes/{lote_id}/itens/{item_id}` S-CN (D-CN7): corrige uma linha antes da confirmação — o nome e o e-mail do cliente, o endereço, o serviço (o código e a descrição), o valor, a data, o incluir e o cadastro. A linha volta a ser conferida (o que falta para ela seguir) e a resposta a traz como ficou; o documento do cliente não se edita (a linha com o documento errado vai num lote novo). **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | | `item_id` | path | string **(obrigatório)** | | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `nome` | string, ou null | | | `email` | string, ou null | | | `manter_email` | boolean, ou null | | | `endereco` | objeto EnderecoLinhaIn, ou null | | | `usar_cadastro` | boolean, ou null | | | `codigo_servico` | string, ou null | | | `descricao` | string, ou null | | | `valor` | string, ou null | | | `data_linha` | string, ou null | | | `manter_data_citada` | boolean, ou null | | | `incluir` | boolean, ou null | | | `atualizar_cadastro` | boolean, ou null | | **Exemplo de chamada** ```bash curl -X PATCH "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/itens/{item_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da linha (lti_…) | | `linha` | integer **(obrigatório)** | A linha no arquivo (1 é a primeira) | | `estado` | string **(obrigatório)** | A situação da linha (veja `contagens.por_estado` no lote) | | `incluir` | boolean **(obrigatório)** | A linha entra no lote (as repetidas e as que já têm nota ficam fora) | | `tomador` | objeto **(obrigatório)** | O cliente da nota: `tipo`, `documento`, `nome`, `email` e `endereco` | | `servico` | objeto **(obrigatório)** | O serviço: `cTribNac`, `descricao` e de onde veio o código | | `valor` | string, ou null | O valor da nota, em reais | | `pendencias` | lista de objeto **(obrigatório)** | O que falta para a linha seguir: `campo` e `motivo` | | `nfse_id` | string, ou null | A nota emitida pela linha (nfse_…), quando saiu | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Uma ação em várias linhas da revisão `POST /api/v1/companies/{company_id}/lotes/{lote_id}/itens/acao` S-CN (D-CN7): a mesma ação em várias linhas de uma vez — o código ou a descrição do serviço, a data, incluir ou ignorar, e o que fazer com o cadastro do cliente que diverge. Devolve quantas linhas mudaram e as contagens. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `acao` | um de: `"codigo"`, `"descricao"`, `"data"`, `"ignorar"`, `"incluir"`, `"atualizar_cadastro"`, `"manter_cadastro"`, `"usar_cadastro"`, `"trocar_na_descricao"` **(obrigatório)** | | | `itens` | lista de string, ou null | | | `valor` | string, ou null | | | `de` | string, ou null | trocar_na_descricao: o texto que sai | | `para` | string, ou null | trocar_na_descricao: o texto que entra | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/itens/acao" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `mudou` | integer **(obrigatório)** | Quantas linhas a ação mudou | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação, depois da ação | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Validar as notas prontas no ambiente de teste do gov.br `POST /api/v1/companies/{company_id}/lotes/{lote_id}/validar` D9 (D-LT3): o teste de cada nota pronta no ambiente de teste do Sistema Nacional, pela fila, uma por vez — sem efeito fiscal e fora da cota. Acompanhe em `validacao` no lote e em cada linha. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `itens` | lista de string, ou null | Só estas linhas (o "Validar as 2 de novo"); sem elas, as prontas sem a marca "aceita no teste" | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/validar" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Pausar a emissão do lote `POST /api/v1/companies/{company_id}/lotes/{lote_id}/pausar` S-CN (D-CN7): a fila para depois da nota que está saindo (ela termina); o lote fica `pausado` até continuar. As notas que já saíram continuam valendo. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/pausar" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Continuar a emissão do lote pausado `POST /api/v1/companies/{company_id}/lotes/{lote_id}/continuar` S-CN (D-CN7): o lote pausado volta à fila — só quem pode emitir continua. A fila confere o certificado e a cota do mês (no Plano Free) a cada nota: se faltar algum, o lote pausa de novo, com o motivo. A partir de 1º/11/2026, a recusa do convênio a uma ME/EPP de cidade sem adesão também pausa o lote de novo, com `pausado.motivo.convenio`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/continuar" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do lote (lot_…) | | `company_id` | string **(obrigatório)** | A empresa emissora do lote | | `origem` | string **(obrigatório)** | "painel", "api" (as linhas em JSON), "conector" (as linhas pela IA conectada) ou "lote_anterior" | | `arquivo` | objeto ArquivoDoLoteOut **(obrigatório)** | | | `arquivo.nome` | string, ou null | O nome do arquivo enviado (ou o `nome` das linhas em JSON) | | `arquivo.tipo` | string, ou null | "xlsx", "csv" ou "json" | | `arquivo.tamanho` | integer, ou null | O tamanho do arquivo, em bytes | | `estado` | string **(obrigatório)** | `lendo` → `em_revisao` (o formato conhecido) ou `aprendendo` → `entendi_assim` (o formato novo, que o painel confere) → `em_revisao` → `pronto_para_confirmar` (enviado a quem emite) → `confirmado` → `emitindo` → `concluido`, `parcial` (alguém cancelou o que faltava) ou `cancelado`. Também: `duvida` (uma pergunta sobre a planilha), `equipe` (a planilha foi à equipe), `acima_do_limite` (mais de 200 linhas), `invalido` (o arquivo não se lê) e `pausado` | | `contagens` | objeto ContagensDoLoteOut ou objeto **(obrigatório)** | As linhas por situação; vazio enquanto o lote lê | | `criado_em` | string (date-time) **(obrigatório)** | | | `atualizado_em` | string (date-time) **(obrigatório)** | | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Enviar aos clientes as notas do lote que ficaram sem e-mail `POST /api/v1/companies/{company_id}/lotes/{lote_id}/entregar` A nota emitida pelo lote vai ao e-mail do cliente da linha ou do cadastro; sem nenhum dos dois, a linha fica `email.status = "sem_email"`. Aqui você informa o e-mail de cada cliente (pelo CPF ou CNPJ), e as notas emitidas dele neste lote vão para a fila de entrega: o PDF e o XML, em nome da empresa, como na entrega do lote. Vale também para corrigir o e-mail que falhou ou que o provedor devolveu (com `guardar_no_cadastro`, o cadastro que guardava o endereço devolvido passa ao novo); a correção conta no teto de e-mails do dia (429 `LIMITE_EMAILS_DO_DIA`). Só a nota ativa vai: a cancelada ou substituída fica de fora. Acompanhe em `GET …/lotes/{lote_id}/itens` (`email.status`: `a_enviar`, `enviando`, depois `enviado` ou `falhou`). Valem as travas da revisão: o e-mail inválido, o domínio com erro de digitação e o e-mail da própria empresa voltam em `recusados`. Cada nota sai uma vez por aqui. Confirmam o dono, o operador e a contabilidade com "Pode emitir notas" (403 `LOTE_SEM_PERMISSAO_DE_EMITIR`). **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `emails` | lista de objeto EmailDoCliente **(obrigatório)** | | | `emails.documento` | string **(obrigatório)** | O CPF ou o CNPJ do cliente, com ou sem pontuação | | `emails.email` | string **(obrigatório)** | O e-mail que recebe as notas dele neste lote | | `emails.itens` | lista de string, ou null | Só estas linhas do cliente (o `id` em `GET …/itens`); sem o campo, todas as que estão sem entrega | | `guardar_no_cadastro` | boolean | Grava o e-mail no cadastro do cliente que ainda não tem; troca só o endereço que o provedor devolveu (nunca sobrescreve outro e-mail cadastrado) Padrão: `true`. | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/entregar" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 200** — OK | Campo | Tipo | Descrição | |---|---|---| | `a_enviar` | integer **(obrigatório)** | Quantas notas foram para a fila de entrega | | `clientes` | integer **(obrigatório)** | De quantos clientes | | `recusados` | lista de objeto EntregaRecusada **(obrigatório)** | Os e-mails recusados pelas travas da revisão do lote | | `recusados.documento` | string **(obrigatório)** | | | `recusados.email` | string **(obrigatório)** | | | `recusados.codigo` | string **(obrigatório)** | `email_invalido`, `email_para_conferir` (com `sugestao`), `email_da_empresa` ou `email_em_outro_cliente` (o mesmo e-mail para dois clientes no pedido) | | `recusados.detalhe` | string **(obrigatório)** | | | `recusados.sugestao` | string, ou null | | | `sem_linha` | lista de string **(obrigatório)** | Os documentos sem linha a entregar neste lote (já enviada, de outro lote ou digitado errado) | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | ### O recibo do lote em CSV `GET /api/v1/companies/{company_id}/lotes/{lote_id}/recibo.csv` S-CN (D-CN7): o recibo do lote em CSV (separador `;`, UTF-8), sem fórmula em nenhuma célula — o mesmo do botão "Baixar o recibo" do painel. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | path | string **(obrigatório)** | Id da empresa (de `GET /companies`) | | `lote_id` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/companies/{company_id}/lotes/{lote_id}/recibo.csv" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Uma linha por nota proposta: a linha do arquivo, o cliente, o valor, a situação e o número da nota emitida (`text/csv`) **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### O modelo da planilha do lote `GET /api/v1/lotes/modelo` E3: o caminho mais curto — as colunas que o lote lê na hora, com a data da prestação e o e-mail (opcional). S-CN (D-CN7): no guia público, para a integração montar o arquivo que o lote lê sem IA. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `formato` | query | um de: `"csv"`, `"xlsx"` | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/lotes/modelo" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — O modelo em XLSX (padrão) ou CSV (`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`) **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 422 | Dados inválidos — `erros` aponta o campo | ## Eventos Cancelar, substituir e ler os eventos de uma nota. ### Cancelar uma nota emitida `POST /api/v1/nfse/{nfse_id}/cancelar` Cancela uma NFS-e já emitida, registrando o evento assinado no Sistema Nacional. Informe o motivo (`cMotivo`) e uma justificativa (`xMotivo`) de 15 a 255 caracteres — ela fica no histórico da nota e aparece na consulta pública. Depois do cancelamento a nota passa a `cancelada` e o DANFSE volta a ser gerado com marca d'água de cancelada. Só nota `ativa` pode ser cancelada: se ela já foi cancelada ou substituída, a resposta é 409 `NFSE_NAO_ATIVA`. O cancelamento tem prazo definido pelo município e pela legislação; se o gov.br recusar (prazo vencido, por exemplo), a resposta é 422 com o `code` oficial do erro e a explicação em `message`. Para corrigir dados de uma nota em vez de simplesmente anulá-la, prefira `POST /nfse/{nfse_id}/substituir`. Exige chave com escopo `emissao`. Aceita `Idempotency-Key`: repetir a chamada com a mesma chave devolve o MESMO cancelamento (200, cabeçalho `X-Idempotent-Replay: true`), em vez do 409 da nota que já está cancelada; uma chamada simultânea com a mesma chave recebe 409 `CANCELAMENTO_EM_ANDAMENTO`. A chave vale por nota. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | | `Idempotency-Key` | header | string, ou null | Texto único por intenção (um UUID serve); veja a seção Idempotência | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `cMotivo` | um de: `"1"`, `"2"`, `"9"` | 1 = erro na emissão (padrão) · 2 = serviço não prestado · 9 = outros Padrão: `"1"`. | | `xMotivo` | string **(obrigatório)** | Justificativa em texto livre, de 15 a 255 caracteres — é ela que aparece na consulta pública | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}/cancelar" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"xMotivo": "Cancelamento de emissao de teste do PV4"}' ``` **Resposta 200** — O cancelamento registrado no Sistema Nacional | Campo | Tipo | Descrição | |---|---|---| | `nfse_id` | string **(obrigatório)** | Identificador da nota cancelada (nfse_…) | | `chave` | string **(obrigatório)** | Chave de acesso da nota cancelada, 50 dígitos | | `status` | string **(obrigatório)** | Situação da nota depois do evento: "cancelada" | | `evento_id` | string **(obrigatório)** | Identificador do evento nesta API (evt_…) | | `codigo_evento` | string **(obrigatório)** | Código oficial do evento de cancelamento (101101) | | `elapsed_ms` | integer **(obrigatório)** | Tempo da conversa com o Sistema Nacional, em milissegundos | **Exemplo de resposta** ```json { "chave": "33333333333333333333333333333333333333330000000001", "codigo_evento": "101101", "elapsed_ms": 4, "evento_id": "evt_65667a18942aca82", "nfse_id": "nfse_4e0cc911d4b7507d", "status": "cancelada" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 502 | O Sistema Nacional ou a Receita respondeu com erro | ### Substituir uma nota por outra corrigida `POST /api/v1/nfse/{nfse_id}/substituir` Emite uma nota NOVA no lugar de `nfse_id`, que passa a valer como substituída. O corpo é o mesmo de `POST /companies/{company_id}/nfse` — a nota **corrigida**, inteira — mais o bloco `motivo` com a justificativa fiscal (`motivo.cMotivo`). Use quando os dados de uma nota já emitida estão errados: a substituta é um documento novo, com número e chave próprios, e a antiga fica com status `substituida` apontando para ela em `substituida_por`. Sem `servico.cMunPrestacao`, a substituta mantém o local da prestação da original (o `local_prestacao` de `GET /nfse/{nfse_id}`) — mande o campo só para corrigir o local. Na nota antiga cujo XML não está guardado, vale o município da empresa. A resposta é a nota nova (201), no mesmo formato da emissão. A substituição conta como uma emissão para a cota do plano, herda o ambiente da nota original (substituir uma nota de teste emite outra de teste) e aceita `Idempotency-Key`: repetir a chamada com a mesma chave devolve a MESMA nota nova em vez de emitir outra — inclusive depois de um 503 `EMISSAO_INCERTA`, quando o gov.br não respondeu a tempo: a repetição confere a substituta antes de emitir. Só nota `ativa` pode ser substituída (senão 409 `NFSE_NAO_ATIVA`), e valem as mesmas validações e rejeições da emissão — 422 com o `code` oficial quando o gov.br recusa a nota nova, e nesse caso a original continua ativa. No Simples Nacional (MEI e ME/EPP) a substituta mantém o tomador, a competência e o valor da original: mudar um deles volta 422 `SUBSTITUICAO_MUDA_O_QUE_O_SIMPLES_MANTEM` antes de ir ao gov.br, e o caminho é cancelar a nota e emitir outra. Exige chave com escopo `emissao`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | | `Idempotency-Key` | header | string, ou null | Texto único por intenção (um UUID serve); veja a seção Idempotência | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `dCompet` | string **(obrigatório)** | Competência no formato AAAA-MM-DD: a data da prestação do serviço. Não pode ser futura | | `servico` | objeto ServicoIn **(obrigatório)** | O serviço prestado: o código nacional, o texto que sai na nota e o detalhamento opcional. | | `servico.cMunPrestacao` | string, ou null | Código IBGE do município onde o serviço foi prestado. Omita para usar o município da empresa emissora — só informe quando prestou em outra cidade | | `servico.cTribNac` | string **(obrigatório)** | Código de tributação nacional do serviço, 6 dígitos (ex.: 010501). É o item da lista nacional; sem pontos | | `servico.descricao` | string **(obrigatório)** | Descrição do serviço que sai impressa na nota | | `servico.cNBS` | string, ou null | Código NBS (9 dígitos), quando o município o exigir | | `servico.informacoes_complementares` | string, ou null | Texto livre impresso no campo de informações complementares da nota | | `servico.itens` | lista de objeto ItemIn, ou null | Detalhamento opcional. Com itens, o valor do serviço pode ser omitido: o total é a soma de quantidade × valor unitário e o detalhe vai nas informações complementares | | `valores` | objeto ValoresIn **(obrigatório)** | Os valores da nota, sempre como string decimal com ponto (`"1500.00"`) — nunca número. | | `valores.vServ` | string, ou null | Valor do serviço em reais (ex.: "1500.00"). Obrigatório, salvo quando servico.itens traz o detalhamento — aí o total é calculado | | `valores.vDescIncond` | string, ou null | Desconto incondicionado — abate a base de cálculo do ISSQN | | `valores.vDescCond` | string, ou null | Desconto condicionado — não abate a base de cálculo | | `valores.pTotTribSN` | string, ou null | Percentual aproximado de tributos (Lei 12.741) para optante do Simples. Omita: ME/EPP usa a alíquota da empresa (a do mês pelo PGDAS-D, ou a confirmada no painel) — sem alíquota nenhuma a emissão para em 422 ALIQUOTA_NAO_CONFIRMADA. O MEI não leva o percentual (o Sistema Nacional o recusa para o MEI, E0710): a nota sai com indTotTrib 0, e mandado volta 422 MEI_NAO_INFORMA_PTOTTRIBSN. Mandado diferente da calculada, a nota da ME/EPP sai como veio e o dono é avisado uma vez por mês | | `tributacao` | objeto TributacaoIn | Tributação do ISSQN. Os defaults cobrem o caso comum: serviço tributado no município, sem retenção. Padrão: `{"tribISSQN": "1", "tpRetISSQN": "1"}`. | | `tributacao.tribISSQN` | um de: `"1"`, `"2"`, `"3"`, `"4"` | 1 = tributável no município (único aceito hoje) · 2 = imunidade · 3 = exportação · 4 = não incidência Padrão: `"1"`. | | `tributacao.tpRetISSQN` | um de: `"1"`, `"2"`, `"3"` | Retenção do ISSQN: 1 = não retido (padrão) · 2 = retido pelo tomador · 3 = retido pelo intermediário (ainda não suportado) Padrão: `"1"`. | | `tributacao.pAliq` | string, ou null | Alíquota do ISSQN em %, string decimal até 5.00 (ex.: "4.53"). Informe SOMENTE quando há retenção (tpRetISSQN=2); sem retenção, a alíquota parametrizada do município é aplicada pelo sistema | | `tomador` | objeto TomadorIn, ou null | O cliente. Opcional: a nota pode sair sem tomador identificado | | `ambiente` | um de: `"producao"`, `"teste"` | "producao" (padrão) emite a nota valendo. "teste" valida tudo no ambiente restrito do gov.br sem efeito fiscal: não consome cota, não aparece nas listagens e é descartada em 24 h Padrão: `"producao"`. | | `motivo` | objeto SubstituicaoMotivoIn **(obrigatório)** | Por que a nota está sendo substituída (justificativa fiscal oficial). | | `motivo.cMotivo` | string **(obrigatório)** | 01 = desenquadramento do Simples Nacional · 02 = enquadramento no Simples Nacional · 03 = inclusão retroativa de imunidade/isenção · 04 = exclusão retroativa de imunidade/isenção · 05 = rejeição pelo tomador (ou intermediário responsável) · 99 = outros (erro de valor, de serviço ou de tomador) | | `motivo.xMotivo` | string, ou null | Explicação em texto livre, de 15 a 255 caracteres; obrigatória no 99 | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}/substituir" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"dCompet": "2026-07-01", "motivo": {"cMotivo": "01"}, "servico": {"cMunPrestacao": "2408102", "cNBS": "111032200", "cTribNac": "010501", "descricao": "LICENCA DE USO DE SOFTWARE - TESTE"}, "tributacao": {"tpRetISSQN": "1", "tribISSQN": "1"}, "valores": {"vServ": "500.00"}}' ``` **Resposta 201** — A nota NOVA, que substitui a anterior | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da nota nesta API (nfse_…) — use nas rotas /nfse/{nfse_id} | | `chave_acesso` | string **(obrigatório)** | Chave de acesso da NFS-e no Sistema Nacional, 50 dígitos | | `serie` | string **(obrigatório)** | Série da DPS, do cadastro da empresa | | `nDPS` | string **(obrigatório)** | Número sequencial da DPS dentro da série | | `numero` | string, ou null | Número oficial da NFS-e (nNFSe) atribuído pelo gov.br — é este que sai no DANFSE e o que o cliente enxerga | | `dps_id` | string **(obrigatório)** | Identificador da DPS assinada que gerou a nota | | `valor_servico` | string, ou null **(obrigatório)** | Valor do serviço em reais, string decimal (ex.: "1500.00") | | `status` | string **(obrigatório)** | Situação da nota: "ativa" logo após a emissão | | `ndps_ressincronizado` | boolean | true quando o número da DPS foi realinhado com o servidor porque outro emissor usava a série Padrão: `false`. | | `elapsed_ms` | integer **(obrigatório)** | Tempo da conversa com o Sistema Nacional, em milissegundos | | `substitui_chave` | string, ou null | Chave da nota substituída, quando esta nota saiu de uma substituição | | `avisos` | lista de objeto AvisoOut, ou null | O que vale conferir numa nota que saiu — hoje, o ISS retido por um tomador de fora do município do ISS (`RETENCAO_COM_TOMADOR_DE_OUTRO_MUNICIPIO`); nulo quando não há nada | **Exemplo de resposta** ```json { "chave_acesso": "33333333333333333333333333333333333333330000000002", "dps_id": "DPS000000000000000000000000000000000000000002", "elapsed_ms": 7, "id": "nfse_6bc91eed52e012d3", "nDPS": "2", "ndps_ressincronizado": false, "numero": "102", "serie": "1", "status": "ativa", "substitui_chave": "33333333333333333333333333333333333333330000000001", "valor_servico": "500.00" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 502 | O Sistema Nacional ou a Receita respondeu com erro | ### Listar os eventos de uma nota `GET /api/v1/nfse/{nfse_id}/eventos` Devolve a linha do tempo de uma nota: cancelamento, substituição e os demais eventos do gov.br. Os eventos vêm do mais antigo para o mais recente (até 100), cada um com `tipo`, o `codigo` oficial, a `descricao` com o nome do evento, `muda_situacao`, a data/hora `dh` e o `detalhe` do que foi registrado — no cancelamento, o motivo e a justificativa; na substituição, o motivo e o id da nota que entrou no lugar. Além dos feitos aqui, entram os que chegam pela importação do Sistema Nacional: o cancelamento deferido por análise fiscal e o por ofício, que também tiram a nota de ativa, e os que só registram histórico, como a rejeição do tomador e o bloqueio por ofício. Use para explicar a situação de uma nota que não está mais `ativa`, ou para auditar o que aconteceu com ela. Nota sem nenhum evento devolve lista vazia. Basta uma chave com escopo `leitura`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}/eventos" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Os eventos da nota, do mais antigo ao mais recente | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do evento nesta API (evt_…) | | `nfse_id` | string, ou null | A nota a que o evento pertence | | `company_id` | string, ou null | Empresa emissora da nota | | `chave` | string, ou null | Chave de acesso da nota, 50 dígitos | | `tipo` | string, ou null | "cancelamento", "substituicao" ou "dfe:" para eventos espelhados do Sistema Nacional | | `codigo` | string, ou null | Código oficial do evento no leiaute nacional: 101101 cancelamento, 105102 substituição, 105104 cancelamento deferido por análise fiscal e 305101 cancelamento por ofício tiram a nota de ativa; os demais (análise fiscal pedida ou indeferida, bloqueio e desbloqueio por ofício, confirmação e rejeição) só registram histórico | | `descricao` | string, ou null | Nome oficial do evento, como "Cancelamento por ofício" ou "Rejeição do tomador" | | `muda_situacao` | boolean, ou null | Se o evento tirou a nota de ativa (cancelamento ou substituição, por qualquer via); os outros só registram histórico | | `detalhe` | objeto, ou null | Dados do evento: no cancelamento, cMotivo e xMotivo; na substituição, cMotivo e o id da nota que substituiu | | `dh` | string (date-time), ou null | Data/hora (UTC) oficial do evento: o dhEvento do XML nos espelhados do gov.br, o registro nesta API nos feitos aqui — é a data que vale para a contabilidade | | `xml_disponivel` | boolean, ou null | Se `GET /nfse/{nfse_id}/eventos/{id}/xml` devolve o XML deste evento | **Exemplo de resposta** ```json [ { "chave": "77777777777777777777777777777777777777777777777777", "codigo": "101101", "company_id": "cmp_af35ed222461262c", "descricao": "Cancelamento", "detalhe": { "nsu": 2, "status": "cancelada" }, "dh": "2026-09-01T01:30:00Z", "id": "evt_dfe_77777777777777777777777777777777777777777777777777_101101", "muda_situacao": true, "nfse_id": "nfse_227e66657b800a34", "tipo": "dfe:101101", "xml_disponivel": true } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Baixar o XML do evento (cancelamento ou substituição) `GET /api/v1/nfse/{nfse_id}/eventos/{evento_id}/xml` Devolve o XML de um evento da nota — os bytes do arquivo, não JSON. É a prova do cancelamento ou da substituição. O XML da nota em `GET /nfse/{id}/xml` é o autorizado e continua idêntico depois do evento, então um sistema contábil que só recebe a nota a importa como válida: mande o evento junto. O `evento_id` vem de `GET /nfse/{id}/eventos`; id que não é desta nota devolve 404 `EVENTO_NAO_ENCONTRADO`. Nem todo evento tem arquivo próprio: a substituição feita por esta API registra um evento local sem XML (o e105102 oficial é gerado pelo Sistema Nacional e chega pela importação do DFe como outro evento da mesma nota) — aí a resposta é 404 `EVENTO_SEM_XML`. Arquivo ainda não disponível no armazenamento devolve 409 `ARQUIVO_INDISPONIVEL`. Basta uma chave com escopo `leitura`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `nfse_id` | path | string **(obrigatório)** | Id da nota (de `GET /nfse` ou da emissão) | | `evento_id` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse/{nfse_id}/eventos/{evento_id}/xml" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -o evento.xml ``` **Resposta 200** — O XML do evento, como o Sistema Nacional o registrou (`application/xml`) **Exemplo de resposta** ```json { "_binario": "application/xml", "_bytes": 396 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Listar o que mudou de situação na conta `GET /api/v1/nfse/eventos` Devolve, em ordem cronológica, as notas da conta que foram canceladas ou substituídas no período — a resposta para "o que mudou desde a última vez que mandei ao contador". `de`/`ate` recortam um período pela hora OFICIAL do evento (inclusivos, como nas outras listagens: "o que foi cancelado em agosto"). Para sincronizar, guarde o maior `cursor` da página e chame com `desde` igual a ele: o que voltar é novidade. O `cursor` é a hora em que o evento entrou aqui, e não a oficial — o cancelamento feito pela prefeitura chega na importação do dia seguinte com data anterior, e pela hora oficial ele nasceria "antes" do seu cursor e nunca seria entregue. Com `desde`, a lista vem na ordem de entrada; sem ele, na ordem cronológica oficial. Quem guardava a `dh` como cursor continua funcionando: no pior caso recebe de novo o último evento, nunca deixa de receber um. Cada item traz a nota (`nfse_id`, `numero`, `chave`), o `codigo` do evento, a situação atual e, na substituição, `substituida_por`; `xml_disponivel` diz se o XML do evento pode ser baixado em `GET /nfse/{nfse_id}/eventos/{id}/xml`. Vem uma linha por mudança: o registro feito aqui e o espelho oficial do gov.br contam uma vez só. Entram os cancelamentos e as substituições por qualquer via — feitos aqui, no portal do gov.br ou pela prefeitura (cancelamento deferido por análise fiscal, cancelamento por ofício) —, cada um com `descricao`. Com `todos=true` vêm também os eventos que só registram histórico, como a rejeição do tomador e o bloqueio por ofício, com `muda_situacao=false`. Sem `desde`, começa do primeiro evento da conta; `limit` vai até 500 — se voltar cheio, repita com `desde` na última `dh`. Data fora do formato devolve 422 `DATA_INVALIDA`. Respeita o recorte de empresas do seu acesso. Basta uma chave com escopo `leitura`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `de` | query | string, ou null | Início do período (inclusivo): `2026-08` (mês), `2026-08-01` (dia) ou ISO 8601 com hora; sem fuso vale Brasília. Para o cursor de sincronização prefira `desde` | | `ate` | query | string, ou null | Fim do período (inclusivo): mês ou dia inteiros, ou ISO 8601 com hora | | `desde` | query | string, ou null | Só o que ENTROU depois deste instante (exclusivo): o maior `cursor` da página anterior — o cursor da sincronização | | `todos` | query | boolean | Inclui os eventos que não mudam a situação da nota: análise fiscal pedida ou indeferida, bloqueio e desbloqueio por ofício, confirmação e rejeição do tomador ou do intermediário | | `company_id` | query | string, ou null | Id da empresa (de `GET /companies`) | | `limit` | query | integer | Quantos eventos por resposta, até 500 | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/nfse/eventos" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Os cancelamentos e substituições da conta no período, do mais antigo ao mais recente | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do evento (evt_…) — serve em `GET /nfse/{nfse_id}/eventos/{id}/xml` | | `nfse_id` | string **(obrigatório)** | A nota que mudou de situação | | `numero` | string, ou null | Número oficial da nota (nNFSe) | | `chave` | string, ou null | Chave de acesso da nota, 50 dígitos | | `company_id` | string, ou null | Empresa emissora da nota | | `codigo` | string, ou null | Código oficial do evento: 101101 cancelamento, 105102 substituição, 105104 cancelamento deferido por análise fiscal, 305101 cancelamento por ofício; com `todos=true`, também os que só registram histórico | | `descricao` | string, ou null | Nome oficial do evento, como "Cancelamento por ofício" | | `muda_situacao` | boolean | Se o evento tirou a nota de ativa; só vem `false` com `todos=true` Padrão: `true`. | | `status` | string, ou null | Situação da nota hoje: `cancelada` ou `substituida` (com `todos=true`, também `ativa`) | | `substituida_por` | string, ou null | Na substituição, o id da nota que entrou no lugar | | `dh` | string (date-time), ou null | Data/hora (UTC) OFICIAL do evento — a que vale para a contabilidade; pode ser de ontem nos que chegam pela importação do Sistema Nacional | | `cursor` | string (date-time), ou null | Quando o evento entrou nesta plataforma. É ISTO que vai em `desde` na próxima chamada: a hora oficial não serve de cursor, porque o cancelamento feito pela prefeitura chega depois com data anterior | | `xml_disponivel` | boolean **(obrigatório)** | Se `GET /nfse/{nfse_id}/eventos/{id}/xml` devolve o XML do evento | **Exemplo de resposta** ```json [ { "chave": "77777777777777777777777777777777777777777777777777", "codigo": "101101", "company_id": "cmp_76efdb177bc3aba2", "cursor": "2026-09-17T18:46:30.139000Z", "descricao": "Cancelamento", "dh": "2026-09-01T01:30:00Z", "id": "evt_dfe_acc_it_77777777777777777777777777777777777777777777777777_101101", "muda_situacao": true, "nfse_id": "nfse_36a9855d503574ee", "numero": "1", "status": "cancelada", "substituida_por": null, "xml_disponivel": true } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ## Tomadores Os clientes (tomadores) da conta e a sugestão pela última nota. ### Listar e buscar tomadores da conta `GET /api/v1/tomadores` Lista os tomadores (clientes) da conta. Sem `q`, devolve todos; com `q`, filtra. A busca por nome ignora acento e maiúsculas — `joao`, `JOÃO` e `João` acham o mesmo cadastro. O termo só é tratado como **documento** quando é de fato um documento: 3 ou mais dígitos e nenhuma letra, ou o CNPJ com letras — letras e números juntos, sem espaço, com ou sem a pontuação (`12.ABC`, `12abc345`); aí o nome também vale (busca por prefixo do CNPJ/CPF, em todos os cadastros da conta — o documento inteiro acha o tomador). Quem acessa com recorte de empresas (membro recortado, ou empresa compartilhada de outra conta) vê os clientes que já receberam nota das empresas dele e os que ele mesmo cadastrou — na lista, na busca por nome e no prefixo do documento; o documento inteiro (11 ou 14 caracteres) acha qualquer cadastro da conta, para ninguém cadastrar o mesmo cliente duas vezes — o de fora do acesso vem com `fora_do_recorte: true` e só o `id`, o documento, o tipo, o nome e a origem (sem e-mail, telefone, endereço, inscrição e data da última nota), e só para quem cadastra clientes (escopo `emissao`; o leitor e a contabilidade com recorte não o recebem). Com recorte, `ultima_nota_em` é a da nota mais recente das empresas do seu acesso (e a ordem padrão segue ela), e o cliente que a conta também atende por uma empresa de fora do seu acesso vem com `de_outras_empresas: true` — o contato e a exclusão dele ficam com o dono da conta. Termo com espaço é sempre busca por nome, mesmo que contenha números ("Loja 2", "Grupo 3R"). `limit` vai de 1 a 200 (padrão 200); valores maiores são reduzidos ao teto. `ordem` aceita `ultima_nota_desc` (padrão — quem recebeu nota mais recentemente primeiro), `nome_asc`, `nome_desc` e `criado_desc`. O cabeçalho `X-Total-Count` traz o total de resultados ANTES do corte por `limit`, então use-o para saber se há mais do que a página devolvida. Lista vazia não é erro: é uma conta sem tomadores ou uma busca sem correspondência. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `q` | query | string, ou null | | | `limit` | query | integer | | | `ordem` | query | um de: `"ultima_nota_desc"`, `"nome_asc"`, `"nome_desc"`, `"criado_desc"` | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/tomadores" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Tomadores encontrados, já ordenados | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do tomador nesta conta — use em `PATCH` e `DELETE /tomadores/{id}` | | `documento` | string **(obrigatório)** | CNPJ (14 caracteres; letras A–Z só nas 12 primeiras posições) ou CPF (11 números), sem pontuação | | `tipo` | um de: `"CNPJ"`, `"CPF"` **(obrigatório)** | Natureza do documento | | `nome` | string **(obrigatório)** | Razão social (CNPJ) ou nome da pessoa (CPF) | | `nome_fantasia` | string, ou null | Nome fantasia, quando houver (só existe em CNPJ) | | `origem` | um de: `"importado"`, `"manual"`, `"link"`, `"serpro"` **(obrigatório)** | De onde veio o cadastro: `importado` (varredura das notas antigas do município), `manual`, `link` (formulário público preenchido pelo próprio cliente) ou `serpro` (autocompletar pela Receita) | | `ultima_nota_em` | string, ou null | Competência (AAAA-MM-DD) da nota mais recente emitida para este tomador; `null` se nunca houve. Para quem tem recorte (membro recortado ou empresa compartilhada), a das empresas do seu acesso | | `inscricao_municipal` | string, ou null | Inscrição municipal do tomador, se informada | | `email` | string, ou null | E-mail para o envio da nota, se informado | | `fone` | string, ou null | Telefone só dígitos, com DDD (celular no formato antigo ganha o 9º dígito ao ser gravado) | | `endereco` | objeto EnderecoTomador, ou null | Endereço, possivelmente parcial; `null` quando o cadastro não tem endereço | | `criado_em` | string (date-time), ou null | Quando o cadastro foi criado (UTC, ISO 8601) | | `atualizado_em` | string (date-time), ou null | Quando o cadastro foi alterado pela última vez (UTC, ISO 8601); `null` se nunca | | `receita_campos` | objeto, ou null | Nos clientes CNPJ comparados com o cadastro da Receita, a origem de cada campo que acompanha a Receita (`nome`, `nome_fantasia`, `endereco`). Ausente nos demais | | `receita_sugestoes` | lista de objeto SugestaoDaReceitaOut, ou null | O que o cadastro da Receita tem de diferente nesta ficha, para aceitar ou dispensar no painel (Tomadores → Sugestões da Receita). E-mail e telefone só aparecem quando a ficha não tem. Ausente quando não há | | `receita_situacao` | objeto SituacaoNaReceitaOut, ou null | O CNPJ baixado, inapto, suspenso ou nulo na Receita: só aviso, a nota sai. Some sozinho quando a Receita volta a dizer ativo. Ausente nos demais | | `receita_pendente` | objeto PendenciaDaReceitaOut, ou null | A ficha espera a atualização pela Receita (o cadastro não respondeu): ela se atualiza sozinha quando ele voltar. Ausente nos demais | | `receita_nao_achado` | objeto NaoAchadoNaReceitaOut, ou null | O CNPJ ainda não aparece no cadastro da Receita do mês (pode ser recente): a ficha fica com os dados das notas, e a comparação se repete no mês seguinte. Ausente nos demais | | `receita_mes` | string, ou null | O mês do cadastro da Receita da última comparação desta ficha (`AAAA-MM`) | | `fora_do_recorte` | boolean, ou null | `true` no cadastro de fora do seu acesso que só a busca pelo documento inteiro acha (membro recortado ou empresa compartilhada): vêm o `id`, o documento, o tipo, o nome e a origem, sem os contatos, o endereço e a data da última nota. Ausente nos demais | | `de_outras_empresas` | boolean, ou null | `true`, para quem tem recorte (membro recortado ou empresa compartilhada), no cliente do seu acesso que a conta também atende por uma empresa de fora dele: o e-mail, o telefone, a inscrição e o endereço valem para as notas e a entrega dessas empresas também, e por isso só o dono da conta os muda ou exclui o cadastro (`PATCH` e `DELETE` devolvem 403 `TOMADOR_DE_OUTRA_EMPRESA`). Ausente nos demais | **Exemplo de resposta** ```json [ { "atualizado_em": null, "criado_em": "2026-09-16T23:42:21.952000Z", "documento": "11222333000181", "email": null, "endereco": null, "fone": null, "id": "tom_6bfa8ab92ccc743b", "inscricao_municipal": null, "nome": "CONDOMINIO SOLAR DAS ACACIAS", "nome_fantasia": null, "origem": "importado", "tipo": "CNPJ", "ultima_nota_em": "2026-05-01" }, { "atualizado_em": null, "criado_em": "2026-09-16T23:42:21.933000Z", "documento": "03635323000140", "email": "fiscal@conselhox.org.br", "endereco": { "CEP": "59064902", "cMun": "2408102", "nro": "2860", "xBairro": "Lagoa Nova", "xCpl": null, "xLgr": "Av. Salgado Filho" }, "fone": "8432110000", "id": "tom_7a9fefc3536e14a7", "inscricao_municipal": null, "nome": "CONSELHO NACIONAL X", "nome_fantasia": null, "origem": "importado", "tipo": "CNPJ", "ultima_nota_em": "2026-04-01" } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ### Cadastrar um tomador `POST /api/v1/tomadores` Cria um tomador (cliente) na conta. Exige chave com escopo `emissao` — chave de `leitura` recebe 403 `PERMISSAO_NEGADA`. O `documento` pode vir com ou sem pontuação: a máscara é removida, os dígitos verificadores são conferidos (422 `DOCUMENTO_INVALIDO` se não baterem) e o cadastro é gravado sem pontuação (o CNPJ pode ter letras nas 12 primeiras posições; minúscula vira maiúscula). O documento é único por conta: se já existir, a resposta é 409 `TOMADOR_JA_EXISTE` — nesse caso localize o cadastro em `GET /tomadores?q=…` e altere com `PATCH /tomadores/{id}`. **CNPJ sem `nome`: o cadastro sai da Receita.** A plataforma busca o CNPJ (a mesma consulta de `GET /consultas/cnpj/{documento}`: pelo cadastro mensal da Receita, sem custo e sem cota; o CNPJ que ainda não está nele vai à consulta em tempo real, que gasta uma unidade da cota mensal do plano) e cadastra com a razão social como `nome`, o nome fantasia e o endereço da Receita. Um `nome_fantasia` mandado vale quando a Receita não tem um. O e-mail da Receita **não** vira o de entrega — ele volta em `receita.email`. A resposta traz `receita` com a situação do CNPJ (`ativa: false` quando ele está suspenso, inapto, baixado ou nulo: o cadastro sai, confira com o cliente). CNPJ que a Receita não conhece: 422 `CNPJ_NAO_ENCONTRADO_NA_RECEITA` (a Receita cobra a resposta). Quando a busca não sai — 402 `COTA_CONSULTAS_ESGOTADA`, 429 `LIMITE_CONSULTAS_DIA` ou `RATE_LIMIT`, 503 `SERPRO_INDISPONIVEL` ou `CONSULTAS_PAUSADAS` —, nada é cadastrado: mande o `nome` e o cadastro segue sem a Receita. **Com o `nome`, nada é consultado e nada é cobrado.** CPF sempre exige o `nome`. O endereço é opcional e pode ser parcial; se mandar `cMun`, use um código IBGE de verdade (`/consultas/cep/{cep}` devolve o código pelo CEP). Cadastrar aqui não emite nota nenhuma: o cadastro só poupa digitação na emissão e guarda o e-mail de entrega. **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `tipo` | string | Natureza do documento: `CNPJ` (padrão) ou `CPF` Padrão: `"CNPJ"`. | | `documento` | string **(obrigatório)** | CNPJ ou CPF do tomador. Aceita com ou sem pontuação (a máscara é removida) e os dígitos verificadores são conferidos; o CNPJ pode ter letras nas 12 primeiras posições (minúscula vira maiúscula). Gravado e devolvido sem pontuação | | `nome` | string, ou null | Razão social (CNPJ) ou nome da pessoa (CPF). Obrigatório no CPF. No CNPJ, sem ele a plataforma busca o cadastro na Receita (pelo cadastro mensal, sem cota; o CNPJ que ainda não está nele usa a cota do plano — veja `POST /tomadores`) | | `nome_fantasia` | string, ou null | Nome fantasia, quando houver (só em CNPJ) | | `inscricao_municipal` | string, ou null | Inscrição municipal do tomador, se houver | | `email` | string, ou null | E-mail para receber a nota emitida | | `fone` | string, ou null | Telefone com DDD, com ou sem máscara; celular no formato antigo (8 dígitos) ganha o 9º | | `endereco` | objeto EnderecoTomador, ou null | Endereço do tomador. Pode ser parcial; se mandar `cMun`, ele precisa ser um código IBGE existente (use `/consultas/cep/{cep}` ou `/consultas/municipio` para obtê-lo, nunca chute) | | `origem` | string | Informativo: `manual` (digitado) ou `serpro` (preenchido a partir de uma consulta à Receita) Padrão: `"manual"`. | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/tomadores" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"documento": "34238864000168", "nome": "NOME ANTIGO", "tipo": "CNPJ"}' ``` **Resposta 201** — Tomador cadastrado | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do tomador nesta conta — use em `PATCH` e `DELETE /tomadores/{id}` | | `documento` | string **(obrigatório)** | CNPJ (14 caracteres; letras A–Z só nas 12 primeiras posições) ou CPF (11 números), sem pontuação | | `tipo` | um de: `"CNPJ"`, `"CPF"` **(obrigatório)** | Natureza do documento | | `nome` | string **(obrigatório)** | Razão social (CNPJ) ou nome da pessoa (CPF) | | `nome_fantasia` | string, ou null | Nome fantasia, quando houver (só existe em CNPJ) | | `origem` | um de: `"importado"`, `"manual"`, `"link"`, `"serpro"` **(obrigatório)** | De onde veio o cadastro: `importado` (varredura das notas antigas do município), `manual`, `link` (formulário público preenchido pelo próprio cliente) ou `serpro` (autocompletar pela Receita) | | `ultima_nota_em` | string, ou null | Competência (AAAA-MM-DD) da nota mais recente emitida para este tomador; `null` se nunca houve. Para quem tem recorte (membro recortado ou empresa compartilhada), a das empresas do seu acesso | | `inscricao_municipal` | string, ou null | Inscrição municipal do tomador, se informada | | `email` | string, ou null | E-mail para o envio da nota, se informado | | `fone` | string, ou null | Telefone só dígitos, com DDD (celular no formato antigo ganha o 9º dígito ao ser gravado) | | `endereco` | objeto EnderecoTomador, ou null | Endereço, possivelmente parcial; `null` quando o cadastro não tem endereço | | `criado_em` | string (date-time), ou null | Quando o cadastro foi criado (UTC, ISO 8601) | | `atualizado_em` | string (date-time), ou null | Quando o cadastro foi alterado pela última vez (UTC, ISO 8601); `null` se nunca | | `receita_campos` | objeto, ou null | Nos clientes CNPJ comparados com o cadastro da Receita, a origem de cada campo que acompanha a Receita (`nome`, `nome_fantasia`, `endereco`). Ausente nos demais | | `receita_sugestoes` | lista de objeto SugestaoDaReceitaOut, ou null | O que o cadastro da Receita tem de diferente nesta ficha, para aceitar ou dispensar no painel (Tomadores → Sugestões da Receita). E-mail e telefone só aparecem quando a ficha não tem. Ausente quando não há | | `receita_situacao` | objeto SituacaoNaReceitaOut, ou null | O CNPJ baixado, inapto, suspenso ou nulo na Receita: só aviso, a nota sai. Some sozinho quando a Receita volta a dizer ativo. Ausente nos demais | | `receita_pendente` | objeto PendenciaDaReceitaOut, ou null | A ficha espera a atualização pela Receita (o cadastro não respondeu): ela se atualiza sozinha quando ele voltar. Ausente nos demais | | `receita_nao_achado` | objeto NaoAchadoNaReceitaOut, ou null | O CNPJ ainda não aparece no cadastro da Receita do mês (pode ser recente): a ficha fica com os dados das notas, e a comparação se repete no mês seguinte. Ausente nos demais | | `receita_mes` | string, ou null | O mês do cadastro da Receita da última comparação desta ficha (`AAAA-MM`) | | `receita` | objeto ReceitaDoCadastroOut, ou null | O resumo da busca na Receita; `null` quando o nome veio no pedido | **Exemplo de resposta** ```json { "atualizado_em": null, "criado_em": "2026-09-16T18:51:55.292479Z", "documento": "34238864000168", "email": null, "endereco": null, "fone": null, "id": "tom_37ce407af8d61b80", "inscricao_municipal": null, "nome": "NOME ANTIGO", "nome_fantasia": null, "origem": "manual", "tipo": "CNPJ", "ultima_nota_em": null } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | | 503 | Serviço externo indisponível ou não configurado | ### Atualizar um tomador `PATCH /api/v1/tomadores/{tomador_id}` Altera um tomador já cadastrado. Exige chave com escopo `emissao`. É um PATCH de verdade: mande **apenas** os campos que quer mudar — o que não vier fica como está. Corpo sem nenhum campo é recusado com 422 `NADA_A_ATUALIZAR`, e `tomador_id` inexistente (ou de outra conta) devolve 404 `TOMADOR_NAO_ENCONTRADO`. O cliente fora do seu acesso (membro recortado ou empresa compartilhada) também devolve 404: quem tem recorte altera só os clientes que já receberam nota das empresas dele e os que ele mesmo cadastrou — mesmo que o documento inteiro, em `GET /tomadores?q=`, ache outro cadastro da conta. O `endereco`, quando enviado, substitui o anterior por inteiro — não é um merge campo a campo. O contato (`email`, `fone`, `inscricao_municipal`, `endereco`) vale para as notas e a entrega de todas as empresas da conta. Por isso quem tem recorte não o muda no cliente que a conta também atende por uma empresa de fora do seu acesso (o `de_outras_empresas: true` da lista): 403 `TOMADOR_DE_OUTRA_EMPRESA` — quem muda é o dono da conta. Mandar de volta o mesmo valor gravado não conta como mudança. `documento` e `tipo` não se alteram por aqui: para corrigir o documento, exclua o cadastro e crie outro. A resposta é o tomador completo já atualizado. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `tomador_id` | path | string **(obrigatório)** | Id do tomador (de `GET /tomadores`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `nome` | string, ou null | Novo nome ou razão social | | `nome_fantasia` | string, ou null | Novo nome fantasia | | `inscricao_municipal` | string, ou null | Nova inscrição municipal | | `email` | string, ou null | Novo e-mail para receber a nota | | `fone` | string, ou null | Novo telefone com DDD; celular de 8 dígitos ganha o 9º ao ser gravado | | `endereco` | objeto EnderecoTomador, ou null | Novo endereço (substitui o anterior por inteiro). Pode ser parcial; `cMun`, se vier, precisa ser um código IBGE existente | **Exemplo de chamada** ```bash curl -X PATCH "https://api.gerenota.com.br/api/v1/tomadores/{tomador_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"nome": "João Wagner Chaves Costa"}' ``` **Resposta 200** — Tomador depois da alteração | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador do tomador nesta conta — use em `PATCH` e `DELETE /tomadores/{id}` | | `documento` | string **(obrigatório)** | CNPJ (14 caracteres; letras A–Z só nas 12 primeiras posições) ou CPF (11 números), sem pontuação | | `tipo` | um de: `"CNPJ"`, `"CPF"` **(obrigatório)** | Natureza do documento | | `nome` | string **(obrigatório)** | Razão social (CNPJ) ou nome da pessoa (CPF) | | `nome_fantasia` | string, ou null | Nome fantasia, quando houver (só existe em CNPJ) | | `origem` | um de: `"importado"`, `"manual"`, `"link"`, `"serpro"` **(obrigatório)** | De onde veio o cadastro: `importado` (varredura das notas antigas do município), `manual`, `link` (formulário público preenchido pelo próprio cliente) ou `serpro` (autocompletar pela Receita) | | `ultima_nota_em` | string, ou null | Competência (AAAA-MM-DD) da nota mais recente emitida para este tomador; `null` se nunca houve. Para quem tem recorte (membro recortado ou empresa compartilhada), a das empresas do seu acesso | | `inscricao_municipal` | string, ou null | Inscrição municipal do tomador, se informada | | `email` | string, ou null | E-mail para o envio da nota, se informado | | `fone` | string, ou null | Telefone só dígitos, com DDD (celular no formato antigo ganha o 9º dígito ao ser gravado) | | `endereco` | objeto EnderecoTomador, ou null | Endereço, possivelmente parcial; `null` quando o cadastro não tem endereço | | `criado_em` | string (date-time), ou null | Quando o cadastro foi criado (UTC, ISO 8601) | | `atualizado_em` | string (date-time), ou null | Quando o cadastro foi alterado pela última vez (UTC, ISO 8601); `null` se nunca | | `receita_campos` | objeto, ou null | Nos clientes CNPJ comparados com o cadastro da Receita, a origem de cada campo que acompanha a Receita (`nome`, `nome_fantasia`, `endereco`). Ausente nos demais | | `receita_sugestoes` | lista de objeto SugestaoDaReceitaOut, ou null | O que o cadastro da Receita tem de diferente nesta ficha, para aceitar ou dispensar no painel (Tomadores → Sugestões da Receita). E-mail e telefone só aparecem quando a ficha não tem. Ausente quando não há | | `receita_situacao` | objeto SituacaoNaReceitaOut, ou null | O CNPJ baixado, inapto, suspenso ou nulo na Receita: só aviso, a nota sai. Some sozinho quando a Receita volta a dizer ativo. Ausente nos demais | | `receita_pendente` | objeto PendenciaDaReceitaOut, ou null | A ficha espera a atualização pela Receita (o cadastro não respondeu): ela se atualiza sozinha quando ele voltar. Ausente nos demais | | `receita_nao_achado` | objeto NaoAchadoNaReceitaOut, ou null | O CNPJ ainda não aparece no cadastro da Receita do mês (pode ser recente): a ficha fica com os dados das notas, e a comparação se repete no mês seguinte. Ausente nos demais | | `receita_mes` | string, ou null | O mês do cadastro da Receita da última comparação desta ficha (`AAAA-MM`) | **Exemplo de resposta** ```json { "atualizado_em": "2026-09-16T18:52:05.346944Z", "criado_em": "2026-09-16T18:52:05.323000Z", "documento": "52998224725", "email": null, "endereco": null, "fone": null, "id": "tom_2a166d137dfd8a7f", "inscricao_municipal": null, "nome": "João Wagner Chaves Costa", "nome_fantasia": null, "origem": "manual", "tipo": "CPF", "ultima_nota_em": null } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Excluir um tomador `DELETE /api/v1/tomadores/{tomador_id}` Remove o cadastro de um tomador da conta. Exige chave com escopo `emissao`. Sucesso devolve 204 sem corpo; `tomador_id` inexistente (ou de outra conta) devolve 404 `TOMADOR_NAO_ENCONTRADO`. O cliente fora do seu acesso (membro recortado ou empresa compartilhada) também devolve 404: quem tem recorte exclui só os clientes que já receberam nota das empresas dele e os que ele mesmo cadastrou — e não exclui o cliente que a conta também atende por uma empresa de fora do seu acesso (o `de_outras_empresas: true` da lista): 403 `TOMADOR_DE_OUTRA_EMPRESA`, porque a entrega e as automações dessas empresas usam o cadastro. A exclusão apaga **somente o cadastro**: as notas já emitidas para esse documento continuam intactas, e o histórico segue disponível em `/nfse` e em `GET /tomadores/{documento}/sugestao`. Não há desfazer — para voltar atrás, cadastre de novo. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `tomador_id` | path | string **(obrigatório)** | Id do tomador (de `GET /tomadores`) | **Exemplo de chamada** ```bash curl -X DELETE "https://api.gerenota.com.br/api/v1/tomadores/{tomador_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 204** — Sem corpo **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Sugerir a próxima emissão pelo histórico `GET /api/v1/tomadores/{documento}/sugestao` Devolve os campos da próxima nota para este tomador, deduzidos das notas anteriores — é o "emitir igual à última". Use antes de montar um `POST /companies/{id}/nfse` para não perguntar ao usuário o que o histórico já responde. O `documento` no caminho é o CNPJ/CPF **sem pontuação** (o CNPJ pode ter letras), e não precisa haver cadastro: o que vale é o histórico de notas. Passe `company_id` em conta com mais de uma empresa — sem ele a busca varre a conta inteira e pode trazer o serviço de outra emissora; com ele, empresa fora do seu acesso devolve 403 `EMPRESA_FORA_DO_RECORTE`. Sem nota anterior a resposta é `{"tem_historico": false, "email_cadastro": …, "cadastrado": …}` (200, não 404); `cadastrado` diz se o documento está no cadastro de clientes da conta. Com acesso a só algumas empresas (membro recortado ou empresa compartilhada), `email_cadastro` só vem do cliente que está no seu acesso, e `cadastrado` do cliente de fora dele só vem `true` para quem cadastra clientes. Com histórico, a descrição e o código do serviço vêm da última nota, e o `sugestao.valor` só é preenchido quando as **duas** notas mais recentes têm o mesmo valor — quando vier `null`, pergunte o valor e use `valores_recentes` para oferecer opções. Se a nota-modelo estiver cancelada ou substituída (`base_cancelada: true`), o serviço ainda serve de modelo, mas o valor nunca é sugerido. Notas de teste não entram nessa memória. `competencia_proposta` traz pronta a data da prestação a propor (o mesmo dia do mês da última nota ativa, nunca no futuro; sem ela, hoje). **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `documento` | path | string **(obrigatório)** | CNPJ ou CPF, sem pontuação (aceita com ela); o CNPJ pode ter letras nas 12 primeiras posições | | `company_id` | query | string, ou null | Id da empresa (de `GET /companies`) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/tomadores/{documento}/sugestao" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Sugestão (ou `tem_historico: false`) | Campo | Tipo | Descrição | |---|---|---| | `tem_historico` | boolean **(obrigatório)** | `false` quando não há nota anterior: só `email_cadastro` acompanha e os demais campos não vêm | | `email_cadastro` | string, ou null | E-mail do cadastro do tomador — vem mesmo sem histórico de notas | | `cadastrado` | boolean, ou null | `true` quando o documento está no cadastro de clientes da conta — vem mesmo sem histórico | | `situacao_na_receita` | objeto, ou null | S-GC: o cliente do cadastro com o CNPJ baixado, inapto, suspenso ou nulo na Receita (`descricao`, `data` — desde quando — e `mes`, o do cadastro conferido). Só aviso: a nota sai mesmo assim — diga ao cliente antes de emitir. Ausente quando o CNPJ está regular ou ainda não foi conferido | | `retencao_historico` | objeto RetencaoHistoricoOut, ou null | Como o ISS foi retido nas notas recentes; ausente quando não há histórico | | `base_cancelada` | boolean, ou null | `true` quando a nota-modelo não está mais ativa: o serviço ainda serve de modelo, o valor não | | `base_status` | string, ou null | Situação da nota-modelo: `ativa`, `cancelada` ou `substituida` | | `baseada_em` | objeto SugestaoBaseOut, ou null | Identificação da nota-modelo | | `sugestao` | objeto SugestaoServicoOut, ou null | Os campos do serviço a repetir | | `valores_recentes` | lista de string, ou null | Até 6 valores das notas mais recentes, do mais novo para o mais antigo (reais com ponto decimal) | | `total_notas` | integer, ou null | Quantas notas entraram na análise (no máximo 12) | | `competencia_proposta` | objeto CompetenciaPropostaOut, ou null | A data da prestação a propor para a próxima nota, já calculada — vem com e sem histórico | **Exemplo de resposta** ```json { "email_cadastro": null, "tem_historico": false } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ## Consultas CNPJ na Receita (pelo cadastro mensal, sem cota; em tempo real, com cota), CPF (com cota), CEP e município (grátis) e a adesão do município ao Sistema Nacional. ### Consultar um CNPJ na Receita (com cache) `GET /api/v1/consultas/cnpj/{documento}` Busca o cadastro de um CNPJ na Receita Federal e devolve razão social, situação cadastral e endereço já no formato usado para cadastrar empresa ou tomador. **De onde vem o dado (`fonte`):** do cadastro mensal da Receita — os Dados Abertos do CNPJ, que a Receita publica uma vez por mês, por isso podem estar algumas semanas atrás do cadastro do dia (`fonte: "gerecnpj"`, com `mes_referencia` e `data_extracao`) —, ou da consulta em tempo real à Receita (`fonte: "serpro"`) quando o CNPJ ainda não está no cadastro do mês (aberto depois da extração), quando o cadastro mensal não responde e com `fresco=true`. Onde terceiros virem o dado, cite a fonte com o mês do dado: "Fonte: Receita Federal (setembro/2026)". **Cota:** a busca pelo cadastro mensal não gasta a cota do plano. A consulta em tempo real do CNPJ que ainda não está no cadastro, e a do `fresco=true`, gastam uma unidade da cota mensal (402 `COTA_CONSULTAS_ESGOTADA` quando acaba) e do limite do dia do plano (429 `LIMITE_CONSULTAS_DIA`); a que vai em tempo real porque o cadastro mensal não respondeu fica por conta da plataforma. A cota vale para todas as portas da conta (a API, o painel, os links de cadastro e o WhatsApp). Toda busca — do cache ou não, inclusive a do CNPJ que não existe — conta no teto técnico de 300 por dia por conta, igual em todos os planos (429 `LIMITE_CONSULTAS_DIA`, sem `upgrade`, renova à 0h de Brasília), e no de 10 por minuto por conta (429 `RATE_LIMIT`). O mesmo CNPJ no mesmo mês do cadastro, ou consultado em tempo real nos últimos 7 dias, sai do cache (`de_cache: true` e `consultado_em`), de qualquer conta. Consulte uma vez e guarde o resultado; não use esta rota para validar documento em laço. Numa empresa compartilhada por outra conta (o `company_id` dela na query), a busca pelo cadastro mensal é de todos; a consulta em tempo real gasta a cota da conta que compartilhou e é de quem cadastra clientes, o papel `operador`: `leitor` e `contabilidade` recebem 403 `PERMISSAO_NEGADA` quando o CNPJ precisa dela. O `documento` no caminho aceita com ou sem pontuação — a máscara é removida e os dígitos verificadores são conferidos antes de qualquer busca (422 `DOCUMENTO_INVALIDO`, sem custo e fora do teto). Na resposta o documento vem sem pontuação — o CNPJ pode ter letras nas 12 primeiras posições (o formato novo da Receita), sempre em maiúsculas. Com `completo=true` a resposta traz o quadro societário (`receita.qsa`: o nome e a qualificação; o sócio menor vem como "Sócio menor"), `receita.informacoes_adicionais` e `regime_sugerido` (com o `opSimpNac` pronto para a emissão; no cadastro mensal, `periodos_simples` traz só o período mais recente, e a saída já marcada para uma data futura vem em `exclusao_marcada`, ainda optante). O cache da busca simples não atende um pedido completo. Com `fresco=true` só vale a consulta em tempo real de hoje — para conferir o regime com a Receita. Com `completo=true&confirmar=true`, o veredito que barraria o cadastro de uma empresa (não optante do Simples nem MEI hoje) é confirmado na Receita em tempo real antes de voltar, por conta da plataforma: só a confirmação traz `regime_sugerido.nao_optante_explicito: true`; sem ela, o cadastro do mês pode estar velho. CNPJ que nem o cadastro mensal nem a Receita em tempo real conhecem devolve 404 `DOCUMENTO_NAO_ENCONTRADO` (a consulta em tempo real conta: a Receita cobra a resposta). Com as fontes indisponíveis: 503 `SERPRO_NAO_CONFIGURADO` ou `SERPRO_INDISPONIVEL`; consultas em tempo real da plataforma pausadas até a virada do dia, 503 `CONSULTAS_PAUSADAS`; credenciais recusadas, 502 `SERPRO_RECUSOU`. Em qualquer um desses casos siga com o cadastro manual. Consultar aqui não cria nada: para cadastrar, chame `POST /tomadores`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `documento` | path | string **(obrigatório)** | CNPJ ou CPF, sem pontuação (aceita com ela); o CNPJ pode ter letras nas 12 primeiras posições | | `completo` | query | boolean | | | `fresco` | query | boolean | | | `confirmar` | query | boolean | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/consultas/cnpj/{documento}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Cadastro do CNPJ na Receita | Campo | Tipo | Descrição | |---|---|---| | `tipo` | string **(obrigatório)** | Sempre `CNPJ` nesta rota | | `documento` | string, ou null | CNPJ consultado, sem pontuação (14 caracteres; pode ter letras nas 12 primeiras) | | `nome` | string **(obrigatório)** | Razão social | | `nome_fantasia` | string, ou null | Nome fantasia, quando houver | | `abertura` | string, ou null | Data de abertura (AAAA-MM-DD) | | `situacao` | objeto SituacaoCnpjOut **(obrigatório)** | Situação cadastral do CNPJ na Receita. | | `situacao.codigo` | string, ou null | Código da situação (ex.: "2" = Ativa) | | `situacao.descricao` | string, ou null | Situação por extenso: Nula, Ativa, Suspensa, Inapta ou Baixada | | `situacao.data` | string, ou null | Data em que a situação passou a valer (AAAA-MM-DD) | | `cnae_principal` | objeto CodigoDescricaoOut, ou null | CNAE da atividade principal | | `email` | string, ou null | E-mail do cadastro na Receita, em minúsculas | | `fone` | string, ou null | Telefone só dígitos, com DDD e o 9º dígito já completado | | `endereco` | objeto EnderecoReceitaOut **(obrigatório)** | Endereço do CNPJ, já com os nomes de campo que a emissão de NFS-e usa. | | `endereco.xLgr` | string, ou null | Logradouro, com o tipo junto (ex.: RUA EXEMPLO) | | `endereco.nro` | string, ou null | Número | | `endereco.xCpl` | string, ou null | Complemento, quando houver | | `endereco.xBairro` | string, ou null | Bairro | | `endereco.CEP` | string, ou null | CEP com 8 dígitos, sem hífen | | `endereco.municipio_nome` | string, ou null | Nome do município | | `endereco.uf` | string, ou null | Sigla da UF, 2 letras | | `endereco.cMun` | string, ou null | Código IBGE do município (7 dígitos). Pode vir `null` quando não foi possível determiná-lo pelo CEP — nesse caso resolva com `/consultas/municipio`, nunca deduza o código | | `receita` | objeto ReceitaOut **(obrigatório)** | Tudo o que a consulta ao CNPJ traz além do cadastro básico. Campos que a Receita não devolveu (ou que só existem na consulta completa) vêm `null` ou lista vazia. | | `receita.situacao_cadastral` | objeto SituacaoCnpjOut, ou null | Situação cadastral e sua data | | `receita.data_abertura` | string, ou null | Data de abertura do CNPJ (AAAA-MM-DD) | | `receita.cnae_principal` | objeto CodigoDescricaoOut, ou null | CNAE da atividade principal | | `receita.cnaes_secundarios` | lista de objeto CodigoDescricaoOut | CNAEs secundários; lista vazia quando não há | | `receita.cnaes_secundarios.codigo` | string, ou null | Código na tabela da Receita | | `receita.cnaes_secundarios.descricao` | string, ou null | O que o código quer dizer, por extenso | | `receita.natureza_juridica` | objeto CodigoDescricaoOut, ou null | Natureza jurídica da empresa | | `receita.porte` | string, ou null | Código do porte informado pela Receita (ex.: "ME") | | `receita.porte_descricao` | string, ou null | Porte por extenso | | `receita.capital_social_centavos` | integer, ou null | Capital social em CENTAVOS, exatamente como a Receita devolve | | `receita.capital_social` | number, ou null | O mesmo capital social convertido para reais (ex.: 5000.0) | | `receita.tipo_estabelecimento` | string, ou null | MATRIZ ou FILIAL | | `receita.tipo_estabelecimento_descricao` | string, ou null | Tipo de estabelecimento por extenso | | `receita.municipio_jurisdicao` | objeto CodigoDescricaoOut, ou null | Município da jurisdição na Receita. ATENÇÃO: este código é interno da Receita e NÃO é o código IBGE — para o IBGE use `endereco.cMun` | | `receita.situacao_especial` | string, ou null | Situação especial, quando houver | | `receita.data_situacao_especial` | string, ou null | Data da situação especial (AAAA-MM-DD) | | `receita.informacoes_adicionais` | objeto InformacoesAdicionaisOut, ou null | Simples Nacional e MEI; só vem na consulta completa (`completo=true`) | | `receita.qsa` | lista de objeto SocioOut, ou null | Quadro societário; só vem na consulta completa (`completo=true`) | | `receita.fonte` | um de: `"serpro"`, `"gerecnpj"`, ou null | De onde veio o bloco: `gerecnpj` (o cadastro mensal) ou `serpro` (em tempo real) | | `receita.mes_referencia` | string, ou null | No cadastro mensal: o mês da publicação da Receita (AAAA-MM) | | `receita.data_extracao` | string, ou null | No cadastro mensal: o dia em que a Receita extraiu os dados (AAAA-MM-DD) | | `receita.atualizando` | boolean, ou null | `true` nos minutos em que o mês novo é aplicado: o dado pode misturar os dois meses e não fica guardado no cache | | `fonte` | um de: `"serpro"`, `"gerecnpj"` **(obrigatório)** | Origem do dado, sempre a Receita Federal: `gerecnpj` = o cadastro mensal (Dados Abertos do CNPJ, publicado uma vez por mês — pode estar algumas semanas atrás); `serpro` = a consulta em tempo real (o CNPJ que ainda não está no cadastro do mês, o `fresco` e quando o cadastro mensal não responde) | | `mes_referencia` | string, ou null | Com `fonte` `gerecnpj`: o mês do cadastro (AAAA-MM). Cite a fonte onde terceiros veem | | `data_extracao` | string, ou null | Com `fonte` `gerecnpj`: o dia em que a Receita extraiu os dados (AAAA-MM-DD) | | `regime_sugerido` | objeto RegimeSugeridoOut, ou null | Só presente quando a chamada usou `completo=true` | | `consulta_id` | string, ou null | Identificador desta consulta guardada na conta; `null` se não foi possível guardar | | `de_cache` | boolean, ou null | `true` quando a resposta veio do cache — o mesmo CNPJ no mesmo mês do cadastro mensal, ou consultado em tempo real nos últimos 7 dias, por qualquer conta —, sem ir à Receita e sem consumir cota. Ausente quando a consulta foi mesmo feita agora | | `consultado_em` | string, ou null | Quando a consulta em cache foi originalmente feita (ISO 8601); só vem com `de_cache` | **Exemplo de resposta** ```json { "abertura": "1967-06-30", "cnae_principal": null, "consulta_id": "cst_2089f6667a87288e", "documento": "34238864000168", "email": "contato@serpro.gov.br", "endereco": { "CEP": "70836900", "cMun": "5300108", "municipio_nome": "Brasília", "nro": "Q.601", "uf": "DF", "xBairro": "ASA NORTE", "xCpl": "LOTE V", "xLgr": "ST DE GRANDE AREA NORTE" }, "fone": "0614338456", "fonte": "serpro", "nome": "SERVICO FEDERAL DE PROCESSAMENTO DE DADOS", "nome_fantasia": "SERPRO", "receita": { "capital_social": null, "capital_social_centavos": null, "cnae_principal": null, "cnaes_secundarios": [], "data_abertura": "1967-06-30", "data_situacao_especial": null, "informacoes_adicionais": null, "municipio_jurisdicao": null, "natureza_juridica": null, "porte": null, "porte_descricao": null, "qsa": null, "situacao_cadastral": { "codigo": "2", "data": "2004-05-22", "descricao": "Ativa" }, "situacao_especial": null, "tipo_estabelecimento": null, "tipo_estabelecimento_descricao": null }, "situacao": { "codigo": "2", "data": "2004-05-22", "descricao": "Ativa" }, "tipo": "CNPJ" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | | 502 | O Sistema Nacional ou a Receita respondeu com erro | | 503 | Serviço externo indisponível ou não configurado | ### Consultar um CPF na Receita (pago, com cache) `GET /api/v1/consultas/cpf/{documento}` Confirma nome e situação cadastral de um CPF na Receita Federal (via SERPRO), para cadastrar um tomador pessoa física. Não devolve endereço nem telefone — para o endereço, use `/consultas/cep/{cep}`. **Esta consulta é paga** (é sempre em tempo real, como a do CNPJ que ainda não está no cadastro mensal): consome a cota mensal do plano (402 `COTA_CONSULTAS_ESGOTADA`), respeita o limite do dia do plano (429 `LIMITE_CONSULTAS_DIA`) e o de 10 chamadas por minuto por conta (429 `RATE_LIMIT`). O cache do CPF é mais curto e mais fechado: o mesmo CPF, com a MESMA data de nascimento, consultado pela mesma conta nas últimas 24 h volta com `de_cache: true` e `consultado_em`, sem gastar nada. Numa empresa compartilhada por outra conta, vale a regra do CNPJ: a consulta paga é do papel `operador` (`leitor` e `contabilidade` recebem 403 `PERMISSAO_NEGADA`), e o cache segue valendo para todos. O parâmetro `nascimento` é **obrigatório**: a Receita valida o par CPF + data de nascimento e, sem ele, a resposta é 422 `NASCIMENTO_OBRIGATORIO`. A data é aceita em `ddmmaaaa`, `dd/mm/aaaa` ou `aaaa-mm-dd`. O `documento` no caminho aceita com ou sem pontuação e tem os dígitos verificadores conferidos antes da chamada paga (422 `DOCUMENTO_INVALIDO`, sem custo). Par que não confere devolve 404 `DOCUMENTO_NAO_ENCONTRADO` — pode ser o número ou a data. CPF de menor de idade devolve 422 `CPF_SEM_RETORNO`: a Receita não fornece os dados, e o cadastro manual é o caminho. Sem credenciais, com a Receita fora do ar ou com as consultas pausadas, 503; credenciais recusadas, 502 `SERPRO_RECUSOU`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `documento` | path | string **(obrigatório)** | CNPJ ou CPF, sem pontuação (aceita com ela); o CNPJ pode ter letras nas 12 primeiras posições | | `nascimento` | query | string, ou null | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/consultas/cpf/{documento}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Cadastro do CPF na Receita | Campo | Tipo | Descrição | |---|---|---| | `tipo` | string **(obrigatório)** | Sempre `CPF` nesta rota | | `documento` | string, ou null | CPF consultado, só números | | `nome` | string **(obrigatório)** | Nome da pessoa | | `nome_social` | string, ou null | Nome social, quando registrado | | `situacao` | objeto SituacaoCpfOut **(obrigatório)** | Situação cadastral do CPF na Receita. | | `situacao.codigo` | string, ou null | Código da situação (ex.: "0" = Regular) | | `situacao.descricao` | string, ou null | Situação por extenso: Regular, Suspensa, Titular falecido, Pendente de regularização, Cancelada por multiplicidade, Nula ou Cancelada de ofício | | `nascimento` | string, ou null | Data de nascimento confirmada pela Receita (AAAA-MM-DD) | | `fonte` | string **(obrigatório)** | Origem do dado: a Receita Federal, via SERPRO | | `consulta_id` | string, ou null | Identificador desta consulta guardada na conta | | `de_cache` | boolean, ou null | `true` quando a resposta veio do cache (o mesmo CPF e a mesma data de nascimento, consultados pela conta nas últimas 24 h), sem consumir cota | | `consultado_em` | string, ou null | Quando a consulta em cache foi originalmente feita (ISO 8601) | **Exemplo de resposta** ```json { "consulta_id": "cst_6f6ebdb8f7703ed2", "documento": "52998224725", "fonte": "serpro", "nascimento": "1970-11-14", "nome": "FULANA DE TAL", "nome_social": "FULANA SOCIAL", "situacao": { "codigo": "0", "descricao": "Regular" }, "tipo": "CPF" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | | 502 | O Sistema Nacional ou a Receita respondeu com erro | | 503 | Serviço externo indisponível ou não configurado | ### Consultar o endereço de um CEP (grátis) `GET /api/v1/consultas/cep/{cep}` Devolve o endereço de um CEP já com os nomes de campo da NFS-e (`xLgr`, `xBairro`, `CEP`, `cMun`), prontos para o bloco de endereço de um tomador ou de uma empresa. É **grátis**: não consome a cota de consultas nem passa pela Receita — a fonte é o ViaCEP. Use esta rota sempre que precisar do código IBGE (`cMun`) de um endereço; é a forma mais confiável de obtê-lo, porque o CEP identifica o município sem ambiguidade. O `cep` no caminho aceita com ou sem hífen, mas precisa ter 8 dígitos (422 `CEP_INVALIDO`). CEP que não existe devolve 404 `CEP_NAO_ENCONTRADO`; ViaCEP fora do ar devolve 503 `VIACEP_INDISPONIVEL` — nesse caso o endereço pode ser preenchido à mão. Em CEP de município inteiro (o "CEP geral") `xLgr` e `xBairro` vêm `null`, e só município, UF e `cMun` são úteis. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `cep` | path | string **(obrigatório)** | CEP com 8 dígitos | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/consultas/cep/{cep}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Endereço do CEP | Campo | Tipo | Descrição | |---|---|---| | `CEP` | string **(obrigatório)** | CEP consultado, 8 dígitos sem hífen | | `xLgr` | string, ou null | Logradouro; `null` em CEP de município inteiro | | `xCpl` | string, ou null | Complemento devolvido pelos Correios, quando houver | | `xBairro` | string, ou null | Bairro; `null` em CEP de município inteiro | | `municipio_nome` | string, ou null | Nome do município | | `uf` | string, ou null | Sigla da UF, 2 letras | | `cMun` | string, ou null **(obrigatório)** | Código IBGE do município (7 dígitos) — é este o valor que vai na nota | **Exemplo de resposta** ```json { "CEP": "70836900", "cMun": "5300108", "municipio_nome": "Brasília", "uf": "DF", "xBairro": "Asa Norte", "xCpl": null, "xLgr": "SGAN 601" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | | 503 | Serviço externo indisponível ou não configurado | ### Buscar o código IBGE de um município pelo nome `GET /api/v1/consultas/municipio` Traduz nome de município + UF no código IBGE (`cMun`) que a NFS-e exige. É grátis, não vai à rede e não consome cota: a tabela oficial do IBGE está embarcada na API. Os dois parâmetros são obrigatórios: `q` com o nome (3 letras ou mais, 422 `MUNICIPIO_INVALIDO` abaixo disso) e `uf` com a sigla de 2 letras (422 `UF_OBRIGATORIA` sem ela). A UF é exigida de propósito: municípios homônimos em estados diferentes são comuns. O casamento é exato, ignorando acento e maiúsculas — não abrevie ("S. J. da Boa Vista" não casa) e não invente. Sem correspondência a resposta é 404 `MUNICIPIO_NAO_ENCONTRADO`: confira a grafia ou, se souber o CEP, use `/consultas/cep/{cep}`, que é mais específico. Nunca deduza um `cMun` a partir de um código parecido — um dígito trocado é outra cidade e a nota sai errada. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `q` | query | string **(obrigatório)** | | | `uf` | query | string, ou null | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/consultas/municipio" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Município encontrado | Campo | Tipo | Descrição | |---|---|---| | `cMun` | string **(obrigatório)** | Código IBGE do município, 7 dígitos | | `nome` | string **(obrigatório)** | Nome oficial do município, na grafia do IBGE | | `uf` | string **(obrigatório)** | Sigla da UF informada na busca, em maiúsculas | **Exemplo de resposta** ```json { "cMun": "2403251", "nome": "Parnamirim", "uf": "RN" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Consultar a adesão de um município ao Nacional `GET /api/v1/municipios/{cmun}` Diz como um município está no Sistema Nacional da NFS-e. Consulte ANTES de cadastrar uma empresa ou de emitir com a prestação em outra cidade — nem todo município brasileiro está lá. O `cmun` no caminho é o código IBGE de 7 dígitos; obtenha-o em `/consultas/cep/{cep}` ou `/consultas/municipio`, nunca de memória. A rota é grátis e não consome cota de consultas. São duas perguntas diferentes, e confundi-las gera rejeição na hora de emitir. `emite_pelo_sistema_nacional` responde pela empresa SEDIADA no município: `false` significa que a prefeitura mantém o sistema próprio: até 31/10/2026, a ME e a EPP de lá ficam na lista de espera; o MEI emite por aqui em qualquer município, e a ME e a EPP também, a partir de 1º/11/2026. `participa_do_ambiente_nacional` responde pelo LOCAL DA PRESTAÇÃO: um município pode aceitar notas com serviço prestado nele sem ser emissor nacional, e o contrário também acontece. A resposta é servida de um cache de 24 h (`verificado_em` diz de quando é). Se o gov.br não responder e não houver nada em cache, a resposta é 503 `ADN_INDISPONIVEL` — tente de novo em instantes; havendo cache, ele é servido mesmo vencido, em vez de travar o cadastro. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `cmun` | path | string **(obrigatório)** | Código IBGE do município (7 dígitos) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/municipios/{cmun}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — Situação do município no Sistema Nacional | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Código IBGE do município consultado, 7 dígitos | | `nome` | string, ou null | Nome do município com a UF, na grafia do IBGE (ex.: "Natal - RN") | | `emite_pelo_sistema_nacional` | boolean **(obrigatório)** | O município emite pelo Sistema Nacional (a prefeitura aderiu). Até 31/10/2026, a ME e a EPP sediadas num município com `false` ficam na lista de espera; o MEI emite em qualquer município e, a partir de 1º/11/2026, a ME e a EPP também | | `participa_do_ambiente_nacional` | boolean **(obrigatório)** | O município aceita notas com a prestação do serviço no território dele. É o campo que decide se você pode usar este município como local da prestação, e NÃO é o mesmo que emitir por aqui | | `aderente_emissor_nacional` | integer **(obrigatório)** | O valor cru do gov.br por trás de `emite_pelo_sistema_nacional` (0 ou 1) | | `aderente_ambiente_nacional` | integer **(obrigatório)** | O valor cru do gov.br por trás de `participa_do_ambiente_nacional` (0 ou 1) | | `situacao_emissao_padrao` | integer, ou null | Situação de emissão padrão dos contribuintes, como o gov.br informa | | `aderente_man` | integer, ou null | Adesão ao Módulo de Apuração Nacional, como o gov.br informa | | `permite_aproveitamento_creditos` | boolean ou integer, ou null | Se o município permite aproveitamento de créditos; repassado como o gov.br devolve (a chave do ADN é grafada `permiteAproveitametoDeCreditos`, sem o n — é assim que o gov.br manda) | | `fonte` | string, ou null | De onde vieram os dados; hoje sempre `adn` (o gov.br) | | `verificado_em` | string (date-time), ou null | Quando a informação foi buscada no gov.br (UTC, ISO 8601). O dado vale por 24 h | **Exemplo de resposta** ```json { "aderente_ambiente_nacional": 1, "aderente_emissor_nacional": 0, "aderente_man": 0, "emite_pelo_sistema_nacional": false, "fonte": "adn", "id": "3550308", "nome": "São Paulo - SP", "participa_do_ambiente_nacional": true, "permite_aproveitamento_creditos": null, "situacao_emissao_padrao": 1, "verificado_em": "2026-09-16T18:49:44.437202Z" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | | 503 | Serviço externo indisponível ou não configurado | ## Serviços Código de serviço (cTribNac): sugerir pela descrição e conferir um código no catálogo nacional. ### Sugerir o código de serviço pela descrição `POST /api/v1/servicos/sugerir` Recebe uma descrição livre do serviço ("consultoria em TI", "aula de inglês para empresa") e devolve até `limit` candidatos do catálogo nacional de serviços, com o código de 6 dígitos que vai em `servico.cTribNac`, o nome oficial e a semelhança. É busca semântica sobre o catálogo oficial (anexo B do leiaute nacional): confirme o candidato com quem conhece o serviço antes de emitir — o código decide alíquota, retenções e se o município da prestação precisa ser informado (`iss_no_local`). Custa uma consulta de embedding por chamada; por isso tem teto de 20 por minuto por conta (429 `RATE_LIMIT`). `descricao` de 3 a 500 caracteres; `limit` de 1 a 10 (padrão 5). Quem já sabe o código usa `GET /servicos/codigo/{codigo}` para conferir o nome. 503 quando o serviço de busca está indisponível. **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `descricao` | string **(obrigatório)** | | | `limit` | integer | Padrão: `5`. | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/servicos/sugerir" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"descricao": "licença de uso de software"}' ``` **Resposta 200** — Candidatos do catálogo nacional, do mais parecido para o menos | Campo | Tipo | Descrição | |---|---|---| | `cTribNac` | string **(obrigatório)** | Código de tributação nacional, 6 dígitos — é o que vai em `servico.cTribNac` | | `descricao` | string **(obrigatório)** | Nome oficial do serviço na lista nacional (anexo B do leiaute) | | `score` | number **(obrigatório)** | Semelhança entre a sua descrição e o item (0 a 1); os candidatos vêm do maior para o menor | | `iss_no_local` | boolean, ou null | True quando o ISS é devido no local da prestação (exceções da LC 116): mande `servico.cMunPrestacao` | | `familia_local` | string, ou null | Família do serviço: `local`, `obra`, `evento`, `tomador` ou `rateio` (`obra` e `evento` também nos códigos em que o Sistema Nacional pede o grupo da obra ou do evento, Anexo I regras 340 e 357); nulo nos demais | | `tomador_pj_responsavel` | boolean, ou null | True nos subitens em que a LC 116 (art. 6º, § 2º, II) faz a pessoa jurídica tomadora responsável pelo ISS onde quer que ela esteja — ali, a retenção por um tomador de outro município não pede aviso | **Exemplo de resposta** ```json [ { "cTribNac": "010501", "descricao": "Licenciamento de software", "familia_local": null, "iss_no_local": false, "score": 0.995 }, { "cTribNac": "070210", "descricao": "Obra civil", "familia_local": null, "iss_no_local": false, "score": 0.0 } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | | 503 | Serviço externo indisponível ou não configurado | ### Conferir um código de serviço no catálogo `GET /api/v1/servicos/codigo/{codigo}` Confere um código de serviço (`cTribNac`, 6 dígitos; aceita com pontos) no catálogo nacional e devolve o nome oficial, se o ISS é devido no local da prestação e a família da exceção. Use antes de emitir com um código que veio de fora (do contador, de um cadastro antigo): 404 `CODIGO_NAO_ENCONTRADO` significa que ele não existe na lista nacional e a emissão seria rejeitada. Não custa nada; teto de 20 por minuto por conta. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `codigo` | path | string **(obrigatório)** | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/servicos/codigo/{codigo}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — O código existe no catálogo nacional | Campo | Tipo | Descrição | |---|---|---| | `cTribNac` | string **(obrigatório)** | Código de tributação nacional, 6 dígitos | | `descricao` | string **(obrigatório)** | Nome oficial do serviço | | `iss_no_local` | boolean **(obrigatório)** | True quando o ISS é devido no local da prestação (mande `servico.cMunPrestacao`) | | `familia_local` | string, ou null | `local`, `obra`, `evento`, `tomador` ou `rateio` (`obra` e `evento` também nos códigos em que o Sistema Nacional pede o grupo da obra ou do evento, Anexo I regras 340 e 357); nulo nos demais | | `regra_local` | string, ou null | Onde o ISS é devido, em uma frase, quando há exceção | | `tomador_pj_responsavel` | boolean | True nos subitens em que a LC 116 (art. 6º, § 2º, II) faz a pessoa jurídica tomadora responsável pelo ISS onde quer que ela esteja — ali, a retenção por um tomador de outro município não pede aviso Padrão: `false`. | **Exemplo de resposta** ```json { "cTribNac": "070201", "descricao": "Execução, por administração, de obras", "familia_local": "obra", "iss_no_local": true, "regra_local": "da execução da obra" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | | 429 | Muitas chamadas — aguarde e repita; ou o teto do dia acabou, e `volta_em` diz quando volta | ## Relatórios Relatório por período e exportação em ZIP (XMLs, PDFs e CSV). ### Gerar o relatório de notas do período `GET /api/v1/reports/nfse` Relatório de NFS-e de um período, com os mesmos filtros da lista de notas: totais por status, quantos clientes diferentes apareceram, o fechamento mês a mês e as notas em si. É síncrono — a resposta já vem pronta; para um pacote com os XMLs e os PDFs, use `POST /api/v1/exports`. `formato=json` (padrão) devolve `filtros`, `totais`, `por_competencia` e `notas`; `formato=csv` devolve o arquivo `text/csv`, separado por ponto e vírgula, com BOM (abre acentuado no Excel em português) e uma linha por nota. O período vai em `de` e `ate` no formato `AAAA-MM` — `competencia_de`/`competencia_ate` continuam aceitos por compatibilidade, mas `de`/`ate` têm precedência — e `periodo_por` escolhe se a faixa vale pela competência (padrão) ou pela data de emissão. Filtre ainda por `company_id`, `status` (`ativa`, `cancelada`, `substituida`), `origem` (`plataforma` ou `importada`) e `q` (busca no nome do cliente, no documento e na descrição do serviço); `limite` (1 a 2000, padrão 500) corta só a lista de `notas` do JSON — os totais e o fechamento por competência são sempre do período inteiro, e o CSV vem sempre COMPLETO (em streaming, sem teto), ignorando `limite`. Notas de teste nunca entram no relatório. Uma empresa fora do seu acesso devolve 403 `EMPRESA_FORA_DO_RECORTE` e um período fora de `AAAA-MM`, 422 `COMPETENCIA_INVALIDA`. As notas trazem `cancelada_em`/`substituida_em` (hora oficial do evento) e `substituida_por`, no JSON e no CSV; `periodo_por=evento` monta o relatório do que saiu de ativa no período. As bordas de `de`/`ate` valem no horário de Brasília. O CSV (`formato=csv`) é do contador, para abrir no Excel em português: cabeçalhos em português ("Chave de acesso", "Competência", "Situação", "Retenção do ISS"…), códigos por extenso (situação, tributação e retenção do ISS, tributos aproximados), a coluna "ISS retido (R$)" com o valor em reais que o contador soma (o apurado na nota; vazia quando não há retenção), separador `;`, competência `dd/mm/aaaa` e as outras datas em Brasília `dd/mm/aaaa hh:mm`, vírgula decimal, texto sem quebras de linha, a nota que substituiu pelo número, e chave, CPF/CNPJ e código do serviço (`01.05.01`) como texto por fórmula (`="…"`) para o Excel não virar notação científica nem perder o zero à esquerda. Para integrar por máquina use o JSON, que mantém os nomes técnicos, UTC e ponto decimal. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `de` | query | string, ou null | AAAA-MM | | `ate` | query | string, ou null | AAAA-MM | | `competencia_de` | query | string, ou null | AAAA-MM (legado; de/ate têm precedência) | | `competencia_ate` | query | string, ou null | AAAA-MM (legado) | | `periodo_por` | query | string | | | `company_id` | query | string, ou null | Id da empresa (de `GET /companies`) | | `status` | query | string, ou null | | | `origem` | query | string, ou null | | | `q` | query | string, ou null | | | `formato` | query | string | | | `limite` | query | integer | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/reports/nfse" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — O relatório: JSON com totais, fechamento por competência e as notas (`formato=json`), ou o arquivo CSV com uma linha por nota (`formato=csv`) | Campo | Tipo | Descrição | |---|---|---| | `filtros` | objeto **(obrigatório)** | O filtro efetivamente aplicado, já com o recorte de empresas do seu acesso — serve de conferência | | `totais` | objeto RelatorioTotaisOut **(obrigatório)** | Os totais do período inteiro — não da fatia devolvida em `notas`. | | `totais.quantidade` | integer **(obrigatório)** | Total de notas do período, somando todos os status | | `totais.valor_total` | number **(obrigatório)** | Soma do valor do serviço de TODAS as notas do período, inclusive canceladas e substituídas | | `totais.tomadores_distintos` | integer **(obrigatório)** | Quantos clientes diferentes aparecem no período | | `totais.por_status` | objeto | Quebra por status — chaves `ativa`, `cancelada` e `substituida`, só as que existem no período | | `por_competencia` | lista de objeto RelatorioCompetenciaOut **(obrigatório)** | Fechamento mês a mês, em ordem crescente de competência | | `por_competencia.competencia` | string **(obrigatório)** | Mês de competência `AAAA-MM`; `—` quando a nota não tem competência gravada | | `por_competencia.quantidade` | integer **(obrigatório)** | Notas com essa competência, em qualquer status | | `por_competencia.valor_ativas` | number **(obrigatório)** | Soma do valor do serviço só das notas ativas do mês, em reais | | `por_competencia.canceladas` | integer **(obrigatório)** | Quantas notas do mês foram canceladas | | `por_competencia.substituidas` | integer **(obrigatório)** | Quantas notas do mês foram substituídas | | `notas` | lista de objeto RelatorioNotaOut **(obrigatório)** | As notas do período, até o `limite` pedido, ordenadas por competência e depois por nDPS | | `notas.id` | string **(obrigatório)** | Identificador da nota (prefixo `nfse_`) — use em `GET /api/v1/nfse/{nfse_id}` | | `notas.company_id` | string, ou null | Empresa emissora da nota | | `notas.chave` | string, ou null | Chave de acesso da NFS-e (50 dígitos) | | `notas.serie` | string, ou null | Série da DPS | | `notas.numero` | string, ou null | Número oficial (nNFSe) impresso no DANFSE; `null` em notas antigas | | `notas.ndps` | integer, ou null | Sequência interna da DPS — use `numero` para falar com o cliente | | `notas.dCompet` | string, ou null | Competência da nota, no formato `AAAA-MM-DD` | | `notas.status` | string, ou null | `ativa`, `cancelada` ou `substituida` | | `notas.origem` | string, ou null | `plataforma` (emitida aqui) ou `importada` (trazida do Sistema Nacional) | | `notas.valor_servico` | string, ou null | Valor do serviço em reais, como texto (ex.: `1500.00`) | | `notas.vDescIncond` | string, ou null | Desconto incondicionado, como texto | | `notas.vDescCond` | string, ou null | Desconto condicionado, como texto | | `notas.descricao_servico` | string, ou null | Descrição do serviço prestado | | `notas.informacoes_complementares` | string, ou null | Texto complementar impresso na nota | | `notas.cTribNac` | string, ou null | Código de tributação nacional do serviço | | `notas.cNBS` | string, ou null | Código NBS do serviço, quando informado | | `notas.tribISSQN` | string, ou null | Tributação do ISSQN declarada na nota | | `notas.tpRetISSQN` | string, ou null | `1` = ISS não retido, `2` = retido pelo tomador | | `notas.pAliq` | string, ou null | Alíquota do ISSQN DECLARADA na emissão. No JSON ela vem como está na nota; a coluna `Alíquota do ISS (%)` do CSV mostra a que VALE — `pAliqAplic` quando existe, esta quando não | | `notas.vBC` | string, ou null | Base de cálculo do ISSQN que o município usou; `null` em nota sem retenção e nas gravadas antes do campo existir | | `notas.pAliqAplic` | string, ou null | A alíquota que o município APLICOU, quando a nota a trouxe — é ela que manda quando difere da declarada | | `notas.vISSQN` | string, ou null | ISSQN apurado na nota pelo Sistema Nacional, em reais; `null` nas notas gravadas antes de a plataforma guardar esse valor | | `notas.tot_trib_tipo` | string, ou null | `pTotTribSN` ou `indTotTrib` — qual regra de totais foi usada | | `notas.tot_trib_valor` | string, ou null | Valor ou percentual dos tributos totais, como texto | | `notas.tomador_nome` | string, ou null | Nome do cliente | | `notas.tomador_documento` | string, ou null | CPF ou CNPJ do cliente, sem pontuação (o CNPJ pode ter letras) | | `notas.emitida_em` | string (date-time), ou null | Quando a nota foi emitida, em UTC (ISO 8601) | | `notas.cancelada_em` | string (date-time), ou null | Quando a nota foi cancelada (UTC, hora oficial do evento); só em status cancelada | | `notas.substituida_em` | string (date-time), ou null | Quando a nota foi substituída (UTC): o dhEvento do e105102 ou a autorização da substituta, o que vier primeiro; só em status substituida | | `notas.substituida_por` | string, ou null | Id da nota que substituiu esta, se for o caso | **Exemplo de resposta** ```json { "_binario": "text/csv", "_bytes": 842 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ### Pedir a exportação de notas em ZIP `POST /api/v1/exports` Pede um pacote ZIP com as notas do período: os XMLs autorizados, os DANFSE em PDF (a menos que `incluir_pdf` seja `false`), um `relatorio.csv` com uma linha por nota e um `relatorio.html` para ler e imprimir, com os totais do período e link para cada arquivo do pacote. A montagem é assíncrona — a resposta 202 sai na hora, com o `id` da exportação, e o pacote fica pronto alguns segundos ou minutos depois. O fluxo tem três passos: chame este endpoint, acompanhe `GET /api/v1/exports/{export_id}` até `status` virar `concluido` e então baixe em `GET /api/v1/exports/{export_id}/download`. Filtre por competência (`competencia_de`/`competencia_ate`, em `AAAA-MM`), por empresa e por status; sem filtro nenhum, o pacote pega tudo o que você pode ver. Acima do tamanho do volume (2.000 notas só com XML, 1.000 com os PDFs) o pacote sai em **volumes** — um por mês, no eixo do recorte — e nunca cortado: veja `volumes` em `GET /api/v1/exports/{export_id}`. Notas de teste ficam de fora e a exportação nunca ultrapassa o seu recorte de empresas — pedir uma empresa fora dele devolve 403 `EMPRESA_FORA_DO_RECORTE`. Quando o pacote fica pronto, quem pediu recebe um e-mail com o relatório anexo e o link de download, na própria conta (numa empresa compartilhada, a pessoa com acesso; por chave de API, quem criou a chave) — se o aviso "Exportação pronta" estiver ligado nas Notificações dela. Além da competência, o pacote aceita a faixa da listagem: `periodo_por` (`competencia`, `emissao` ou `evento`) com `de`/`ate` (`AAAA-MM` ou `AAAA-MM-DD`, bordas no horário de Brasília). `periodo_por=evento` monta o pacote do que foi cancelado ou substituído no período — com os XMLs dos eventos em `eventos/`. Misturar os dois jeitos de faixa devolve 422 `FILTROS_CONFLITANTES`. No ZIP, as ativas ficam na raiz de `xml/` e `pdf/`; canceladas e substituídas em subpastas. **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `competencia_de` | string, ou null | Primeira competência do pacote, `AAAA-MM`. Ausente = desde a primeira nota | | `competencia_ate` | string, ou null | Última competência do pacote, `AAAA-MM`. Ausente = até a nota mais recente | | `company_id` | string, ou null | Restringe a uma empresa. Ausente = todas as empresas do seu acesso | | `status` | string, ou null | Só notas neste status: `ativa`, `cancelada` ou `substituida`. Ausente = todos | | `incluir_pdf` | boolean | Inclui o DANFSE em PDF de cada nota. `false` deixa o pacote só com os XMLs e o CSV Padrão: `true`. | | `periodo_por` | string, ou null | Campo da faixa `de`/`ate`: `competencia` (padrão), `emissao` (data de autorização) ou `evento` (quando a nota saiu de ativa: cancelamento ou substituição) | | `de` | string, ou null | Início da faixa, `AAAA-MM` (mês inteiro) ou `AAAA-MM-DD`; bordas no horário de Brasília. Alternativa a `competencia_de` — não misture os dois jeitos | | `ate` | string, ou null | Fim da faixa (inclusivo), no mesmo formato de `de`. Alternativa a `competencia_ate` | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/exports" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"ate": "2026-09-16", "de": "2026-09-16", "incluir_pdf": false, "periodo_por": "evento"}' ``` **Resposta 202** — Pedido aceito: a exportação entrou na fila | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da exportação (prefixo `exp_`) — use em `GET /api/v1/exports/{export_id}` | | `status` | string **(obrigatório)** | Sempre `pendente` aqui: o pacote começa a ser montado logo depois da resposta | **Exemplo de resposta** ```json { "id": "exp_a0fe5a0d9950fd8a", "status": "pendente" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ### Consultar o estado de uma exportação `GET /api/v1/exports/{export_id}` Diz em que pé está uma exportação pedida em `POST /api/v1/exports`. Consulte de tempos em tempos (alguns segundos entre uma chamada e outra) até `status` virar `concluido` — só aí o download funciona. `status` vale `pendente` (na fila), `processando` (montando o ZIP), `concluido` (pronto, com `total_notas` preenchido) ou `erro`, e nesse caso o campo `erro` traz o motivo em português. Esta chamada não recomeça nada: uma exportação que terminou em `erro` precisa ser pedida de novo. Exportação inexistente ou de outra conta devolve 404 `EXPORT_NAO_ENCONTRADO`; de empresa fora do seu acesso, 403 `EMPRESA_FORA_DO_RECORTE`. Acima do tamanho do volume (2.000 notas só com XML, 1.000 com os PDFs) o pacote vem em `volumes` (um por mês, no eixo do recorte; mês grande em partes), nunca cortado: o primeiro item é o `resumo` (relatório do período inteiro + CSV completo) e os demais trazem os arquivos de cada mês. Baixe cada um em `GET …/download?volume=`. `total_no_recorte` é sempre igual a `total_notas`; ficou pela compatibilidade. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `export_id` | path | string **(obrigatório)** | Id da exportação (de `POST /exports`) | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/exports/{export_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — O estado atual da exportação | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da exportação (prefixo `exp_`) | | `status` | string **(obrigatório)** | `pendente` (na fila), `processando` (montando o ZIP), `concluido` (pronto para baixar) ou `erro` | | `total_notas` | integer, ou null | Quantas notas entraram no pacote; só tem significado com `status: concluido` | | `total_no_recorte` | integer, ou null | Sempre igual a `total_notas` — o campo nasceu para dizer que o teto cortou, e não há mais corte: acima do tamanho do volume o pacote sai em `volumes`. Mantido pela compatibilidade | | `volumes` | lista de objeto, ou null | Quando o recorte passa do tamanho do volume (2.000 notas só com XML, 1.000 com os PDFs) o pacote sai em VOLUMES — um por mês no eixo do recorte; mês grande parte em `(1 de N)`; se a contagem do período não pôde ser feita, partes de até um volume na ordem de numeração — e nunca cortado. O primeiro item é o `resumo` (`relatorio.html` do período inteiro + `relatorio.csv` completo); os demais trazem `rotulo`, `de`, `ate`, `total_notas`, `ativas`, `valor_ativas` e `bytes`. Baixe cada um em `GET …/download?volume=resumo\|1\|2\|…`; sem o parâmetro vem o resumo. Ausente ou com um item só = pacote de um arquivo, como sempre | | `incluir_pdf` | boolean, ou null | Se o pacote inclui os PDFs (DANFSE) | | `filtros` | objeto, ou null | O filtro aplicado, já com o recorte de empresas do seu acesso | | `erro` | string, ou null | Motivo em português quando `status` é `erro` | | `criado_em` | string (date-time), ou null | Quando a exportação foi pedida, em UTC (ISO 8601) | | `concluido_em` | string (date-time), ou null | Quando o pacote ficou pronto, em UTC (ISO 8601) | **Exemplo de resposta** ```json { "concluido_em": "2026-09-16T21:47:12.989000Z", "criado_em": "2026-09-16T21:47:12.975000Z", "erro": null, "filtros": { "$and": [ { "$or": [ { "cancelada_em": { "$gte": "2026-09-16T03:00:00Z", "$lt": "2026-09-17T03:00:00Z" } }, { "substituida_em": { "$gte": "2026-09-16T03:00:00Z", "$lt": "2026-09-17T03:00:00Z" } } ] } ], "ambiente": { "$ne": "teste" } }, "id": "exp_a0fe5a0d9950fd8a", "incluir_pdf": false, "status": "concluido", "total_notas": 1 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Baixar o ZIP de uma exportação `GET /api/v1/exports/{export_id}/download` Baixa o pacote pronto de uma exportação. A resposta é um **302**: o `Location` aponta o arquivo num link temporário do armazenamento (vale 5 minutos), e a API não relê o pacote para servi-lo. Siga o redirecionamento — `curl -L`, ou `requests`/`httpx` com redirecionamento ligado (os dois não repassam a sua chave para o outro endereço) — e grave os bytes em disco: o arquivo é `application/zip`, NÃO é JSON. O nome do arquivo fica por sua conta (o link não sugere um). Não guarde o link do `Location`: para baixar de novo, chame esta rota de novo. Dentro do ZIP vêm `relatorio.html` (o relatório do período para ler e imprimir: os totais, o fechamento por competência e a lista de notas, cada uma com link para os arquivos deste mesmo pacote), `relatorio.csv` (uma linha por nota, com a situação, quando foi cancelada ou substituída e o número da nota que substituiu), `xml/` e `pdf/` com as notas ATIVAS, `xml/canceladas/` e `xml/substituidas/` (e o mesmo em `pdf/`) com as que saíram de ativa, e `eventos/` com o XML de cada cancelamento ou substituição — quem importa `xml/` sem recursão recebe só o que vale, e o sistema contábil que também lê `eventos/` fica com a prova. PDFs só quando a exportação foi pedida com `incluir_pdf`. Cada arquivo é nomeado pela data de emissão (Brasília), número oficial da nota e chave de acesso — a ordem alfabética segue a numeração. O `relatorio.csv` é do contador e abre no Excel em português: cabeçalhos em português, códigos por extenso, competência `dd/mm/aaaa`, datas em Brasília `dd/mm/aaaa hh:mm`, vírgula decimal, o ISS retido em reais, texto numa linha só, e chave, CPF/CNPJ e código do serviço como texto por fórmula `="…"`. Só funciona com a exportação em `concluido`: enquanto ela estiver `pendente`, `processando` ou em `erro`, a resposta é 409 `EXPORT_NAO_CONCLUIDO`. Exportação inexistente devolve 404 `EXPORT_NAO_ENCONTRADO` e empresa fora do seu acesso, 403 `EMPRESA_FORA_DO_RECORTE`. **Pacote em volumes** (veja `volumes` em `GET /api/v1/exports/{export_id}`): sem `volume`, ou com `volume=resumo`, vem o resumo — `relatorio.html` do período inteiro e o `relatorio.csv` completo; `volume=1`, `2`, … traz os arquivos de cada volume, na ordem da lista (cada um com a sua `listagem.html`, `listagem.csv`, `xml/`, `pdf/` e `eventos/`). Um número fora da lista devolve 404 `VOLUME_NAO_ENCONTRADO`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `export_id` | path | string **(obrigatório)** | Id da exportação (de `POST /exports`) | | `volume` | query | string, ou null | Num pacote em volumes: `resumo`, ou o número do volume (`1`, `2`, …) na ordem de `volumes`. Ausente = o resumo. Num pacote de um arquivo só, ignorado | **Exemplo de chamada** ```bash curl -L -X GET "https://api.gerenota.com.br/api/v1/exports/{export_id}/download" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -o pacote.zip ``` **Resposta 302** — Redireciona (`Location`) para o arquivo num link temporário do armazenamento, válido por 5 minutos — siga o redirecionamento; para baixar de novo, chame esta rota de novo **Resposta 200** — O pacote ZIP (`relatorio.html`, `relatorio.csv`, `xml/…`, `pdf/…`), entregue pelo armazenamento DEPOIS do redirecionamento 302 (`application/zip`) **Exemplo de resposta** ```json { "_binario": "application/zip", "_bytes": 912 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Pegar o link temporário do ZIP de uma exportação `GET /api/v1/exports/{export_id}/link` O mesmo arquivo de `GET /exports/{export_id}/download`, mas o link vem no corpo, em JSON, em vez de um redirecionamento 302. É para quem não consegue seguir o redirecionamento sem repassar a própria chave — o navegador, por exemplo: o painel pede o link aqui e abre o endereço, e o arquivo baixa como anexo, com o nome de `arquivo`. O link vale 5 minutos e não leva a sua chave; para baixar de novo, peça outro. As mesmas regras do download: 409 `EXPORT_NAO_CONCLUIDO` antes de `concluido`, 404 `EXPORT_NAO_ENCONTRADO`, 403 `EMPRESA_FORA_DO_RECORTE` e, num pacote em volumes, `volume` como no download (404 `VOLUME_NAO_ENCONTRADO` fora da lista). **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `export_id` | path | string **(obrigatório)** | Id da exportação (de `POST /exports`) | | `volume` | query | string, ou null | Num pacote em volumes: `resumo`, ou o número do volume (`1`, `2`, …) na ordem de `volumes`. Ausente = o resumo. Num pacote de um arquivo só, ignorado | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/exports/{export_id}/link" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — O link temporário do arquivo, em JSON | Campo | Tipo | Descrição | |---|---|---| | `url` | string **(obrigatório)** | O link do arquivo no armazenamento, válido por 5 minutos. Abra ou baixe SEM cabeçalho de autenticação (o link já é a autorização); o arquivo vem como anexo, com o nome de `arquivo` | | `expira_em` | string (date-time) **(obrigatório)** | Quando o link deixa de valer (UTC) | | `arquivo` | string **(obrigatório)** | O nome com que o arquivo é baixado (ex.: "gerenota-2026-06-a-2026-06.zip") | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ## Automações Emissões recorrentes e agendadas: criar, editar, pausar, rodar agora e ver as execuções. ### Listar as automações da conta `GET /api/v1/automations` Lista tudo o que roda sozinho na conta — tanto as emissões recorrentes (uma NFS-e por mês para um cliente fixo) quanto os relatórios agendados —, cada uma com a agenda, a próxima execução e um resumo da última vez que rodou. Com uma chamada só dá para montar um painel de automações, sem consultar item por item. O campo `tipo` separa as duas famílias: `emissao_recorrente` traz o conteúdo da nota em `params` (empresa, tomador, serviço, valor); `relatorio` traz em `definicao` o período e os destinatários do e-mail. `ativo` diz se está rodando, e `pausada_por` explica quando a pausa foi automática (`falhas` seguidas ou `fatura` vencida) em vez de manual. `campos_pendentes` com `valor` significa que a automação pergunta o valor antes de emitir, em vez de emitir sozinha. O parâmetro `ordem` aceita `criado_desc` (padrão, as mais recentes primeiro), `proxima_asc` (a que dispara primeiro no topo) ou `nome_asc`. Devolve no máximo 200 automações, sem paginação, e só as das empresas que você pode ver: o relatório de todas as empresas (a definição sem `company_id`) só aparece para quem vê todas as empresas da conta. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `ordem` | query | um de: `"criado_desc"`, `"proxima_asc"`, `"nome_asc"` | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/automations" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — As automações da conta, na ordem pedida | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da automação (prefixo `aut_`) | | `nome` | string **(obrigatório)** | Nome que aparece na lista | | `tipo` | string, ou null | `emissao_recorrente` (emite uma NFS-e) ou `relatorio` (envia um relatório por e-mail) | | `ativo` | boolean **(obrigatório)** | `false` = pausada: continua existindo, mas não dispara na agenda | | `cron` | string **(obrigatório)** | A agenda em cron de 5 campos, no horário de Brasília | | `agenda` | string, ou null | A mesma agenda em português, ex.: `todo dia 5 às 08:00` | | `proxima_execucao` | string (date-time), ou null | Quando a automação dispara da próxima vez, em UTC (ISO 8601) | | `last_run` | string (date-time), ou null | Última execução com desfecho final, em UTC | | `params` | objeto, ou null | O conteúdo da emissão recorrente: `company_id`, `tomador`, `servico`, `valor`, e os opcionais `tributacao`, `competencia` e `local`. `null` em automações de relatório | | `campos_pendentes` | lista de string | O que a automação pergunta antes de emitir, em vez de assumir: `valor` e/ou `complemento`. Lista vazia = emite sozinha | | `entrega_tomador` | boolean, ou null | Se a nota emitida é enviada ao e-mail do cadastro do cliente | | `avisos` | objeto, ou null | Quem é avisado a cada disparo e por quais canais (`ativo`, `canais`, `para`) | | `falhas_consecutivas` | integer, ou null | Falhas seguidas até agora; a automação se pausa sozinha ao chegar a 2 | | `pausada_por` | string, ou null | Motivo de uma pausa automática: `falhas` (falhou seguidas vezes), `fatura`, `sem_destinos` (o último destino do relatório saiu da lista pelo link do e-mail) ou `empresa_inativa`. `null` quando a pausa foi manual ou não há pausa | | `report_definition_id` | string, ou null | Definição de relatório vinculada, se houver | | `definicao` | objeto AutomacaoDefinicaoOut, ou null | Os dados do relatório vinculado, já resolvidos (só na listagem) | | `ultima_execucao` | objeto AutomacaoUltimaExecucaoOut, ou null | Resumo da última execução (só na listagem) | | `pendencia_aberta` | boolean, ou null | Só na resposta do PATCH: `true` quando há uma emissão esperando resposta, que sairá com os dados novos | | `criado_por` | string, ou null | Quem criou a automação | | `criado_em` | string (date-time), ou null | Quando a automação foi criada, em UTC (ISO 8601) | **Exemplo de resposta** ```json [ { "account_id": "acc_it", "agenda": "todo dia 1 às 08:00", "ativo": true, "avisos": { "ativo": true, "canais": { "email": true, "whatsapp": true }, "para": "criador_membros" }, "campos_pendentes": [], "criado_em": "2026-09-16T18:40:13.750000Z", "criado_por": "it@gerenota.test", "cron": "0 8 1 * *", "definicao": { "company_id": null, "destinos": [ "contador@escritorio.com.br" ], "id": "rpt_075e70c21e337fa4", "incluir_zip": false, "nome": "Fechamento mensal", "periodo": null }, "entrega_tomador": false, "falhas_consecutivas": 0, "id": "aut_2292755582553e37", "last_run": "2026-09-16T18:40:13.795000Z", "nome": "Fechamento mensal", "params": null, "pausada_por": null, "proxima_execucao": "2026-10-01T11:00:00Z", "report_definition_id": "rpt_075e70c21e337fa4", "tipo": "relatorio", "ultima_execucao": { "desfecho": "relatorio_enviado", "em": "2026-09-16T18:40:13.795000Z", "erro_codigo": null, "erro_msg": null, "ndps": null, "nfse_id": null, "notas": 0, "numero": null, "valor": null } } ] ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ### Criar uma automação de emissão recorrente `POST /api/v1/automations/recorrente` Cria uma automação que emite, todo mês no `dia` informado (1 a 28), uma nota para o tomador `tomador_documento` (CPF só com números; CNPJ com 14 caracteres, sem pontuação) pela empresa da última nota emitida para ele — a automação copia dessa nota a empresa, o NBS e o nome do tomador. Passe `company_id` em conta com mais de uma empresa: com ele, a nota-base é a mais nova do tomador NESSA empresa, e a automação emite por ela; sem ele, é a mais nova entre todas as empresas do seu acesso, que pode ser de outra emissora. Com `company_id`, empresa fora do seu acesso devolve 403 `EMPRESA_FORA_DO_RECORTE`, e empresa sem nota para o tomador, 404 `PADRAO_NAO_ENCONTRADO`. Com `valor`, a nota sai sozinha; sem `valor`, a automação pergunta o valor ao dono a cada rodada antes de emitir. `cTribNac` e `descricao` são opcionais: sem eles, a automação usa o serviço e a descrição da última nota emitida para esse tomador. Sem nota anterior para o tomador, 404 `PADRAO_NAO_ENCONTRADO` (emita a primeira pelo Emitir). `tributacao` sobrepõe a tributação da última nota; `entrega_tomador` liga o envio por e-mail ao cliente (padrão: liga se o cadastro tiver e-mail); `avisos` ajusta os avisos ao dono. Sem `tributacao`, a retenção do ISS vem das notas do tomador na mesma empresa, quando todas foram retidas. Com retenção (decidida ou do histórico), o tomador precisa de endereço completo no cadastro (422 `RETENCAO_SEM_TOMADOR`) e de `pAliq` (422 `ALIQUOTA_OBRIGATORIA`) — menos na ME/EPP no DAS que tem o ISS do mês: aí cada disparo usa o ISS do mês da prestação, e a `pAliq`, se vier, só vale quando a empresa não tiver ISS naquele mês. Com o ISS fora do DAS, a `pAliq` é a alíquota do município. Exige escopo `emissao`. Conta no limite de automações do plano (402 `LIMITE_DO_PLANO`; pausadas também contam). Já existe automação ativa para o mesmo tomador e serviço → 409 `AUTOMACAO_DUPLICADA` (com acesso a só algumas empresas — membro recortado ou empresa compartilhada —, a duplicata é procurada nas automações dessas empresas). Valor não positivo → 422 `VALOR_INVALIDO`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `company_id` | query | string, ou null | Id da empresa (de `GET /companies`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `tomador_documento` | string **(obrigatório)** | | | `dia` | integer **(obrigatório)** | | | `valor` | string, ou null | | | `cTribNac` | string, ou null | | | `descricao` | string, ou null | | | `nome` | string | Padrão: `""`. | | `avisos` | objeto, ou null | | | `entrega_tomador` | boolean, ou null | | | `tributacao` | objeto, ou null | | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/automations/recorrente" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"dia": 5, "tomador_documento": "03635323000140", "valor": "100.00"}' ``` **Resposta 201** — Automação criada e agendada | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Id da automação (use em /automations/{id}/…) | | `nome` | string **(obrigatório)** | Nome exibido no painel e nos avisos | | `cron` | string **(obrigatório)** | Agenda em cron de 5 campos, derivada do dia do mês informado | | `proxima_execucao` | string (date-time), ou null | Quando a próxima nota sai (UTC) | | `com_lacuna` | boolean | True quando a automação pergunta o valor a cada rodada (criada sem `valor`) Padrão: `false`. | **Exemplo de resposta** ```json { "com_lacuna": false, "cron": "0 8 5 * *", "id": "aut_8ae401c95d0d3109", "nome": "Recorrente — CONSELHO NACIONAL X", "proxima_execucao": "2026-10-05T08:00:00-03:00" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Editar, pausar ou reativar uma automação `PATCH /api/v1/automations/{automation_id}` Altera uma automação existente. O corpo é um objeto solto com apenas os campos que você quer mudar; qualquer outro campo é ignorado em silêncio. São aceitos: `ativo` (`false` pausa, `true` reativa), `nome`, `cron` (a nova agenda, 5 campos, horário de Brasília), `params` (o conteúdo da emissão recorrente — `company_id`, `tomador`, `servico`, `valor` e os opcionais `tributacao`, `competencia` e `local`), `campos_pendentes` (`["valor"]` faz a automação perguntar o valor antes de emitir, `["complemento"]` idem para as informações complementares, lista vazia deixa tudo fixo), `avisos` e `entrega_tomador`. Pausar e reativar passa por aqui: `{"ativo": false}` para a automação sem apagar nada e `{"ativo": true}` religa, zera a contagem de falhas e reagenda a partir de agora — nunca no minuto seguinte por causa de uma agenda velha; mudar o `cron` reagenda do mesmo jeito — e, numa recorrente de uma nota por mês cuja nota deste mês já saiu, a agenda nova começa no mês seguinte: mudar o dia nunca emite uma segunda nota no mesmo mês. Numa automação de emissão recorrente, mexer em `params` ou em `cron` revalida o conteúdo da nota na hora de salvar (serviço, valor, itens, retenção, competência e local), de modo que um 422 aqui evita uma rejeição no dia do disparo — e o tomador de uma automação nunca muda: para outro cliente, crie outra automação. Se houver uma emissão esperando resposta, o campo `pendencia_aberta` da resposta avisa que ela sairá com os dados novos. Corpo sem nenhum campo conhecido devolve 422 `NADA_A_ALTERAR`; automação inexistente, 404 `AUTOMACAO_NAO_ENCONTRADA`; automação de empresa fora do seu acesso, ou `params.company_id` trocado para uma delas, 403 `EMPRESA_FORA_DO_RECORTE` — e o relatório de todas as empresas só é alterado (ou pausado) por quem vê todas as empresas da conta; reativar uma automação que foi pausada por fatura vencida devolve 402 `PAUSADA_POR_FATURA`. Precisa de chave com escopo `emissao`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `automation_id` | path | string **(obrigatório)** | Id da automação (de `GET /automations`) | **Corpo (JSON)** _(sem campos declarados)_ **Exemplo de chamada** ```bash curl -X PATCH "https://api.gerenota.com.br/api/v1/automations/{automation_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{"entrega_tomador": true}' ``` **Resposta 200** — A automação depois da alteração, com a agenda recalculada | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da automação (prefixo `aut_`) | | `nome` | string **(obrigatório)** | Nome que aparece na lista | | `tipo` | string, ou null | `emissao_recorrente` (emite uma NFS-e) ou `relatorio` (envia um relatório por e-mail) | | `ativo` | boolean **(obrigatório)** | `false` = pausada: continua existindo, mas não dispara na agenda | | `cron` | string **(obrigatório)** | A agenda em cron de 5 campos, no horário de Brasília | | `agenda` | string, ou null | A mesma agenda em português, ex.: `todo dia 5 às 08:00` | | `proxima_execucao` | string (date-time), ou null | Quando a automação dispara da próxima vez, em UTC (ISO 8601) | | `last_run` | string (date-time), ou null | Última execução com desfecho final, em UTC | | `params` | objeto, ou null | O conteúdo da emissão recorrente: `company_id`, `tomador`, `servico`, `valor`, e os opcionais `tributacao`, `competencia` e `local`. `null` em automações de relatório | | `campos_pendentes` | lista de string | O que a automação pergunta antes de emitir, em vez de assumir: `valor` e/ou `complemento`. Lista vazia = emite sozinha | | `entrega_tomador` | boolean, ou null | Se a nota emitida é enviada ao e-mail do cadastro do cliente | | `avisos` | objeto, ou null | Quem é avisado a cada disparo e por quais canais (`ativo`, `canais`, `para`) | | `falhas_consecutivas` | integer, ou null | Falhas seguidas até agora; a automação se pausa sozinha ao chegar a 2 | | `pausada_por` | string, ou null | Motivo de uma pausa automática: `falhas` (falhou seguidas vezes), `fatura`, `sem_destinos` (o último destino do relatório saiu da lista pelo link do e-mail) ou `empresa_inativa`. `null` quando a pausa foi manual ou não há pausa | | `report_definition_id` | string, ou null | Definição de relatório vinculada, se houver | | `definicao` | objeto AutomacaoDefinicaoOut, ou null | Os dados do relatório vinculado, já resolvidos (só na listagem) | | `ultima_execucao` | objeto AutomacaoUltimaExecucaoOut, ou null | Resumo da última execução (só na listagem) | | `pendencia_aberta` | boolean, ou null | Só na resposta do PATCH: `true` quando há uma emissão esperando resposta, que sairá com os dados novos | | `criado_por` | string, ou null | Quem criou a automação | | `criado_em` | string (date-time), ou null | Quando a automação foi criada, em UTC (ISO 8601) | **Exemplo de resposta** ```json { "account_id": "acc_it", "agenda": "todo dia 5 às 08:00", "ativo": true, "avisos": { "ativo": true, "canais": { "email": true, "whatsapp": true }, "para": "criador_membros" }, "campos_pendentes": [ "valor" ], "criado_em": "2026-09-16T18:50:35.562000Z", "criado_por": "it@gerenota.test", "cron": "0 8 5 * *", "entrega_tomador": true, "falhas_consecutivas": 0, "id": "aut_b8cd9a2c0d288d6c", "last_run": "2026-09-16T18:50:35.582000Z", "nome": "Recorrente — CONSELHO NACIONAL X", "params": { "company_id": "cmp_25e91effb674033c", "servico": { "cNBS": null, "cTribNac": "010501", "descricao": "Licenca mensal" }, "tomador": { "documento": "03635323000140", "nome": "CONSELHO NACIONAL X", "tipo": "CNPJ" }, "valor": null }, "pausada_por": null, "pendencia_aberta": true, "proxima_execucao": "2026-10-05T11:00:00Z", "report_definition_id": null, "tipo": "emissao_recorrente" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 402 | O plano da conta não inclui isto, o teto do plano (empresas, automações, acessos) foi atingido ou a cota do mês acabou — veja `hint`, `upgrade` e `volta_em` | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Excluir uma automação `DELETE /api/v1/automations/{automation_id}` Apaga a automação e todo o histórico de execuções dela. As notas já emitidas NÃO são afetadas: continuam válidas e nada é cancelado no Sistema Nacional. Uma emissão que estava esperando resposta (o valor do mês, por exemplo) é descartada — ninguém deve responder a uma automação que não existe mais. Excluir é a única forma de liberar uma vaga na contagem de automações do plano; pausar não libera. Não há como desfazer, então para parar só por um tempo prefira `PATCH /api/v1/automations/{automation_id}` com `{"ativo": false}`. Automação inexistente devolve 404 `AUTOMACAO_NAO_ENCONTRADA` e empresa fora do seu acesso, 403 `EMPRESA_FORA_DO_RECORTE` — inclusive o relatório de todas as empresas, que só quem vê todas as empresas da conta exclui. Precisa de chave com escopo `emissao`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `automation_id` | path | string **(obrigatório)** | Id da automação (de `GET /automations`) | **Exemplo de chamada** ```bash curl -X DELETE "https://api.gerenota.com.br/api/v1/automations/{automation_id}" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — A automação e o histórico dela foram apagados | Campo | Tipo | Descrição | |---|---|---| | `id` | string **(obrigatório)** | Identificador da automação excluída | | `excluida` | boolean **(obrigatório)** | Sempre `true` | **Exemplo de resposta** ```json { "excluida": true, "id": "aut_2292755582553e37" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 422 | Dados inválidos — `erros` aponta o campo | ### Rodar uma automação agora `POST /api/v1/automations/{automation_id}/run` Dispara a automação na hora, ignorando o cron. Isto EMITE DE VERDADE: numa automação de emissão recorrente sai uma NFS-e real no Sistema Nacional, que consome cota, avisa quem está na lista de avisos e só sai da vida do cliente por cancelamento — não é uma simulação. Funciona também em automação pausada, o que serve para conferir um conserto antes de reativar, e a agenda seguinte é recalculada normalmente. A resposta traz o `desfecho`: `emitida` (com `nfse_id` e `numero`, o número oficial da nota), `pendencia` (faltava o valor do mês, veja `pendencia_id`), `em_fila` (automação de relatório: o pacote entrou na fila e o e-mail sai quando ele fica pronto — acompanhe em `runs`, onde a execução vira `relatorio_enviado`, `relatorio_parcial` ou `relatorio_nao_entregue`), `falha` (com `erro_codigo`) ou `pulada` (a conta não podia emitir agora, por cota ou por pagamento, ou a empresa do Simples está sem alíquota nenhuma — `ALIQUOTA_NAO_CONFIRMADA` —, numa nota retida, sem o ISS do mês — `ALIQUOTA_ISS_DO_MES_AUSENTE` — ou, desde 1º/11/2026, o Sistema Nacional ainda recusa pelo convênio a ME/EPP de cidade sem adesão — `E0016`, `E0037`, `E0038` ou `E0039`). Rodar agora repete o relatório mesmo que ele já tenha saído hoje. Uma execução malsucedida NÃO vira erro HTTP: a chamada devolve 200 com `desfecho: falha` — sempre leia o campo antes de dar o disparo por bem-sucedido. Se a mesma automação já estiver rodando (o agendador chegou primeiro, ou outra chamada sua), a resposta é 409 `AUTOMACAO_OCUPADA`: espere alguns segundos e consulte `GET /api/v1/automations/{automation_id}/runs`. Precisa de chave com escopo `emissao` — chave de `leitura` recebe 403 `PERMISSAO_NEGADA` —, automação inexistente devolve 404 `AUTOMACAO_NAO_ENCONTRADA` e a de empresa fora do seu acesso, 403 `EMPRESA_FORA_DO_RECORTE` — inclusive o relatório de todas as empresas, que só quem vê todas as empresas da conta roda. **Antecipar** (corpo `{"ocorrencia": ""}`): numa emissão recorrente ativa, a nota da próxima ocorrência sai agora e a ocorrência fica feita — no dia dela, nada sai de novo. Rodar sem o corpo NÃO tira a próxima ocorrência da agenda: a nota dela também sai no dia. Só se antecipa a nota do mês corrente, e nunca na regra de competência do mês anterior, porque a nota sairia com a competência que já saiu: fora disso, 422 `ANTECIPACAO_FORA_DA_COMPETENCIA`. Se a agenda já andou desde que você a leu, 409 `OCORRENCIA_MUDOU`; automação pausada ou de relatório, 422. Saindo a nota, a resposta traz `antecipada` e a nova `proxima_execucao`; não saindo, a nota continua no dia dela. A exceção é a falha `EMISSAO_INCERTA` (o Sistema Nacional não respondeu e a nota pode ter saído): a ocorrência fica feita, e a nova tentativa em cerca de 1 hora confere a nota antes de emitir. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `automation_id` | path | string **(obrigatório)** | Id da automação (de `GET /automations`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `ocorrencia` | string (date-time), ou null | Para ANTECIPAR uma emissão recorrente: o `proxima_execucao` que a automação mostra agora (ISO 8601). A nota dessa ocorrência sai agora e a ocorrência fica feita. Sem o campo, roda na hora como sempre | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/automations/{automation_id}/run" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 200** — O desfecho da execução — inclusive quando ela falhou | Campo | Tipo | Descrição | |---|---|---| | `automation_id` | string **(obrigatório)** | A automação que rodou | | `run_id` | string **(obrigatório)** | Identificador desta execução (prefixo `run_`), o mesmo do histórico | | `desfecho` | string **(obrigatório)** | `emitida`, `pendencia`, `em_fila` (automação de relatório: o pacote entrou na fila — acompanhe em `runs`, onde a execução vira `relatorio_enviado`, `relatorio_parcial` ou `relatorio_nao_entregue` pelo que o provedor de e-mail aceitou), `falha` ou `pulada`. Rodar agora sempre repete, então aqui não aparece `repetida` | | `nfse_id` | string, ou null | Nota emitida — use em `GET /api/v1/nfse/{nfse_id}` para o XML e o PDF | | `numero` | string, ou null | Número oficial (nNFSe) da nota emitida | | `ndps` | integer, ou null | Sequência interna da DPS da nota emitida | | `pendencia_id` | string, ou null | A emissão que ficou esperando resposta, quando o desfecho foi `pendencia` | | `notas` | integer, ou null | Quantas notas entraram no relatório enviado | | `erro_codigo` | string, ou null | Código do erro quando o desfecho foi `falha` ou `pulada` | | `erro_msg` | string, ou null | Motivo em português da falha ou do pulo — o mesmo texto do histórico | | `observacao` | string, ou null | O que a execução diz além do desfecho: o município do cliente que mudou pela Receita (a nota saiu com o endereço novo, que é o do cadastro do CNPJ) — uma vez só por mudança | **Exemplo de resposta** ```json { "automation_id": "aut_b8cd9a2c0d288d6c", "desfecho": "pendencia", "erro_codigo": null, "ndps": null, "nfse_id": null, "notas": null, "numero": null, "pendencia_id": "pend_436712321422c6c1", "run_id": "run_c2dc6853e2851928" } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Pular a próxima nota de uma emissão recorrente `POST /api/v1/automations/{automation_id}/pular` Pula UMA nota de uma emissão recorrente: a ocorrência informada não sai, e a agenda passa para a seguinte. Nada é emitido nem cancelado, e o histórico de execuções não ganha linha — o pulo fica na trilha de atividades. Mande em `ocorrencia` o `proxima_execucao` que a automação mostra agora: se a agenda já andou (a nota saiu, ou alguém pulou antes), a resposta é 409 `OCORRENCIA_MUDOU`, e nada muda — recarregue e decida de novo. Se a automação estiver rodando neste instante, 409 `AUTOMACAO_OCUPADA`. Reativar a automação ou mudar a agenda depois não traz a nota pulada de volta: na recorrente de uma nota por mês, nenhuma outra sai no mês da pulada. Com uma nota esperando (a execução saiu `pulada` ou `falha` e a automação tenta de novo), a agenda mostra a nova tentativa, e pular é pular a nota que espera: `pulada` traz a data dela. O pedido de valor que já está aberto se pula em `POST /api/v1/emissoes-pendentes/{pendencia_id}/pular`. Só vale para automação de emissão recorrente ativa: a de relatório ou a pausada devolve 422. Automação inexistente devolve 404 `AUTOMACAO_NAO_ENCONTRADA` e a de empresa fora do seu acesso, 403 `EMPRESA_FORA_DO_RECORTE`. Precisa de chave com escopo `emissao`. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `automation_id` | path | string **(obrigatório)** | Id da automação (de `GET /automations`) | **Corpo (JSON)** | Campo | Tipo | Descrição | |---|---|---| | `ocorrencia` | string (date-time) **(obrigatório)** | A nota que não deve sair: o `proxima_execucao` que a automação mostra agora, em ISO 8601 | **Exemplo de chamada** ```bash curl -X POST "https://api.gerenota.com.br/api/v1/automations/{automation_id}/pular" \ -H "Authorization: Bearer $GERENOTA_KEY" \ -H "Content-Type: application/json" \ -d '{ … }' ``` **Resposta 200** — A nota pulada e a próxima execução | Campo | Tipo | Descrição | |---|---|---| | `automation_id` | string **(obrigatório)** | A automação | | `pulada` | string (date-time) **(obrigatório)** | A ocorrência que não vai sair, em UTC | | `proxima_execucao` | string (date-time) **(obrigatório)** | A próxima execução depois do pulo, em UTC | **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 404 | Não encontrado nesta conta | | 409 | Conflito com o estado atual (ex.: nota já cancelada, empresa inativa, emissão em andamento) | | 422 | Dados inválidos — `erros` aponta o campo | ### Listar as execuções de uma automação `GET /api/v1/automations/{automation_id}/runs` Histórico de uma automação, da execução mais recente para a mais antiga: quando rodou, se o disparo foi automático ou manual, o desfecho e o que saiu dali. É por aqui que se confere se a nota do mês saiu, ou se investiga uma falha. Cada item traz `desfecho` (`emitida`, `pendencia`, `relatorio_enviado`, `relatorio_parcial`, `relatorio_nao_entregue`, `em_fila`, `repetida`, `falha` ou `pulada`), `disparo` (`agendado` ou `manual`), `numero` — o número oficial da NFS-e — e `valor` nas emissões, `notas` nos relatórios, e `erro_codigo` mais `erro_msg`, já em português, quando deu errado. O relatório mensal nasce `em_fila` (o pacote é montado numa fila) e, quando sai, vira o que o provedor de e-mail aceitou: `relatorio_enviado` (todos os destinos), `relatorio_parcial` (parte deles — `erro_msg` diz quem ficou sem) ou `relatorio_nao_entregue` (nenhum; conta como falha e tenta de novo em 1 hora). O e-mail aos destinos sai mesmo com os avisos desligados: é a entrega, não um aviso. `repetida` é o relatório da mesma definição que já saiu no dia. `pulada` não é falha da automação: é a conta que não podia emitir naquela hora, por cota ou por pagamento, a empresa do Simples sem alíquota nenhuma (`erro_codigo` `ALIQUOTA_NAO_CONFIRMADA`), numa nota retida, sem o ISS do mês (`ALIQUOTA_ISS_DO_MES_AUSENTE`) ou, desde 1º/11/2026, a ME/EPP de cidade sem adesão que o Sistema Nacional ainda recusa pelo convênio (`erro_codigo` `E0016`, `E0037`, `E0038` ou `E0039`) — tenta de novo no dia seguinte. A paginação é por `limit` (1 a 100, padrão 20) e `skip`, e `total` é a contagem completa, independente da página. Automação inexistente — ou já excluída, já que o histórico vai junto — devolve lista vazia, não 404; pedir o histórico de uma automação de empresa fora do seu acesso devolve 403 `EMPRESA_FORA_DO_RECORTE` — inclusive o do relatório de todas as empresas, que só quem vê todas as empresas da conta acompanha. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `automation_id` | path | string **(obrigatório)** | Id da automação (de `GET /automations`) | | `limit` | query | integer | | | `skip` | query | integer | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/automations/{automation_id}/runs" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — A página pedida do histórico, da execução mais recente para a mais antiga | Campo | Tipo | Descrição | |---|---|---| | `total` | integer **(obrigatório)** | Total de execuções da automação, ignorando `limit`/`skip` | | `itens` | lista de objeto AutomacaoRunOut **(obrigatório)** | Execuções da página, da mais recente para a mais antiga | | `itens.id` | string **(obrigatório)** | Identificador da execução (prefixo `run_`) | | `itens.automation_id` | string **(obrigatório)** | A automação que rodou | | `itens.disparo` | string **(obrigatório)** | `agendado` (a agenda venceu) ou `manual` (alguém mandou rodar agora) | | `itens.desfecho` | string **(obrigatório)** | `emitida`, `pendencia`, `relatorio_enviado`, `relatorio_parcial` (o e-mail do relatório foi aceito só para parte dos destinos — `erro_msg` diz quem ficou sem), `relatorio_nao_entregue` (nenhum destino aceitou; conta como falha e tenta de novo em 1 hora), `em_fila` (o relatório está na fila de pacotes; vira um dos três quando o trabalhador entrega), `repetida` (o relatório desta definição já saiu hoje por outra execução agendada — não se repete), `falha` ou `pulada` | | `itens.iniciado_em` | string (date-time), ou null | Quando a execução começou, em UTC (ISO 8601) | | `itens.duracao_ms` | integer, ou null | Quanto a execução demorou, em milissegundos | | `itens.nfse_id` | string, ou null | Nota emitida nesta execução | | `itens.numero` | string, ou null | Número oficial (nNFSe) da nota emitida | | `itens.ndps` | integer, ou null | Sequência interna da DPS da nota emitida | | `itens.valor` | string, ou null | Valor do serviço da nota emitida, em reais, como texto | | `itens.pendencia_id` | string, ou null | A emissão que ficou esperando resposta | | `itens.notas` | integer, ou null | Quantas notas entraram no relatório enviado | | `itens.erro_codigo` | string, ou null | Código do erro quando o desfecho foi `falha` — ou, no relatório, `relatorio_parcial` / `relatorio_nao_entregue`: `EMAIL_PARCIAL`, `EMAIL_RECUSADO`, `EMAIL_SUPRIMIDO_TESTE`, `EMAIL_SEM_DESTINO` | | `itens.erro_msg` | string, ou null | Motivo em português da falha ou do pulo | | `itens.observacao` | string, ou null | O que a execução diz além do desfecho: o município do cliente que mudou pela Receita (a nota saiu com o endereço novo, que é o do cadastro do CNPJ) — uma vez só por mudança | | `itens.user_id` | string, ou null | Quem mandou rodar, no disparo manual | | `itens.avisos` | lista de objeto, ou null | Avisos disparados por esta execução: canal, destino e situação do envio | **Exemplo de resposta** ```json { "itens": [ { "account_id": "acc_it", "automation_id": "aut_2292755582553e37", "avisos": [ { "canal": "email", "enviados": 1 } ], "desfecho": "relatorio_enviado", "disparo": "manual", "duracao_ms": 2, "erro_codigo": null, "erro_msg": null, "id": "run_6f6bdbaf6a41e4ac", "iniciado_em": "2026-09-16T18:40:13.795000Z", "ndps": null, "nfse_id": null, "notas": 0, "numero": null, "pendencia_id": null, "user_id": "it@gerenota.test", "valor": null } ], "total": 1 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ## Atividades A trilha de quem fez o quê na conta. ### Listar a trilha de atividades da conta `GET /api/v1/atividades` Lista o que aconteceu na conta, do mais recente para o mais antigo: notas emitidas e canceladas, exportações pedidas, automações que rodaram, membros que entraram, cadastros alterados. Serve tanto para um feed de "últimas atividades" quanto para uma tela de auditoria. A paginação é por `limit` (1 a 100, padrão 10) e `skip`, e `total` traz a contagem completa dos filtros, independente da página. Filtros disponíveis: `company_id` (uma empresa — que também devolve os eventos da conta inteira, gravados sem empresa), `user_id` (quem fez), `tipo` (um ou vários, separados por vírgula) e o período `de`/`ate` em `AAAA-MM-DD`, com `ate` inclusivo. Numa empresa compartilhada por outra conta, a trilha da conta inteira dela fica de fora: vêm os eventos da empresa e, dos gravados sem empresa, só os que você mesmo fez; os de gestão de acesso da empresa (quem recebeu acesso, com que papel) também ficam de fora. Quem não é dono da conta nunca recebe eventos de cobrança, mesmo pedindo por eles em `tipo`. Pedir uma empresa fora do seu acesso devolve 403 `EMPRESA_FORA_DO_RECORTE`; sem chave válida, 401. **Parâmetros** | Parâmetro | Onde | Tipo | Descrição | |---|---|---|---| | `limit` | query | integer | | | `skip` | query | integer | | | `company_id` | query | string, ou null | Id da empresa (de `GET /companies`) | | `user_id` | query | string, ou null | | | `tipo` | query | string, ou null | | | `de` | query | string, ou null | | | `ate` | query | string, ou null | | **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/api/v1/atividades" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — A página pedida da trilha, do evento mais recente para o mais antigo | Campo | Tipo | Descrição | |---|---|---| | `total` | integer **(obrigatório)** | Total de eventos que casam com os filtros, ignorando `limit`/`skip` | | `itens` | lista de objeto AtividadeOut **(obrigatório)** | Eventos da página, do mais recente para o mais antigo | | `itens.id` | string **(obrigatório)** | Identificador do evento (prefixo `atv_`) | | `itens.tipo` | string **(obrigatório)** | Tipo do evento, ex.: `nfse_emitida`, `nfse_cancelada`, `export`, `automacao_emitida` | | `itens.texto` | string **(obrigatório)** | Frase pronta para exibir, já em português | | `itens.quem` | string, ou null | Quem fez: nome do membro, e-mail, `WhatsApp` ou `Chave de API`. `null` quando foi o próprio sistema | | `itens.papel` | string, ou null | Papel de quem fez no momento do evento (`owner`, `operador`, `contabilidade`, `leitor`) ou `automação` | | `itens.company_id` | string, ou null | Empresa do evento. `null` nos eventos da conta inteira (membros, cobrança, entrada por link) | | `itens.criado_em` | string (date-time), ou null | Quando aconteceu, em UTC (ISO 8601) | **Exemplo de resposta** ```json { "itens": [ { "company_id": "cmp_a7ee8f7a44edd30e", "criado_em": "2026-09-16T18:39:19.656000Z", "id": "atv_bd13aa18da1f0c1d", "papel": "", "quem": null, "texto": "Alíquota 7.30% confirmada para 2026-09 (calculada)", "tipo": "aliquota_confirmada" }, { "company_id": "cmp_a7ee8f7a44edd30e", "criado_em": "2026-09-16T18:39:19.038000Z", "id": "atv_1dc7638aa30e365e", "papel": "owner", "quem": "it", "texto": "Certificado A1 enviado — EMPRESA TESTE ALIQUOTAS LTDA (válido até 13/07/2027)", "tipo": "certificado_enviado" } ], "total": 2 } ``` **Erros** | Status | Quando | |---|---| | 401 | Chave de API ausente, inválida ou revogada | | 403 | Sem permissão: escopo da chave (leitura × emissão), papel de quem a criou ou empresa fora do seu acesso | | 422 | Dados inválidos — `erros` aponta o campo | ## Meta Saúde do serviço. ### Conferir a saúde do serviço `GET /health` Diz se o serviço está de pé. É a única rota sem autenticação — feita para monitor externo e para o seu "smoke test" antes de integrar. Devolve `status` (`ok` ou `degraded`), a versão da API e do núcleo de emissão e o ambiente que respondeu. `degraded` quer dizer serviço no ar com algo defeituoso atrás: banco indisponível ou agendador de automações sem sinal há mais de 5 minutos (`scheduler_ha_s` diz há quantos segundos foi o último). O código HTTP é 200 nos dois casos, então alarme pelo campo `status`, nunca pelo código HTTP. **Exemplo de chamada** ```bash curl -X GET "https://api.gerenota.com.br/health" \ -H "Authorization: Bearer $GERENOTA_KEY" ``` **Resposta 200** — O serviço respondeu (veja o campo `status`) | Campo | Tipo | Descrição | |---|---|---| | `status` | string **(obrigatório)** | `ok` ou `degraded` (o HTTP é 200 nos dois casos) | | `api` | string **(obrigatório)** | Versão da API | | `core` | string **(obrigatório)** | Versão do núcleo de emissão | | `env` | string **(obrigatório)** | Ambiente que respondeu (ex.: `producao`) | | `scheduler_ha_s` | integer, ou null | Há quantos segundos o agendador deu sinal; acima de 300 vira `degraded` | | `mongo` | string, ou null | Presente só quando o banco não respondeu | **Exemplo de resposta** ```json { "api": "0.1.0", "core": "0.1.0", "env": "dev", "status": "ok" } ```