Pular para conteúdo

Validação e diagnósticos

Todo documento passa por um conjunto de regras antes de consumir numeração e antes de ir à SEFAZ. É de propósito: uma recusa nossa não queima número, enquanto uma rejeição da SEFAZ queima. Quanto mais cedo o erro aparece, menos lacuna você tem para inutilizar depois.

O que recusamos antes da SEFAZ

  • Campos desconhecidos. Somos estritos: nós recusamos em voz alta um campo que não está no subconjunto suportado, em vez de ignorá-lo em silêncio. Isso é deliberado: se o seu sistema depende de um campo que ainda não mapeamos, você descobre no primeiro teste, e não no DANFE. O subconjunto suportado está na página de compatibilidade de cada dialeto.
  • Consistência do documento. Os mesmos rejeitos que a SEFAZ aplicaria, verificados aqui: totais, tributos, CFOP, dados do consumidor, data de emissão.
  • Série fora da faixa permitida para o modelo.
  • CEST divergente do NCM. Um CEST que não corresponde ao NCM do item bloqueia, porque a SEFAZ rejeitaria. Um NCM que tem CEST associado, mas não o informa, apenas avisa. A operação pode legitimamente estar fora de substituição tributária.
  • Grupo IBS/CBS ausente. Ver IBS/CBS é obrigatório.

IBS/CBS é obrigatório

Desde a transição de 2026, a SEFAZ rejeita qualquer NFC-e sem o grupo da reforma tributária (rejeição 1115, IBS/CBS não informado). A regra vale inclusive para documentos do Simples Nacional com CSOSN 102. Nós validamos a presença do grupo antes do envio, para poupar a viagem e o número.

Todo item precisa carregar o grupo:

No mínimo ibs_cbs_situacao_tributaria (CST, 3 dígitos) e ibs_cbs_classificacao_tributaria (cClassTrib, 6 dígitos) por item. Informar só um dos dois é erro de validação. Os valores (ibs_cbs_base_calculo, ibs_uf_aliquota, ibs_uf_valor, ibs_mun_aliquota, ibs_mun_valor, ibs_valor_total, cbs_aliquota, cbs_valor) acompanham quando a operação os exigir.

O grupo imposto.IBSCBS por item, com CST e cClassTrib. Os valores vão em gIBSCBS (vBC, gIBSUF, gIBSMun, gCBS, vIBS). Se gIBSCBS for informado, as três pernas (gIBSUF, gIBSMun, gCBS) devem vir juntas.

Nós calculamos os totais da reforma a partir dos grupos por item. Não os envie.

Como o motivo chega até você

Internamente, cada diagnóstico tem três partes: campo, problema e solução. Cada dialeto projeta isso no formato do provedor:

Recusa antes da SEFAZ vira 422:

{
  "codigo": "erro_validacao",
  "mensagem": "Erro de validação (Grupo IBS/CBS não informado no item.)",
  "erros": [
    {
      "mensagem": "Grupo IBS/CBS não informado no item.",
      "campo": "det[1].imposto.IBSCBS"
    }
  ]
}

Rejeição da SEFAZ vira 201 com status: "erro_autorizacao", status_sefaz e mensagem_sefaz. O código HTTP não distingue os dois desfechos na emissão, exatamente como no provedor.

Recusa antes da SEFAZ vira um documento com status: "erro". Não há resposta da SEFAZ para reportar, então codigo_status vem nulo e o bloco autorizacao carrega o diagnóstico:

{
  "status": "erro",
  "autorizacao": {
    "status": "erro",
    "codigo_status": null,
    "motivo_status": "Grupo IBS/CBS não informado no item.",
    "mensagem": "Informe o grupo IBS/CBS do item (obrigatório desde 2026).",
    "numero_protocolo": null,
    "data_recebimento": null,
    "chave_acesso": null
  }
}

motivo_status carrega o problema e mensagem, a orientação. Rejeição da SEFAZ vira status: "rejeitado" com codigo_status preenchido (inteiro).

Alguns cantos não têm resposta em banda: JSON malformado, id desconhecido, pré-condição de operação não atendida. Neles respondemos com código HTTP honesto (404, 422, 502, 503) e um corpo mínimo. O contrato do ACBrAPI não descreve esses casos. O do FocusNFE descreve. Cada página de compatibilidade lista o formato exato do seu dialeto.