> ## Documentation Index
> Fetch the complete documentation index at: https://docs.engineapi.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Emissão de NF-e

> Todos os campos, regimes tributários e tratamento de erros para transmitir uma NF-e à SEFAZ numa única chamada.

Emita uma Nota Fiscal Eletrônica (NF-e, modelo 55) e transmita para a SEFAZ em uma única chamada REST.

**Endpoint:** `POST https://api.engineapi.com.br/v1/nfe`

## Situação indeterminada

Uma resposta perdida depois da transmissão não significa rejeição. Consulte
`GET /v1/nfe?situacao=indeterminada&page=1&limit=20` para listar NF-e com chave de acesso
sem desfecho terminal. O parâmetro não pode ser combinado com `status`; cada item traz
`situacao`, o `status` persistido, `updatedAt`, `proximaVerificacaoEm` e o motivo.

<Info>
  **Quais campos enviar?** Este guia cobre os campos mais usados. A lista **completa**,
  navegável por grupo (Identificação, Destinatário, Itens, Impostos, Transporte,
  Pagamento...) e gerada direto do contrato real, está no
  [**Catálogo de campos: NF-e**](/api-reference/campos-nfe). Para navegar por endpoint
  em vez de por documento, veja a [Referência da API](/api-reference/overview).
</Info>

<Note>
  Este é o guia **completo** (todos os campos, regimes tributários, tratamento de
  erros). Se você só quer o checklist rápido antes da 1ª emissão, veja [Primeira
  Emissão](/guides/first-emission).
</Note>

Como a emissão flui do cadastro à autorização (ou rejeição) da SEFAZ:

```mermaid theme={null}
flowchart LR
    A("Empresa cadastrada<br/>POST /v1/companies") --> B("Certificado enviado<br/>POST /v1/companies/id/certificate")
    B --> C("POST /v1/nfe")
    C --> D{"SEFAZ"}
    D -->|aprova| E("AUTHORIZED<br/>webhook invoice.authorized")
    D -->|rejeita| F("400 com error.erros[]<br/>webhook invoice.rejected")

    classDef nucleo fill:#1E56B1,stroke:#0F2A5E,color:#fff
    classDef destaque fill:#2D7AF6,stroke:#0F2A5E,color:#fff
    classDef autorizada fill:#16a34a,stroke:#15803d,color:#fff
    classDef rejeitada fill:#dc2626,stroke:#991b1b,color:#fff
    class A,B nucleo
    class C,D destaque
    class E autorizada
    class F rejeitada
```

***

## Pré-requisitos

<Steps>
  <Step title="Conta criada">
    Obtenha seu token via `POST /v1/auth/login` ou uma API Key (`ek_live_`/`ek_test_`) no Dashboard.
  </Step>

  <Step title="Empresa cadastrada">
    Cadastre o CNPJ emissor via `POST /v1/companies`. Guarde o `id` retornado.
  </Step>

  <Step title="Certificado digital enviado">
    Faça upload do `.pfx` via `POST /v1/companies/{id}/certificate` (campo multipart **`file`**). Sem certificado, a emissão falha.
  </Step>

  <Step title="Ambiente definido">
    Todo emissor nasce em homologação (`ambienteFiscal: 2`). Ver [Ambiente de testes](/guides/sandbox) para o estado real de ir pra produção.
  </Step>
</Steps>

<Info>
  Notas em homologação (`ambienteFiscal: 2`) são transmitidas para o SEFAZ de teste e **não têm validade fiscal**. Use para testar sem risco.
</Info>

<Info>
  **Emissor (`issuerId`)** é **opcional** no payload de NF-e/NFC-e. Com um único emissor
  cadastrado, pode omitir (a API usa o seu emissor). Com dois ou mais, informe
  `issuerId` (UUID) para escolher o CNPJ; sem ele a API responde `400`. Ver
  [Autenticação](/authentication#multi-tenancy).
</Info>

***

## Exemplos de Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.engineapi.com.br/v1/nfe \
    -H "Authorization: Bearer SEU_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "naturezaOperacao": "VENDA DE MERCADORIA",
      "idDest": 1,
      "indFinal": 1,
      "destinatario": {
        "cnpjCpf": "99888777000100",
        "nome": "Cliente Exemplo SA",
        "endereco": {
          "logradouro": "Av Goiás",
          "numero": "500",
          "bairro": "Centro",
          "codigoMunicipio": "5208707",
          "municipio": "Goiânia",
          "uf": "GO",
          "cep": "74063010"
        },
        "indicadorIE": 9
      },
      "items": [{
        "codigo": "PROD001",
        "descricao": "Camiseta Algodão P",
        "ncm": "61091000",
        "cfop": "5102",
        "unidade": "UN",
        "quantidade": 2,
        "valorUnitario": 59.90,
        "icms": {
          "origem": 0,
          "csosn": "102"
        }
      }],
      "pagamentos": [{ "forma": "01", "valor": 119.80 }]
    }'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch('https://api.engineapi.com.br/v1/nfe', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      naturezaOperacao: 'VENDA DE MERCADORIA',
      idDest: 1,
      indFinal: 1,
      destinatario: {
        cnpjCpf: '99888777000100',
        nome: 'Cliente Exemplo SA',
        endereco: {
          logradouro: 'Av Goiás', numero: '500',
          bairro: 'Centro', codigoMunicipio: '5208707',
          municipio: 'Goiânia', uf: 'GO', cep: '74063010',
        },
        indicadorIE: 9,
      },
      items: [{
        codigo: 'PROD001', descricao: 'Camiseta Algodão P',
        ncm: '61091000', cfop: '5102', unidade: 'UN',
        quantidade: 2, valorUnitario: 59.90,
        icms: { origem: 0, csosn: '102' },
      }],
      pagamentos: [{ forma: '01', valor: 119.80 }],
    }),
  });

  const { data } = await response.json();
  console.log('NFe autorizada:', data.accessKey, data.status);
  ```

  ```python Python theme={null}
  import httpx

  response = httpx.post(
      'https://api.engineapi.com.br/v1/nfe',
      headers={'Authorization': f'Bearer {token}'},
      json={
          'naturezaOperacao': 'VENDA DE MERCADORIA',
          'idDest': 1,
          'indFinal': 1,
          'destinatario': {
              'cnpjCpf': '99888777000100',
              'nome': 'Cliente Exemplo SA',
              'endereco': {
                  'logradouro': 'Av Goiás', 'numero': '500',
                  'bairro': 'Centro', 'codigoMunicipio': '5208707',
                  'municipio': 'Goiânia', 'uf': 'GO', 'cep': '74063010',
              },
              'indicadorIE': 9,
          },
          'items': [{
              'codigo': 'PROD001', 'descricao': 'Camiseta Algodão P',
              'ncm': '61091000', 'cfop': '5102', 'unidade': 'UN',
              'quantidade': 2, 'valorUnitario': 59.90,
              'icms': {'origem': 0, 'csosn': '102'},
          }],
          'pagamentos': [{'forma': '01', 'valor': 119.80}],
      },
  )

  data = response.json()['data']
  print(f"NFe autorizada: {data['accessKey']} ({data['status']})")
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init('https://api.engineapi.com.br/v1/nfe');
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_POST => true,
      CURLOPT_HTTPHEADER => [
          'Authorization: Bearer SEU_TOKEN',
          'Content-Type: application/json',
      ],
      CURLOPT_POSTFIELDS => json_encode([
          'naturezaOperacao' => 'VENDA DE MERCADORIA',
          'idDest' => 1,
          'indFinal' => 1,
          'destinatario' => [
              'cnpjCpf' => '99888777000100',
              'nome' => 'Cliente Exemplo SA',
              'endereco' => [
                  'logradouro' => 'Av Goiás', 'numero' => '500',
                  'bairro' => 'Centro', 'codigoMunicipio' => '5208707',
                  'municipio' => 'Goiânia', 'uf' => 'GO', 'cep' => '74063010',
              ],
              'indicadorIE' => 9,
          ],
          'items' => [[
              'codigo' => 'PROD001', 'descricao' => 'Camiseta Algodão P',
              'ncm' => '61091000', 'cfop' => '5102', 'unidade' => 'UN',
              'quantidade' => 2, 'valorUnitario' => 59.90,
              'icms' => ['origem' => 0, 'csosn' => '102'],
          ]],
          'pagamentos' => [['forma' => '01', 'valor' => 119.80]],
      ]),
  ]);

  $data = json_decode(curl_exec($ch), true)['data'];
  echo "NFe autorizada: " . $data['accessKey'];
  ```
</CodeGroup>

<Warning>
  **Vendendo para outra empresa (contribuinte de ICMS)?** Informe `indicadorIE: 1` e a
  `ie` **real** do destinatário: a SEFAZ valida o vínculo IE×CNPJ no cadastro dela.
  Sem a IE a nota é rejeitada com cStat **728**; com IE que não pertence ao CNPJ, cStat
  **234**. Destinatário isento usa `indicadorIE: 2` (sem `ie`); consumidor que não é
  contribuinte (o exemplo acima), `indicadorIE: 9`.
</Warning>

***

<h2 id="icms-por-regime-tributario">
  ICMS por Regime Tributário
</h2>

O campo `icms` do item muda conforme o regime da empresa emissora:

<AccordionGroup>
  <Accordion title="Simples Nacional (CSOSN)">
    Informe `origem` e `csosn`.

    ```json theme={null}
    "icms": {
      "origem": 0,
      "csosn": "400"
    }
    ```

    | CSOSN | Quando usar                                            |
    | ----- | ------------------------------------------------------ |
    | `102` | Tributada pelo Simples, sem permissão de crédito       |
    | `400` | Não tributada pelo Simples Nacional                    |
    | `500` | ICMS cobrado anteriormente por substituição tributária |
    | `900` | Outros                                                 |
  </Accordion>

  <Accordion title="Lucro Real / Lucro Presumido (CST)">
    O emissor `crt: 3` **não informa `cst` à mão**: `icms.cst` no payload é recusado com
    `422 CST_NAO_SUPORTADO_NFE` (o leiaute exige a modalidade da base de cálculo, campo
    fora deste contrato). O caminho que autoriza é a emissão assistida:
    `"resolverTributacao": true` no corpo da requisição, com o item trazendo só `icms.origem`.
    O motor calcula CST, base, alíquota e valor a partir de NCM, CFOP, UF do emissor e
    origem da mercadoria:

    ```json theme={null}
    "icms": {
      "origem": 0
    }
    ```

    | CST  | Significado                    | Suportado hoje                                               |
    | ---- | ------------------------------ | ------------------------------------------------------------ |
    | `00` | Tributada integralmente        | Sim, único CST que esta fase resolve                         |
    | `20` | Com redução de base de cálculo | Não, `422 TRIBUTACAO_NAO_RESOLVIDA`                          |
    | `40` | Isenta                         | Não, `422 TRIBUTACAO_NAO_RESOLVIDA`                          |
    | `41` | Não tributada                  | Não, `422 TRIBUTACAO_NAO_RESOLVIDA`                          |
    | `60` | Cobrada anteriormente por ST   | Não, o NCM arrolado no CEST já recusa antes de chegar ao CST |

    Detalhe completo do cenário (pré-requisitos, resposta, XML, erros e limitações) em
    [Regime Normal](/guides/regime-normal).
  </Accordion>

  <Accordion title="Origem da mercadoria">
    | Código | Origem                                                         |
    | ------ | -------------------------------------------------------------- |
    | `0`    | Nacional                                                       |
    | `1`    | Estrangeira (importação direta)                                |
    | `2`    | Estrangeira (adquirida no mercado interno)                     |
    | `3`    | Nacional com mais de 40% de conteúdo estrangeiro               |
    | `4`    | Nacional produzida conforme processos básicos                  |
    | `5`    | Nacional com até 40% de conteúdo estrangeiro                   |
    | `6`    | Estrangeira por importação direta, sem similar nacional        |
    | `7`    | Estrangeira adquirida no mercado interno, sem similar nacional |
    | `8`    | Nacional com mais de 70% de conteúdo estrangeiro               |
  </Accordion>

  <Accordion title="Emissão assistida (Cérebro Fiscal): resolverTributacao">
    Com `"resolverTributacao": true` no corpo da requisição, itens **sem** tributação
    manual (sem `icms.csosn` e sem `ibsCbs`) recebem CSOSN e o grupo IBS/CBS
    (Reforma Tributária) resolvidos automaticamente. Requer feature de plano +
    `Issuer.fiscalBrainEnabled`; sem isso, **403**. Item não-resolvível → **422**
    com `{index, motivo}` por item e **nada é emitido**. `icms.origem` nunca é
    opinado pelo Cérebro: sempre vem do seu payload (ausente = `0`, nacional).
    Este `422` é diferente da rejeição SEFAZ (sempre `400`); ver
    [Erros e respostas](/guides/errors).
  </Accordion>
</AccordionGroup>

***

<h2 id="pis-cofins-e-ipi">
  PIS, COFINS e IPI
</h2>

O motor é **passthrough**: o que você informa é o que vai no documento, nada é
calculado aqui. Quando uma combinação não pode ser escrita no documento com
segurança, a emissão recusa com `422` **antes** de consumir número fiscal (ver
[Erros e respostas](/guides/errors)). Campo aceito e ignorado em silêncio não
existe nesta API.

<AccordionGroup>
  <Accordion title="PIS e COFINS (NF-e e NFC-e)">
    ```json theme={null}
    "pis":    { "cst": "01", "baseCalculo": 1000.00, "aliquota": 1.65, "valor": 16.50 },
    "cofins": { "cst": "01", "baseCalculo": 1000.00, "aliquota": 7.60, "valor": 76.00 }
    ```

    | CST                                         | Grupo no documento     | O que enviar                                                     |
    | ------------------------------------------- | ---------------------- | ---------------------------------------------------------------- |
    | `01`, `02`                                  | Tributado por alíquota | `baseCalculo`, `aliquota` e `valor` (os três)                    |
    | `04`–`09`                                   | Não tributado          | só `cst` (valores diferentes de zero → `422`)                    |
    | `49`–`56`, `60`–`67`, `70`–`75`, `98`, `99` | Outras operações       | `baseCalculo`, `aliquota` e `valor` juntos, ou nenhum            |
    | `03`                                        | Por quantidade         | **não suportado** (`422`), depende de campos fora deste contrato |

    Códigos fora dessas faixas (ex.: `57`, `68`, `76`) não existem na tabela do
    leiaute 4.00 e são recusados com `422`. CST de 1 dígito é normalizado
    (`"1"` → `"01"`).

    Omitir `pis`/`cofins` mantém o comportamento padrão (`CST 99` com valores
    zerados). Os valores informados também somam em `vPIS`/`vCOFINS` no total
    da nota.
  </Accordion>

  <Accordion title="IPI (só NF-e, modelo 55)">
    ```json theme={null}
    "ipi": { "cst": "50", "baseCalculo": 1000.00, "aliquota": 10, "valor": 100.00, "cEnq": "999" }
    ```

    | CST                    | Grupo no documento    | O que enviar                                  |
    | ---------------------- | --------------------- | --------------------------------------------- |
    | `00`, `49`, `50`, `99` | Tributado (IPITrib)   | `baseCalculo`, `aliquota` e `valor` (os três) |
    | `01`–`05`, `51`–`55`   | Não tributado (IPINT) | só `cst` (valores diferentes de zero → `422`) |

    `cEnq` (Código de Enquadramento Legal) é opcional: ausente, transmitimos
    `"999"` (demais casos), o mesmo default do leiaute.

    <Warning>
      **O IPI compõe o total da nota.** Com IPI informado, o documento sai com
      `vNF = produtos + IPI`, e a soma de `pagamentos[].valor` precisa fechar
      com esse total (senão `422 PAGAMENTO_DIVERGENTE`). O `amount` devolvido
      pela API é sempre o `vNF` transmitido.
    </Warning>

    A **NFC-e (modelo 65) não tem grupo de IPI** no leiaute: enviar `ipi` numa
    NFC-e devolve `422 IPI_NAO_SUPORTADO` em vez de emitir sem o imposto.
  </Accordion>

  <Accordion title="IBS/CBS com redução de alíquota (Reforma Tributária)">
    O leiaute da NT 2025.002 separa **dois** números por componente
    (IBS-UF, IBS-Município e CBS):

    * a alíquota **nominal**, que é a que o documento grava em
      `pIBSUF`/`pIBSMun`/`pCBS`;
    * a **redução** do `cClassTrib` mais a alíquota **efetiva**, que vão no
      grupo `gRed` do documento.

    Se o produto tem redução de alíquota (alimento, medicamento, cesta básica
    e a maior parte dos NCMs com anexo), informe os três campos:

    ```json theme={null}
    "ibsCbs": {
      "cst": "200",
      "cClassTrib": "200034",
      "ibsUf":  { "p": 0.04, "pNominal": 0.10, "pRedAliq": 60 },
      "ibsMun": { "p": 0.00, "pNominal": 0.00, "pRedAliq": 60 },
      "cbs":    { "p": 0.36, "pNominal": 0.90, "pRedAliq": 60 }
    }
    ```

    | Campo      | O que é                                                                            |
    | ---------- | ---------------------------------------------------------------------------------- |
    | `p`        | Alíquota **efetiva** (%). É ela que gera o valor do tributo (`v = p × vBC`)        |
    | `pNominal` | Alíquota **nominal** (%), antes da redução; vai no campo da alíquota do documento  |
    | `pRedAliq` | Redução do `cClassTrib` (%, 0 a 100); maior que zero faz o documento emitir `gRed` |

    `pNominal` e `pRedAliq` andam **juntos**, e `p` precisa ser igual a
    `pNominal × (1 − pRedAliq/100)`. Fora disso, a emissão recusa antes de
    consumir número fiscal.

    Produto **sem** redução continua exatamente como antes: só `p` (nominal e
    efetiva são o mesmo número), e o documento sai sem `gRed`.

    <Warning>
      Informar só a alíquota efetiva em `p`, num item que tem redução, faz a
      SEFAZ rejeitar com **cStat 1026** ("Alíquota do IBS da UF inválida"): ela
      compara o campo contra a alíquota nominal vigente. Informar a nominal sem
      o `gRed` cai no outro lado: **cStat 1033** ("o CST obriga informação de
      redução"). Os três campos juntos são o caminho que autoriza.
    </Warning>

    Com `resolverTributacao: true` você não precisa preencher nada disso: o
    Cérebro Fiscal resolve nominal, redução e efetiva do NCM sozinho.
  </Accordion>

  <Accordion title="CEST e ICMS-ST">
    `cest` tem 7 dígitos (ex.: `"0100100"`). Máscara é aceita e normalizada
    (`"01.001.00"` → `0100100`); o que não fecha 7 dígitos → `422 CEST_INVALIDO`.

    Os campos ANTIGOS de **ICMS-ST** (`icms.baseCalculoST`, `aliquotaST`,
    `valorST`) nunca chegaram ao documento e continuam **sem efeito**:
    informá-los com valor diferente de zero devolve `422 ICMS_ST_NAO_SUPORTADO`
    (tudo zero continua emitindo, o documento sai igual). O vocabulário que vale
    é o do leiaute, e ele já emite na NF-e:

    * **Simples Nacional pleno** (`crt: 1`): `icms.csosn` `"201"`, `"202"` ou
      `"203"`, com `modBCST`, `vBCST`, `pICMSST` e `vICMSST`; no `"201"`,
      também `pCredSN` e `vCredICMSSN` (o crédito do artigo 23 da LC 123/2006,
      que sai da sua apuração).
    * **Regime Normal e Simples com excesso de sublimite** (`crt: 3`/`crt: 2`):
      `icms.cst` `"10"`, `"30"` ou `"70"` com os mesmos campos de ST, mais o
      ICMS próprio nos códigos `"10"` e `"70"`.

    Na **NFC-e** a substituição cobrada na operação continua fora, nos dois
    regimes: emita uma NF-e para documentar essa operação.

    No Regime Normal (`resolverTributacao: true`) a recusa acontece **antes**
    disso: basta o **NCM do item estar arrolado no CEST** (Convênio ICMS
    142/2018) para o motor devolver `422 TRIBUTACAO_NAO_RESOLVIDA`, mesmo sem
    nenhum campo de ST no payload. Ver [Regime Normal](/guides/regime-normal)
    para a lista de segmentos afetados.
  </Accordion>
</AccordionGroup>

***

## Campos de Referência

Nomes de campo divergentes deste contrato são rejeitados com `400`.

### Raiz

| Campo                                                 | Tipo    | Obrigatório                              | Descrição                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ----------------------------------------------------- | ------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `naturezaOperacao`                                    | string  | Não                                      | Ex: `"VENDA DE MERCADORIA"`                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `serie`/`numero`/`tpNF`/`indFinal`/`indPres`/`finNFe` | número  | Não                                      | Campos de identificação (`ide`), todos opcionais. `finNFe` aceita 1=normal, 2=complementar, 3=ajuste, 4=devolução, 5=crédito e 6=débito; 2/3/4 exigem `referenciadas`. As finalidades 5/6 existem no leiaute, mas seus casos de uso ainda não têm cobertura ponta a ponta publicada pela engineAPI. Ausente `indFinal`: o motor deriva 1 quando o destinatário é não contribuinte (`indicadorIE: 9` ou CPF); informar 0 nessa hipótese recusa 422 `INDFINAL_INCOERENTE_COM_DESTINATARIO` antes de numerar |
| `idDest`                                              | número  | Não                                      | 1=interna, 2=interestadual, 3=exterior. Ausente: derivado do 1º dígito do CFOP dos itens. A UF do emissor vem do cadastro. Explícito vence sempre. Itens com CFOPs que derivam `idDest` diferentes recusam 422 `CFOP_IDDEST_DIVERGENTE`                                                                                                                                                                                                                                                                   |
| `referenciadas`                                       | array   | Não (**exigido** em `finNFe: 2`/`3`/`4`) | Documento fiscal referenciado, ver abaixo                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `destinatario`                                        | objeto  | **Sim**                                  | Dados do destinatário                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `items`                                               | array   | **Sim** (mín. 1)                         | **Não é `itens`**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `transporte`                                          | objeto  | Não                                      | Dados de transporte (`modFrete` obrigatório se enviado)                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `pagamentos`                                          | array   | **Sim** (mín. 1)                         | **Não é `pagamento` singular**                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `troco`                                               | número  | Não                                      | Troco (NFC-e/venda a consumidor)                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `informacoesComplementares`/`informacoesFisco`        | string  | Não                                      | Informações adicionais                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `resolverTributacao`                                  | boolean | Não                                      | Ativa a emissão assistida (ver acima)                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |

### Destinatário

| Campo         | Tipo                   | Obrigatório | Descrição                                                                                                |
| ------------- | ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------- |
| `cnpjCpf`     | string (11–14 dígitos) | **Sim**     | **Não é `cnpj`/`cpf`** separados                                                                         |
| `nome`        | string                 | **Sim**     | Razão social ou nome                                                                                     |
| `ie`          | string                 | Não         | **Não é `inscricaoEstadual`**. Obrigatória (e validada pela SEFAZ contra o CNPJ) quando `indicadorIE: 1` |
| `indicadorIE` | número                 | Não         | `1` = contribuinte (exige `ie`) · `2` = isento · `9` = não contribuinte                                  |
| `email`       | string                 | Não         | N/A                                                                                                      |
| `endereco.*`  | objeto                 | **Sim**     | Endereço completo (todos os subcampos obrigatórios exceto `complemento`)                                 |

### Item

| Campo           | Tipo                    | Obrigatório | Descrição                                                                                       |
| --------------- | ----------------------- | ----------- | ----------------------------------------------------------------------------------------------- |
| `codigo`        | string                  | **Sim**     | Código interno do produto                                                                       |
| `descricao`     | string                  | **Sim**     | Descrição do produto                                                                            |
| `ncm`           | string (2 ou 8 dígitos) | **Sim**     | Nomenclatura Comum do Mercosul                                                                  |
| `cfop`          | string                  | **Sim**     | Ver [CFOP](/conceitos/cfop-ncm-cst)                                                             |
| `unidade`       | string                  | **Sim**     | `UN`, `KG`, `MT`, `CX`, etc.                                                                    |
| `quantidade`    | número (min 0.0001)     | **Sim**     | Quantidade                                                                                      |
| `valorUnitario` | número (min 0.01)       | **Sim**     | Valor por unidade em R\$                                                                        |
| `valorTotal`    | número                  | Não         | Calculado se ausente                                                                            |
| `cest`          | string (7 dígitos)      | Não         | Código Especificador da ST, sem pontuação (`422 CEST_INVALIDO` se divergir)                     |
| `icms`/`ibsCbs` | objeto                  | Não         | Dados tributários do item (obrigatórios de fato só sem `resolverTributacao`)                    |
| `pis`/`cofins`  | objeto                  | Não         | `cst` + `baseCalculo`/`aliquota`/`valor`, transmitidos como informados (ver acima)              |
| `ipi`           | objeto                  | Não         | Só NF-e. `cst` + `baseCalculo`/`aliquota`/`valor` + `cEnq` opcional. **Compõe o total da nota** |

### Documento referenciado

`referenciadas` é um array na raiz do corpo. Cada entrada tem `chaveAcesso` (44 dígitos, a
chave de acesso da NF-e/NFC-e original), obrigatória em `finNFe: 2` (complementar), `3`
(ajuste) e `4` (devolução):

| Campo         | Tipo                | Obrigatório | Descrição                                                                                                                                                                                                                        |
| ------------- | ------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chaveAcesso` | string (44 dígitos) | **Sim**     | Chave de acesso do documento referenciado: NF-e (`55`), NFC-e (`65`) ou CF-e SAT (`59`). Dígito verificador, código de UF, ano/mês, modelo e número são conferidos antes de emitir (`422 REFERENCIADA_INVALIDA` se não fecharem) |

<Info>
  `finNFe: 3` (ajuste) e `4` (devolução) exigem também a forma de pagamento `"90"` (Sem
  Pagamento): `pagamentos: [{ "forma": "90", "valor": 0 }]`, única entrada e sem `troco`. A
  forma `"90"` descreve uma operação sem contraprestação (remessa, bonificação, comodato,
  devolução), e a conferência de soma dos pagamentos contra o total da nota não se aplica a
  ela. Outra forma junto de `"90"`, ou `troco` maior que zero, recusa com
  `422 SEM_PAGAMENTO_INVALIDO`; na NFC-e a forma `"90"` é vedada
  (`422 SEM_PAGAMENTO_VEDADO_NFCE`). Ver [Erros e
  Rejeições](/guides/errors#documento-referenciado-invlido-e-a-forma-sem-pagamento-422).
</Info>

Na devolução (`finNFe: 4`), cada item precisa informar `documentoReferenciado.nItem` (número do item na nota original, NT 2025.002-RTC VC03). A chave pode vir de `referenciadas[0].chaveAcesso` ou de `documentoReferenciado.chaveAcesso`. Uma devolução completa combina `finNFe: 4`, `referenciadas` apontando a nota original e a
forma de pagamento `"90"`:

```json theme={null}
{
  "naturezaOperacao": "DEVOLUCAO DE MERCADORIA",
  "finNFe": 4,
  "idDest": 1,
  "indFinal": 1,
  "referenciadas": [{ "chaveAcesso": "52260111222333000181550010000001231123456785" }],
  "destinatario": {
    "cnpjCpf": "99888777000100",
    "nome": "Cliente Exemplo SA",
    "endereco": {
      "logradouro": "Av Goiás",
      "numero": "500",
      "bairro": "Centro",
      "codigoMunicipio": "5208707",
      "municipio": "Goiânia",
      "uf": "GO",
      "cep": "74063010"
    },
    "indicadorIE": 9
  },
  "items": [{
    "codigo": "PROD001",
    "descricao": "Camiseta Algodão P",
    "ncm": "61091000",
    "cfop": "5202",
    "unidade": "UN",
    "quantidade": 2,
    "valorUnitario": 59.90,
    "icms": {
      "origem": 0,
      "csosn": "102"
    },
    "documentoReferenciado": { "nItem": 1 }
  }],
  "pagamentos": [{ "forma": "90", "valor": 0 }]
}
```

Escopo de `referenciadas` hoje: só a chave de acesso (`refNFe` do leiaute), aceita para NF-e (`55`), NFC-e (`65`) e CF-e SAT (`59`).
Nota de papel, produtor rural, CT-e e cupom de ECF ainda não são suportados. Ver
[Cobertura fiscal](/cobertura) e [Erros e
Rejeições](/guides/errors#documento-referenciado-invlido-e-a-forma-sem-pagamento-422).

***

## Ciclo de vida da NF-e

Os estados possíveis de uma nota e as transições entre eles:

```mermaid theme={null}
stateDiagram-v2
    [*] --> PROCESSING : POST /v1/nfe
    PROCESSING --> AUTHORIZED : SEFAZ aprova
    PROCESSING --> REJECTED : SEFAZ rejeita (400 com erros[])
    AUTHORIZED --> CANCELED : POST /v1/nfe/{idOuChave}/cancelar (até 24h)
    CANCELED --> [*]
    AUTHORIZED --> [*] : XML + PDF disponíveis

    classDef autorizada fill:#16a34a,stroke:#15803d,color:#fff
    classDef rejeitada fill:#dc2626,stroke:#991b1b,color:#fff
    classDef emAndamento fill:#2D7AF6,stroke:#0F2A5E,color:#fff
    classDef encerrada fill:#0F2A5E,stroke:#0F2A5E,color:#fff
    class AUTHORIZED autorizada
    class REJECTED rejeitada
    class PROCESSING emAndamento
    class CANCELED encerrada
```

<h2 id="contingncia-svc">
  Contingência SVC
</h2>

Quando a SEFAZ do estado do emissor está fora do ar, a engineAPI **reroteia
automaticamente** a transmissão para a SEFAZ Virtual de Contingência (SVC): você não
aciona nada, não muda o payload, não escolhe rota. A mesma chamada `POST /v1/nfe` segue
funcionando; só muda, por baixo, qual webservice recebe a nota.

<Info>
  Zero campo novo no payload. Não existe (nem precisa existir) um campo do tipo
  `contingencia`/`forcarContingencia` no corpo do `POST /v1/nfe`: a decisão é 100%
  automática, calculada a cada emissão a partir do status real da SEFAZ da UF do emissor.
</Info>

Como a engineAPI decide, a cada `POST /v1/nfe`:

1. Consulta o status da SEFAZ da UF do emissor (cache de 5 minutos).
2. **UP**: transmite normal, nada muda.
3. **DOWN**: reroteia para a SVC-AN ou a SVC-RS (o mapa por UF é definido pelo fisco;
   a engineAPI escolhe a rota certa automaticamente).
4. Quando a SEFAZ da UF volta a ficar **UP**, a próxima emissão já transmite normal de
   novo, sem nenhuma ação sua.

<Warning>
  A engineAPI implementa contingência via **SVC (SVC-AN/SVC-RS)**, não via **EPEC**. Se
  algum dia você inspecionar o XML autorizado, o jeito de confirmar que uma nota saiu em
  contingência é o campo `tpEmis` da identificação: normal usa `tpEmis` = 1, SVC-AN usa
  `tpEmis` = 6, SVC-RS usa `tpEmis` = 7. A engineAPI não expõe um status separado tipo
  `CONTINGENCY` no `Invoice`: a nota chega a `AUTHORIZED` (ou `REJECTED`) do mesmo jeito,
  só que autorizada pela SVC.
</Warning>

### Consultar o status da SEFAZ

Para monitorar disponibilidade antes de decidir se vale a pena reagendar um lote, use:

```bash theme={null}
curl https://api.engineapi.com.br/v1/nfe/sefaz-status/GO \
  -H "Authorization: Bearer SEU_TOKEN"
```

```json theme={null}
{
  "data": {
    "uf": "GO",
    "status": "UNKNOWN",
    "message": "Serviço em Operação",
    "responseTimeMs": 245,
    "checkedAt": "2026-07-20T18:00:00.000Z",
    "cStat": 107
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": "2026-07-20T18:00:00.000Z"
  }
}
```

<Warning>
  Esta rota pública **não** usa o certificado de nenhum emissor, por isso `status`
  sempre vem `UNKNOWN` nela (nunca `UP`/`DOWN`): é desenho deliberado, sem uma consulta
  real (cert-backed) a engineAPI nunca fabrica "no ar"/"fora do ar". `message` e `cStat`
  continuam vindo do provider (ex.: `cStat` 107 = Serviço em Operação); só `status` fica
  `UNKNOWN` aqui. A decisão UP/DOWN que de fato aciona o reroteamento pra SVC roda por
  dentro, com o certificado do SEU emissor, no momento de cada emissão, e não é o que esta
  rota devolve. Use-a para inspecionar `message`/`cStat`, não para prever se a próxima
  emissão vai sair via SVC.
</Warning>

`GET /v1/nfe/sefaz-status` (sem UF) devolve o mesmo formato para as 27 UFs de uma vez,
com o mesmo cache de 5 minutos. Ver também [SEFAZ e Webservices](/conceitos/sefaz).

***

## Response de sucesso

Mesmo contrato de resposta nos dois caminhos de emissão (síncrono e fila), envelopado em
`{ data, meta }`:

```json theme={null}
{
  "data": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "AUTHORIZED",
    "accessKey": "35260211222333000181550010000000011000000019",
    "protocol": "135260000001234",
    "number": 1,
    "series": 1,
    "model": "55",
    "amount": "119.8",
    "destCNPJ": "99888777000100",
    "destName": "Cliente Exemplo SA",
    "createdAt": "2026-07-06T12:00:00.000Z",
    "updatedAt": "2026-07-06T12:00:01.000Z",
    "downloads": {
      "xml": "/v1/nfe/xml/35260211222333000181550010000000011000000019",
      "pdf": "/v1/nfe/pdf/35260211222333000181550010000000011000000019"
    }
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": "2026-07-06T12:00:00.000Z"
  }
}
```

<Warning>
  Sem `issuer`/`customer` embutidos (o parceiro já conhece os dois: foi ele quem cadastrou
  o emissor e enviou o destinatário no payload) e sem `xmlPath`/`pdfPath` (caminho de arquivo
  interno do container). `amount` é **string decimal** (`"119.8"`, o `Decimal` do banco
  serializa sem zero à direita, mesmo formato do webhook), nunca `number` cru (evita
  imprecisão de ponto flutuante) nem o formato serializado do decimal interno
  (`{"s":1,"e":2,"d":[...]}"`, bug já corrigido). `downloads.xml`/`downloads.pdf`
  substituem os caminhos internos: são os endpoints reais de download
  (`GET /v1/nfe/xml/{accessKey}`, `GET /v1/nfe/pdf/{accessKey}`).
</Warning>

<Warning>
  **DANFE, mudança de contrato (30/07/2026):** `GET /v1/nfe/pdf/{accessKey}` devolvia
  `text/html`. Agora devolve `application/pdf`: o DANFE oficial gerado a partir do **XML
  autorizado** da nota (ambiente, CST/CSOSN e informações complementares vêm do documento).
  Sem XML autorizado armazenado no ambiente, a resposta é **409** com
  `code: DANFE_INDISPONIVEL`, nunca um documento aproximado.
</Warning>

| Status persistido (`Invoice.status`) | Significado                                   | Ação                                         |
| ------------------------------------ | --------------------------------------------- | -------------------------------------------- |
| `AUTHORIZED`                         | Aprovada pela SEFAZ                           | Nenhuma. Nota válida                         |
| `REJECTED`                           | Rejeitada (resposta HTTP é `400`, ver abaixo) | Corrija e reenvie com nova `Idempotency-Key` |
| `CANCELED`                           | Cancelada                                     | Nota cancelada                               |

***

<h2 id="emisso-em-lote">
  Emissão em lote
</h2>

`POST /v1/nfe/batch` **enfileira** várias notas de uma vez. Cada item de `notas[]` segue
**exatamente o mesmo contrato de `POST /v1/nfe`**: mesmo schema, mesmos campos
obrigatórios, mesmas recusas. Não existe um "formato de lote" separado.

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/nfe/batch \
  -H "x-api-key: ek_live_sua_chave" \
  -H "Content-Type: application/json" \
  -d '{
    "notas": [
      {
        "destinatario": {
          "cnpjCpf": "99888777000100",
          "nome": "Cliente Exemplo SA",
          "endereco": {
            "logradouro": "Av. Paulista",
            "numero": "1000",
            "bairro": "Bela Vista",
            "codigoMunicipio": "3550308",
            "municipio": "São Paulo",
            "uf": "SP",
            "cep": "01310100"
          }
        },
        "items": [
          {
            "codigo": "SKU-001",
            "descricao": "Camiseta Algodão",
            "ncm": "61091000",
            "cfop": "6102",
            "unidade": "UN",
            "quantidade": 2,
            "valorUnitario": 59.9,
            "icms": { "csosn": "102" }
          }
        ],
        "pagamentos": [{ "forma": "01", "valor": 119.8 }]
      }
    ]
  }'
```

Resposta `201`: confirma o **enfileiramento**, não a autorização:

```json theme={null}
{
  "data": { "queued": 1, "ids": ["4b1f0a6e-..."] },
  "meta": { "requestId": "req_abc123", "timestamp": "2026-07-31T12:00:00.000Z" }
}
```

### Regras do lote

São **dois** limites independentes: o de notas e o de tamanho do corpo. O que
morder primeiro depende de quantos itens suas notas têm.

| Regra                            | Comportamento                                                                                                                                                                                                                                                                                                 |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Máximo de notas por chamada      | **50**. Acima disso: `422` com `code: LOTE_ACIMA_DO_LIMITE`, e **nenhuma** nota do envio é enfileirada                                                                                                                                                                                                        |
| Máximo de tamanho do corpo       | **100 kB** (limite global da API, não só do lote). Acima disso: `413` com `code: PAYLOAD_TOO_LARGE` e `details.limiteBytes`/`details.tamanhoBytes`                                                                                                                                                            |
| Validação de cada nota           | Idêntica ao `POST /v1/nfe`. Qualquer nota inválida reprova o **lote inteiro** com `400`                                                                                                                                                                                                                       |
| Onde o erro aponta               | `errors[].field` traz o índice da nota, ex.: `notas.2.items.0.ncm`                                                                                                                                                                                                                                            |
| Ordem de checagem                | Forma **antes** de tamanho de lote: um envio com 60 notas em que uma é inválida recebe `400` (validação), não `422`. Corrija a nota e o `422` do limite aparece no reenvio                                                                                                                                    |
| Emissor                          | Um lote emite por **um** emissor: use `issuerId` na raiz do corpo. `issuerId` dentro de uma nota divergindo do lote → `422` `ISSUER_DIVERGENTE_NO_LOTE`                                                                                                                                                       |
| `numero` explícito               | Se você mandar `numero` nas notas, a API **não** checa colisão entre as notas do mesmo lote. Duas notas com o mesmo `numero`/série: a primeira emite, a segunda falha na SEFAZ por duplicidade e aparece como `FAILED` em `GET /v1/nfe/queue`. Omita `numero` para deixar a numeração automática cuidar disso |
| Campos não previstos no contrato | São descartados antes do enfileiramento (mesmo comportamento do endpoint singular)                                                                                                                                                                                                                            |

<Info>
  **Quantas notas cabem de verdade?** Uma nota com 1 item ocupa \~1,3 kB de JSON;
  com 10 itens, \~3,5 kB. Na prática: 50 notas de 1 item cabem folgado (\~64 kB),
  mas 50 notas de 10 itens somam \~175 kB e batem no `413`. Se você emite notas
  com muitos itens, use lotes menores; o corpo do `413` diz o tamanho enviado e
  o limite.
</Info>

<Warning>
  **Mudança de contrato (31/07/2026):** até esta versão o lote **não validava nada**: um
  payload que o `POST /v1/nfe` recusaria era aceito e só quebrava lá na frente, dentro da
  fila. Agora o lote recusa na porta, com o mesmo `400`/`422` do endpoint singular. Se a sua
  integração de lote enviava algo que o singular já recusava, ela passa a receber a recusa;
  o corpo do erro diz exatamente qual nota e qual campo.
</Warning>

### Consultando o desfecho

O `201` é só o aceite na fila. O desfecho fiscal de cada nota vem de
`GET /v1/nfe/queue` (filtrável por `status`: `PENDING`, `PROCESSING`, `DONE`, `FAILED`):

```bash theme={null}
curl https://api.engineapi.com.br/v1/nfe/queue?status=FAILED \
  -H "x-api-key: ek_live_sua_chave"
```

Item que falhou traz `lastError` (texto) e `resultData.error` com o **código estruturado**
(`code`): o mesmo código que o endpoint singular devolveria para o mesmo payload. Recusa
determinística (ex.: `CST_REGIME_INCOMPATIVEL`, `PAGAMENTO_DIVERGENTE`,
`CADASTRO_EMISSOR_INCOMPLETO`, `EMISSOR_INEXISTENTE`) vai direto para `FAILED`, **sem
retry**: repetir não muda o desfecho, e **nenhum número da sequência fiscal é consumido**.
Corrija o payload e reenvie.

<Info>
  `EMISSOR_INEXISTENTE` cobre o caso de o emissor ser removido **entre** o
  enfileiramento e o processamento: a nota falha na hora, sem gastar tentativas e
  sem consumir número. Reenvie o lote apontando para um emissor válido.
</Info>

***

<h2 id="cancelamento">
  Cancelamento
</h2>

Cancele uma NF-e autorizada em até **24 horas** após a autorização. Prazo geral, também
regulamentado por UF.

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/nfe/{idOuChave}/cancelar \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "justificativa": "Erro nos dados do destinatário informado na venda" }'
```

`idOuChave` aceita o `id` (UUID) da NF-e **ou** a chave de acesso (44 dígitos). O campo
do corpo é `justificativa` (mínimo 15  caracteres); a rota aceita tanto JWT do painel
quanto `x-api-key` de integração.

<Warning>
  O prazo da **NFC-e** (modelo 65) é **muito menor**: 30 minutos, padrão nacional por UF. Não
  assuma o mesmo prazo para os dois modelos; veja o [guia de NFC-e](/guides/nfce#cancelamento)
  para os detalhes.
</Warning>

Se o cancelamento for solicitado fora do prazo, a SEFAZ rejeita (cStat 501) e a engineAPI
repassa o desfecho verbatim no `400`, mesmo formato descrito em
[Tratamento de Erros](#tratamento-de-erros) abaixo.

<Warning>
  **O DANFE de uma nota cancelada não traz carimbo de cancelamento.** O PDF servido por
  `GET /v1/nfe/pdf/{accessKey}` é o documento gerado a partir do **XML de autorização**:
  ele não muda quando o cancelamento é homologado, porque o evento de cancelamento é um
  documento fiscal separado (o XML do evento, com o protocolo). Para provar que a nota foi
  cancelada, use o `status` do documento (`CANCELED`) ou o XML do evento, nunca a ausência
  de carimbo no DANFE.
</Warning>

***

## Carta de Correção (CC-e)

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/nfe/{accessKey}/carta-correcao \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "correcao": "Corrijo o endereço do destinatário para Av Brasil, 500" }'
```

Só permitida em NF-e com status `AUTHORIZED`; limite de 20 CC-e por nota. O corpo aceita
`correcao` (mínimo 15 caracteres). Assim como o cancelamento, aceita JWT **ou** `x-api-key`.

***

<h2 id="inutilizao">
  Inutilização
</h2>

Inutilize uma **faixa de numeração** que nunca será usada. O caso típico é uma nota
rejeitada de forma definitiva, que consome o número mas nunca chega a `AUTHORIZED`: sem
inutilizar, esse número fica um gap permanente na sequência fiscal.

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/nfe/inutilizar \
  -H "x-api-key: SUA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "serie": 1,
    "numInicial": 45,
    "numFinal": 45,
    "justificativa": "Numero pulado por falha no sistema de emissao"
  }'
```

| Campo           | Tipo                          | Obrigatório | Descrição                                                                                                                                                                                                                                                                                                                                                                  |
| --------------- | ----------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `serie`         | número (ou string só-dígitos) | **Sim**     | Série da faixa a inutilizar (inteiro 0–999 )                                                                                                                                                                                                                                                                                                                               |
| `numInicial`    | número (ou string só-dígitos) | **Sim**     | Primeiro número da faixa (inteiro 1–999999999 )                                                                                                                                                                                                                                                                                                                            |
| `numFinal`      | número (ou string só-dígitos) | **Sim**     | Último número da faixa (inteiro 1–999999999 ), precisa ser **maior ou igual** a `numInicial`, e a faixa (`numFinal - numInicial + 1`) não pode passar de **10.000  números por chamada**                                                                                                                                                                                   |
| `justificativa` | string                        | **Sim**     | Entre **15  e 255  caracteres** (limite do campo `xJust` do leiaute)                                                                                                                                                                                                                                                                                                       |
| `issuerId`      | string (UUID)                 | Não         | Só necessário com 2+ emissores cadastrados                                                                                                                                                                                                                                                                                                                                 |
| `ano`           | número                        | Não         | Ano-calendário da numeração inutilizada, **entre `anoCorrente - 5 {/* fact:validation.inutilizarNfe.anoJanelaAnos */}` e `anoCorrente`**. Default: ano corrente. Use quando o número foi pulado num ano e a inutilização só está sendo feita no ano seguinte (ex.: gap aberto em dezembro, inutilizado em janeiro). Sem isso a inutilização seria registrada no ano ERRADO |

O corpo é validado com mensagens de erro no padrão pt-BR do resto da API
(ex.: "Justificativa deve ter no mínimo 15  caracteres (exigência SEFAZ)"). Os campos numéricos aceitam `number` ou `string` só-dígitos
(`"45"`), mas rejeitam `null`, `""`, array e boolean com uma mensagem pt-BR acionável (nunca o
"Invalid input" genérico) e nunca coagem silenciosamente pra `0`.

Quando a SEFAZ **homologa** a inutilização (`cStat 102`), a resposta vem `HTTP 200` com
`success` `true`:

```json theme={null}
{
  "data": {
    "success": true,
    "protocol": "135260000009876",
    "message": "Inutilização série 1 nº 45 a 45 homologada",
    "xml": "<inutNFe>...</inutNFe>"
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": "2026-07-20T12:00:00.000Z"
  }
}
```

<Warning>
  O campo `xml` (XML de retorno da SEFAZ) é servido **quando o motor fiscal o devolve**:
  trate como opcional na sua integração, não como garantia contratual. `protocol` e
  `message` são os campos com prova de emissão real.
</Warning>

Quando a SEFAZ **rejeita** o pedido (qualquer `cStat` diferente de 102), a engineAPI
NÃO traduz isso em `4xx`: o desfecho vem no próprio corpo, ainda em `HTTP 200`, com
`success` `false`:

```json theme={null}
{
  "data": {
    "success": false,
    "cStat": 563,
    "xMotivo": "Rejeicao: Ja existe pedido de Inutilizacao com a mesma faixa de numeracao",
    "erros": [
      { "codigo": "563", "descricao": "Rejeicao: Ja existe pedido de Inutilizacao com a mesma faixa de numeracao" }
    ],
    "message": "Rejeicao: Ja existe pedido de Inutilizacao com a mesma faixa de numeracao"
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": "2026-07-20T12:00:00.000Z"
  }
}
```

<Warning>
  Ramifique pelo campo **`success`**, não pelo status HTTP: rejeição da SEFAZ na
  inutilização **não** é `400`. Ver também [Erros e respostas](/guides/errors).
</Warning>

**Outros status possíveis** (nenhum é "sempre 200": só o desfecho da SEFAZ é):

| Status | Quando                                                                                                                                         | Corpo                               |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
| `400`  | `serie`/`numInicial`/`numFinal`/`justificativa` inválidos (shape, tipo ou `numFinal < numInicial`), ou 2+ emissores cadastrados sem `issuerId` | Erro de validação padrão (RFC 7807) |
| `403`  | Partner sem nenhum emissor cadastrado                                                                                                          | Erro padrão                         |
| `404`  | `issuerId` informado não pertence ao partner autenticado                                                                                       | Erro padrão                         |
| `422`  | `CERTIFICADO_AUSENTE` (emissor sem certificado A1 instalado) ou `FAIXA_INUTILIZACAO_MUITO_GRANDE` (mais de 10.000  números na faixa)           | `{ code, message, details }`        |
| `500`  | Timeout na comunicação com a SEFAZ (120s): a inutilização **pode ou não** ter sido homologada do lado da SEFAZ, a resposta não chegou a tempo  | Erro genérico                       |

<Warning>
  **O 500 de timeout é ambíguo de propósito** (a SEFAZ pode ter homologado sem a
  resposta voltar a tempo). Nunca reenvie a mesma faixa sem cuidado: um reenvio comum
  pode colidir com uma inutilização que JÁ foi homologada (`cStat 563`, "já existe
  pedido"). Envie sempre com o header **`Idempotency-Key: <uuid>`** (suportado
  globalmente por todo `POST`/`PUT`/`PATCH` da API). Reenviar com a MESMA key repete o
  resultado já concluído (replay), sem reprocessar. Gere uma key nova só quando for de
  fato uma faixa diferente.
</Warning>

Mesmo motor por trás do [`POST /v1/nfce/inutilizar`](/guides/nfce#inutilizao) (modelo 65):
o worker de emissão e o desfecho da SEFAZ são genéricos por modelo; só o endpoint muda.

***

<h2 id="tratamento-de-erros">
  Tratamento de Erros
</h2>

### Rejeição SEFAZ (400)

Quando a SEFAZ rejeita a nota (cStat de rejeição), a API responde **HTTP 400**
com o envelope de erro padrão (RFC 7807) carregando `error.erros[]`, o
`cStat`/`xMotivo` **verbatim** da SEFAZ, sem tradução:

```json theme={null}
{
  "error": {
    "type": "https://engineapi.com.br/errors/BAD_REQUEST",
    "title": "Requisição Inválida",
    "status": 400,
    "detail": "SEFAZ rejeitou (CStat=696): Rejeicao: Obrigatoria as informacoes do responsavel tecnico pela emissao do DF-e",
    "erros": [
      {
        "codigo": "696",
        "descricao": "Rejeicao: Obrigatoria as informacoes do responsavel tecnico pela emissao do DF-e"
      }
    ],
    "instance": "/v1/nfe",
    "requestId": "req_uofirusmuamw",
    "timestamp": "2026-07-05T11:06:14.453Z"
  }
}
```

<Warning>
  Ramifique pelo `error.erros[].codigo` (o cStat da SEFAZ) e consulte a
  [tabela oficial de rejeições](https://www.nfe.fazenda.gov.br/portal/listaConteudo.aspx?tipoConteudo=BMPFMBoln3w=)
  da Fazenda. A nota fica com status `REJECTED` e o webhook `invoice.rejected`
  é disparado com o mesmo `erros[]`. Rejeição é um desfecho **determinístico**:
  reenviar com a mesma `Idempotency-Key` devolve a **mesma** rejeição (replay,
  sem retransmitir à SEFAZ). Corrija os dados e emita com uma key nova.
  Falhas de infraestrutura genuínas (timeout, indisponibilidade da SEFAZ)
  continuam respondendo `500` e podem ser retentadas com a mesma key.
  Certificado A1 ausente e cadastro do emissor incompleto (IE, endereço) **não**
  chegam a `500`: a API valida ANTES de acionar o worker de emissão e responde `422`
  estruturado: ver [Pré-voo do emissor](/guides/errors#pr-voo-do-emissor-422-quando-aparece).
</Warning>

***

## Webhook após emissão

A engineAPI dispara automaticamente um evento `invoice.authorized` quando a SEFAZ aprova:

```json theme={null}
{
  "id": "9f1c2b3a-...-uuid",
  "type": "invoice.authorized",
  "timestamp": "2026-04-26T18:30:00.000Z",
  "data": {
    "invoiceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "model": "55",
    "number": 1,
    "series": 1,
    "accessKey": "35260211222333000181550010000000011000000019",
    "status": "AUTHORIZED",
    "amount": 119.80
  }
}
```

Configure seus webhooks em **Dashboard → Configurações → Webhooks** ou via [guia de webhooks](/guides/webhooks).

***

## Veja também

* **[Cancelar/Corrigir](/api-reference/overview):** cancelamento e Carta de Correção (ver acima).
* **[Erros e respostas](/guides/errors):** o envelope RFC 7807 completo.
* **[Webhooks](/guides/webhooks):** receba notificações automáticas em tempo real.
* **[Paginação](/guides/paginacao):** contrato de `page`/`limit`/`sortBy` usado em `GET /v1/nfe`.
