
# Conceitos

## A emissão é assíncrona

`POST /v1/nfe` e `POST /v1/nfse` não esperam a SEFAZ ou o Sistema Nacional. Eles validam o pedido, calculam os impostos, guardam a nota e respondem `202` com `"status": "queued"`. O envio acontece em segundo plano, com novas tentativas automáticas quando o órgão está fora do ar.

O resultado chega de duas formas:

- **webhook** (recomendado): `nfe.authorized`, `nfe.rejected`, `nfse.authorized`... Veja [Webhooks](../webhooks/);
- **consulta**: `GET /v1/nfe/{id}` ou `GET /v1/nfe?externalId=...`.

## Situações da nota

| Situação | O que significa | O que fazer |
|---|---|---|
| `queued`, `sending`, `pending` | Na fila ou em envio | Esperar |
| `unknown` | A resposta do órgão se perdeu; a emitza está conferindo se a nota foi registrada | Esperar. Nunca emita de novo com outro `externalId` |
| `authorized` | Autorizada, com valor fiscal (em produção) | Baixar o XML e o PDF |
| `rejected` | Recusada pelo órgão, com o motivo em `rejection` | Corrigir e reenviar com o **mesmo** `externalId` |
| `denied` | Uso denegado (NF-e): registrada, mas sem valor, por irregularidade do emitente ou do destinatário | Resolver a situação cadastral; o número fica consumido |
| `failed` | Parou sem resposta do órgão (ex.: certificado vencido) | Corrigir a causa e chamar `POST /v1/nfe/{id}/retry` |
| `cancelled` | Cancelada por evento | Nada |

Quando `attention` vem preenchido, a nota precisa de ação manual. O campo traz um código (por exemplo, `reconcile_exhausted`, quando a conferência com o órgão não fechou). Fale com o suporte da emitza informando o `id` da nota.

## Idempotência: o externalId

O `externalId` é o seu identificador do pedido, e é ele que impede nota em dobro:

- repetir o mesmo pedido com o mesmo `externalId` devolve a nota que já existe, com status `200`, sem emitir outra. Use isso à vontade quando a sua requisição cair no meio;
- enviar o mesmo `externalId` com **outro** conteúdo devolve `409`, exceto quando a nota foi rejeitada;
- nota `rejected`: reenvie o pedido corrigido com o mesmo `externalId`. Ela é reenviada com a mesma série e o mesmo número.

Use um `externalId` por documento fiscal, por exemplo o número do pedido ou da ordem de serviço.

## Erros

Todo erro tem o mesmo formato:

```json
{
  "error": {
    "code": "validation_failed",
    "message": "Dados inválidos",
    "details": [{ "path": "items[0].ncm", "message": "deve ter 8 dígitos" }]
  }
}
```

| Status | `code` | Quando |
|---|---|---|
| 400 | `bad_request` | JSON malformado |
| 401 | `unauthorized` | Chave ausente, inválida ou no endereço errado |
| 404 | `not_found` | Recurso inexistente ou de outro cliente |
| 409 | `conflict` | `externalId` com outro conteúdo, nota em situação que não permite a ação |
| 422 | `validation_failed` e outros | Campos inválidos (veja `details`) ou regra de negócio: `series_missing`, `certificate_unavailable`, `sandbox_homologation_only`... |
| 429 | `rate_limited` | Limite de requisições; espere o tempo do cabeçalho `Retry-After` |
| 503 | `busy` | Serviço ocupado; tente de novo depois do `Retry-After` |

Campos desconhecidos são recusados: um erro de digitação aparece na hora, em vez de ser ignorado em silêncio.

Rejeição da SEFAZ não é erro HTTP: a nota é aceita (`202`) e depois fica `rejected`, com `rejection.cStat` e `rejection.reason`.

## Valores e formatos

- Decimais em texto, com ponto: `"1500.00"`, `"7.6"`. Nunca número JSON, para não perder centavos.
- Datas no formato `AAAA-MM-DD`; data e hora em ISO 8601.
- CNPJ, CEP e códigos aceitam pontuação, que é removida.

## Limites

- 20 requisições por segundo por cliente, com picos de até 40.
- Corpo de até 1 MB.
- Até 990 itens por NF-e.

## Ambientes

Cada empresa tem um `environment`: `homologation` (testes, sem valor fiscal) ou `production`. Com a chave de teste, a empresa fica sempre em homologação. As séries e a numeração são separadas por ambiente: nota de teste nunca consome número de produção.
