Como manifestar uma NFS-e recebida
Manifestação é o registro formal do tomador sobre uma NFS-e recebida — usado para auditoria fiscal, conformidade tributária, e (em caso de rejeição) sinalização ao prestador de que a nota tem inconsistência. O padrão nacional aceita apenas dois tipos: Ciência (203202) e Rejeição (203206). Esta receita mostra o fluxo completo de ponta a ponta, incluindo o callback assíncrono e os códigos cStat retornados pelo SEFIN Nacional.
Sumário
Pré-requisitos
- Empresa com NFS-e Inbound ativo — veja Integração REST.
accessKeyda NFS-e (50 dígitos) — obtenha listando documentos ou recebendo o webhookinbound.serviceInvoice.received.- Decisão informada: Ciência confirma conhecimento da nota; Rejeição contesta formalmente (pode bloquear créditos tributários do tomador).
- Endpoint de webhook configurado (recomendado) — para receber o callback
inbound.manifestation.submittedassincronamente.
Fluxo
Solução
A submissão de manifestação é assíncrona: o POST retorna 202 Accepted com status: "Pending" imediatamente. O worker da NFE.io processa em background, dialoga com o SEFIN Nacional e transita o status para Accepted, Rejected ou Failed. Você acompanha por polling em GET /manifestations/{id} ou pelo callback webhook inbound.manifestation.submitted.
Etapa 1: Decidir Ciência ou Rejeição
Use Ciência (203202) quando concorda com a nota e quer apenas registrar conhecimento — caso padrão para a maioria dos serviços recebidos legitimamente. Pode ser automatizado ativando isAutomaticManifestationEnabled na empresa.
Use Rejeição (203206) quando a nota tem inconsistência fiscal ou foi emitida indevidamente. Exige um reasonCode codificado e, opcionalmente, um texto livre em justification (≤ 255 caracteres pelo XSD do SEFIN).
reasonCode | Descrição |
|---|---|
1 | Duplicata |
2 | Já emitida pelo tomador |
3 | Sem fato gerador |
4 | Erro de responsabilidade tributária |
5 | Erro de valor, serviço ou data |
9 | Outros (use o justification para descrever) |
Etapa 2: Submeter a manifestação
# Ciência — sem body (reasonCode/justification não se aplicam)
curl -X POST \
"$BASE/v2/companies/$COMPANY_ID/inbound/nfse/by-access-key/$ACCESS_KEY/manifestations?eventCode=203202" \
-H "Authorization: $NFEIO_API_KEY"
# Rejeição — body obrigatório com reasonCode
curl -X POST \
"$BASE/v2/companies/$COMPANY_ID/inbound/nfse/by-access-key/$ACCESS_KEY/manifestations?eventCode=203206" \
-H "Authorization: $NFEIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reasonCode": 1,
"justification": "Nota duplicada da NFS-e 35250612345..."
}'
Resposta esperada 202 Accepted com o NFSeManifestationEventResource inicial:
{
"id": "69e193685b7241b5c4fe8e3c",
"companyId": "5f9b1c2d3e4f5a6b7c8d9e0f",
"accessKey": "35503081223301943000745000000002734526036434454892",
"eventCode": 203202,
"reasonCode": null,
"justification": null,
"status": "Pending",
"environment": "Production",
"createdAt": "2026-05-27T13:42:11Z",
"submittedAt": null,
"acceptedAt": null,
"errorCode": null,
"errorMessage": null
}
O header Location aponta para GET /v2/companies/{companyId}/inbound/nfse/manifestations/{id} — use para polling.
Etapa 3: Acompanhar o estado terminal
Via webhook (preferido): ao concluir, a NFE.io dispara inbound.manifestation.submitted com manifestation.status igual a Accepted, Rejected ou Failed. Veja o catálogo de eventos do webhook para o payload completo.
Via polling:
curl "$BASE/v2/companies/$COMPANY_ID/inbound/nfse/manifestations/$MANIFEST_ID" \
-H "Authorization: $NFEIO_API_KEY"
O detalhe inclui os XMLs de request e response do SEFIN em GZip+Base64 (requestXmlGZipB64, responseXmlGZipB64) — úteis para auditoria fiscal e investigação de rejeições. Códigos cStat mais comuns:
errorCode | Significado | Ação |
|---|---|---|
135 | Evento registrado e vinculado | Sucesso. |
136 | Evento registrado, não vinculado à NFS-e | Sucesso parcial — chave pode estar incorreta. |
217 | NFS-e não consta na base SEFIN | Aguarde latência ADN (alguns minutos) e tente novamente. |
573 | Duplicidade de evento | Já existe evento do mesmo tipo — consulte GET /manifestations por accessKey. |
999 | Erro interno SEFIN | Retentar após 5–10 minutos. |
Variações
- Automação total da Ciência: ative
isAutomaticManifestationEnabled: truecomautomaticManifestationDelaySeconds(ex.:3600= 1 hora) na empresa viaPUT /v2/companies/{companyId}/inbound/nfse/details. A NFE.io envia Ciência sozinha após o delay. Rejeição nunca é automatizada — sempre exige decisão humana. - Manifestação em lote: itere sobre
GET /v2/companies/{companyId}/inbound/nfse?type=Nfse&status=Processede dispare uma manifestação por documento. Respeite rate limits internos do SEFIN — não paralelize além de 5 chamadas simultâneas. - Auditoria fiscal: decode o
responseXmlGZipB64para obter o XML literal da resposta SEFIN (comcStat,xMotivo,dhRegEventoe o protocolo gerado). Útil em fiscalizações que exigem comprovante de tentativa. - Listar manifestações já submetidas:
GET /v2/companies/{companyId}/inbound/nfse/by-access-key/{accessKey}/manifestationsretorna o histórico para uma NFS-e específica.
Armadilhas comuns
409 Conflictao submeter: já existe uma manifestaçãoPendingpara o par(accessKey, eventCode). ConsulteGET /manifestationsantes de re-submeter — provavelmente a primeira ainda está em processamento.422 Unprocessable Entity: corpo ausente paraeventCode=203206oureasonCodeinválido (fora de 1/2/3/4/5/9). Sempre inclua o body em rejeições.justificationtruncada: o XSD do SEFIN Nacional limita o campo a 255 caracteres. Mensagens maiores são truncadas silenciosamente — encurte antes de enviar.cStat=217logo após receber a NFS-e: o SEFIN tem latência entre publicar no ADN e indexar para consulta de evento. Aguarde alguns minutos antes de manifestar uma nota recém-capturada.- Rejeição não cancela a NFS-e: a nota permanece válida no ADN; a rejeição apenas a marca como contestada. Cancelamento efetivo é responsabilidade do prestador (evento
101101). automaticManifestationDelaySecondsmáximo: o valor é validado contra604800segundos (7 dias). Valores maiores são rejeitados na ativação.
Veja também
- Catálogo de eventos do webhook — payload completo de
inbound.manifestation.submitted - Integração REST — ativação da empresa e configuração de
isAutomaticManifestationEnabled - Troubleshooting — diagnóstico de
cStatSEFIN e estados de erro - Arquitetura — onde a manifestação se encaixa no fluxo SEFIN → ADN → NFE.io