# Referência da API

> Prévia: a API abre junto com o painel.

Gerada a partir do contrato [openapi.yaml](https://nfseia.com.br/docs/openapi.yaml) (OpenAPI 3.1, versão 1.0.0-previa). Endereço base: `https://api.nfseia.com.br/v1`. Autenticação, ambientes e idempotência estão em [Autenticação](https://nfseia.com.br/docs/autenticacao); erros e limites, em [Erros e limites](https://nfseia.com.br/docs/erros).

- **Notas:** [Emitir nota](#emitir-nota), [Listar notas](#listar-notas), [Consultar nota](#consultar-nota), [Cancelar nota](#cancelar-nota), [Baixar o XML](#baixar-o-xml), [Baixar o PDF](#baixar-o-pdf), [Reenviar a nota por e-mail](#reenviar-a-nota-por-e-mail).
- **Recorrências:** [Criar recorrência](#criar-recorrencia), [Listar recorrências](#listar-recorrencias), [Consultar recorrência](#consultar-recorrencia), [Editar, pausar ou retomar](#editar-pausar-ou-retomar), [Encerrar recorrência](#encerrar-recorrencia).
- **Tomadores:** [Salvar tomador](#salvar-tomador), [Listar e buscar tomadores](#listar-e-buscar-tomadores), [Consultar tomador](#consultar-tomador), [Editar tomador](#editar-tomador), [Excluir tomador](#excluir-tomador).
- **Consultas:** [Consultar CNPJ](#consultar-cnpj), [Buscar código de serviço](#buscar-codigo-de-servico).
- **Gatilhos:** [Criar gatilho de pagamento](#criar-gatilho-de-pagamento), [Listar gatilhos](#listar-gatilhos), [Consultar gatilho](#consultar-gatilho), [Editar ou pausar gatilho](#editar-ou-pausar-gatilho), [Excluir gatilho](#excluir-gatilho), [Trocar o segredo do gatilho](#trocar-o-segredo-do-gatilho), [Receber aviso de pagamento](#receber-aviso-de-pagamento).
- **Webhooks:** [Cadastrar webhook](#cadastrar-webhook), [Listar webhooks](#listar-webhooks), [Consultar webhook](#consultar-webhook), [Editar, pausar ou reativar webhook](#editar-pausar-ou-reativar-webhook), [Excluir webhook](#excluir-webhook), [Trocar o segredo do webhook](#trocar-o-segredo-do-webhook), [Listar entregas](#listar-entregas), [Reenviar entrega](#reenviar-entrega).
- **Empresa:** [Consultar empresa](#consultar-empresa), [Gerar link de envio do certificado](#gerar-link-de-envio-do-certificado).

## Notas

Emissão, consulta, cancelamento, XML, PDF e reenvio por e-mail da nota fiscal de serviço.

Ciclo de vida da nota:

1. **Reserva (interna, não aparece na API):** numa só transação, o NFSeIA reserva a
   `referencia_externa` para a empresa e o ambiente, numera a DPS e grava o Id dela, antes de
   qualquer envio. Pedido concorrente com a mesma referência, mesmo com outra
   `Idempotency-Key`, recebe essa mesma nota (pendente ou final), nunca uma segunda DPS.
2. **`pendente`**, com o motivo em `pendencia.motivo`:
   - `aguardando_sefin`: enviada e sem resposta no prazo. O NFSeIA consulta pelo Id da DPS
     em 30 s, 2 min, 10 min, 1 h e 6 h.
   - `conferindo_identidade`: a SEFIN disse que a DPS já existe (E0014), a consulta foi
     inconclusiva ou o XML recebido não confere com a DPS enviada. O NFSeIA busca a NFS-e
     pela chave e confere se ela é mesmo desta DPS antes de adotar.
   - `colisao_numeracao`: o número da DPS foi usado fora do NFSeIA (por exemplo no emissor
     do governo). A nota não é adotada nem reenviada; o e-mail da empresa é avisado.
   - `requer_intervencao`: as consultas acabaram sem resposta definitiva. O e-mail da
     empresa e o evento `nota.pendente` avisam, e o suporte resolve pelo chamado.
3. **Estados finais:** `autorizada` (número, chave de acesso, XML e PDF), `rejeitada` (recusa
   definitiva da SEFIN, conferida pelo Id da DPS: a nota não existe lá) e `cancelada`.

A referência e o número da DPS só são liberados quando a nota fica `rejeitada`. Em
`pendente`, por qualquer motivo, os dois continuam presos à nota, sem prazo: nada é
renumerado nem reenviado com outro Id, e repetir a referência devolve a nota pendente.

### Emitir nota

`POST /notas`

Escopo: `notas:emitir`. Exige `Idempotency-Key`.

Emite uma nota fiscal de serviço em nome da empresa da chave. O prestador, a série, o número
da DPS, o município emissor e o ambiente vêm da empresa e da chave; não envie.

Campos de `servico` e `valores` que você omitir vêm dos padrões da nota da empresa
(`padroes_da_nota` em `GET /empresa`, definidos no cadastro), campo a campo. Depois da
mistura, a nota inteira passa pela mesma validação. Se o tomador já estiver salvo em
`/tomadores`, basta o `documento`; os outros dados vêm do cadastro dele.

A `referencia_externa` é reservada, junto com o número da DPS, antes de qualquer envio
(veja o ciclo de vida em Notas). Os prefixos `pagamento:`, `recorrencia:` e `mcp:` são
reservados (`400 referencia_reservada`).

Respostas:

- `201`: autorizada.
- `202`: `pendente`, com o motivo em `pendencia.motivo` (por exemplo, a SEFIN não respondeu
  em 25 s). Acompanhe por webhook ou por `GET /notas/{id}`.
- `200`: a `referencia_externa` já tinha nota não rejeitada (autorizada, pendente ou
  cancelada), inclusive de um pedido concorrente com outra `Idempotency-Key`. Volta essa
  nota, com o cabeçalho `NFSeIA-Recurso-Existente: true`, e nada é emitido.
- `400 dados_invalidos`: nada foi enviado à SEFIN.
- `422 nota_rejeitada`: recusa definitiva da SEFIN, conferida pelo Id da DPS; a nota fica
  guardada como `rejeitada` e a referência é liberada. Recusa que ainda precisa de
  conferência (por exemplo "DPS já existe") volta como `202` pendente.

No ambiente de teste, coloque `[simular:rejeitada]` ou `[simular:pendente]` na descrição do
serviço para ver esses caminhos; a pendente vira autorizada em cerca de 1 minuto.

#### Corpo

Pedido de emissão. Campo desconhecido é recusado. Não envie prestador, série, número,
município emissor nem ambiente: vêm da empresa e da chave.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `referencia_externa` | texto | sim | Id do pedido, fatura ou cobrança no seu sistema. Única por empresa e ambiente: se já houver nota não rejeitada com ela, volta essa nota e nada é emitido. |
| `competencia` | data | não | Data da competência (AAAA-MM-DD). Se omitida, a data de hoje no horário de Brasília. |
| `tomador` | objeto | não | Tomador ou intermediário na entrada. Se o documento já estiver salvo em `/tomadores`, basta ele; os campos que você enviar valem só para esta nota. Quem está no exterior ainda não é atendido. |
| `tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `tomador.endereco` | objeto | não |  |
| `tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `intermediario` | objeto | não | Tomador ou intermediário na entrada. Se o documento já estiver salvo em `/tomadores`, basta ele; os campos que você enviar valem só para esta nota. Quem está no exterior ainda não é atendido. |
| `intermediario.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `intermediario.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `intermediario.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `intermediario.endereco` | objeto | não |  |
| `intermediario.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `intermediario.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `intermediario.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `intermediario.endereco.numero` | texto | sim | Até 60 caracteres. |
| `intermediario.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `intermediario.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `intermediario.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `intermediario.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `valores` | objeto | sim | Campos omitidos vêm de `padroes_da_nota.valores` da empresa. Regras da SEFIN conferidas antes do envio: MEI não tem ISS retido (E0583), não informa alíquota (E0600) nem percentual do Simples (E0710); ME/EPP informa o percentual (E0712); com tudo pelo Simples, a alíquota é obrigatória com ISS retido (E0621, mínimo 1.80) e proibida sem retenção (E0625). |
| `valores.valor_servico` | texto | sim | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `valores.retencao_iss` | texto | não | Com retenção pelo tomador, o tomador e o endereço dele são obrigatórios (E0204, E0237). Um de: `nao_retido`, `retido_pelo_tomador`, `retido_pelo_intermediario`. |
| `valores.aliquota_iss` | texto ou nulo | não | Alíquota do ISS, de 0.01 a 5.00 (E0595). Para ME/EPP com tudo pelo Simples: obrigatória com ISS retido, no mínimo 1.80 (E0621), e proibida sem retenção (E0625). MEI não informa (E0600). |
| `valores.percentual_tributos_simples` | texto | não | Percentual com ponto e duas casas. |
| `enviar_email` | booleano | não | Liga ou desliga o e-mail desta nota. Se omitido, vale o que está no tomador e na empresa. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/notas' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "referencia_externa": "pedido-1042",
  "tomador": {
    "documento": "12345678000195"
  },
  "valores": {
    "valor_servico": "1500.00"
  }
}'
```

Outro corpo: tudo explícito, tomador ainda não salvo.

```json
{
  "referencia_externa": "pedido-1043",
  "competencia": "2026-11-05",
  "tomador": {
    "documento": "12.345.678/0001-95",
    "nome": "Padaria Pão Quente Ltda",
    "email": "financeiro@paoquente.com.br",
    "endereco": {
      "municipio": "4106902",
      "cep": "80020-310",
      "logradouro": "Rua XV de Novembro",
      "numero": "1000",
      "bairro": "Centro"
    }
  },
  "servico": {
    "codigo_tributacao_nacional": "010801",
    "codigo_nbs": null,
    "descricao": "Manutenção do site, novembro de 2026",
    "municipio_prestacao": "4106902"
  },
  "valores": {
    "valor_servico": "1500.00",
    "retencao_iss": "nao_retido",
    "percentual_tributos_simples": "6.00"
  },
  "enviar_email": true
}
```

#### Respostas

- `200`: A `referencia_externa` já tinha nota. Volta a nota existente e nada é emitido. [Nota](#objeto-nota).
- `201`: Nota autorizada. [Nota](#objeto-nota).
- `202`: A SEFIN não respondeu a tempo. A nota fica `pendente` e o NFSeIA resolve sozinho. [Nota](#objeto-nota).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `402`: Teste grátis encerrado, cota do mês esgotada ou assinatura em atraso. Códigos: `cota_esgotada`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `409`: A mesma `Idempotency-Key` está em uso por outra requisição ou veio com outro corpo. Códigos: `idempotencia_em_andamento`, `idempotencia_reutilizada`.
- `422`: A SEFIN recusou a nota. Ela fica guardada como `rejeitada`, com o id em `nota_id`. Códigos: `nota_rejeitada`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "nota_01JC8Z4M3QK7T2V9X5B6N1R0PD",
  "ambiente": "producao",
  "status": "autorizada",
  "origem": "api",
  "referencia_externa": "pedido-1042",
  "numero": "18",
  "chave_acesso": "41069021245723174000110000000000001826117319502647",
  "dps": {
    "id": "DPS410690224572317400011000001000000000000042",
    "serie": "1",
    "numero": "42"
  },
  "competencia": "2026-11-05",
  "municipio_emissor": "4106902",
  "prestador": {
    "cnpj": "45723174000110",
    "inscricao_municipal": "1234567",
    "simples_nacional": "me_epp",
    "apuracao_simples": "tudo_pelo_simples"
  },
  "tomador": {
    "documento": "12345678000195",
    "nome": "Padaria Pão Quente Ltda",
    "inscricao_municipal": null,
    "endereco": {
      "municipio": "4106902",
      "cep": "80020310",
      "logradouro": "Rua XV de Novembro",
      "numero": "1000",
      "complemento": null,
      "bairro": "Centro"
    },
    "telefone": null,
    "email": "financeiro@paoquente.com.br"
  },
  "intermediario": null,
  "servico": {
    "codigo_tributacao_nacional": "010801",
    "codigo_nbs": null,
    "descricao": "Manutenção do site, novembro de 2026",
    "municipio_prestacao": "4106902"
  },
  "valores": {
    "valor_servico": "1500.00",
    "retencao_iss": "nao_retido",
    "aliquota_iss": null,
    "percentual_tributos_simples": "6.00"
  },
  "pendencia": null,
  "rejeicao": null,
  "cancelamento": null,
  "emails": [
    {
      "destinatario": "tomador",
      "endereco": "financeiro@paoquente.com.br",
      "status": "enviado",
      "enviado_em": "2026-11-05T14:03:20-03:00"
    },
    {
      "destinatario": "emissor",
      "endereco": "financeiro@estudioaurora.com.br",
      "status": "enviado",
      "enviado_em": "2026-11-05T14:03:20-03:00"
    }
  ],
  "links": {
    "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/xml",
    "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/pdf",
    "consulta_publica": "https://www.nfse.gov.br/consultapublica"
  },
  "recorrencia_id": null,
  "gatilho_id": null,
  "criada_em": "2026-11-05T14:03:09-03:00",
  "autorizada_em": "2026-11-05T14:03:12-03:00",
  "atualizada_em": "2026-11-05T14:03:20-03:00"
}
```

### Listar notas

`GET /notas`

Escopo: `notas:ler`.

Lista as notas do ambiente da chave, da mais nova para a mais antiga, com paginação por
cursor. Filtrando pela `referencia_externa`, a primeira da lista é a tentativa vigente (a
única não rejeitada: autorizada, pendente ou cancelada), se houver; as demais são o
histórico de tentativas rejeitadas.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `referencia_externa` | consulta | texto | não | Referência exata usada na emissão. Até 100 caracteres. |
| `numero` | consulta | texto | não | Número da NFS-e, como aparece na nota. |
| `status` | consulta | texto | não | Um de: `autorizada`, `pendente`, `rejeitada`, `cancelada`. |
| `tomador_documento` | consulta | texto | não | CPF ou CNPJ do tomador, só números. |
| `de` | consulta | data | não | Criadas a partir desta data (inclusive), no horário de Brasília. |
| `ate` | consulta | data | não | Criadas até esta data (inclusive), no horário de Brasília. |
| `limite` | consulta | inteiro | não | Itens por página, de 1 a 100. De 1 a 100. Padrão: `20`. |
| `cursor` | consulta | texto | não | Valor de `proximo_cursor` da página anterior. Até 200 caracteres. |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/notas?referencia_externa=pedido-1042' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Página de notas. Lista de [Nota](#objeto-nota) em `dados`, com `proximo_cursor`.
- `400`: Requisição malformada. Códigos: `requisicao_invalida`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "dados": [
    {
      "id": "nota_01JC8Z4M3QK7T2V9X5B6N1R0PD",
      "ambiente": "producao",
      "status": "autorizada",
      "origem": "api",
      "referencia_externa": "pedido-1042",
      "numero": "18",
      "chave_acesso": "41069021245723174000110000000000001826117319502647",
      "dps": {
        "id": "DPS410690224572317400011000001000000000000042",
        "serie": "1",
        "numero": "42"
      },
      "competencia": "2026-11-05",
      "municipio_emissor": "4106902",
      "prestador": {
        "cnpj": "45723174000110",
        "inscricao_municipal": "1234567",
        "simples_nacional": "me_epp",
        "apuracao_simples": "tudo_pelo_simples"
      },
      "tomador": {
        "documento": "12345678000195",
        "nome": "Padaria Pão Quente Ltda",
        "email": "financeiro@paoquente.com.br"
      },
      "intermediario": null,
      "servico": {
        "codigo_tributacao_nacional": "010801",
        "codigo_nbs": null,
        "descricao": "Manutenção do site, novembro de 2026",
        "municipio_prestacao": "4106902"
      },
      "valores": {
        "valor_servico": "1500.00",
        "retencao_iss": "nao_retido",
        "percentual_tributos_simples": "6.00"
      },
      "pendencia": null,
      "rejeicao": null,
      "cancelamento": null,
      "emails": [],
      "links": {
        "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/xml",
        "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/pdf",
        "consulta_publica": "https://www.nfse.gov.br/consultapublica"
      },
      "recorrencia_id": null,
      "gatilho_id": null,
      "criada_em": "2026-11-05T14:03:09-03:00",
      "autorizada_em": "2026-11-05T14:03:12-03:00",
      "atualizada_em": "2026-11-05T14:03:12-03:00"
    }
  ],
  "proximo_cursor": "eyJpZCI6Im5vdGFfMDFKQzhaNE0zUUs3VDJWOVg1QjZOMVIwUEQifQ"
}
```

### Consultar nota

`GET /notas/{id}`

Escopo: `notas:ler`.

Devolve a nota com o estado atual. Nota `pendente` muda sozinha; consulte de novo ou use webhooks.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: A nota. [Nota](#objeto-nota).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "nota_01JC8Z4M3QK7T2V9X5B6N1R0PD",
  "ambiente": "producao",
  "status": "autorizada",
  "origem": "api",
  "referencia_externa": "pedido-1042",
  "numero": "18",
  "chave_acesso": "41069021245723174000110000000000001826117319502647",
  "dps": {
    "id": "DPS410690224572317400011000001000000000000042",
    "serie": "1",
    "numero": "42"
  },
  "competencia": "2026-11-05",
  "municipio_emissor": "4106902",
  "prestador": {
    "cnpj": "45723174000110",
    "inscricao_municipal": "1234567",
    "simples_nacional": "me_epp",
    "apuracao_simples": "tudo_pelo_simples"
  },
  "tomador": {
    "documento": "12345678000195",
    "nome": "Padaria Pão Quente Ltda",
    "inscricao_municipal": null,
    "endereco": {
      "municipio": "4106902",
      "cep": "80020310",
      "logradouro": "Rua XV de Novembro",
      "numero": "1000",
      "complemento": null,
      "bairro": "Centro"
    },
    "telefone": null,
    "email": "financeiro@paoquente.com.br"
  },
  "intermediario": null,
  "servico": {
    "codigo_tributacao_nacional": "010801",
    "codigo_nbs": null,
    "descricao": "Manutenção do site, novembro de 2026",
    "municipio_prestacao": "4106902"
  },
  "valores": {
    "valor_servico": "1500.00",
    "retencao_iss": "nao_retido",
    "aliquota_iss": null,
    "percentual_tributos_simples": "6.00"
  },
  "pendencia": null,
  "rejeicao": null,
  "cancelamento": null,
  "emails": [
    {
      "destinatario": "tomador",
      "endereco": "financeiro@paoquente.com.br",
      "status": "enviado",
      "enviado_em": "2026-11-05T14:03:20-03:00"
    },
    {
      "destinatario": "emissor",
      "endereco": "financeiro@estudioaurora.com.br",
      "status": "enviado",
      "enviado_em": "2026-11-05T14:03:20-03:00"
    }
  ],
  "links": {
    "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/xml",
    "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/pdf",
    "consulta_publica": "https://www.nfse.gov.br/consultapublica"
  },
  "recorrencia_id": null,
  "gatilho_id": null,
  "criada_em": "2026-11-05T14:03:09-03:00",
  "autorizada_em": "2026-11-05T14:03:12-03:00",
  "atualizada_em": "2026-11-05T14:03:20-03:00"
}
```

### Cancelar nota

`POST /notas/{id}/cancelar`

Escopo: `notas:cancelar`.

**Contrato provisório até o mapeamento do Anexo II da SEFIN** (leiaute do evento de
cancelamento): `codigo_motivo` e os limites de `motivo` podem mudar antes da abertura.

Pede à SEFIN o cancelamento de uma nota `autorizada`. Cada nota tem no máximo um pedido de
cancelamento em andamento, com identidade própria (`cancelamento.id`), gravada antes do
envio do evento. Repetir o pedido, ou pedir ao mesmo tempo com outra `Idempotency-Key`,
enquanto `cancelamento.status` é `pendente` devolve esse mesmo pedido (`202`), sem enviar
outro evento e sem trocar o motivo. Depois de concluído, repetir devolve a nota cancelada
(`200`), sem novo evento. Se a SEFIN recusar (`422`), a nota continua `autorizada` e um novo
pedido pode ser feito. O tomador e o emissor recebem e-mail avisando, se o envio de e-mail
estiver ligado.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `codigo_motivo` | texto | sim | Um de: `erro_na_emissao`, `servico_nao_prestado`, `outros`. |
| `motivo` | texto | sim | Justificativa que vai para a SEFIN. Até 255 caracteres. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/cancelar' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "codigo_motivo": "erro_na_emissao",
  "motivo": "Valor do serviço informado errado, nota será emitida de novo."
}'
```

#### Respostas

- `200`: Nota cancelada. [Nota](#objeto-nota).
- `202`: A SEFIN não respondeu a tempo. `cancelamento.status` fica `pendente` e o NFSeIA confirma sozinho. [Nota](#objeto-nota).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `409`: A operação não cabe no estado atual do recurso. Códigos: `estado_invalido`.
- `422`: A SEFIN recusou o cancelamento. A nota continua `autorizada`. Códigos: `cancelamento_recusado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "nota_01JC8Z4M3QK7T2V9X5B6N1R0PD",
  "ambiente": "producao",
  "status": "cancelada",
  "origem": "api",
  "referencia_externa": "pedido-1042",
  "numero": "18",
  "chave_acesso": "41069021245723174000110000000000001826117319502647",
  "dps": {
    "id": "DPS410690224572317400011000001000000000000042",
    "serie": "1",
    "numero": "42"
  },
  "competencia": "2026-11-05",
  "municipio_emissor": "4106902",
  "prestador": {
    "cnpj": "45723174000110",
    "inscricao_municipal": "1234567",
    "simples_nacional": "me_epp",
    "apuracao_simples": "tudo_pelo_simples"
  },
  "tomador": {
    "documento": "12345678000195",
    "nome": "Padaria Pão Quente Ltda",
    "inscricao_municipal": null,
    "endereco": null,
    "telefone": null,
    "email": "financeiro@paoquente.com.br"
  },
  "intermediario": null,
  "servico": {
    "codigo_tributacao_nacional": "010801",
    "codigo_nbs": null,
    "descricao": "Manutenção do site, novembro de 2026",
    "municipio_prestacao": "4106902"
  },
  "valores": {
    "valor_servico": "1500.00",
    "retencao_iss": "nao_retido",
    "aliquota_iss": null,
    "percentual_tributos_simples": "6.00"
  },
  "pendencia": null,
  "rejeicao": null,
  "cancelamento": {
    "id": "canc_01JC99V8X1Z4B7D0F3H6K9M2P5",
    "status": "concluido",
    "codigo_motivo": "erro_na_emissao",
    "motivo": "Valor do serviço informado errado, nota será emitida de novo.",
    "solicitado_em": "2026-11-06T09:12:40-03:00",
    "concluido_em": "2026-11-06T09:12:43-03:00",
    "erros": []
  },
  "emails": [
    {
      "destinatario": "tomador",
      "endereco": "financeiro@paoquente.com.br",
      "status": "enviado",
      "enviado_em": "2026-11-06T09:12:50-03:00"
    },
    {
      "destinatario": "emissor",
      "endereco": "financeiro@estudioaurora.com.br",
      "status": "enviado",
      "enviado_em": "2026-11-06T09:12:50-03:00"
    }
  ],
  "links": {
    "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/xml",
    "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/pdf",
    "consulta_publica": "https://www.nfse.gov.br/consultapublica"
  },
  "recorrencia_id": null,
  "gatilho_id": null,
  "criada_em": "2026-11-05T14:03:09-03:00",
  "autorizada_em": "2026-11-05T14:03:12-03:00",
  "atualizada_em": "2026-11-06T09:12:50-03:00"
}
```

### Baixar o XML

`GET /notas/{id}/xml`

Escopo: `notas:ler`.

XML oficial da NFS-e, como a SEFIN autorizou, guardado por 5 anos. Disponível para nota
`autorizada` ou `cancelada`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/xml' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -o nota.xml
```

#### Respostas

- `200`: O XML da NFS-e.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `409`: A operação não cabe no estado atual do recurso. Códigos: `estado_invalido`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

### Baixar o PDF

`GET /notas/{id}/pdf`

Escopo: `notas:ler`.

Documento auxiliar da nota (DANFSe) em PDF, gerado pelo NFSeIA. No ambiente de teste, sai com
a marca "sem valor fiscal". Disponível para nota `autorizada` ou `cancelada` (com a marca
"cancelada").

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/pdf' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -o nota.pdf
```

#### Respostas

- `200`: O PDF.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `409`: A operação não cabe no estado atual do recurso. Códigos: `estado_invalido`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

### Reenviar a nota por e-mail

`POST /notas/{id}/reenviar-email`

Escopo: `notas:enviar_email`.

Envia de novo o e-mail da nota, com PDF, XML e o link da consulta pública. Sem corpo, vai para
o tomador e para o emissor. No ambiente de teste, vai só para o e-mail do emissor, nunca para
o tomador. A permissão é própria (`notas:enviar_email`), separada da de emissão. Pelo MCP, o
envio vai só para os e-mails do cadastro do tomador e do emissor; endereço novo pede
aprovação humana.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `destinatarios` | lista de e-mail | não | Se omitido, tomador e emissor. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/reenviar-email' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "destinatarios": [
    "contas@paoquente.com.br"
  ]
}'
```

#### Respostas

- `202`: Envio agendado. O resultado aparece em `emails` na nota.
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `409`: A operação não cabe no estado atual do recurso. Códigos: `estado_invalido`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `nota_id` | texto | sim |  |
| `destinatarios` | lista de texto | sim |  |
| `agendado_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |

Exemplo de resposta `202`:

```json
{
  "nota_id": "nota_01JC8Z4M3QK7T2V9X5B6N1R0PD",
  "destinatarios": [
    "contas@paoquente.com.br"
  ],
  "agendado_em": "2026-11-06T10:01:00-03:00"
}
```

## Recorrências

Nota que sai sozinha todo mês para o mesmo tomador. A referência de cada nota é
`recorrencia:{id}:{AAAA-MM}`, então cada mês gera no máximo uma nota.

Cada mês vira uma **ocorrência**, reservada no começo do dia da emissão (0h, horário de
Brasília). A reserva congela a competência, a referência e os dados da nota (tomador,
serviço e valores, já com os padrões da empresa aplicados); toda nova tentativa daquele mês
usa exatamente a ocorrência congelada. Editar, pausar ou encerrar a recorrência vale para as
ocorrências ainda não reservadas e não muda a que já foi reservada; para desfazer uma nota
que saiu, cancele a nota.

No MVP, recorrência não aceita intermediário nem `retido_pelo_intermediario`.

### Criar recorrência

`POST /recorrencias`

Escopo: `recorrencias:escrever`. Exige `Idempotency-Key`.

Configura uma nota que sai sozinha todo mês, no `dia_do_mes`, pela manhã (horário de
Brasília). Nos meses mais curtos, sai no último dia. O emissor recebe e-mail
`aviso_antes_dias` antes e outro quando a nota sai.

A descrição aceita `{mes}` e `{ano}`, trocados pelo mês por extenso e pelo ano da
competência. A ocorrência de cada mês é reservada às 0h do dia da emissão e congela
competência, referência e dados (veja Recorrências); se a nota do mês não puder sair (cota,
certificado, pagamento), o NFSeIA tenta de novo a mesma ocorrência uma vez por dia por 3 dias
e avisa por e-mail.

A `Idempotency-Key` é obrigatória e é a identidade da criação: repetir com a mesma chave
devolve a mesma recorrência, nunca uma segunda. Intermediário e
`retido_pelo_intermediario` são recusados no MVP.

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `tomador` | objeto | sim | Tomador ou intermediário na entrada. Se o documento já estiver salvo em `/tomadores`, basta ele; os campos que você enviar valem só para esta nota. Quem está no exterior ainda não é atendido. |
| `tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `tomador.endereco` | objeto | não |  |
| `tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `valores` | objeto | sim | Valores das recorrências, dos gatilhos e do MCP. No MVP, esses fluxos recusam `retido_pelo_intermediario`. |
| `valores.valor_servico` | texto | sim | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `valores.retencao_iss` | texto | não | Com retenção pelo tomador, o tomador e o endereço dele são obrigatórios (E0204, E0237). Um de: `nao_retido`, `retido_pelo_tomador`. |
| `valores.aliquota_iss` | texto ou nulo | não | Alíquota do ISS, de 0.01 a 5.00 (E0595). Para ME/EPP com tudo pelo Simples: obrigatória com ISS retido, no mínimo 1.80 (E0621), e proibida sem retenção (E0625). MEI não informa (E0600). |
| `valores.percentual_tributos_simples` | texto | não | Percentual com ponto e duas casas. |
| `dia_do_mes` | inteiro | sim | Nos meses mais curtos, a nota sai no último dia. De 1 a 31. |
| `inicio` | texto | sim | Primeiro mês (AAAA-MM). |
| `fim` | texto ou nulo | não | Último mês (AAAA-MM), ou `null` para sem fim. |
| `aviso_antes_dias` | inteiro | não | Dias de antecedência do e-mail de aviso ao emissor; 0 desliga o aviso. De 0 a 10. Padrão: `3`. |
| `enviar_email` | booleano ou nulo | não | E-mail da nota ao tomador. `null` segue o tomador e a empresa. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/recorrencias' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "tomador": {
    "documento": "12345678000195"
  },
  "servico": {
    "descricao": "Manutenção do site, {mes} de {ano}"
  },
  "valores": {
    "valor_servico": "1500.00"
  },
  "dia_do_mes": 5,
  "inicio": "2026-12"
}'
```

#### Respostas

- `201`: Recorrência criada. [Recorrência](#objeto-recorrencia).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `409`: A mesma `Idempotency-Key` está em uso por outra requisição ou veio com outro corpo. Códigos: `idempotencia_em_andamento`, `idempotencia_reutilizada`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `201`:

```json
{
  "id": "rec_01JC90B7W2D5F8H1K4M6P9R3T5",
  "ambiente": "producao",
  "status": "ativa",
  "tomador": {
    "documento": "12345678000195",
    "nome": "Padaria Pão Quente Ltda"
  },
  "servico": {
    "descricao": "Manutenção do site, {mes} de {ano}"
  },
  "valores": {
    "valor_servico": "1500.00"
  },
  "dia_do_mes": 5,
  "inicio": "2026-12",
  "fim": null,
  "aviso_antes_dias": 3,
  "enviar_email": null,
  "proxima_emissao": "2026-12-05",
  "ultima_nota": null,
  "criada_em": "2026-11-05T15:20:00-03:00",
  "atualizada_em": "2026-11-05T15:20:00-03:00"
}
```

### Listar recorrências

`GET /recorrencias`

Escopo: `recorrencias:ler`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `status` | consulta | texto | não | Um de: `ativa`, `pausada`, `encerrada`. |
| `tomador_documento` | consulta | texto | não |  |
| `limite` | consulta | inteiro | não | Itens por página, de 1 a 100. De 1 a 100. Padrão: `20`. |
| `cursor` | consulta | texto | não | Valor de `proximo_cursor` da página anterior. Até 200 caracteres. |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/recorrencias?tomador_documento=12345678000195' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Página de recorrências. Lista de [Recorrência](#objeto-recorrencia) em `dados`, com `proximo_cursor`.
- `400`: Requisição malformada. Códigos: `requisicao_invalida`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "dados": [
    {
      "id": "rec_01JC90B7W2D5F8H1K4M6P9R3T5",
      "ambiente": "producao",
      "status": "ativa",
      "tomador": {
        "documento": "12345678000195",
        "nome": "Padaria Pão Quente Ltda"
      },
      "servico": {
        "descricao": "Manutenção do site, {mes} de {ano}"
      },
      "valores": {
        "valor_servico": "1500.00"
      },
      "dia_do_mes": 5,
      "inicio": "2026-12",
      "fim": null,
      "aviso_antes_dias": 3,
      "enviar_email": null,
      "proxima_emissao": "2026-12-05",
      "ultima_nota": null,
      "criada_em": "2026-11-05T15:20:00-03:00",
      "atualizada_em": "2026-11-05T15:20:00-03:00"
    }
  ],
  "proximo_cursor": null
}
```

### Consultar recorrência

`GET /recorrencias/{id}`

Escopo: `recorrencias:ler`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/recorrencias/rec_01JC90B7W2D5F8H1K4M6P9R3T5' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: A recorrência. [Recorrência](#objeto-recorrencia).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "rec_01JC90B7W2D5F8H1K4M6P9R3T5",
  "ambiente": "producao",
  "status": "ativa",
  "tomador": {
    "documento": "12345678000195",
    "nome": "Padaria Pão Quente Ltda"
  },
  "servico": {
    "descricao": "Manutenção do site, {mes} de {ano}"
  },
  "valores": {
    "valor_servico": "1500.00"
  },
  "dia_do_mes": 5,
  "inicio": "2026-12",
  "fim": null,
  "aviso_antes_dias": 3,
  "enviar_email": null,
  "proxima_emissao": "2026-12-05",
  "ultima_nota": null,
  "criada_em": "2026-11-05T15:20:00-03:00",
  "atualizada_em": "2026-11-05T15:20:00-03:00"
}
```

### Editar, pausar ou retomar

`PATCH /recorrencias/{id}`

Escopo: `recorrencias:escrever`.

Mude só o que enviar. `status: pausada` para de emitir; `status: ativa` retoma no próximo
`dia_do_mes`. Meses pausados não são emitidos depois. A mudança vale para as ocorrências
ainda não reservadas: a do mês já reservada (`ocorrencia_reservada`) sai com os dados
congelados, e as notas já emitidas não mudam.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `status` | texto | não | Um de: `ativa`, `pausada`. |
| `tomador` | objeto | não | Tomador ou intermediário na entrada. Se o documento já estiver salvo em `/tomadores`, basta ele; os campos que você enviar valem só para esta nota. Quem está no exterior ainda não é atendido. |
| `tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `tomador.endereco` | objeto | não |  |
| `tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `valores` | objeto | não | Valores das recorrências, dos gatilhos e do MCP. No MVP, esses fluxos recusam `retido_pelo_intermediario`. |
| `valores.valor_servico` | texto | não | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `valores.retencao_iss` | texto | não | Com retenção pelo tomador, o tomador e o endereço dele são obrigatórios (E0204, E0237). Um de: `nao_retido`, `retido_pelo_tomador`. |
| `valores.aliquota_iss` | texto ou nulo | não | Alíquota do ISS, de 0.01 a 5.00 (E0595). Para ME/EPP com tudo pelo Simples: obrigatória com ISS retido, no mínimo 1.80 (E0621), e proibida sem retenção (E0625). MEI não informa (E0600). |
| `valores.percentual_tributos_simples` | texto | não | Percentual com ponto e duas casas. |
| `dia_do_mes` | inteiro | não | De 1 a 31. |
| `fim` | texto ou nulo | não |  |
| `aviso_antes_dias` | inteiro | não | De 0 a 10. |
| `enviar_email` | booleano ou nulo | não |  |

#### Exemplo

```sh
curl -X PATCH 'https://api.nfseia.com.br/v1/recorrencias/rec_01JC90B7W2D5F8H1K4M6P9R3T5' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "pausada"
}'
```

Outro corpo: reajustar o valor.

```json
{
  "valores": {
    "valor_servico": "1650.00"
  }
}
```

#### Respostas

- `200`: Recorrência atualizada. [Recorrência](#objeto-recorrencia).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `409`: A operação não cabe no estado atual do recurso. Códigos: `estado_invalido`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "rec_01JC90B7W2D5F8H1K4M6P9R3T5",
  "ambiente": "producao",
  "status": "pausada",
  "tomador": {
    "documento": "12345678000195",
    "nome": "Padaria Pão Quente Ltda"
  },
  "servico": {
    "descricao": "Manutenção do site, {mes} de {ano}"
  },
  "valores": {
    "valor_servico": "1500.00"
  },
  "dia_do_mes": 5,
  "inicio": "2026-12",
  "fim": null,
  "aviso_antes_dias": 3,
  "enviar_email": null,
  "proxima_emissao": null,
  "ultima_nota": null,
  "criada_em": "2026-11-05T15:20:00-03:00",
  "atualizada_em": "2026-11-06T08:00:00-03:00"
}
```

### Encerrar recorrência

`DELETE /recorrencias/{id}`

Escopo: `recorrencias:escrever`.

Encerra de vez; nenhuma ocorrência nova é reservada. A ocorrência já reservada, se houver,
segue até o fim, e as notas já emitidas continuam valendo.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl -X DELETE 'https://api.nfseia.com.br/v1/recorrencias/rec_01JC90B7W2D5F8H1K4M6P9R3T5' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `204`: Recorrência encerrada.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

## Tomadores

Clientes salvos da empresa. Com o CNPJ, a consulta pública preenche nome e endereço.

### Salvar tomador

`POST /tomadores`

Escopo: `tomadores:escrever`. Exige `Idempotency-Key`.

Salva um cliente. Com CNPJ e sem `nome`, a consulta pública preenche nome e endereço
(`origem_dos_dados: consulta_publica`); com CPF, o `nome` é obrigatório. O documento é único
por empresa e ambiente: salvar de novo um documento existente devolve o tomador salvo
(`200`, com `NFSeIA-Recurso-Existente: true`); para mudar, use `PATCH`.

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `documento` | texto | sim | CPF ou CNPJ. Pontuação é aceita e removida. |
| `nome` | texto | não | Obrigatório para CPF. Para CNPJ, se omitido, vem da consulta pública. Até 300 caracteres. |
| `inscricao_municipal` | texto | não | Até 15 caracteres. |
| `endereco` | objeto | não |  |
| `endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `endereco.numero` | texto | sim | Até 60 caracteres. |
| `endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `endereco.bairro` | texto | sim | Até 60 caracteres. |
| `telefone` | texto | não |  |
| `email` | e-mail | não | Até 80 caracteres. |
| `enviar_email` | booleano | não | Envia a nota por e-mail a este tomador. Padrão: `true`. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/tomadores' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "documento": "12345678000195",
  "email": "financeiro@paoquente.com.br"
}'
```

Outro corpo: pessoa física.

```json
{
  "documento": "529.982.247-25",
  "nome": "Marina Souza",
  "email": "marina.souza@exemplo.com.br"
}
```

#### Respostas

- `200`: O documento já estava salvo. Volta o tomador existente, sem mudança. [Tomador](#objeto-tomador).
- `201`: Tomador salvo. [Tomador](#objeto-tomador).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `409`: A mesma `Idempotency-Key` está em uso por outra requisição ou veio com outro corpo. Códigos: `idempotencia_em_andamento`, `idempotencia_reutilizada`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "tom_01JC8YQ2N5R8T1W4Y7A0C3E6G9",
  "ambiente": "producao",
  "documento": "12345678000195",
  "nome": "Padaria Pão Quente Ltda",
  "inscricao_municipal": null,
  "endereco": {
    "municipio": "4106902",
    "cep": "80020310",
    "logradouro": "Rua XV de Novembro",
    "numero": "1000",
    "complemento": null,
    "bairro": "Centro"
  },
  "telefone": null,
  "email": "financeiro@paoquente.com.br",
  "enviar_email": true,
  "origem_dos_dados": "consulta_publica",
  "criado_em": "2026-11-02T10:15:00-03:00",
  "atualizado_em": "2026-11-02T10:15:00-03:00"
}
```

### Listar e buscar tomadores

`GET /tomadores`

Escopo: `tomadores:ler`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `busca` | consulta | texto | não | Parte do nome ou do documento. Até 100 caracteres. |
| `documento` | consulta | texto | não | CPF ou CNPJ exato, só números. |
| `limite` | consulta | inteiro | não | Itens por página, de 1 a 100. De 1 a 100. Padrão: `20`. |
| `cursor` | consulta | texto | não | Valor de `proximo_cursor` da página anterior. Até 200 caracteres. |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/tomadores?busca=padaria' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Página de tomadores. Lista de [Tomador](#objeto-tomador) em `dados`, com `proximo_cursor`.
- `400`: Requisição malformada. Códigos: `requisicao_invalida`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "dados": [
    {
      "id": "tom_01JC8YQ2N5R8T1W4Y7A0C3E6G9",
      "ambiente": "producao",
      "documento": "12345678000195",
      "nome": "Padaria Pão Quente Ltda",
      "inscricao_municipal": null,
      "endereco": {
        "municipio": "4106902",
        "cep": "80020310",
        "logradouro": "Rua XV de Novembro",
        "numero": "1000",
        "complemento": null,
        "bairro": "Centro"
      },
      "telefone": null,
      "email": "financeiro@paoquente.com.br",
      "enviar_email": true,
      "origem_dos_dados": "consulta_publica",
      "criado_em": "2026-11-02T10:15:00-03:00",
      "atualizado_em": "2026-11-02T10:15:00-03:00"
    }
  ],
  "proximo_cursor": null
}
```

### Consultar tomador

`GET /tomadores/{id}`

Escopo: `tomadores:ler`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/tomadores/tom_01JC8YQ2N5R8T1W4Y7A0C3E6G9' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: O tomador. [Tomador](#objeto-tomador).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "tom_01JC8YQ2N5R8T1W4Y7A0C3E6G9",
  "ambiente": "producao",
  "documento": "12345678000195",
  "nome": "Padaria Pão Quente Ltda",
  "inscricao_municipal": null,
  "endereco": {
    "municipio": "4106902",
    "cep": "80020310",
    "logradouro": "Rua XV de Novembro",
    "numero": "1000",
    "complemento": null,
    "bairro": "Centro"
  },
  "telefone": null,
  "email": "financeiro@paoquente.com.br",
  "enviar_email": true,
  "origem_dos_dados": "consulta_publica",
  "criado_em": "2026-11-02T10:15:00-03:00",
  "atualizado_em": "2026-11-02T10:15:00-03:00"
}
```

### Editar tomador

`PATCH /tomadores/{id}`

Escopo: `tomadores:escrever`.

Mude só o que enviar. O documento não muda; para outro documento, salve outro tomador.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `nome` | texto | não | Até 300 caracteres. |
| `inscricao_municipal` | texto ou nulo | não | Até 15 caracteres. |
| `endereco` | objeto ou nulo | não |  |
| `endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `endereco.numero` | texto | sim | Até 60 caracteres. |
| `endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `endereco.bairro` | texto | sim | Até 60 caracteres. |
| `telefone` | texto ou nulo | não |  |
| `email` | texto ou nulo | não | Até 80 caracteres. |
| `enviar_email` | booleano | não |  |

#### Exemplo

```sh
curl -X PATCH 'https://api.nfseia.com.br/v1/tomadores/tom_01JC8YQ2N5R8T1W4Y7A0C3E6G9' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "contas@paoquente.com.br",
  "enviar_email": false
}'
```

#### Respostas

- `200`: Tomador atualizado. [Tomador](#objeto-tomador).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "tom_01JC8YQ2N5R8T1W4Y7A0C3E6G9",
  "ambiente": "producao",
  "documento": "12345678000195",
  "nome": "Padaria Pão Quente Ltda",
  "inscricao_municipal": null,
  "endereco": {
    "municipio": "4106902",
    "cep": "80020310",
    "logradouro": "Rua XV de Novembro",
    "numero": "1000",
    "complemento": null,
    "bairro": "Centro"
  },
  "telefone": null,
  "email": "financeiro@paoquente.com.br",
  "enviar_email": true,
  "origem_dos_dados": "consulta_publica",
  "criado_em": "2026-11-02T10:15:00-03:00",
  "atualizado_em": "2026-11-02T10:15:00-03:00"
}
```

### Excluir tomador

`DELETE /tomadores/{id}`

Escopo: `tomadores:escrever`.

Remove o cadastro. Notas já emitidas guardam os dados do tomador como estavam.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl -X DELETE 'https://api.nfseia.com.br/v1/tomadores/tom_01JC8YQ2N5R8T1W4Y7A0C3E6G9' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `204`: Tomador excluído.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `409`: A operação não cabe no estado atual do recurso. Códigos: `estado_invalido`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

## Consultas

Consulta pública de CNPJ e busca do código de serviço.

### Consultar CNPJ

`GET /consultas/cnpj/{cnpj}`

Escopo: `tomadores:ler`.

Dados públicos do CNPJ (razão social, endereço, situação cadastral e Simples Nacional), sem
salvar nada. Útil para conferir o cliente antes de salvar ou emitir.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `cnpj` | caminho | texto | sim | CNPJ, só números. |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/consultas/cnpj/12345678000195' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Dados públicos do CNPJ.
- `400`: Requisição malformada. Códigos: `requisicao_invalida`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.
- `503`: Serviço fora do ar por alguns instantes. Códigos: `indisponivel`.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `cnpj` | texto | sim |  |
| `razao_social` | texto | sim |  |
| `nome_fantasia` | texto ou nulo | não |  |
| `situacao_cadastral` | texto | sim | Um de: `ativa`, `suspensa`, `inapta`, `baixada`, `nula`. |
| `endereco` | objeto ou nulo | não |  |
| `endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `endereco.numero` | texto | sim | Até 60 caracteres. |
| `endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `endereco.bairro` | texto | sim | Até 60 caracteres. |
| `simples_nacional` | objeto | não |  |
| `simples_nacional.optante` | booleano | não |  |
| `simples_nacional.mei` | booleano | não |  |
| `consultado_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |

Exemplo de resposta `200`:

```json
{
  "cnpj": "12345678000195",
  "razao_social": "Padaria Pão Quente Ltda",
  "nome_fantasia": "Pão Quente",
  "situacao_cadastral": "ativa",
  "endereco": {
    "municipio": "4106902",
    "cep": "80020310",
    "logradouro": "Rua XV de Novembro",
    "numero": "1000",
    "complemento": null,
    "bairro": "Centro"
  },
  "simples_nacional": {
    "optante": true,
    "mei": false
  },
  "consultado_em": "2026-11-05T14:00:02-03:00"
}
```

### Buscar código de serviço

`GET /codigos-servico`

Qualquer chave.

Busca na lista nacional de serviços por palavra. A resposta sugere; a escolha do código é da
empresa e do contador dela, e o NFSeIA não decide enquadramento fiscal.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `busca` | consulta | texto | sim | Palavras do serviço, por exemplo "manutenção de site". Até 100 caracteres. |
| `limite` | consulta | inteiro | não | Itens por página, de 1 a 100. De 1 a 100. Padrão: `20`. |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/codigos-servico?busca=manuten%C3%A7%C3%A3o%20de%20site' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Códigos encontrados, do mais parecido para o menos.
- `400`: Requisição malformada. Códigos: `requisicao_invalida`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `dados` | lista de objeto | sim |  |
| `dados[].codigo_tributacao_nacional` | texto | sim |  |
| `dados[].item_lista` | texto | sim | Item da lista de serviços (Lei Complementar 116), por exemplo `01.08`. |
| `dados[].descricao` | texto | sim |  |
| `aviso` | texto | sim | Lembrete de que a escolha do código é da empresa e do contador. |

Exemplo de resposta `200`:

```json
{
  "dados": [
    {
      "codigo_tributacao_nacional": "010801",
      "item_lista": "01.08",
      "descricao": "Planejamento, confecção, manutenção e atualização de páginas eletrônicas."
    },
    {
      "codigo_tributacao_nacional": "010701",
      "item_lista": "01.07",
      "descricao": "Suporte técnico em informática, inclusive instalação, configuração e manutenção de programas de computação e bancos de dados."
    }
  ],
  "aviso": "A escolha do código de serviço é da sua empresa e do seu contador. Confirme antes de emitir."
}
```

## Gatilhos

Emissão automática ao receber pagamento ("recebeu, emitiu"). Cada gatilho tem um endereço de
entrada que recebe o aviso de pagamento, assinado com o segredo do gatilho, e emite a nota a
partir de um modelo.

A identidade da nota é `pagamento:{provedor}:{conta}:{pagamento_id}`, com `provedor` e
`conta` vindos da configuração do gatilho (`origem`). Gatilhos com o mesmo provedor e a mesma
conta compartilham a identidade: o mesmo pagamento nunca gera duas notas, mesmo que chegue
por dois deles. O prefixo `pagamento:` é reservado e recusado na emissão manual
(`POST /notas`).

No MVP, gatilho não aceita intermediário nem `retido_pelo_intermediario`.

### Criar gatilho de pagamento

`POST /gatilhos`

Escopo: `gatilhos:gerenciar`. Exige `Idempotency-Key`.

Cria um endereço de entrada para avisos de pagamento. A resposta traz o `segredo` uma única
vez: guarde no seu sistema, ele assina cada aviso.

`origem.provedor` e `origem.conta` identificam de onde vêm os pagamentos (por exemplo o
seu sistema de cobrança e a conta nele) e entram na identidade da nota,
`pagamento:{provedor}:{conta}:{pagamento_id}`. Gatilhos com a mesma origem compartilham
essa identidade.

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `nome` | texto | sim | Até 80 caracteres. |
| `origem` | objeto | sim | De onde vêm os pagamentos do gatilho. Entra na identidade da nota, `pagamento:{provedor}:{conta}:{pagamento_id}`, e não muda depois da criação. |
| `origem.provedor` | texto | sim | Nome curto do sistema de cobrança, escolhido por você (por exemplo `meu-sistema`). |
| `origem.conta` | texto | sim | A conta nesse sistema, para separar duas contas do mesmo provedor. |
| `modelo` | objeto | sim |  |
| `modelo.usar_valor_do_aviso` | booleano | sim | `true`: o valor vem de `valor` no aviso. `false`: vale `valores.valor_servico` do modelo. |
| `modelo.tomador` | objeto ou nulo | não | Tomador fixo. Com `null`, o tomador vem em cada aviso. |
| `modelo.tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `modelo.tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `modelo.tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `modelo.tomador.endereco` | objeto | não |  |
| `modelo.tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `modelo.tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `modelo.tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `modelo.tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `modelo.tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `modelo.tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `modelo.tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `modelo.tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `modelo.servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `modelo.servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `modelo.servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `modelo.servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `modelo.servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `modelo.valores` | objeto | não | Valores das recorrências, dos gatilhos e do MCP. No MVP, esses fluxos recusam `retido_pelo_intermediario`. |
| `modelo.valores.valor_servico` | texto | não | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `modelo.valores.retencao_iss` | texto | não | Com retenção pelo tomador, o tomador e o endereço dele são obrigatórios (E0204, E0237). Um de: `nao_retido`, `retido_pelo_tomador`. |
| `modelo.valores.aliquota_iss` | texto ou nulo | não | Alíquota do ISS, de 0.01 a 5.00 (E0595). Para ME/EPP com tudo pelo Simples: obrigatória com ISS retido, no mínimo 1.80 (E0621), e proibida sem retenção (E0625). MEI não informa (E0600). |
| `modelo.valores.percentual_tributos_simples` | texto | não | Percentual com ponto e duas casas. |
| `modelo.enviar_email` | booleano ou nulo | não |  |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/gatilhos' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "nome": "Assinaturas do sistema",
  "origem": {
    "provedor": "meu-sistema",
    "conta": "principal"
  },
  "modelo": {
    "usar_valor_do_aviso": true,
    "tomador": null,
    "servico": {
      "descricao": "Assinatura mensal do sistema de gestão"
    },
    "valores": {}
  }
}'
```

#### Respostas

- `201`: Gatilho criado, com o segredo (só nesta resposta). [Gatilho](#objeto-gatilho), com `segredo`.
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `409`: A mesma `Idempotency-Key` está em uso por outra requisição ou veio com outro corpo. Códigos: `idempotencia_em_andamento`, `idempotencia_reutilizada`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `201`:

```json
{
  "id": "gat_01JC91D3F6H9K2M5P8R1T4W7Y0",
  "ambiente": "producao",
  "nome": "Assinaturas do sistema",
  "origem": {
    "provedor": "meu-sistema",
    "conta": "principal"
  },
  "status": "ativo",
  "url": "https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0/eventos",
  "segredo": "gsec_6fQ2xN8vR1kT4mW7zB0cE3hJ5",
  "modelo": {
    "usar_valor_do_aviso": true,
    "tomador": null,
    "servico": {
      "descricao": "Assinatura mensal do sistema de gestão"
    },
    "valores": {}
  },
  "ultimo_evento_em": null,
  "criado_em": "2026-11-05T16:00:00-03:00",
  "atualizado_em": "2026-11-05T16:00:00-03:00"
}
```

### Listar gatilhos

`GET /gatilhos`

Escopo: `gatilhos:gerenciar`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `limite` | consulta | inteiro | não | Itens por página, de 1 a 100. De 1 a 100. Padrão: `20`. |
| `cursor` | consulta | texto | não | Valor de `proximo_cursor` da página anterior. Até 200 caracteres. |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/gatilhos' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Página de gatilhos (sem os segredos). Lista de [Gatilho](#objeto-gatilho) em `dados`, com `proximo_cursor`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "dados": [
    {
      "id": "gat_01JC91D3F6H9K2M5P8R1T4W7Y0",
      "ambiente": "producao",
      "nome": "Assinaturas do sistema",
      "origem": {
        "provedor": "meu-sistema",
        "conta": "principal"
      },
      "status": "ativo",
      "url": "https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0/eventos",
      "modelo": {
        "usar_valor_do_aviso": true,
        "tomador": null,
        "servico": {
          "descricao": "Assinatura mensal do sistema de gestão"
        },
        "valores": {}
      },
      "ultimo_evento_em": "2026-11-05T16:42:10-03:00",
      "criado_em": "2026-11-05T16:00:00-03:00",
      "atualizado_em": "2026-11-05T16:00:00-03:00"
    }
  ],
  "proximo_cursor": null
}
```

### Consultar gatilho

`GET /gatilhos/{id}`

Escopo: `gatilhos:gerenciar`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: O gatilho (sem o segredo). [Gatilho](#objeto-gatilho).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "gat_01JC91D3F6H9K2M5P8R1T4W7Y0",
  "ambiente": "producao",
  "nome": "Assinaturas do sistema",
  "origem": {
    "provedor": "meu-sistema",
    "conta": "principal"
  },
  "status": "ativo",
  "url": "https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0/eventos",
  "modelo": {
    "usar_valor_do_aviso": true,
    "tomador": null,
    "servico": {
      "descricao": "Assinatura mensal do sistema de gestão"
    },
    "valores": {}
  },
  "ultimo_evento_em": "2026-11-05T16:42:10-03:00",
  "criado_em": "2026-11-05T16:00:00-03:00",
  "atualizado_em": "2026-11-05T16:00:00-03:00"
}
```

### Editar ou pausar gatilho

`PATCH /gatilhos/{id}`

Escopo: `gatilhos:gerenciar`.

Mude só o que enviar. Gatilho `pausado` responde `409 estado_invalido` aos avisos, e eles
podem ser reenviados depois. A `origem` não muda depois da criação: mudar a identidade dos
pagamentos abriria espaço para nota em dobro.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `nome` | texto | não | Até 80 caracteres. |
| `status` | texto | não | Um de: `ativo`, `pausado`. |
| `modelo` | objeto | não |  |
| `modelo.usar_valor_do_aviso` | booleano | sim | `true`: o valor vem de `valor` no aviso. `false`: vale `valores.valor_servico` do modelo. |
| `modelo.tomador` | objeto ou nulo | não | Tomador fixo. Com `null`, o tomador vem em cada aviso. |
| `modelo.tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `modelo.tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `modelo.tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `modelo.tomador.endereco` | objeto | não |  |
| `modelo.tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `modelo.tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `modelo.tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `modelo.tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `modelo.tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `modelo.tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `modelo.tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `modelo.tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `modelo.servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `modelo.servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `modelo.servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `modelo.servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `modelo.servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `modelo.valores` | objeto | não | Valores das recorrências, dos gatilhos e do MCP. No MVP, esses fluxos recusam `retido_pelo_intermediario`. |
| `modelo.valores.valor_servico` | texto | não | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `modelo.valores.retencao_iss` | texto | não | Com retenção pelo tomador, o tomador e o endereço dele são obrigatórios (E0204, E0237). Um de: `nao_retido`, `retido_pelo_tomador`. |
| `modelo.valores.aliquota_iss` | texto ou nulo | não | Alíquota do ISS, de 0.01 a 5.00 (E0595). Para ME/EPP com tudo pelo Simples: obrigatória com ISS retido, no mínimo 1.80 (E0621), e proibida sem retenção (E0625). MEI não informa (E0600). |
| `modelo.valores.percentual_tributos_simples` | texto | não | Percentual com ponto e duas casas. |
| `modelo.enviar_email` | booleano ou nulo | não |  |

#### Exemplo

```sh
curl -X PATCH 'https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "pausado"
}'
```

#### Respostas

- `200`: Gatilho atualizado. [Gatilho](#objeto-gatilho).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "gat_01JC91D3F6H9K2M5P8R1T4W7Y0",
  "ambiente": "producao",
  "nome": "Assinaturas do sistema",
  "origem": {
    "provedor": "meu-sistema",
    "conta": "principal"
  },
  "status": "pausado",
  "url": "https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0/eventos",
  "modelo": {
    "usar_valor_do_aviso": true,
    "tomador": null,
    "servico": {
      "descricao": "Assinatura mensal do sistema de gestão"
    },
    "valores": {}
  },
  "ultimo_evento_em": "2026-11-05T16:42:10-03:00",
  "criado_em": "2026-11-05T16:00:00-03:00",
  "atualizado_em": "2026-11-06T08:00:00-03:00"
}
```

### Excluir gatilho

`DELETE /gatilhos/{id}`

Escopo: `gatilhos:gerenciar`.

O endereço para de aceitar avisos na hora. Notas já emitidas não mudam.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl -X DELETE 'https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `204`: Gatilho excluído.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

### Trocar o segredo do gatilho

`POST /gatilhos/{id}/rotacionar-segredo`

Escopo: `gatilhos:gerenciar`. Exige `Idempotency-Key`.

Gera um segredo novo, em um de dois modos:

- `normal`: o segredo anterior continua aceito por 24 horas, para dar tempo de trocar no
  seu sistema. No máximo um anterior fica valendo: uma nova troca normal revoga o mais
  antigo na hora.
- `emergencia`: revoga todos os anteriores na hora, sem sobreposição. Use se o segredo
  vazou.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `modo` | texto | sim | `normal`: o anterior vale mais 24 horas (no máximo um anterior). `emergencia`: revoga todos os anteriores na hora. Um de: `normal`, `emergencia`. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0/rotacionar-segredo' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "modo": "normal"
}'
```

#### Respostas

- `200`: Segredo novo (só nesta resposta).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `segredo` | texto | sim |  |
| `anterior_valido_ate` | data e hora ou nulo | sim | `null` no modo `emergencia`. |

Exemplo de resposta `200`:

```json
{
  "segredo": "gsec_9aL4pR7sV0xY3bD6fH8jK1mN2",
  "anterior_valido_ate": "2026-11-07T11:30:00-03:00"
}
```

### Receber aviso de pagamento

`POST /gatilhos/{id}/eventos`

Endereço público: sem chave de API, só com `NFSeIA-Assinatura`.

Endereço público do gatilho: o seu sistema avisa que um pagamento foi confirmado e a nota sai
pelo modelo do gatilho. Não usa chave de API; o aviso vale só com `NFSeIA-Assinatura`
calculada com o segredo do gatilho sobre o corpo bruto, como nos webhooks.

A identidade da nota é `pagamento:{provedor}:{conta}:{pagamento_id}`, com provedor e conta
da `origem` do gatilho; ela é reservada antes de qualquer envio, como na emissão. Repetir o
aviso do mesmo pagamento, por este ou por outro gatilho da mesma origem, devolve a nota
existente (`200`), nunca uma segunda. Valor e tomador passam pela mesma validação da
emissão; intermediário e `retido_pelo_intermediario` são recusados no MVP.

Proteções: o carimbo de tempo `t` precisa estar a até 5 minutos do horário atual, no
passado ou no futuro (assine cada envio na hora, com `t` novo a cada tentativa); o limite
por IP vale antes de conferir a assinatura, inclusive para assinatura inválida, e o limite
por gatilho e por empresa vale depois.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `pagamento_id` | texto | sim | Id do pagamento (não do cliente nem do pedido). Vira a identidade `pagamento:{provedor}:{conta}:{pagamento_id}`. |
| `valor` | texto | não | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `pago_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `tomador` | objeto | não | Tomador ou intermediário na entrada. Se o documento já estiver salvo em `/tomadores`, basta ele; os campos que você enviar valem só para esta nota. Quem está no exterior ainda não é atendido. |
| `tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `tomador.endereco` | objeto | não |  |
| `tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/gatilhos/gat_01JC91D3F6H9K2M5P8R1T4W7Y0/eventos' \
  -H "NFSeIA-Assinatura: t=$T,v1=$ASSINATURA" \
  -H "Content-Type: application/json" \
  -d '{
  "pagamento_id": "fatura-2026-11-0087",
  "valor": "89.90",
  "pago_em": "2026-11-05T16:42:07-03:00",
  "tomador": {
    "documento": "33445566000186",
    "nome": "Clínica Bem Viver Ltda",
    "email": "adm@bemviver.com.br"
  }
}'
```

#### Respostas

- `200`: Este pagamento já tinha nota. Volta a nota existente. [Nota](#objeto-nota).
- `201`: Nota autorizada. [Nota](#objeto-nota).
- `202`: A SEFIN não respondeu a tempo; a nota fica `pendente`. [Nota](#objeto-nota).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Aviso de pagamento sem assinatura válida. Códigos: `assinatura_invalida`.
- `402`: Teste grátis encerrado, cota do mês esgotada ou assinatura em atraso. Códigos: `cota_esgotada`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `409`: A operação não cabe no estado atual do recurso. Códigos: `estado_invalido`.
- `422`: A SEFIN recusou a nota. Ela fica guardada como `rejeitada`, com o id em `nota_id`. Códigos: `nota_rejeitada`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "nota_01JC92F5H8K1M4P7R0T3W6Y9A2",
  "ambiente": "producao",
  "status": "autorizada",
  "origem": "gatilho",
  "referencia_externa": "pagamento:meu-sistema:principal:fatura-2026-11-0087",
  "numero": "19",
  "chave_acesso": "41069021245723174000110000000000001926118402736915",
  "dps": {
    "id": "DPS410690224572317400011000001000000000000045",
    "serie": "1",
    "numero": "45"
  },
  "competencia": "2026-11-05",
  "municipio_emissor": "4106902",
  "prestador": {
    "cnpj": "45723174000110",
    "inscricao_municipal": "1234567",
    "simples_nacional": "me_epp",
    "apuracao_simples": "tudo_pelo_simples"
  },
  "tomador": {
    "documento": "33445566000186",
    "nome": "Clínica Bem Viver Ltda",
    "inscricao_municipal": null,
    "endereco": null,
    "telefone": null,
    "email": "adm@bemviver.com.br"
  },
  "intermediario": null,
  "servico": {
    "codigo_tributacao_nacional": "010801",
    "codigo_nbs": null,
    "descricao": "Assinatura mensal do sistema de gestão",
    "municipio_prestacao": "4106902"
  },
  "valores": {
    "valor_servico": "89.90",
    "retencao_iss": "nao_retido",
    "aliquota_iss": null,
    "percentual_tributos_simples": "6.00"
  },
  "pendencia": null,
  "rejeicao": null,
  "cancelamento": null,
  "emails": [
    {
      "destinatario": "tomador",
      "endereco": "adm@bemviver.com.br",
      "status": "agendado",
      "enviado_em": null
    }
  ],
  "links": {
    "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC92F5H8K1M4P7R0T3W6Y9A2/xml",
    "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC92F5H8K1M4P7R0T3W6Y9A2/pdf",
    "consulta_publica": "https://www.nfse.gov.br/consultapublica"
  },
  "recorrencia_id": null,
  "gatilho_id": "gat_01JC91D3F6H9K2M5P8R1T4W7Y0",
  "criada_em": "2026-11-05T16:42:08-03:00",
  "autorizada_em": "2026-11-05T16:42:11-03:00",
  "atualizada_em": "2026-11-05T16:42:11-03:00"
}
```

## Webhooks

Endereços do seu sistema que recebem os eventos das notas, assinados com HMAC-SHA256.

### Cadastrar webhook

`POST /webhooks`

Escopo: `webhooks:gerenciar`. Exige `Idempotency-Key`.

Cadastra um endereço do seu sistema para receber eventos. A resposta traz o `segredo` uma
única vez.

Só HTTPS público. O endereço é conferido no cadastro, na edição, em cada entrega e em cada
reenvio: o nome é resolvido no DNS a cada envio, todos os IPs devolvidos precisam ser
públicos (nada interno, privado, de rede local ou reservado) e a conexão vai para o IP
aprovado nessa conferência. Redirecionamento não é seguido. Cada tentativa tem até 10
segundos e lê no máximo 64 KB da resposta.

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `url` | endereço (URL) | sim | Só HTTPS público. Até 500 caracteres. |
| `eventos` | lista de texto | sim |  |
| `descricao` | texto | não | Até 200 caracteres. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/webhooks' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://meusistema.com.br/avisos/nfseia",
  "eventos": [
    "nota.autorizada",
    "nota.rejeitada",
    "nota.pendente_resolvida",
    "nota.cancelada"
  ],
  "descricao": "Atualiza o pedido quando a nota sai"
}'
```

#### Respostas

- `201`: Webhook cadastrado, com o segredo (só nesta resposta). [Webhook](#objeto-webhook), com `segredo`.
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `409`: A mesma `Idempotency-Key` está em uso por outra requisição ou veio com outro corpo. Códigos: `idempotencia_em_andamento`, `idempotencia_reutilizada`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `201`:

```json
{
  "id": "wh_01JC93H7K0M3P6R9T2W5Y8A1C4",
  "ambiente": "producao",
  "url": "https://meusistema.com.br/avisos/nfseia",
  "eventos": [
    "nota.autorizada",
    "nota.rejeitada",
    "nota.pendente_resolvida",
    "nota.cancelada"
  ],
  "descricao": "Atualiza o pedido quando a nota sai",
  "status": "ativo",
  "segredo": "whsec_3kD8nQ1rT6vX9zB2eG5hL7pS0",
  "criado_em": "2026-11-05T17:00:00-03:00",
  "atualizado_em": "2026-11-05T17:00:00-03:00"
}
```

### Listar webhooks

`GET /webhooks`

Escopo: `webhooks:gerenciar`.

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/webhooks' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Webhooks do ambiente (sem os segredos). Lista de [Webhook](#objeto-webhook) em `dados`, com `proximo_cursor`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "dados": [
    {
      "id": "wh_01JC93H7K0M3P6R9T2W5Y8A1C4",
      "ambiente": "producao",
      "url": "https://meusistema.com.br/avisos/nfseia",
      "eventos": [
        "nota.autorizada",
        "nota.rejeitada",
        "nota.pendente_resolvida",
        "nota.cancelada"
      ],
      "descricao": "Atualiza o pedido quando a nota sai",
      "status": "ativo",
      "criado_em": "2026-11-05T17:00:00-03:00",
      "atualizado_em": "2026-11-05T17:00:00-03:00"
    }
  ],
  "proximo_cursor": null
}
```

### Consultar webhook

`GET /webhooks/{id}`

Escopo: `webhooks:gerenciar`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/webhooks/wh_01JC93H7K0M3P6R9T2W5Y8A1C4' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: O webhook (sem o segredo). [Webhook](#objeto-webhook).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "wh_01JC93H7K0M3P6R9T2W5Y8A1C4",
  "ambiente": "producao",
  "url": "https://meusistema.com.br/avisos/nfseia",
  "eventos": [
    "nota.autorizada"
  ],
  "descricao": "Atualiza o pedido quando a nota sai",
  "status": "ativo",
  "criado_em": "2026-11-05T17:00:00-03:00",
  "atualizado_em": "2026-11-05T17:00:00-03:00"
}
```

### Editar, pausar ou reativar webhook

`PATCH /webhooks/{id}`

Escopo: `webhooks:gerenciar`.

Mude só o que enviar. Um `url` novo passa pela mesma conferência do cadastro. Reativar um
webhook `desativado` volta a entregar só os eventos novos.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `url` | endereço (URL) | não | Até 500 caracteres. |
| `eventos` | lista de texto | não |  |
| `descricao` | texto | não | Até 200 caracteres. |
| `status` | texto | não | Um de: `ativo`, `pausado`. |

#### Exemplo

```sh
curl -X PATCH 'https://api.nfseia.com.br/v1/webhooks/wh_01JC93H7K0M3P6R9T2W5Y8A1C4' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "eventos": [
    "nota.autorizada",
    "nota.rejeitada",
    "nota.pendente_resolvida",
    "nota.cancelada",
    "nota_recorrente.emitida"
  ]
}'
```

#### Respostas

- `200`: Webhook atualizado. [Webhook](#objeto-webhook).
- `400`: Dados recusados antes de qualquer envio à SEFIN (`dados_invalidos`), JSON malformado (`requisicao_invalida`) ou POST sem `Idempotency-Key` (`idempotency_key_ausente`). Nada foi criado. Códigos: `dados_invalidos`, `idempotency_key_ausente`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "wh_01JC93H7K0M3P6R9T2W5Y8A1C4",
  "ambiente": "producao",
  "url": "https://meusistema.com.br/avisos/nfseia",
  "eventos": [
    "nota.autorizada",
    "nota.rejeitada",
    "nota.pendente_resolvida",
    "nota.cancelada",
    "nota_recorrente.emitida"
  ],
  "descricao": "Atualiza o pedido quando a nota sai",
  "status": "ativo",
  "criado_em": "2026-11-05T17:00:00-03:00",
  "atualizado_em": "2026-11-06T08:00:00-03:00"
}
```

### Excluir webhook

`DELETE /webhooks/{id}`

Escopo: `webhooks:gerenciar`.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl -X DELETE 'https://api.nfseia.com.br/v1/webhooks/wh_01JC93H7K0M3P6R9T2W5Y8A1C4' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `204`: Webhook excluído; entregas pendentes são descartadas.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

### Trocar o segredo do webhook

`POST /webhooks/{id}/rotacionar-segredo`

Escopo: `webhooks:gerenciar`. Exige `Idempotency-Key`.

Gera um segredo novo, em um de dois modos:

- `normal`: por 24 horas, cada entrega leva duas assinaturas em `NFSeIA-Assinatura` (`v1`
  com o segredo novo e `v1` com o anterior); aceite qualquer uma que confira. No máximo um
  anterior fica valendo: uma nova troca normal revoga o mais antigo na hora.
- `emergencia`: revoga todos os anteriores na hora; as entregas passam a levar só o `v1` do
  segredo novo. Use se o segredo vazou.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |

#### Corpo

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `modo` | texto | sim | `normal`: o anterior vale mais 24 horas (no máximo um anterior). `emergencia`: revoga todos os anteriores na hora. Um de: `normal`, `emergencia`. |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/webhooks/wh_01JC93H7K0M3P6R9T2W5Y8A1C4/rotacionar-segredo' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "modo": "emergencia"
}'
```

#### Respostas

- `200`: Segredo novo (só nesta resposta).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `segredo` | texto | sim |  |
| `anterior_valido_ate` | data e hora ou nulo | sim | `null` no modo `emergencia`. |

Exemplo de resposta `200`:

```json
{
  "segredo": "whsec_8tF1mK4qW7zC0eH3jN6rV9yB2",
  "anterior_valido_ate": null
}
```

### Listar entregas

`GET /webhooks/{id}/entregas`

Escopo: `webhooks:gerenciar`.

Histórico de entregas do webhook nos últimos 30 dias, da mais nova para a mais antiga.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |
| `status` | consulta | texto | não | Um de: `entregue`, `tentando`, `falhou`. |
| `limite` | consulta | inteiro | não | Itens por página, de 1 a 100. De 1 a 100. Padrão: `20`. |
| `cursor` | consulta | texto | não | Valor de `proximo_cursor` da página anterior. Até 200 caracteres. |

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/webhooks/wh_01JC93H7K0M3P6R9T2W5Y8A1C4/entregas' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: Página de entregas. Lista de [Entrega](#objeto-entrega) em `dados`, com `proximo_cursor`.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "dados": [
    {
      "id": "ent_01JC94K9M2P5R8T1W4Y7A0C3E6",
      "evento_id": "evt_01JC8Z4P6R9T2W5Y8A1C4E7G0J",
      "tipo": "nota.autorizada",
      "status": "tentando",
      "tentativas": 2,
      "ultima_tentativa": {
        "em": "2026-11-05T14:04:15-03:00",
        "http_status": 503,
        "duracao_ms": 412,
        "erro": null
      },
      "proxima_tentativa_em": "2026-11-05T14:34:15-03:00",
      "criada_em": "2026-11-05T14:03:12-03:00"
    }
  ],
  "proximo_cursor": null
}
```

### Reenviar entrega

`POST /webhooks/{id}/entregas/{entrega_id}/reenviar`

Escopo: `webhooks:gerenciar`.

Tenta entregar o evento de novo, agora, com a mesma conferência de endereço de uma entrega
normal e um carimbo de tempo novo na assinatura. O `id` do evento é o mesmo, para o seu
sistema descartar repetidos.

#### Parâmetros

| Nome | Onde | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- | --- |
| `id` | caminho | texto | sim |  |
| `entrega_id` | caminho | texto | sim |  |

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/webhooks/wh_01JC93H7K0M3P6R9T2W5Y8A1C4/entregas/ent_01JC94K9M2P5R8T1W4Y7A0C3E6/reenviar' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `202`: Reenvio agendado. [Entrega](#objeto-entrega).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `404`: Não existe, é de outra empresa ou de outro ambiente. Códigos: `nao_encontrado`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `202`:

```json
{
  "id": "ent_01JC94K9M2P5R8T1W4Y7A0C3E6",
  "evento_id": "evt_01JC8Z4P6R9T2W5Y8A1C4E7G0J",
  "tipo": "nota.autorizada",
  "status": "tentando",
  "tentativas": 2,
  "ultima_tentativa": {
    "em": "2026-11-05T14:04:15-03:00",
    "http_status": 503,
    "duracao_ms": 412,
    "erro": null
  },
  "proxima_tentativa_em": "2026-11-05T14:10:00-03:00",
  "criada_em": "2026-11-05T14:03:12-03:00"
}
```

## Empresa

Dados da empresa da chave, plano, cota e certificado digital (só os metadados).

O certificado nunca passa por esta API. Para enviar ou trocar, gere um link de envio
(`POST /empresa/certificado/link-de-envio` ou no painel): ele abre o cofre, em outro endereço
(`cofre.nfseia.com.br`), e o arquivo e a senha vão direto para lá. A troca só vale depois da
confirmação pelo link enviado ao e-mail da empresa.

### Consultar empresa

`GET /empresa`

Escopo: `empresa:ler`.

Dados da empresa da chave, padrões da nota, plano, cota usada, limites e certificado digital.
Do certificado, só metadados (titular, CNPJ, validade); nunca o arquivo, a senha ou a chave
privada.

#### Exemplo

```sh
curl 'https://api.nfseia.com.br/v1/empresa' \
  -H "Authorization: Bearer $NFSEIA_CHAVE"
```

#### Respostas

- `200`: A empresa. [Empresa](#objeto-empresa).
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

Exemplo de resposta `200`:

```json
{
  "id": "emp_01JC8V2B5D8F1H4K7M0P3R6T9W",
  "cnpj": "45723174000110",
  "razao_social": "Estúdio Aurora Design Ltda",
  "nome_fantasia": "Estúdio Aurora",
  "inscricao_municipal": "1234567",
  "municipio": {
    "codigo_ibge": "4106902",
    "nome": "Curitiba",
    "uf": "PR"
  },
  "simples_nacional": "me_epp",
  "apuracao_simples": "tudo_pelo_simples",
  "padroes_da_nota": {
    "servico": {
      "codigo_tributacao_nacional": "010801",
      "codigo_nbs": null,
      "descricao": "Manutenção do site",
      "municipio_prestacao": "4106902"
    },
    "valores": {
      "retencao_iss": "nao_retido",
      "aliquota_iss": null,
      "percentual_tributos_simples": "6.00"
    }
  },
  "plano": {
    "nome": "essencial",
    "cota_mensal": 500,
    "periodo_inicio": "2026-11-01",
    "periodo_fim": "2026-11-30",
    "notas_usadas": 18,
    "notas_restantes": 482
  },
  "teste_gratis": null,
  "producao_liberada": true,
  "limites": {
    "notas_por_dia": 500,
    "valor_maximo_por_nota": "100000.00"
  },
  "certificado": {
    "status": "valido",
    "titular": "ESTUDIO AURORA DESIGN LTDA:45723174000110",
    "cnpj": "45723174000110",
    "valido_de": "2026-03-10",
    "valido_ate": "2027-03-10",
    "enviado_em": "2026-11-01T09:30:00-03:00"
  },
  "email": {
    "envio_ligado": true,
    "emissor": "financeiro@estudioaurora.com.br"
  },
  "chave": {
    "prefixo": "nfs_live_7Hq2",
    "ambiente": "producao",
    "escopos": [
      "notas:ler",
      "notas:emitir",
      "notas:enviar_email",
      "notas:cancelar",
      "empresa:ler"
    ]
  }
}
```

### Gerar link de envio do certificado

`POST /empresa/certificado/link-de-envio`

Escopo: `empresa:certificado`. Exige `Idempotency-Key`.

Gera um link curto (15 minutos, uso único, amarrado à empresa) para enviar ou trocar o
certificado A1 no cofre, em `cofre.nfseia.com.br`. O arquivo e a senha vão do navegador
direto para o cofre, sem passar por esta API. O cofre confere se o certificado é e-CNPJ da
própria empresa, dentro da validade e não revogado; a troca só vale depois da confirmação
pelo e-mail da empresa.

#### Exemplo

```sh
curl -X POST 'https://api.nfseia.com.br/v1/empresa/certificado/link-de-envio' \
  -H "Authorization: Bearer $NFSEIA_CHAVE" \
  -H "Idempotency-Key: $(uuidgen)"
```

#### Respostas

- `201`: Link criado.
- `401`: Chave ausente, errada, revogada ou de outro ambiente. Códigos: `chave_invalida`.
- `403`: Falta escopo na chave, produção não liberada, certificado indisponível ou valor acima do limite. Códigos: `certificado_indisponivel`, `sem_permissao`.
- `429`: Limite de requisições ou teto diário de notas. Códigos: `limite_de_requisicoes`.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `url` | endereço (URL) | sim | Abre o cofre, em `cofre.nfseia.com.br`. Uso único. |
| `expira_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |

Exemplo de resposta `201`:

```json
{
  "url": "https://cofre.nfseia.com.br/enviar#t=ct_01JC95M1P4R7T0W3Y6A9C2E5G8",
  "expira_em": "2026-11-05T17:45:00-03:00"
}
```

## Eventos de webhook

Cada evento chega por `POST` no endereço cadastrado, com corpo JSON e estes cabeçalhos. Como conferir a assinatura: [Webhooks](https://nfseia.com.br/docs/webhooks).

| Cabeçalho | Descrição |
| --- | --- |
| `NFSeIA-Assinatura` | `t=<segundos desde 1970>,v1=<HMAC-SHA256 em hexadecimal>` sobre `"{t}.{corpo bruto}"`, com o segredo do webhook. Cada tentativa leva um `t` novo; recuse `t` a mais de 5 minutos do seu horário, no passado ou no futuro, e descarte repetidos pelo `id` do corpo já autenticado. Na troca normal de segredo, vêm dois `v1`. Exemplo: `t=1793898192,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd`. |
| `NFSeIA-Evento-Id` | Igual ao `id` do corpo. Use para descartar entregas repetidas. Exemplo: `evt_01JC8Z4P6R9T2W5Y8A1C4E7G0J`. |
| `NFSeIA-Evento-Tipo` |  |
| `NFSeIA-Tentativa` | Número da tentativa, começando em 1. Exemplo: `1`. |

### `nota.autorizada`

A nota foi autorizada. Chega para toda nota autorizada, inclusive as que passaram por
`pendente`, as recorrentes e as de gatilho.

```json
{
  "id": "evt_01JC8Z4P6R9T2W5Y8A1C4E7G0J",
  "tipo": "nota.autorizada",
  "criado_em": "2026-11-05T14:03:12-03:00",
  "ambiente": "producao",
  "dados": {
    "nota": {
      "id": "nota_01JC8Z4M3QK7T2V9X5B6N1R0PD",
      "referencia_externa": "pedido-1042",
      "status": "autorizada",
      "numero": "18",
      "chave_acesso": "41069021245723174000110000000000001826117319502647",
      "links": {
        "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/xml",
        "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/pdf"
      }
    }
  }
}
```

### `nota.rejeitada`

A SEFIN recusou a nota. Os erros traduzidos estão na nota (`GET /notas/{id}`).

```json
{
  "id": "evt_01JC96P3R6T9W2Y5A8C1E4G7J0",
  "tipo": "nota.rejeitada",
  "criado_em": "2026-11-05T14:20:31-03:00",
  "ambiente": "producao",
  "dados": {
    "nota": {
      "id": "nota_01JC8ZA1C4E7G0J3M6P9S2V5X8",
      "referencia_externa": "pedido-1050",
      "status": "rejeitada",
      "numero": null,
      "chave_acesso": null,
      "links": {
        "xml": null,
        "pdf": null
      }
    }
  }
}
```

### `nota.pendente`

A nota ficou pendente; o motivo está em `dados.nota.motivo_pendencia`. Com
`aguardando_sefin` ou `conferindo_identidade`, nada a fazer: o NFSeIA resolve sozinho. O
evento chega de novo se o motivo mudar para `colisao_numeracao` ou `requer_intervencao`,
que pedem atenção (o e-mail da empresa também é avisado).

```json
{
  "id": "evt_01JC97R5T8W1Y4A7C0E3G6J9M2",
  "tipo": "nota.pendente",
  "criado_em": "2026-11-05T14:30:26-03:00",
  "ambiente": "producao",
  "dados": {
    "nota": {
      "id": "nota_01JC8ZC3E6G9J2M5P8S1V4X7Z0",
      "referencia_externa": "pedido-1051",
      "status": "pendente",
      "motivo_pendencia": "aguardando_sefin",
      "numero": null,
      "chave_acesso": null,
      "links": {
        "xml": null,
        "pdf": null
      }
    }
  }
}
```

### `nota.pendente_resolvida`

A nota pendente teve resposta definitiva; `dados.nota.status` diz qual (`autorizada` ou
`rejeitada`). O evento do status final (`nota.autorizada` ou `nota.rejeitada`) também é
enviado.

```json
{
  "id": "evt_01JC98T7W0Y3A6C9E2G5J8M1P4",
  "tipo": "nota.pendente_resolvida",
  "criado_em": "2026-11-05T14:31:02-03:00",
  "ambiente": "producao",
  "dados": {
    "nota": {
      "id": "nota_01JC8ZC3E6G9J2M5P8S1V4X7Z0",
      "referencia_externa": "pedido-1051",
      "status": "autorizada",
      "numero": "20",
      "chave_acesso": "41069021245723174000110000000000002026118264013957",
      "links": {
        "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC8ZC3E6G9J2M5P8S1V4X7Z0/xml",
        "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC8ZC3E6G9J2M5P8S1V4X7Z0/pdf"
      }
    }
  }
}
```

### `nota.cancelada`

A nota foi cancelada na SEFIN.

```json
{
  "id": "evt_01JC99W9Y2A5C8E1G4J7M0P3S6",
  "tipo": "nota.cancelada",
  "criado_em": "2026-11-06T09:12:44-03:00",
  "ambiente": "producao",
  "dados": {
    "nota": {
      "id": "nota_01JC8Z4M3QK7T2V9X5B6N1R0PD",
      "referencia_externa": "pedido-1042",
      "status": "cancelada",
      "numero": "18",
      "chave_acesso": "41069021245723174000110000000000001826117319502647",
      "links": {
        "xml": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/xml",
        "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JC8Z4M3QK7T2V9X5B6N1R0PD/pdf"
      }
    }
  }
}
```

### `nota_recorrente.emitida`

A nota do mês de uma recorrência foi autorizada. `nota.autorizada` também é enviado.

```json
{
  "id": "evt_01JCA0Y1A4C7E0G3J6M9P2S5V8",
  "tipo": "nota_recorrente.emitida",
  "criado_em": "2026-12-05T08:00:41-03:00",
  "ambiente": "producao",
  "dados": {
    "recorrencia_id": "rec_01JC90B7W2D5F8H1K4M6P9R3T5",
    "competencia": "2026-12",
    "nota": {
      "id": "nota_01JDQ3B6D9F2H5K8N1Q4S7V0X3",
      "referencia_externa": "recorrencia:rec_01JC90B7W2D5F8H1K4M6P9R3T5:2026-12",
      "status": "autorizada",
      "numero": "31",
      "chave_acesso": "41069021245723174000110000000000003126124517390826",
      "links": {
        "xml": "https://api.nfseia.com.br/v1/notas/nota_01JDQ3B6D9F2H5K8N1Q4S7V0X3/xml",
        "pdf": "https://api.nfseia.com.br/v1/notas/nota_01JDQ3B6D9F2H5K8N1Q4S7V0X3/pdf"
      }
    }
  }
}
```

### `certificado.vencendo`

O certificado digital vence em 30, 15, 7 e 1 dia. Sem certificado válido, a emissão em produção para.

```json
{
  "id": "evt_01JCA1A3C6E9G2J5M8P1S4V7Y0",
  "tipo": "certificado.vencendo",
  "criado_em": "2027-02-23T08:00:00-03:00",
  "ambiente": "producao",
  "dados": {
    "certificado": {
      "titular": "ESTUDIO AURORA DESIGN LTDA:45723174000110",
      "valido_ate": "2027-03-10",
      "dias_restantes": 15
    }
  }
}
```

### `cota.perto_do_fim`

A empresa usou 80% e depois 95% da cota de notas do mês.

```json
{
  "id": "evt_01JCA2C5E8G1J4M7P0S3V6Y9B2",
  "tipo": "cota.perto_do_fim",
  "criado_em": "2026-11-24T11:02:00-03:00",
  "ambiente": "producao",
  "dados": {
    "cota": {
      "plano": "essencial",
      "cota_mensal": 500,
      "notas_usadas": 400,
      "percentual": 80,
      "periodo_fim": "2026-11-30"
    }
  }
}
```

## Objetos

Campos dos objetos que as operações devolvem. Datas no horário de Brasília; valores em texto com ponto e duas casas.

### Objeto Nota

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim |  |
| `ambiente` | texto | sim | `producao` emite na SEFIN; `teste` é o ambiente simulado, sem valor fiscal. Um de: `producao`, `teste`. |
| `status` | texto | sim | Um de: `autorizada`, `pendente`, `rejeitada`, `cancelada`. |
| `origem` | texto | sim | Um de: `api`, `painel`, `mcp`, `recorrencia`, `gatilho`. |
| `referencia_externa` | texto | sim |  |
| `numero` | texto ou nulo | não | Número da NFS-e, dado pela SEFIN. Só em nota autorizada ou cancelada. |
| `chave_acesso` | texto ou nulo | não | Chave de acesso de 50 números. No ambiente de teste, fictícia. |
| `dps` | objeto | não | Declaração de prestação de serviço enviada à SEFIN. O Id é fixo para sempre, e é ele que impede nota em dobro. |
| `dps.id` | texto | não |  |
| `dps.serie` | texto | não |  |
| `dps.numero` | texto | não |  |
| `competencia` | data | não |  |
| `municipio_emissor` | texto | não | Código do município no IBGE, 7 números. |
| `prestador` | objeto | não | A empresa da chave. O CNPJ é sempre o do certificado digital. |
| `prestador.cnpj` | texto | sim |  |
| `prestador.inscricao_municipal` | texto ou nulo | não |  |
| `prestador.simples_nacional` | texto | sim | `mei` ou `me_epp` (Microempresa ou Empresa de Pequeno Porte do Simples). Um de: `mei`, `me_epp`. |
| `prestador.apuracao_simples` | texto ou nulo | não | Só para ME/EPP; MEI não informa (regra E0162). Um de: `tudo_pelo_simples`, `iss_fora_do_simples`, `tudo_fora_do_simples`. |
| `tomador` | objeto ou nulo | não |  |
| `tomador.documento` | texto | sim |  |
| `tomador.nome` | texto | sim |  |
| `tomador.inscricao_municipal` | texto ou nulo | não |  |
| `tomador.endereco` | objeto ou nulo | não |  |
| `tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `tomador.telefone` | texto ou nulo | não |  |
| `tomador.email` | texto ou nulo | não |  |
| `intermediario` | objeto ou nulo | não |  |
| `intermediario.documento` | texto | sim |  |
| `intermediario.nome` | texto | sim |  |
| `intermediario.inscricao_municipal` | texto ou nulo | não |  |
| `intermediario.endereco` | objeto ou nulo | não |  |
| `intermediario.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `intermediario.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `intermediario.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `intermediario.endereco.numero` | texto | sim | Até 60 caracteres. |
| `intermediario.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `intermediario.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `intermediario.telefone` | texto ou nulo | não |  |
| `intermediario.email` | texto ou nulo | não |  |
| `servico` | objeto | não |  |
| `servico.codigo_tributacao_nacional` | texto | sim |  |
| `servico.codigo_nbs` | texto ou nulo | sim |  |
| `servico.descricao` | texto | sim |  |
| `servico.municipio_prestacao` | texto | sim | Código do município no IBGE, 7 números. |
| `valores` | objeto | não |  |
| `valores.valor_servico` | texto | sim | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `valores.retencao_iss` | texto | sim | Um de: `nao_retido`, `retido_pelo_tomador`, `retido_pelo_intermediario`. |
| `valores.aliquota_iss` | texto ou nulo | não |  |
| `valores.percentual_tributos_simples` | texto ou nulo | não |  |
| `pendencia` | objeto ou nulo | não | Só em nota pendente. |
| `pendencia.motivo` | texto | sim | `aguardando_sefin`: sem resposta da SEFIN no prazo. `conferindo_identidade`: "DPS já existe", consulta inconclusiva ou XML que não confere; a NFS-e está sendo conferida. `colisao_numeracao`: o número foi usado fora do NFSeIA. `requer_intervencao`: as consultas acabaram sem resposta definitiva. Em nenhum caso a referência ou o número são liberados. Um de: `aguardando_sefin`, `conferindo_identidade`, `colisao_numeracao`, `requer_intervencao`. |
| `pendencia.desde` | data e hora | sim | ISO 8601 com o fuso de Brasília. |
| `pendencia.tentativas` | inteiro | sim | Consultas feitas à SEFIN até agora. |
| `pendencia.proxima_consulta_em` | data e hora ou nulo | não | `null` em `colisao_numeracao` e `requer_intervencao`. |
| `rejeicao` | objeto ou nulo | não | Só em nota rejeitada. |
| `rejeicao.erros` | lista de objeto | sim |  |
| `rejeicao.erros[].campo` | texto | sim | Caminho do campo, por exemplo `tomador.documento`. Vazio quando é a nota inteira. |
| `rejeicao.erros[].mensagem` | texto | sim | O que está errado, em português. |
| `rejeicao.erros[].codigo_sefin` | texto | não | Código da regra da SEFIN, quando houver. |
| `rejeicao.rejeitada_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |
| `cancelamento` | objeto ou nulo | não | Contrato provisório até o mapeamento do Anexo II da SEFIN. |
| `cancelamento.id` | texto | sim | Identidade do pedido de cancelamento, gravada antes do envio do evento. |
| `cancelamento.status` | texto | sim | Um de: `pendente`, `concluido`, `recusado`. |
| `cancelamento.codigo_motivo` | texto | sim | Um de: `erro_na_emissao`, `servico_nao_prestado`, `outros`. |
| `cancelamento.motivo` | texto | sim |  |
| `cancelamento.solicitado_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |
| `cancelamento.concluido_em` | data e hora ou nulo | não | ISO 8601 com o fuso de Brasília. |
| `cancelamento.erros` | lista de objeto | não |  |
| `cancelamento.erros[].campo` | texto | sim | Caminho do campo, por exemplo `tomador.documento`. Vazio quando é a nota inteira. |
| `cancelamento.erros[].mensagem` | texto | sim | O que está errado, em português. |
| `cancelamento.erros[].codigo_sefin` | texto | não | Código da regra da SEFIN, quando houver. |
| `emails` | lista de objeto | não |  |
| `emails[].destinatario` | texto | sim | Um de: `tomador`, `emissor`, `outro`. |
| `emails[].endereco` | texto | sim |  |
| `emails[].status` | texto | sim | Um de: `agendado`, `enviado`, `falhou`, `desligado`, `sem_endereco`. |
| `emails[].enviado_em` | data e hora ou nulo | não | ISO 8601 com o fuso de Brasília. |
| `links` | objeto | não |  |
| `links.xml` | endereço (URL) ou nulo | não |  |
| `links.pdf` | endereço (URL) ou nulo | não |  |
| `links.consulta_publica` | endereço (URL) ou nulo | não | Consulta pública oficial da NFS-e, que pede a chave de acesso. |
| `recorrencia_id` | texto ou nulo | não |  |
| `gatilho_id` | texto ou nulo | não |  |
| `criada_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |
| `autorizada_em` | data e hora ou nulo | não | ISO 8601 com o fuso de Brasília. |
| `atualizada_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |

### Objeto Recorrência

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim |  |
| `ambiente` | texto | sim | `producao` emite na SEFIN; `teste` é o ambiente simulado, sem valor fiscal. Um de: `producao`, `teste`. |
| `status` | texto | sim | Um de: `ativa`, `pausada`, `encerrada`. |
| `tomador` | objeto | sim | Tomador ou intermediário na entrada. Se o documento já estiver salvo em `/tomadores`, basta ele; os campos que você enviar valem só para esta nota. Quem está no exterior ainda não é atendido. |
| `tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `tomador.endereco` | objeto | não |  |
| `tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `valores` | objeto | não | Valores das recorrências, dos gatilhos e do MCP. No MVP, esses fluxos recusam `retido_pelo_intermediario`. |
| `valores.valor_servico` | texto | não | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `valores.retencao_iss` | texto | não | Com retenção pelo tomador, o tomador e o endereço dele são obrigatórios (E0204, E0237). Um de: `nao_retido`, `retido_pelo_tomador`. |
| `valores.aliquota_iss` | texto ou nulo | não | Alíquota do ISS, de 0.01 a 5.00 (E0595). Para ME/EPP com tudo pelo Simples: obrigatória com ISS retido, no mínimo 1.80 (E0621), e proibida sem retenção (E0625). MEI não informa (E0600). |
| `valores.percentual_tributos_simples` | texto | não | Percentual com ponto e duas casas. |
| `dia_do_mes` | inteiro | sim |  |
| `inicio` | texto | sim |  |
| `fim` | texto ou nulo | não |  |
| `aviso_antes_dias` | inteiro | não |  |
| `enviar_email` | booleano ou nulo | não |  |
| `proxima_emissao` | data ou nulo | não | `null` quando pausada ou encerrada. |
| `ocorrencia_reservada` | objeto ou nulo | não | Ocorrência do mês já reservada (às 0h do dia da emissão), com competência, referência e dados congelados. Edições, pausa e encerramento não a mudam. `null` fora desse período. |
| `ocorrencia_reservada.competencia` | data | sim |  |
| `ocorrencia_reservada.referencia_externa` | texto | sim |  |
| `ocorrencia_reservada.reservada_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |
| `ocorrencia_reservada.nota_id` | texto ou nulo | não |  |
| `ultima_nota` | objeto ou nulo | não |  |
| `ultima_nota.id` | texto | não |  |
| `ultima_nota.competencia` | texto | não |  |
| `ultima_nota.status` | texto | não | Um de: `autorizada`, `pendente`, `rejeitada`, `cancelada`. |
| `criada_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `atualizada_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |

### Objeto Tomador

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim |  |
| `ambiente` | texto | sim | `producao` emite na SEFIN; `teste` é o ambiente simulado, sem valor fiscal. Um de: `producao`, `teste`. |
| `documento` | texto | sim |  |
| `nome` | texto | sim |  |
| `inscricao_municipal` | texto ou nulo | não |  |
| `endereco` | objeto ou nulo | não |  |
| `endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `endereco.numero` | texto | sim | Até 60 caracteres. |
| `endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `endereco.bairro` | texto | sim | Até 60 caracteres. |
| `telefone` | texto ou nulo | não |  |
| `email` | texto ou nulo | não |  |
| `enviar_email` | booleano | sim |  |
| `origem_dos_dados` | texto | sim | Um de: `informado`, `consulta_publica`. |
| `criado_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `atualizado_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |

### Objeto Gatilho

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim |  |
| `ambiente` | texto | sim | `producao` emite na SEFIN; `teste` é o ambiente simulado, sem valor fiscal. Um de: `producao`, `teste`. |
| `nome` | texto | sim |  |
| `origem` | objeto | sim | De onde vêm os pagamentos do gatilho. Entra na identidade da nota, `pagamento:{provedor}:{conta}:{pagamento_id}`, e não muda depois da criação. |
| `origem.provedor` | texto | sim | Nome curto do sistema de cobrança, escolhido por você (por exemplo `meu-sistema`). |
| `origem.conta` | texto | sim | A conta nesse sistema, para separar duas contas do mesmo provedor. |
| `status` | texto | sim | Um de: `ativo`, `pausado`. |
| `url` | endereço (URL) | sim | Endereço que recebe os avisos de pagamento. |
| `modelo` | objeto | sim |  |
| `modelo.usar_valor_do_aviso` | booleano | sim | `true`: o valor vem de `valor` no aviso. `false`: vale `valores.valor_servico` do modelo. |
| `modelo.tomador` | objeto ou nulo | não | Tomador fixo. Com `null`, o tomador vem em cada aviso. |
| `modelo.tomador.documento` | texto | sim | CPF (11 números) ou CNPJ (14 números). Pontuação é aceita e removida. |
| `modelo.tomador.nome` | texto | não | Obrigatório quando o documento não está salvo. Até 300 caracteres. |
| `modelo.tomador.inscricao_municipal` | texto | não | Até 15 caracteres. |
| `modelo.tomador.endereco` | objeto | não |  |
| `modelo.tomador.endereco.municipio` | texto | sim | Código do município no IBGE, 7 números. |
| `modelo.tomador.endereco.cep` | texto | sim | 8 números; hífen é aceito na entrada e removido. |
| `modelo.tomador.endereco.logradouro` | texto | sim | Até 255 caracteres. |
| `modelo.tomador.endereco.numero` | texto | sim | Até 60 caracteres. |
| `modelo.tomador.endereco.complemento` | texto ou nulo | não | Até 156 caracteres. |
| `modelo.tomador.endereco.bairro` | texto | sim | Até 60 caracteres. |
| `modelo.tomador.telefone` | texto | não | DDD e número, de 6 a 20 números. |
| `modelo.tomador.email` | e-mail | não | Recebe a nota por e-mail, se o envio estiver ligado. Até 80 caracteres. |
| `modelo.servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `modelo.servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `modelo.servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `modelo.servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `modelo.servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `modelo.valores` | objeto | não | Valores das recorrências, dos gatilhos e do MCP. No MVP, esses fluxos recusam `retido_pelo_intermediario`. |
| `modelo.valores.valor_servico` | texto | não | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `modelo.valores.retencao_iss` | texto | não | Com retenção pelo tomador, o tomador e o endereço dele são obrigatórios (E0204, E0237). Um de: `nao_retido`, `retido_pelo_tomador`. |
| `modelo.valores.aliquota_iss` | texto ou nulo | não | Alíquota do ISS, de 0.01 a 5.00 (E0595). Para ME/EPP com tudo pelo Simples: obrigatória com ISS retido, no mínimo 1.80 (E0621), e proibida sem retenção (E0625). MEI não informa (E0600). |
| `modelo.valores.percentual_tributos_simples` | texto | não | Percentual com ponto e duas casas. |
| `modelo.enviar_email` | booleano ou nulo | não |  |
| `ultimo_evento_em` | data e hora ou nulo | não | ISO 8601 com o fuso de Brasília. |
| `criado_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `atualizado_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |

### Objeto Webhook

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim |  |
| `ambiente` | texto | sim | `producao` emite na SEFIN; `teste` é o ambiente simulado, sem valor fiscal. Um de: `producao`, `teste`. |
| `url` | endereço (URL) | sim |  |
| `eventos` | lista de texto | sim |  |
| `descricao` | texto ou nulo | não |  |
| `status` | texto | sim | `desativado` depois de 3 dias seguidos de falha, com aviso por e-mail. Um de: `ativo`, `pausado`, `desativado`. |
| `criado_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `atualizado_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |

### Objeto Entrega

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim |  |
| `evento_id` | texto | sim |  |
| `tipo` | texto | sim | Um de: `nota.autorizada`, `nota.rejeitada`, `nota.pendente`, `nota.pendente_resolvida`, `nota.cancelada`, `nota_recorrente.emitida`, `certificado.vencendo`, `cota.perto_do_fim`. |
| `status` | texto | sim | `falhou` depois de 24 horas sem sucesso. Um de: `entregue`, `tentando`, `falhou`. |
| `tentativas` | inteiro | sim |  |
| `ultima_tentativa` | objeto ou nulo | não |  |
| `ultima_tentativa.em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `ultima_tentativa.http_status` | inteiro ou nulo | não |  |
| `ultima_tentativa.duracao_ms` | inteiro | não |  |
| `ultima_tentativa.erro` | texto ou nulo | não | Falha de rede ou de tempo, quando não houve status HTTP. |
| `proxima_tentativa_em` | data e hora ou nulo | não | ISO 8601 com o fuso de Brasília. |
| `criada_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |

### Objeto Empresa

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim |  |
| `cnpj` | texto | sim |  |
| `razao_social` | texto | sim |  |
| `nome_fantasia` | texto ou nulo | não |  |
| `inscricao_municipal` | texto ou nulo | não |  |
| `municipio` | objeto | não |  |
| `municipio.codigo_ibge` | texto | não | Código do município no IBGE, 7 números. |
| `municipio.nome` | texto | não |  |
| `municipio.uf` | texto | não |  |
| `simples_nacional` | texto | sim | Um de: `mei`, `me_epp`. |
| `apuracao_simples` | texto ou nulo | não | Um de: `tudo_pelo_simples`, `iss_fora_do_simples`, `tudo_fora_do_simples`. |
| `padroes_da_nota` | objeto | não | Definidos no cadastro. Preenchem, campo a campo, o que a emissão omitir. |
| `padroes_da_nota.servico` | objeto | não | Campos omitidos vêm de `padroes_da_nota.servico` da empresa. |
| `padroes_da_nota.servico.codigo_tributacao_nacional` | texto | não | Item, subitem e desdobro da lista nacional, 6 números. A escolha é da empresa e do contador. |
| `padroes_da_nota.servico.codigo_nbs` | texto ou nulo | não | Código NBS, 9 números, ou `null` se não houver. |
| `padroes_da_nota.servico.descricao` | texto | não | Descrição do serviço. Aceita quebra de linha. Até 2000 caracteres. |
| `padroes_da_nota.servico.municipio_prestacao` | texto | não | Código do município no IBGE, 7 números. |
| `padroes_da_nota.valores` | objeto | não |  |
| `padroes_da_nota.valores.retencao_iss` | texto | não | Um de: `nao_retido`, `retido_pelo_tomador`, `retido_pelo_intermediario`. |
| `padroes_da_nota.valores.aliquota_iss` | texto ou nulo | não |  |
| `padroes_da_nota.valores.percentual_tributos_simples` | texto ou nulo | não |  |
| `plano` | objeto | sim |  |
| `plano.nome` | texto | não | Um de: `teste`, `essencial`, `pro`, `integrador`. |
| `plano.cota_mensal` | inteiro | não |  |
| `plano.periodo_inicio` | data | não |  |
| `plano.periodo_fim` | data | não |  |
| `plano.notas_usadas` | inteiro | não |  |
| `plano.notas_restantes` | inteiro | não |  |
| `teste_gratis` | objeto ou nulo | não | Só durante o teste grátis. |
| `teste_gratis.notas_restantes` | inteiro | não |  |
| `teste_gratis.termina_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `producao_liberada` | booleano | sim | Liberada só por ação no painel, confirmada pelo e-mail da empresa. |
| `limites` | objeto | não |  |
| `limites.notas_por_dia` | inteiro | não |  |
| `limites.valor_maximo_por_nota` | texto | não | Reais com ponto e duas casas, maior que zero (de 0.01 a 999999999999999.99). |
| `certificado` | objeto ou nulo | não | Só metadados. Nunca o arquivo, a senha ou a chave privada. |
| `certificado.status` | texto | não | Um de: `valido`, `vencendo`, `vencido`, `revogado`. |
| `certificado.titular` | texto | não |  |
| `certificado.cnpj` | texto | não |  |
| `certificado.valido_de` | data | não |  |
| `certificado.valido_ate` | data | não |  |
| `certificado.enviado_em` | data e hora | não | ISO 8601 com o fuso de Brasília. |
| `email` | objeto | não |  |
| `email.envio_ligado` | booleano | não |  |
| `email.emissor` | texto | não | Recebe cópia de cada nota e as respostas dos tomadores. |
| `chave` | objeto | sim | A chave usada nesta requisição. |
| `chave.prefixo` | texto | não |  |
| `chave.ambiente` | texto | não | `producao` emite na SEFIN; `teste` é o ambiente simulado, sem valor fiscal. Um de: `producao`, `teste`. |
| `chave.escopos` | lista de texto | não |  |

### Objeto Erro

Só estes campos saem num erro. Nunca vão em resposta, erro ou conteúdo do MCP: o corpo bruto
da SEFIN, XML de DPS ou NFS-e, credenciais, segredos, nem material de certificado. As
mensagens da SEFIN chegam traduzidas, com o código em `codigo_sefin`.

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `erro` | objeto | sim |  |
| `erro.codigo` | texto | sim | Código estável, em snake_case. Lista em `x-nfseia-erros`. |
| `erro.mensagem` | texto | sim | O que aconteceu, em português. |
| `erro.como_resolver` | texto | sim | O que fazer, em português. |
| `erro.detalhes` | lista de objeto | sim |  |
| `erro.detalhes[].campo` | texto | sim | Caminho do campo, por exemplo `tomador.documento`. Vazio quando é a nota inteira. |
| `erro.detalhes[].mensagem` | texto | sim | O que está errado, em português. |
| `erro.detalhes[].codigo_sefin` | texto | não | Código da regra da SEFIN, quando houver. |
| `erro.codigo_sefin` | texto | não | Código da SEFIN, quando a recusa veio dela. |
| `erro.nota_id` | texto | não | Nota envolvida, quando houver (por exemplo a nota rejeitada). |
| `erro.requisicao_id` | texto | sim | Mesmo valor do cabeçalho `NFSeIA-Requisicao-Id`. |

### Objeto Evento

| Campo | Tipo | Obrigatório | Descrição |
| --- | --- | --- | --- |
| `id` | texto | sim | Único por evento. Repetido em todas as tentativas de entrega. |
| `tipo` | texto | sim | Um de: `nota.autorizada`, `nota.rejeitada`, `nota.pendente`, `nota.pendente_resolvida`, `nota.cancelada`, `nota_recorrente.emitida`, `certificado.vencendo`, `cota.perto_do_fim`. |
| `criado_em` | data e hora | sim | ISO 8601 com o fuso de Brasília. |
| `ambiente` | texto | sim | `producao` emite na SEFIN; `teste` é o ambiente simulado, sem valor fiscal. Um de: `producao`, `teste`. |
| `dados` | objeto | sim |  |
