> ## 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 NFC-e

> Como emitir o documento fiscal de venda a consumidor final, com QR Code e cupom em PDF, numa única chamada.

A NFC-e (modelo 65) é o documento fiscal para **vendas a consumidor final** no varejo. Substitui o cupom fiscal e deve ser emitida no momento da venda.

**Endpoint base:** `https://api.engineapi.com.br/v1/nfce`

## Situação indeterminada

Consulte `GET /v1/nfce?situacao=indeterminada&page=1&limit=20` quando uma NFC-e tiver
chave de acesso e ainda não tiver desfecho terminal. Este filtro é exclusivo de `status`,
preserva o modelo 65 e informa `situacao`, `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, Itens, Impostos, Pagamento...) e gerada direto do
  contrato real, está no [**Catálogo de campos: NFC-e**](/api-reference/campos-nfce). Para
  navegar por endpoint em vez de por documento, veja a
  [Referência da API](/api-reference/overview).
</Info>

<CardGroup cols={3}>
  <Card title="Ponto de venda" icon="cash-register">
    Ideal para varejo e e-commerce com venda direta
  </Card>

  <Card title="QR Code incluso" icon="qrcode">
    Resposta inclui `qrCode` para consulta do consumidor
  </Card>

  <Card title="DANFCE em PDF" icon="file-pdf">
    Download do cupom fiscal em PDF, gerado do XML autorizado
  </Card>
</CardGroup>

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

***

## Pré-requisitos

<Steps>
  <Step title="Empresa e certificado, como na NF-e">
    NFC-e usa o **mesmo cadastro de emissor** da NF-e: CNPJ (`POST /v1/companies`), IE,
    endereço completo e certificado digital A1. Ver [Emissão de NF-e](/guides/emitir-nfe) (seção
    Pré-requisitos, no topo do guia).
  </Step>

  <Step title="CSC: Código de Segurança do Contribuinte (obrigatório fora do sandbox)">
    Todo emissor **real** (fora do ambiente sandbox/homologação de testes) precisa ter
    `csc` (o token) e `cscId` (o ID do token) cadastrados em **Dashboard → Emissores →
    (selecione o emissor) → aba NFC-e**, antes de emitir. Gere/consulte o CSC no portal
    da SEFAZ do seu estado (Contribuinte → NFC-e → Autorização de Uso do CSC). Sem ele, a
    API responde **422 `CSC_AUSENTE`**, nenhum número da sequência fiscal é consumido.
    Emissores em sandbox (toda conta nova nasce assim) emitem normalmente sem CSC.

    **Copie o código sem sujeira.** O CSC entra byte a byte no hash do QR-Code:
    um espaço no fim, uma quebra de linha do copiar-e-colar ou um caractere
    invisível (espaço não separável, zero-width, BOM) mudam o hash e a SEFAZ
    rejeita a nota com **`CStat 464`: Código de Hash no QR-Code difere do
    calculado**. Por isso o cadastro recusa esses valores na entrada: `csc`
    aceita só caracteres imprimíveis sem espaço, e `cscId` só de 1 a 6 dígitos
    (é o `cIdToken` do leiaute). Se o 464 aparecer mesmo com o código limpo, o
    par `csc`/`cscId` gravado não é o que a SEFAZ tem registrado para o seu
    CNPJ. Confira no portal e regrave **os dois juntos**.
  </Step>
</Steps>

***

## Diferenças NF-e vs NFC-e

| Aspecto      | NF-e (modelo 55)                               | NFC-e (modelo 65)                            |
| ------------ | ---------------------------------------------- | -------------------------------------------- |
| Destinatário | `destinatario` completo (endereço obrigatório) | `destCPF`/`destNome` opcionais, sem endereço |
| CFOP         | 5102, 6102...                                  | Predominantemente estadual                   |
| QR Code      | Não                                            | Sim, no campo `qrCode` da resposta           |
| Cancelamento | Até 24h                                        | Até **30 minutos**                           |
| Uso          | B2B e B2C                                      | Somente B2C (varejo)                         |

***

## Emitir NFC-e

O item da NFC-e reusa o mesmo grupo `ibsCbs` da NF-e (Reforma Tributária); os demais campos
são específicos.

<Note>
  Produto com **redução de alíquota** (alimento, medicamento, cesta básica, o
  caso comum no varejo de NFC-e) precisa de `pNominal` e `pRedAliq` além da
  alíquota efetiva `p` em cada componente do `ibsCbs`. A regra é a mesma da
  NF-e: ver [IBS/CBS com redução de alíquota](/guides/emitir-nfe#pis-cofins-e-ipi).
  Com `resolverTributacao: true` o Cérebro Fiscal resolve isso sozinho.
</Note>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.engineapi.com.br/v1/nfce \
    -H "x-api-key: SUA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "destCPF": "12345678909",
      "destNome": "Consumidor Final",
      "items": [{
        "codigo": "PROD001",
        "descricao": "Camiseta Azul M",
        "ncm": "61091000",
        "cfop": "5102",
        "unidade": "UN",
        "quantidade": 1,
        "valorUnitario": 89.90,
        "icms": { "origem": 0, "csosn": "400" }
      }],
      "pagamentos": [
        {
          "forma": "03",
          "valor": 89.90,
          "cartao": {
            "tpIntegra": 1,
            "cnpjInstituicao": "00000000000191",
            "bandeira": "01",
            "autorizacao": "AUTH123456"
          }
        }
      ]
    }'
  ```

  ```typescript TypeScript theme={null}
  const nfce = await fetch('https://api.engineapi.com.br/v1/nfce', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.ENGINE_API_KEY!,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      destCPF: '12345678909',
      destNome: 'Consumidor Final',
      items: [{
        codigo: 'PROD001', descricao: 'Camiseta Azul M',
        ncm: '61091000', cfop: '5102', unidade: 'UN',
        quantidade: 1, valorUnitario: 89.90,
        icms: { origem: 0, csosn: '400' },
      }],
      pagamentos: [{
        forma: '03',
        valor: 89.90,
        cartao: {
          tpIntegra: 1,
          cnpjInstituicao: '00000000000191',
          bandeira: '01',
          autorizacao: 'AUTH123456',
        },
      }],
    }),
  }).then(r => r.json());

  console.log('NFCe autorizada:', nfce.data.accessKey);
  console.log('QR Code:', nfce.data.qrCode);
  ```
</CodeGroup>

<h3 id="campos-de-referncia">
  Campos de referência
</h3>

| Campo                       | Tipo    | Obrigatório      | Descrição                                                                                                                                                                                                                                                                                                                                                         |
| --------------------------- | ------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `serie`/`numero`            | número  | Não              | Identificação, geralmente alocados automaticamente                                                                                                                                                                                                                                                                                                                |
| `destCPF`/`destNome`        | string  | Não              | Dados do consumidor final (sem endereço)                                                                                                                                                                                                                                                                                                                          |
| `indPres`                   | número  | Não              | Indicador de presença do comprador. `1` presencial (padrão quando ausente), `2` internet, `3` teleatendimento, `4` NFC-e com entrega em domicílio, `5` presencial fora do estabelecimento, `9` não presencial outros. Declare o valor real da operação: venda por delivery/telefone/internet emitida com `indPres=1` (ou ausente) é uma declaração falsa ao fisco |
| `items`                     | array   | **Sim** (mín. 1) | Mesmos campos de item da NF-e (`codigo`, `descricao`, `ncm`, `cfop`, `unidade`, `quantidade`, `valorUnitario`, `cest`, `icms`/`pis`/`cofins`/`ibsCbs`)                                                                                                                                                                                                            |
| `pagamentos`                | array   | **Sim** (mín. 1) | `{ forma, valor, cartao? }`, **não é objeto singular `pagamento`**. Formas `"03"`/`"04"`/`"17"` exigem `cartao.tpIntegra` (`1` ou `2`). Sem ele a API recusa `422 PAGAMENTO_SEM_DADOS_DO_MEIO` antes de numerar. Demais campos do grupo são opcionais                                                                                                             |
| `troco`                     | número  | Não              | N/A                                                                                                                                                                                                                                                                                                                                                               |
| `informacoesComplementares` | string  | Não              | N/A                                                                                                                                                                                                                                                                                                                                                               |
| `resolverTributacao`        | boolean | Não              | Emissão assistida (Cérebro Fiscal), mesmo contrato da NF-e, ver [Emissão de NF-e](/guides/emitir-nfe#icms-por-regime-tributario)                                                                                                                                                                                                                                  |

`pis`/`cofins` e `cest` seguem exatamente as regras da NF-e (valores informados
vão para o documento; combinação sem efeito é recusada com `422`, ver
[PIS, COFINS e IPI](/guides/emitir-nfe#pis-cofins-e-ipi)). **IPI não existe no
modelo 65** e **ICMS-ST não é escrito**: os campos `ipi` e
`icms.baseCalculoST/aliquotaST/valorST` são aceitos no contrato **apenas para
poder recusar**: com valor diferente de zero devolvem `422 IPI_NAO_SUPORTADO`
e `422 ICMS_ST_NAO_SUPORTADO`, em vez de emitir a NFC-e sem o dado.

***

## Formas de Pagamento

| Código | Forma             |
| ------ | ----------------- |
| `01`   | Dinheiro          |
| `02`   | Cheque            |
| `03`   | Cartão de Crédito |
| `04`   | Cartão de Débito  |
| `05`   | Crédito Loja      |
| `10`   | Vale Alimentação  |
| `11`   | Vale Refeição     |
| `13`   | Vale Presente     |
| `15`   | Boleto            |
| `99`   | Outros            |

***

## Response de Sucesso

Envelopado em `{ data, meta }`, **sem** aninhamento `nfce`:

```json theme={null}
{
  "data": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "AUTHORIZED",
    "accessKey": "35260211222333000181650010000000011000000019",
    "protocol": "135260000001234",
    "number": 1,
    "series": 1,
    "model": "65",
    "amount": "89.9",
    "destCNPJ": "12345678909",
    "destName": "Consumidor Final",
    "qrCode": "https://www.fazenda.sp.gov.br/nfce/qrcode?p=35260...",
    "createdAt": "2026-07-06T12:00:00.000Z",
    "updatedAt": "2026-07-06T12:00:01.000Z",
    "downloads": {
      "xml": "/v1/nfce/xml/35260211222333000181650010000000011000000019",
      "pdf": "/v1/nfce/pdf/35260211222333000181650010000000011000000019"
    }
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": "2026-07-06T12:00:00.000Z"
  }
}
```

Sem `issuer`/`customer` embutidos e sem `xml`/`xmlPath`/`pdfPath`/`invoiceId`/`message`
(caminho de arquivo interno / shape antigo, removido). `status` é `"AUTHORIZED"` (inglês,
mesmo enum de sempre). `amount` é **string decimal** (`"89.9"`, sem zero à direita). `qrCode` é exclusivo da
NFC-e, não é coluna do banco, só existe na resposta da emissão (guarde-o no seu lado se
precisar reimprimir o cupom depois). Não há campos `cupomUrl`/`xmlUrl`, use
`downloads.xml`/`downloads.pdf` (mesmas rotas de download descritas abaixo).

***

## Download do Cupom Fiscal

O DANFCE é retornado como **PDF** (`Content-Type: application/pdf`), não passa pelo
envelope `{data,meta}`, o corpo é o arquivo:

```bash theme={null}
curl https://api.engineapi.com.br/v1/nfce/pdf/{accessKey} \
  -H "x-api-key: SUA_API_KEY" \
  -o cupom.pdf
```

O documento é gerado a partir do **XML autorizado** da própria nota, no layout de cupom
fiscal: ambiente (`tpAmb`), tributação (CST/CSOSN) e informações complementares saem do
documento, nunca de uma remontagem.

<Warning>
  **Mudança de contrato (30/07/2026):** esta rota devolvia `text/html`. Agora devolve
  `application/pdf`. Se você salvava a resposta como `.html`, passe a salvar como `.pdf`.
</Warning>

Quando o XML autorizado não está armazenado neste ambiente (por exemplo, emissão em
sandbox), a resposta é **409** com `code: DANFE_INDISPONIVEL`, nunca um documento
aproximado.

### Download do XML

```bash theme={null}
curl https://api.engineapi.com.br/v1/nfce/xml/{accessKey} \
  -H "x-api-key: SUA_API_KEY"
```

***

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

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/nfce/{idOuChave}/cancelar \
  -H "x-api-key: SUA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "justificativa": "Erro na forma de pagamento informada na venda" }'
```

`{idOuChave}` aceita o **UUID** (`id` da resposta de emissão) **ou** a **chave de acesso**
(44 dígitos numéricos) da NFC-e, mesmo contrato do [cancelamento de NF-e](/guides/emitir-nfe#cancelamento).
Sempre escopado ao seu partner (usar id/chave de outro partner devolve o mesmo 404 de
"não existe"). O campo do corpo é `justificativa` (mínimo 15  caracteres), **não** `motivo`.

<Warning>
  **O DANFCE de uma nota cancelada não traz carimbo de cancelamento.** O PDF servido por
  `GET /v1/nfce/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 DANFCE.
</Warning>

<Warning>
  **Prazo: 30 minutos** contados da autorização de uso, desde que a mercadoria não tenha
  circulado. Esse é o prazo **padrão nacional** (Ajuste SINIEF 07/18) e é definido **por UF**;
  em **Goiás**, está fixado no **art. 167-S-Q do RCTE-GO**. É muito menor que o prazo da
  NF-e (24h): não assuma o mesmo prazo para os dois modelos.
</Warning>

### Fora do prazo: cStat 501

Se o cancelamento for solicitado após o prazo da UF, a SEFAZ rejeita e a engineAPI repassa
o desfecho **verbatim** no corpo `400`:

```json theme={null}
{
  "error": {
    "erros": [
      {
        "codigo": "501",
        "descricao": "Rejeicao: Prazo de cancelamento superior ao previsto na Legislacao"
      }
    ]
  }
}
```

A nota permanece com status `AUTHORIZED`. **Não existe cancelamento extemporâneo de NFC-e
via API**. O remédio legal é emitir uma **NF-e de devolução** com `finNFe: 4`, a
nota original em `referenciadas` e pagamento sem pagamento (`forma: "90"`, valor
zero); a API aceita e valida essa finalidade antes de numerar. Veja também o catálogo
de [Erros e respostas](/guides/errors).

***

<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.

<Warning>
  Este endpoint é **exclusivo da NFC-e (modelo 65)**. Para NF-e (modelo 55), use
  [`POST /v1/nfe/inutilizar`](/guides/emitir-nfe#inutilizao): mesmo contrato, mesmo motor por
  trás (o worker de emissão e o desfecho da SEFAZ são genéricos por modelo).
</Warning>

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/nfce/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 PDV local"
  }'
```

| Campo           | Tipo                          | Obrigatório | Descrição                                                                                                                                                                                                                                                                                                                                                                   |
| --------------- | ----------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `serie`         | número (ou string só-dígitos) | **Sim**     | Série da faixa a inutilizar (inteiro 0–999 ); ver [Campos de referência](#campos-de-referncia)                                                                                                                                                                                                                                                                              |
| `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.inutilizarNfce.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/nfe/inutilizar`](/guides/emitir-nfe#inutilizao) (modelo 55):
o worker de emissão e o desfecho da SEFAZ são genéricos por modelo; só o endpoint muda.

***

## Contingência offline (SEFAZ fora do ar)

Quando a SEFAZ da UF do emissor está indisponível, a engineAPI **emite mesmo assim**:
a NFC-e é assinada em **contingência offline** (`tpEmis 9`), devolvida com XML, QR Code e
DANFCE para o PDV imprimir na hora, e transmitida automaticamente quando o autorizador
voltar. O caixa não para.

<Info>
  Isto vale para o PDV que **alcança a engineAPI** e não consegue chegar à SEFAZ, que é o
  caso comum de indisponibilidade estadual. Um PDV **sem nenhuma internet** não é resolvido
  por API na nuvem: se esse é o seu cenário, fale com o time antes de desenhar a integração.
</Info>

### Quando a contingência entra

Sem você fazer nada, em três situações:

| gatilho                  | quando acontece                                                                                                                                                                                                                               |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Você pede**            | `"contingencia": true` no corpo do `POST /v1/nfce`. Use quando o seu PDV já sabe que a SEFAZ caiu                                                                                                                                             |
| **Monitoramento**        | a engineAPI consulta as 27 UFs a cada 5 minutos com certificado próprio; UF marcada como fora do ar entra em contingência automaticamente                                                                                                     |
| **Falha na transmissão** | a transmissão normal estourou o tempo/conexão **e** a consulta da chave na SEFAZ respondeu que **a nota não existe lá**. Uma **rejeição fiscal** (CSOSN errado, NCM inválido) nunca vira contingência: o erro continua sendo devolvido a você |

Para **desligar** a contingência automática numa nota específica, envie
`"contingencia": false`. Nesse caso a emissão falha quando a SEFAZ estiver fora, e você
decide o que fazer.

#### Quando a SEFAZ não responde nem à consulta

No terceiro gatilho, a engineAPI **só** emite a segunda nota se a SEFAZ responder que a
chave não existe. Existem dois outros desfechos, e eles importam para o seu caixa:

| a consulta responde                | o que acontece                                                               | por quê                                                                                                                                                                           |
| ---------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **a nota já está autorizada**      | você recebe `201` com `status: "AUTHORIZED"` e o **protocolo real** da SEFAZ | a nota existe; era só a resposta que tinha se perdido. Emitir de novo criaria duas notas com o mesmo número                                                                       |
| **a consulta também não responde** | `503` com o código `CONTINGENCIA_SITUACAO_INDETERMINADA`                     | não dá para saber se a SEFAZ autorizou. Emitir em contingência com o mesmo número colocaria na mão do consumidor um cupom que a SEFAZ vai recusar depois, e isso não tem conserto |

No caso do `503`, a nota fica registrada com a chave original e a engineAPI a **reconcilia
sozinha**: quando a SEFAZ voltar, você recebe `invoice.authorized` ou `invoice.rejected`.
Para continuar vendendo na hora, emita a **próxima venda** com `"contingencia": true`: ela
sai em contingência offline com número próprio. O corpo do erro traz `details.invoiceId`,
`details.accessKey`, `details.numero` e `details.serie` para você registrar o ocorrido.

### Emitir em contingência

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/nfce \
  -H "Authorization: Bearer $ENGINEAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contingencia": true,
    "justificativaContingencia": "SEFAZ GO sem resposta desde as 14h30",
    "items": [
      {
        "codigo": "001",
        "descricao": "Agua mineral 500ml",
        "ncm": "22011000",
        "cfop": "5102",
        "unidade": "UN",
        "quantidade": 2,
        "valorUnitario": 3.5,
        "icms": { "origem": 0, "csosn": "102" }
      }
    ],
    "pagamentos": [{ "forma": "01", "valor": 7.0 }]
  }'
```

`justificativaContingencia` é **opcional** e tem de 15 a 256 caracteres (é o `xJust` do
leiaute, impresso no documento fiscal). Fora dessa faixa a API responde
**422 `JUSTIFICATIVA_CONTINGENCIA_INVALIDA`** antes de consumir qualquer número. Sem o
campo, a engineAPI usa "Indisponibilidade do servico de autorizacao da SEFAZ da UF do
emitente".

### Resposta

```json theme={null}
{
  "data": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "CONTINGENCIA_PENDENTE",
    "accessKey": "35260911222333000181650010000000429000000429",
    "protocol": null,
    "number": 42,
    "series": 1,
    "model": "65",
    "amount": "7",
    "qrCode": "https://www.sefaz.go.gov.br/nfeweb/sites/nfce/danfeNFCe?p=35260...",
    "contingencia": {
      "tpEmis": "9",
      "motivo": "SOLICITADA_PELO_INTEGRADOR",
      "justificativa": "SEFAZ GO sem resposta desde as 14h30",
      "entrouEmContingenciaEm": "2026-09-17T14:31:02.000Z",
      "transmitirAte": "2026-09-18T14:31:02.000Z",
      "horasRestantes": 24,
      "descricao": "Documento assinado e válido para entrega ao consumidor. A engineAPI transmite automaticamente quando a SEFAZ voltar; o desfecho chega pelos webhooks invoice.authorized ou invoice.rejected."
    },
    "downloads": {
      "xml": "/v1/nfce/xml/35260911222333000181650010000000429000000429",
      "pdf": "/v1/nfce/pdf/35260911222333000181650010000000429000000429"
    }
  }
}
```

Três diferenças em relação à emissão normal, e cada uma importa para o seu código:

* **`status` é `CONTINGENCIA_PENDENTE`**, não `AUTHORIZED`. O documento é legal e pode ser
  entregue ao consumidor, mas a SEFAZ ainda não o autorizou.
* **`protocol` é `null`.** Protocolo só existe depois da transmissão. Não trate a ausência
  como erro.
* O **35º dígito da chave de acesso é `9`** (é o `tpEmis`). O número fiscal é o mesmo de
  sempre, sem pulo na sequência.

O `qrCode` e o PDF são do documento **real assinado**: imprima e entregue normalmente.

O QR de contingência segue o **Manual de Padrões Técnicos do QR Code, versão 2**. O
parâmetro `p` carrega `chNFe|nVersao|tpAmb|dhEmi|vNF|vICMS|digVal|cIdToken|cHashQRCode`,
com `dhEmi` e `digVal` em hexadecimal e o hash em SHA-1 (40 posições). A engineAPI lê esse
QR do XML assinado e **confere o formato antes de devolver a nota**: se vier fora do
padrão, a emissão é recusada em vez de sair um cupom que o consumidor não consegue
conferir. No **sandbox** o QR tem o mesmo formato, com valores de demonstração: programe o
seu leitor contra ele à vontade.

### O que acontece depois

A engineAPI tenta transmitir a nota a cada 2 minutos enquanto a SEFAZ não responder, e
avisa você por webhook em cada etapa:

| evento                        | quando                                       | o que fazer                                                                        |
| ----------------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------- |
| `invoice.contingency`         | assim que a nota é emitida offline           | registre que o documento existe sem protocolo                                      |
| `invoice.authorized`          | a retransmissão foi autorizada               | desfecho normal. O payload traz `emitidaEmContingencia: true` para você distinguir |
| `invoice.rejected`            | a SEFAZ **rejeitou** a nota na retransmissão | atenção: a mercadoria já saiu. O payload traz `erros[]` com o `cStat` verbatim     |
| `invoice.contingency.expired` | passaram-se **24 h** sem autorização         | prazo legal estourado; regularize com a contabilidade                              |

Assine os eventos em **Dashboard → Webhooks** (ver [Webhooks](/guides/webhooks)). Você
também pode consultar o estado a qualquer momento com `GET /v1/nfce/{id}`.

<Warning>
  **O prazo é de 24 horas**, contado da emissão. Passado esse prazo sem autorização, a nota
  fica em `CONTINGENCIA_EXPIRADA`, um estado terminal e visível (nunca some em silêncio), e
  a regularização passa a ser do contribuinte. A engineAPI nunca deixa de avisar, mas não
  pode transmitir fora do prazo.
</Warning>

### Diferença para a NFe

A [NF-e (modelo 55) usa SVC](/guides/emitir-nfe#contingncia-svc), a SEFAZ Virtual de
Contingência: um autorizador alternativo que autoriza na hora. A NFC-e **não tem SVC**,
e isso é regra da SEFAZ: SVC-AN e SVC-RS atendem só o modelo 55. Por isso a contingência
da NFC-e é offline, com transmissão diferida.

Para acompanhar a disponibilidade da SEFAZ antes de uma venda, use
`GET /v1/nfe/sefaz-status/{uf}` (rota compartilhada entre os dois modelos, ver
[Consultar o status da SEFAZ](/guides/emitir-nfe#consultar-o-status-da-sefaz)).

***

## Veja também

* **[Emissão de NF-e](/guides/emitir-nfe):** para vendas B2B com dados completos do destinatário.
* **[Webhooks](/guides/webhooks):** receba eventos de NFC-e em tempo real.
* **[Paginação](/guides/paginacao):** contrato de `page`/`limit`/`sortBy` usado em `GET /v1/nfce`.
