engineAPIengineAPI
// guias

Guia: NFCe

Emita Notas Fiscais de Consumidor Eletrônicas (NFCe, modelo 65) para varejo via engineAPI.

NFCe: Nota Fiscal de Consumidor Eletrônica

A NFCe (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

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: NFCe. Para navegar por endpoint em vez de por documento, veja a Referência por Endpoint.

Ponto de venda

Ideal para varejo e e-commerce com venda direta

QR Code incluso

Resposta inclui qrCode para consulta do consumidor

DANFCE em PDF

Download do cupom fiscal em PDF, gerado do XML autorizado

Emissor (issuerId) é opcional no payload de NFCe. 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.


Pré-requisitos

·

Empresa e certificado, como na NFe

NFCe usa o mesmo cadastro de emissor da NFe: CNPJ (POST /v1/companies), IE, endereço completo e certificado digital A1. Ver Emitir NFe (seção Pré-requisitos, no topo do guia).

·

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 NFCe, antes de emitir. Gere/consulte o CSC no portal da SEFAZ do seu estado (Contribuinte → NFCe → 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.


Diferenças NFe vs NFCe

AspectoNFe (modelo 55)NFCe (modelo 65)
Destinatáriodestinatario completo (endereço obrigatório)destCPF/destNome opcionais, sem endereço
CFOP5102, 6102...Predominantemente estadual
QR CodeNãoSim, no campo qrCode da resposta
CancelamentoAté 24hAté 30 minutos
UsoB2B e B2CSomente B2C (varejo)

Emitir NFCe

O item da NFCe reusa o mesmo grupo ibsCbs da NFe (Reforma Tributária); os demais campos são específicos.

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. Com resolverTributacao: true o Cérebro Fiscal resolve isso sozinho.

bash
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 }
    ]
  }'

Campos de referência

CampoTipoObrigatórioDescrição
serie/numeronúmeroNãoIdentificação, geralmente alocados automaticamente
destCPF/destNomestringNãoDados do consumidor final (sem endereço)
itemsarraySim (mín. 1)Mesmos campos de item da NFe (codigo, descricao, ncm, cfop, unidade, quantidade, valorUnitario, cest, icms/pis/cofins/ibsCbs)
pagamentosarraySim (mín. 1){ forma, valor }, não é objeto singular pagamento
troconúmeroNãoN/A
informacoesComplementaresstringNãoN/A
resolverTributacaobooleanNãoEmissão assistida (Cérebro Fiscal), mesmo contrato da NFe, ver Emitir NFe

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). 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ódigoForma
01Dinheiro
02Cheque
03Cartão de Crédito
04Cartão de Débito
05Crédito Loja
10Vale Alimentação
11Vale Refeição
13Vale Presente
15Boleto
99Outros

Response de Sucesso

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

json
{
  "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 NFCe, 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
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.

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.

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
curl https://api.engineapi.com.br/v1/nfce/xml/{accessKey} \
  -H "x-api-key: SUA_API_KEY"

Cancelamento

bash
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 NFCe, mesmo contrato do cancelamento de NFe. 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.

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.

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 NFe (24h): não assuma o mesmo prazo para os dois modelos.

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
{
  "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 NFCe via API. O remédio legal é emitir uma nota de devolução. Veja também o catálogo de Erros e Rejeições.


Inutilização

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.

Este endpoint é exclusivo da NFCe (modelo 65). Para NFe (modelo 55), use POST /v1/nfe/inutilizar: mesmo contrato, mesmo motor por trás (worker ACBr e desfecho da SEFAZ são genéricos por modelo).

bash
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"
  }'
CampoTipoObrigatórioDescrição
serienúmero (ou string só-dígitos)SimSérie da faixa a inutilizar (inteiro 0–999); ver Campos de referência
numInicialnúmero (ou string só-dígitos)SimPrimeiro número da faixa (inteiro 1–999999999)
numFinalnú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
justificativastringSimEntre 15 e 255 caracteres (limite do campo xJust do leiaute)
issuerIdstring (UUID)NãoSó necessário com 2+ emissores cadastrados
anonúmeroNãoAno-calendário da numeração inutilizada, entre anoCorrente - 5 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
{
  "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"
  }
}

O campo xml (XML de retorno da SEFAZ) é servido quando a ACBrLib 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.

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
{
  "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"
  }
}

Ramifique pelo campo success, não pelo status HTTP: rejeição da SEFAZ na inutilização não é 400. Ver também Erros e Rejeições.

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

StatusQuandoCorpo
400serie/numInicial/numFinal/justificativa inválidos (shape, tipo ou numFinal < numInicial), ou 2+ emissores cadastrados sem issuerIdErro de validação padrão (RFC 7807)
403Partner sem nenhum emissor cadastradoErro padrão
404issuerId informado não pertence ao partner autenticadoErro padrão
422CERTIFICADO_AUSENTE (emissor sem certificado A1 instalado) ou FAIXA_INUTILIZACAO_MUITO_GRANDE (mais de 10.000 números na faixa){ code, message, details }
500Timeout do worker que fala com a ACBrLib/SEFAZ (120s): a inutilização pode ou não ter sido homologada do lado da SEFAZ, a resposta não chegou a tempoErro genérico

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.


Contingência

🗓 Fora do contrato hoje. A NFCe (modelo 65) não tem contingência: toda emissão sai com tpEmis=1 (normal), fixo. Diferente da NFe, que reroteia automaticamente para a SEFAZ Virtual de Contingência (SVC) quando a SEFAZ da UF está fora do ar, a NFCe não tem SVC (o leiaute nem prevê essa rota para o modelo 65) nem o modo offline (tpEmis=9, DPEC/venda com transmissão diferida) implementado. Se a SEFAZ da UF do emissor estiver indisponível no momento da venda, o POST /v1/nfce falha em vez de emitir por rota alternativa.

Se sua operação de varejo depende de continuar vendendo com a SEFAZ fora do ar (o cenário que o modo offline resolve no ACBr/PDV tradicional), fale com o time em suporte@engineapi.com.br, é candidato de roadmap, sem data. 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).


Próximos passos