# Autenticação e ambientes

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

Toda chamada leva a chave de API no cabeçalho `Authorization`:

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

O endereço é o mesmo nos dois ambientes, `https://api.nfseia.com.br/v1`. Quem decide se a nota é de
teste ou de verdade é a chave.

## Chaves

- **`nfs_test_...`:** ambiente de teste. SEFIN simulada, sem certificado digital e sem valor fiscal.
  Sai na hora, no cadastro.
- **`nfs_live_...`:** produção. Só existe depois que o dono da conta libera a produção no painel, com
  confirmação pelo e-mail da empresa.

Cada chave pertence a uma empresa (um CNPJ) e a um ambiente. No plano Integrador, crie uma chave por
empresa. A chave aparece inteira uma única vez, ao ser criada: guardamos só o hash dela. Para trocar,
crie a nova, atualize o seu sistema e revogue a antiga no painel.

Guarde a chave em variável de ambiente ou no cofre de segredos do seu servidor. Nunca no código, no
repositório ou no navegador do seu cliente: a API não deve ser chamada direto do front-end.

As credenciais da IA (chaves `nfs_mcp_test_...` e `nfs_mcp_live_...` e os acessos por OAuth do Claude
e do ChatGPT) têm audiência própria e só valem no servidor MCP. Nesta API, são recusadas com
`403 credencial_do_mcp`. Veja [Conectar no Claude e no ChatGPT](https://nfseia.com.br/docs/mcp).

## Escopos

Cada chave tem escopos, e cada operação da [referência](https://nfseia.com.br/docs/referencia) diz qual exige. Faltou
escopo, a resposta é `403 sem_permissao`.

| Escopo | Libera |
| --- | --- |
| `notas:ler` | consultar e listar notas, baixar XML e PDF |
| `notas:emitir` | emitir notas |
| `notas:cancelar` | cancelar notas |
| `notas:enviar_email` | reenviar a nota por e-mail |
| `recorrencias:ler` | consultar e listar recorrências |
| `recorrencias:escrever` | criar, editar, pausar e encerrar recorrências |
| `tomadores:ler` | consultar tomadores e a consulta pública de CNPJ |
| `tomadores:escrever` | salvar, editar e excluir tomadores |
| `gatilhos:gerenciar` | criar e administrar gatilhos de pagamento |
| `webhooks:gerenciar` | criar e administrar webhooks |
| `empresa:ler` | dados da empresa, plano, cota e certificado |
| `empresa:certificado` | gerar o link de envio do certificado |

A credencial da IA (MCP) nasce no teste e não tem os escopos de webhooks, gatilhos, tomadores
(escrita) e certificado.

## Idempotência

Rede cai, servidor reinicia, a requisição sai duas vezes. Duas proteções garantem que isso não vira
nota em dobro.

### `Idempotency-Key`

Cabeçalho obrigatório em todo POST que cria ou muda estado, com até 255 caracteres, guardado por 24
horas. A chave vale para a empresa, o ambiente, o método, a operação e o recurso alvo, junto com o
hash do corpo:

- Repetir tudo igual devolve a resposta original, com `NFSeIA-Idempotencia-Repetida: true`. Antes de
  devolver, a permissão da chave é conferida de novo.
- Qualquer diferença (outro corpo, outra operação, outro recurso) dá `409 idempotencia_reutilizada`.
- Enquanto a primeira ainda está em andamento, `409 idempotencia_em_andamento`, com `Retry-After`.
- Respostas sem efeito não ficam guardadas: `400`, `401`, `402`, `403`, `404`, `413`,
  `409 idempotencia_em_andamento`, `429` e `5xx` antes de qualquer efeito. Corrija ou espere e repita
  com a mesma chave.
- Depois do envio à SEFIN, a operação fica preservada: repetir com a mesma chave devolve o estado
  atual dela, mesmo que a primeira resposta tenha sido um erro.

Exceções, em que a chave é opcional:

| Operação | Por quê |
| --- | --- |
| `POST /notas/{id}/cancelar` | Cada nota tem um só pedido de cancelamento; repetir devolve o mesmo pedido. |
| `POST /notas/{id}/reenviar-email` | Repetir é o objetivo; o limite é de 5 envios por nota por dia. |
| `POST /webhooks/{id}/entregas/{entrega_id}/reenviar` | Repetir é o objetivo; o evento leva o mesmo `id`. |
| `POST /gatilhos/{id}/eventos` | Não usa chave de API; a identidade é o pagamento. |

### `referencia_externa`

No corpo da emissão, obrigatória: o id do pedido, da fatura ou da cobrança no seu sistema, única por
empresa e ambiente, sem prazo.

- **Reservada antes de tudo.** Numa só transação, a referência é reservada junto com o número da
  declaração (DPS), antes de qualquer envio à SEFIN. Dois pedidos ao mesmo tempo com a mesma
  referência, mesmo com `Idempotency-Key` diferentes, recebem a mesma nota (pendente ou final),
  nunca uma segunda.
- **Repetir devolve a nota.** Se já houver nota autorizada, pendente ou cancelada com ela, a API
  devolve essa nota (`200`, com `NFSeIA-Recurso-Existente: true`) e não emite outra.
- **Só a rejeição definitiva libera.** A referência volta a ficar livre apenas quando a nota fica
  `rejeitada`, depois de conferido na SEFIN que ela não existe. Pendente, por qualquer motivo,
  continua presa à referência.
- **Prefixos reservados.** `pagamento:`, `recorrencia:` e `mcp:` são das notas de gatilho, das
  recorrências e da IA; na emissão manual dão `400 referencia_reservada`.

Na prática: gere a `Idempotency-Key` uma vez por tentativa, guarde junto do pedido e reutilize em
toda repetição da mesma chamada. Corrigiu os dados depois de uma recusa definitiva? Mande com uma
`Idempotency-Key` nova e a mesma `referencia_externa`.

## Formatos

- Campos em português, em snake_case: `referencia_externa`, `valor_servico`.
- Valores e percentuais em texto, com ponto e duas casas: `"1500.00"`, `"6.00"`. Assim não se perde
  centavo em conversão de número.
- Números fiscais (número da nota, série, número da DPS) também em texto.
- Datas em ISO 8601 com o fuso de Brasília: `"2026-11-05T14:03:12-03:00"`; datas sem hora como
  `"2026-11-05"`.
- CPF, CNPJ e CEP aceitam pontuação na entrada; na resposta, só números.
- Campo desconhecido é recusado com `400`: um erro de digitação não passa despercebido.
- Corpo em JSON, com `Content-Type: application/json`, até 64 KB.

## Listas e paginação

As listas devolvem `{ "dados": [...], "proximo_cursor": "..." }`, da mais nova para a mais antiga.
Para a próxima página, repita a chamada com `cursor` igual ao `proximo_cursor`; quando ele vier
`null`, acabou. `limite` vai de 1 a 100 (padrão 20).

## Identificadores

Os ids têm prefixo pelo tipo: `nota_`, `rec_`, `tom_`, `gat_`, `wh_`, `ent_`, `evt_`, `emp_`. Toda
resposta traz `NFSeIA-Requisicao-Id`; informe esse valor no chamado se precisar de ajuda.

## Versões

A versão vai no endereço (`/v1`). Dentro da mesma versão, só entram mudanças que não quebram:
campos e eventos novos, valores novos em listas. Escreva o seu código para ignorar campos que não
conhece.
