NF-e verification
XML verification
Submits the raw NF-e XML; returns the Tier-1 verdict and the parsed invoice and starts the SEFAZ verification.
/openapi/v3/consultas/nf-e/xmlRequires the token, timestamp and sign signature headers, see Authentication.
Submits the raw NF-e XML. Returns the Tier-1 verdict and the parsed invoice data synchronously; on Tier-1 pass, Tier-2 SEFAZ verification starts automatically and the final verdict arrives through the invoice.verify.completed webhook (see NF-e verification).
HTTP 200 means the request was accepted, not that the invoice passed. A well-formed XML that fails validation still returns 200; the verdict is in the validation block. Never branch on the HTTP status to decide validity.
Parameters
Headers
Content-Typestringrequiredapplication/xmlortext/xml.forceRevalidatebooleanoptionalOptional, default
false. Sendtrueto force re-verification even when a reusable terminal verdict exists. Not part of the signature. See Idempotency and re-verification below.
Responses
Request accepted. Parsed invoice data plus the validation block with the Tier-1 verdict. Includes failed validation: check validation.validationStatus and validation.errors.
tipostringDocument type.
Values:NF-eNFC-emodelostringDocument model.
Values:5565statusstringSEFAZ fiscal status.
Values:AutorizadaCanceladaDenegadaInutilizadaNaoEncontradaDesconhecidastatusDescriptionstringLocalized description of
status, per request language (see Response localization in NF-e verification).ambienteEmissaostringEnvironment the document was issued in.
Values:ProducaoHomologacaonumerostringInvoice number nNF, no leading zeros.
seriestringSeries number.
dataEmissaostringIssue time dhEmi, ISO-8601 with UTC offset, verbatim from the document (e.g.
2026-07-23T11:20:05-03:00).chaveAcessostring44-digit access key.
emitenteobjectIssuer.
destinatarioobjectRecipient.
itensarrayInvoice line items.
dataAutorizacaostring | nullSEFAZ authorization time dhRecbto (ISO-8601); null when the submitted XML carries no protocol node.
protocoloobject | nullAuthorization protocol; null when there is no protocol node.
valorTotalnumberInvoice net total vNF (after discounts), 2 decimal places.
validationobjectTier-1 verdict block. Present on this endpoint only.
Errors
| Code | HTTP | |
|---|---|---|
| 10015000 | 400 | Empty request body. Send the XML in the body. |
| 10015001 | 400 | Body exceeds 1 MB. An authentic single NF-e never exceeds this; check that you are not wrapping or double-encoding. |
| 10015002 | 400 | DTD detected ( |
| 10015003 | 400 | Encoding is not UTF-8. Convert to UTF-8 before submitting. |
Request body and signing
- Preferred: the full nfeProc authorized document (including the
protNFeprotocol node). A bareNFewithout the protocol node is also accepted: it produces a warning but is processed normally. - Hard limits: max 1 MB, UTF-8 only, DTD forbidden (any
<!DOCTYPEis rejected outright). - Signing: the body participates in the signature after stripping every CR and LF, while the request body itself is sent unchanged:
sign = md5Hex(app_secret + "/openapi/v3/consultas/nf-e/xml" + xmlWithoutCrLf + timestamp)
The forceRevalidate header is not part of the signature. Full rules in Authentication.
Amount semantics
Line-level itens[].valorTotal is the gross line amount (vProd, before discount); root-level valorTotal is the net invoice total (vNF, after discount). The difference equals the total discount.
Tier-1 validation errors
Returned with HTTP 200 inside validation.errors[]. These are not transport errors: the request succeeded, the document failed. All are blocking (terminal REJECTED) except PROTOCOL_MISSING, which is a warning.
| errors[].code | Numeric | Meaning |
|---|---|---|
XML_MALFORMED | 10015100 | XML syntax invalid |
XSD_INVALID | 10015101 | Does not conform to the NF-e 4.00 XSD layout |
SIGNATURE_INVALID | 10015102 | Digital signature verification failed (content tampered, or certificate expired at signing time) |
SIGNATURE_CERT_MISMATCH | 10015103 | Signing certificate CNPJ does not match the issuer |
ACCESS_KEY_INVALID | 10015104 | chave structure / check digit invalid |
ACCESS_KEY_MISMATCH | 10015105 | chave segments do not match the document fields |
PROTOCOL_MISMATCH | 10015106 | Protocol block inconsistent with the document |
PROTOCOL_MISSING | 10015107 | No protocol node (warning, non-blocking) |
XML_VERSION_UNSUPPORTED | 10015108 | Layout version is not 4.00 |
Tier-2 outcomes (webhook)
Once Tier 1 passes, the final verdict arrives only through the invoice.verify.completed webhook; headers, payload and receiver requirements are in NF-e verification. These are not HTTP errors.
| validationStatus | Terminal? | Action |
|---|---|---|
VALIDATED | Yes | Safe to proceed (release goods, settle, etc.) |
REJECTED | Yes | Do not proceed; reason explains the SEFAZ verdict (cancelled / denied / voided / not found / protocol mismatch) |
VALIDATION_ERROR | No | Platform-side verification failure, not an invoice judgment; resubmit later with forceRevalidate: true |
Idempotency and re-verification
- XML verification is idempotent on the chave: resubmitting while a verification is in progress returns the current progress; terminal verdicts are reused for 24 hours (no duplicate verification cost).
- Forced re-verification: send the header
forceRevalidate: true(not part of the signature). The chave lookup has a fixed GET shape with no re-verification channel; to force a re-check, resubmit through this endpoint. - A Tier-1 blocking
REJECTEDhas no Tier-2 record; re-verification requires resubmitting the XML.
