Available via API | Available via SDK | Needs configuration on Veriff's side | Needs a separate integration | Needs a solution-specific webhook |
|---|---|---|---|---|
✅ | ❌ | ✅ | ✅ | ❌ |
NOM-151 Certification lets you meet the Mexican legal requirement to preserve identity-verification data with a timestamped, digitally signed artifact - a constancia de conservación - that can be presented to regulators and courts. You supply the PDF, Veriff hashes it and sends the hash to FIMPE (the accredited Prestador de Servicios de Certificación (PSC)), which returns a signed certificate proving the document has not changed since the certified timestamp.
In a nutshell, the flow involves the following steps:
You (the customer) upload the PDF to Veriff and submit the session.
Veriff hashes the PDF and sends the hash to FIMPE. The PDF itself never leaves Veriff.
FIMPE (the government-accredited PSC) signs the hash with a trusted timestamp and returns a CMS/PKCS#7 certificate to Veriff.
Veriff stores the certificate and notifies you via the decision webhook.
You retrieve the signed certificate and the source PDF via a dedicated endpoint.
NOM-151 Certification is available only via API. The solution can be used as a standalone check or alongside other Veriff products such as INE/CURP registry checks.
All session-related info is returned via decision webhook and can be polled from different API endpoints. The signed certificate is retrieved via a dedicated endpoint (see Retrieve the signed certificate). The results can also be viewed in the Veriff Customer Portal, in the webhooks view.
Contact your solutions engineer for info and configuration.
Prerequisites
You have an integration set up with Veriff
The NOM_151_CERTIFICATION step and the FIMPE connector are configured for that integration by your Solutions Engineer
You have configured the decision webhook to get responses from Veriff (see the how-to in webhooks' Set up webhooks section)
If using the API, Veriff strongly recommends you create and send us the endUserId or vendorData
Your PDF meets the upload requirements: single file, maximum 15 pages
Key terminology
Term | Description |
|---|---|
CA | Certification Authority |
| Opaque UUID referencing the stored certificate, used to retrieve it via |
CMS / PKCS#7 token | The cryptographic certificate blob returned by FIMPE, typically a few KB |
Constancia de conservación | The NOM-151 preservation certificate. A cryptographic artifact that pairs a SHA-family digest of the document with a trusted timestamp, sealed under the PSC's CA key. Any subsequent change to the document breaks the hash and invalidates the proof. |
FIMPE | The accredited PSC Veriff integrates with. Acts as sub-processor; never receives file contents |
| The NOM-151 Certification result object |
NOM-151-SCFI-2016 | Mexican federal standard issued by the Secretaría de Economía under Article 49 of the Código de Comercio. It defines how electronic documents must be preserved so they retain legal validity before Mexican courts and regulators. Proves document integrity and time only, not the truthfulness of the content, signer identity, or that it replaces a physical original. |
PSC | Prestador de Servicios de Certificación - a government-accredited certification service provider. Veriff uses FIMPE as its PSC. FIMPE acts as a sub-processor and never receives the file contents, only the hash. |
Flow overview
NOM-151 Certification is available only via API. You are responsible for the PDF capture and upload.
Use via API
Standalone NOM-151 Certification
Use when you have a finished PDF you want to certify. Veriff hashes the document. No data extraction or identity checks occur.
Generate a verification session using the API keys and the
baseURLof your integration (see the API Documentation and API Reference how to find these).Veriff strongly recommends you create and send the
endUserIdorvendorData
Session creation example
curl -X POST \
--url '/v1/sessions/' \
-H 'X-AUTH-CLIENT: your-api-key' \
-H 'Content-Type: application/json' \
-d '{
"verification": {
"callback": "https://veriff.com",
"vendorData": "12345678"
}
}'
{
"verification": {
"callback": "https://veriff.com",
"vendorData": "12345678"
}
}
Upload the PDF via POST /sessions/{sessionId}/media call.
Specify the
image.contextasgeneric-document-front(see Context types (image, video) for more info about image context types)This endpoint requires endpoint level authentication via
X-HMAC-SIGNATUREheader. See HMAC Authentication and Endpoint Security for general info about signature creation.
Media upload example
curl -X POST \
--url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media' \
-H 'X-AUTH-CLIENT: your-api-key' \
-H 'X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53' \
-H 'Content-Type: application/json' \
-d '{
"image": {
"context": "generic-document-front",
"content": "data:application/pdf;base64,<base64-encoded-pdf>"
}
}'
{
"image": {
"context": "generic-document-front",
"content": "data:application/pdf;base64,<base64-encoded-pdf>"
}
}
Patch session status to
submittedstatus using PATCH /sessions/{sessionId} call.This endpoint requires endpoint level authentication via
X-HMAC-SIGNATUREheader. See HMAC Authentication and Endpoint Security for general info about signature creation.
Session update example
curl -X PATCH \
--url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7' \
-H 'X-AUTH-CLIENT: your-api-key' \
-H 'X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53' \
-H 'Content-Type: application/json' \
-d '{
"verification": {
"status": "submitted"
}
}'
{
"verification": {
"status": "submitted"
}
}
Check the decision data from the decision webhook and/or query the data from the GET /sessions/{sessionId}/decision endpoint. Solution-specific overview of what to expect is provided below in the Find decision and/or session related info > Solution-specific parameters section.
Session lifecycle flow diagram
Click to open session flow diagram
sequenceDiagram
participant Your system
participant Veriff API
participant FIMPE
Note over Your system,FIMPE: Session setup
Your system->>Veriff API: POST /sessions
Your system->>Veriff API: POST /sessions/{id}/media (PDF)
Your system->>Veriff API: PATCH /sessions/{id} (submit)
Note over Your system,FIMPE: Certification
Veriff API->>Veriff API: Hash PDF
Veriff API->>FIMPE: Send hash for signing
FIMPE-->>Veriff API: Signed certificate (CMS/PKCS#7)
Veriff API->>Veriff API: Store certificate
Note over Your system,FIMPE: Retrieve result
Veriff API-)Your system: DECISION webhook
Your system->>Veriff API: GET /sessions/{id}/certificates
Veriff API-->>Your system: Certificate + source PDF URLsequenceDiagram
participant Your system
participant Veriff API
participant FIMPE
Note over Your system,FIMPE: Session setup
Your system->>Veriff API: POST /sessions
Your system->>Veriff API: POST /sessions/{id}/media (PDF)
Your system->>Veriff API: PATCH /sessions/{id} (submit)
Note over Your system,FIMPE: Certification
Veriff API->>Veriff API: Hash PDF
Veriff API->>FIMPE: Send hash for signing
FIMPE-->>Veriff API: Signed certificate (CMS/PKCS#7)
Veriff API->>Veriff API: Store certificate
Note over Your system,FIMPE: Retrieve result
Veriff API-)Your system: DECISION webhook
Your system->>Veriff API: GET /sessions/{id}/certificates
Veriff API-->>Your system: Certificate + source PDF URL
Find decision and/or session related info
You can get the data from four sources:
Receive the decision webhook (full example with placeholder values below)
Query the results via GET /sessions/{sessionId}/decision endpoint (payload identical to webhook)
View the session in Veriff Customer Portal > webhooks view
Retrieve the signed certificate and source PDF via a dedicated endpoint (see Retrieve the signed certificate below or in API documentation)
Note that the decision webhook and GET /sessions/{sessionId}/decision API response payloads are identical.
Solution-specific parameters
Info related to NOM-151 Certification is returned in the registryValidations.MX_NOM_151 object. This object contains the overall certification result, the individual validation outcomes, certificate metadata, and error details when applicable.
Structure of MX_NOM_151 object
{
"MX_NOM_151": {
"status": "success | failure | error",
"data": { ... } | null,
"validations": {
"processed": { "result": "...", "reason": "..." },
"is_input_valid": { "result": "...", "reason": "..." }
} | null,
"error": { ... } | null,
"timestamp": "ISO-8601 string | null"
}
}
Parameters in MX_NOM_151 explained
verification:objectVerification results objectregistryValidations:objectRegistry validation results objectMX_NOM_151:objectNOM-151 Certification resultstatus:stringOverall result of the certification step. One of:success,failure, orerror. See below for more info.data:object | nullCertificate metadata returned by FIMPE. Present onsuccess;nullonfailureorerrorcertificateId:string (UUID)Opaque identifier of the stored certificate. Use this to retrieve the full certificate and source PDF via/certificatesendpoints in Public API v1 documentationserialNumber:stringCertificate serial number from the issuing CAauthorityName:stringDistinguished name of the accredited PSC CAissuerName:stringDistinguished name of the NOM-151 notaryhashValue:stringBase64-encoded digest that was timestamped by FIMPEhashAlgorithm:stringDigest algorithm used (e.g.,sha256)issueDate:stringISO-8601 UTC legally certified issuance timestamprsaSignature:stringBase64 RSA signature of the certificate by the CApolicy:stringObject identifier (OID) of the PSC issuance policy under NOM-151
validations:object | nullMap of validation check results.nullwhenstatusiserrorprocessed:objectOverall execution and FIMPE connectivity checkresult:stringAlwayssuccess. If the check fails, this field is not returnedreason:string | nullMachine-readable reason,nullonsuccess
is_input_valid:objectInput precondition check (confirms the PDF was uploaded)result:stringOne of:success,failurereason:string | nullMachine-readable reason.nullonsuccess. See reason codes table below
error:object | nullError details whenstatusiserror.nullotherwisecode:stringMachine-readable error codemessage:stringHuman-readable error description
timestamp:string | nullISO-8601 UTC legally certified issuance timestamp. null when no certificate was issued.
Validations object
processed shows the overall execution and FIMPE connectivity check:
|
| Meaning |
|---|---|---|
|
| FIMPE returned a valid certificate |
N/A | N/A | Check failed. |
is_input_valid shows whether the input precondition check (the PDF was uploaded) passed or not:
|
| Meaning |
|---|---|---|
|
| PDF was uploaded and passed precondition checks |
|
| No PDF was uploaded before the session was submitted |
→ See Status and reason codes for more info about session outcomes
Note on session outcomes
If the certificate has been issued, the session status in verification.status is approved and registryValidations.MX_NOM_151.status is success.
The solution has two distinct failure modes. Both result in verification.status: declined, but they differ in MX_NOM_151.status and in the verification.reasonCode returned:
FIMPE error (
MX_NOM_151.status: error): the error surfaces inMX_NOM_151.errorobject and at the top level viaverification.reasonandverification.reasonCode. See the table below for more info.PDF not uploaded (
MX_NOM_151.status: failure): error surfaces inMX_NOM_151.validations.is_input_validobject and at the top level viaverification.reasonandverification.reasonCode. See the table below for more info.
Outcome |
|
|
|
|---|---|---|---|
Certificate issued |
|
|
|
FIMPE unreachable or invalid certificate |
|
|
|
FIMPE timed out |
|
|
|
Request rejected or internal error |
|
|
|
No PDF uploaded |
|
|
|
→ See Status and reason codes section for other reason strings and error codes
Note about object and field visibility
No document data is extracted in this flow. verification.person.* and verification.document.* fields reflect data passed during session creation, or null if not provided. additionalVerifiedData is always {}.
When MX_NOM_151.status is success
datais present. Alldata.*fields are individually optional, and fields with no value are omitted rather than returned asnull. Do not assume any individualdata.*field is present.validationslists the checks that ran, each withreason: nullerrorisnulltimestampcarries the certified issuance time
When MX_NOM_151.status is failure or error
dataisnullOn
failure,validationslists the checks, including the one that failed and itsreason.errorisnull.On
error,validationsisnulland the cause is inerror.codeinsteadtimestampisnull, because no certificate was issued
Sample payload of registryValidations.MX_NOM_151 object
The following is a sample response for an approved session. All strings and IDs are placeholder values used for illustrative purposes only.
{
"verification": {
"registryValidations": {
"MX_NOM_151": {
"status": "success",
"data": {
"certificateId": "c4a6b5e2-1dfa-4d6b-a9e7-2c0b3f8e1d42",
"serialNumber": "02377f31",
"authorityName": "email=acr2se@economia.gob.mx, O=Secretaria de Economia, OU=Direccion General de Normatividad Mercantil, ST=Distrito Federal, C=MX, CN=Autoridad Certificadora Raiz Segunda de Secretaria de Economia",
"issuerName": "email=psc@seguridata.com, O=SeguriData Privada S.A. de C.V., OU=Servicios de Certificacion Digital, ST=Distrito Federal, C=MX, CN=Servicio NOM151 de SeguriData",
"hashValue": "K8mQ2rT5vX9aB3dF6hJ0lN4pS7uW1yZ+cE5gI8kM2oQ=",
"hashAlgorithm": "sha256",
"issueDate": "2026-06-18T10:33:23",
"rsaSignature": "BBY+xf2j...",
"policy": "2.16.484.101.10.316.2.5.1.2.2.1.2"
},
"validations": {
"processed": { "result": "success", "reason": null },
"is_input_valid": { "result": "success", "reason": null }
},
"error": null,
"timestamp": "2026-06-18T10:33:23"
}
}
}
}
Webhook payload
The example below uses placeholder data to show all mandatory parameters and possible NOM-151 Certification fields. While mandatory fields are always present, solution-specific keys are omitted if data is unavailable. Depending on your integration's configuration, your production payload may contain additional parameters; for info on fields from other solutions, see the decision webhook's documentation.
Sample requests
Click to open an example of an approved session (certificate issued)
approved session (certificate issued){
"status": "success",
"verification": {
"id": "12df6045-3846-3e45-946a-14fa6136d78b",
"attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
"vendorData": null,
"endUserId": null,
"status": "approved",
"code": 9001,
"reason": null,
"reasonCode": null,
"acceptanceTime": "2026-06-18T10:33:06.267690Z",
"submissionTime": "2026-06-18T10:33:17.825166Z",
"decisionTime": "2026-06-18T10:33:23.860027Z",
"person": {
"firstName": null,
"lastName": null,
"citizenship": null,
"idNumber": null,
"gender": null,
"dateOfBirth": null,
"yearOfBirth": null,
"placeOfBirth": null,
"nationality": null,
"pepSanctionMatch": null
},
"document": {
"number": null,
"type": null,
"country": null,
"validFrom": null,
"validUntil": null,
"state": null
},
"comments": [],
"additionalVerifiedData": {},
"registryValidations": {
"MX_NOM_151": {
"status": "success",
"data": {
"certificateId": "c4a6b5e2-1dfa-4d6b-a9e7-2c0b3f8e1d42",
"serialNumber": "02377f31",
"authorityName": "email=acr2se@economia.gob.mx, O=Secretaria de Economia, OU=Direccion General de Normatividad Mercantil, ST=Distrito Federal, C=MX, CN=Autoridad Certificadora Raiz Segunda de Secretaria de Economia",
"issuerName": "email=psc@seguridata.com, O=SeguriData Privada S.A. de C.V., OU=Servicios de Certificacion Digital, ST=Distrito Federal, C=MX, CN=Servicio NOM151 de SeguriData",
"hashValue": "K8mQ2rT5vX9aB3dF6hJ0lN4pS7uW1yZ+cE5gI8kM2oQ=",
"hashAlgorithm": "sha256",
"issueDate": "2026-06-18T10:33:23",
"rsaSignature": "BBY+xf2j...",
"policy": "2.16.484.101.10.316.2.5.1.2.2.1.2"
},
"validations": {
"processed": { "result": "success", "reason": null },
"is_input_valid": { "result": "success", "reason": null }
},
"error": null,
"timestamp": "2026-06-18T10:33:23"
}
}
},
"technicalData": {
"ip": null
}
}
Click to open an example of a declined session where FIMPE was unavailable
declined session where FIMPE was unavailable{
"status": "success",
"verification": {
"acceptanceTime": "2026-06-18T11:04:23.244560Z",
"submissionTime": "2026-06-18T11:04:26.401341Z",
"decisionTime": "2026-06-18T11:04:28.864208Z",
"id": "a3f8c2d1-7e4b-4a9c-b5f2-1d8e3c7a0b6f",
"attemptId": "b1e2d3c4-a5f6-4b7c-8d9e-0f1a2b3c4d5e",
"vendorData": null,
"endUserId": null,
"status": "declined",
"code": 9102,
"reason": "Registry provider is unavailable",
"reasonCode": 566,
"person": {
"firstName": null,
"lastName": null,
"citizenship": null,
"idNumber": null,
"gender": null,
"dateOfBirth": null,
"yearOfBirth": null,
"placeOfBirth": null,
"nationality": null,
"pepSanctionMatch": null
},
"document": {
"number": null,
"type": null,
"country": null,
"validFrom": null,
"validUntil": null,
"state": null
},
"comments": [],
"additionalVerifiedData": {},
"registryValidations": {
"MX_NOM_151": {
"status": "error",
"data": null,
"validations": null,
"error": {
"code": "registry_unavailable",
"message": "Provider returned unexpected response"
},
"timestamp": null
}
}
},
"technicalData": {
"ip": null
}
}
Click to open an example of a declined session due to an internal FIMPE error
declined session due to an internal FIMPE error{
"status": "success",
"verification": {
"acceptanceTime": "2026-06-18T10:30:48.200504Z",
"submissionTime": "2026-06-18T10:30:58.490795Z",
"decisionTime": "2026-06-18T10:31:00.051842Z",
"id": "d2e3f4a5-b6c7-4d8e-9f0a-1b2c3d4e5f6a",
"attemptId": "e3f4a5b6-c7d8-4e9f-0a1b-2c3d4e5f6a7b",
"vendorData": null,
"endUserId": null,
"status": "declined",
"code": 9102,
"reason": "Internal error",
"reasonCode": 566,
"person": {
"firstName": null,
"lastName": null,
"citizenship": null,
"idNumber": null,
"gender": null,
"dateOfBirth": null,
"yearOfBirth": null,
"placeOfBirth": null,
"nationality": null,
"pepSanctionMatch": null
},
"document": {
"number": null,
"type": null,
"country": null,
"validFrom": null,
"validUntil": null,
"state": null
},
"comments": [],
"additionalVerifiedData": {},
"registryValidations": {
"MX_NOM_151": {
"status": "error",
"data": null,
"validations": null,
"error": {
"code": "technical_issues",
"message": "Internal error occurred"
},
"timestamp": null
}
}
},
"technicalData": {
"ip": null
}
}
Click to open an example of a declined session where no PDF was uploaded
declined session where no PDF was uploaded{
"status": "success",
"verification": {
"acceptanceTime": "2026-06-30T16:05:53.551808Z",
"submissionTime": "2026-06-30T16:06:02.566320Z",
"decisionTime": "2026-06-30T16:06:04.047839Z",
"id": "12df6045-3846-3e45-946a-14fa6136d78b",
"attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
"vendorData": null,
"endUserId": null,
"status": "declined",
"code": 9102,
"reason": "No PDF was uploaded for certification",
"reasonCode": 586,
"person": {
"firstName": null,
"lastName": null,
"citizenship": null,
"idNumber": null,
"gender": null,
"dateOfBirth": null,
"yearOfBirth": null,
"placeOfBirth": null,
"nationality": null,
"pepSanctionMatch": null
},
"document": {
"number": null,
"type": null,
"country": null,
"validFrom": null,
"validUntil": null,
"state": null
},
"comments": [],
"additionalVerifiedData": {},
"udocs": {
"metadata": {
"pageCount": null
}
},
"registryValidations": {
"MX_NOM_151": {
"status": "failure",
"data": null,
"validations": {
"is_input_valid": { "result": "failure", "reason": "input_not_provided" },
"processed": { "result": "success", "reason": null }
},
"error": null,
"timestamp": null
}
}
},
"technicalData": {
"ip": null
}
}
Request properties explained
The following covers the mandatory parameters common to all decision webhook payloads. For NOM-151 Certification-specific fields, see Parameters in MX_NOM_151 explained.
status:stringStatus of the responseverification:objectVerification request decision objectid:stringUUID v4 identifying the verification sessionattemptId:stringUUID v4 of the attempt which received a statusvendorData:string | nullThe unique identifier you created for the session.nullif not specifiedstatus:stringVerification status, one ofapproved,declined,resubmission_requested,expired,abandonedcode:integerVerification session decision code, one of9001,9102,9103,9104,9121reason:string | nullHuman-readable reason for the decision. Examples:"Registry provider is unavailable","Internal error".nullonapprovedreasonCode:integer | nullNumeric reason code.nullonapprovedacceptanceTime:stringISO-8601 timestamp of session creationsubmissionTime:stringISO-8601 timestamp of when the session was submitteddecisionTime:string | nullISO-8601 timestamp of the decisionperson:objectData about the verified person. No data is extracted from documents in this flow. Fields reflect data passed during session creation, ornullif not providedfirstName:string | nullPerson's first namelastName:string | nullPerson's last namecitizenship:nullDeprecated, always returnsnullidNumber:string | nullNational identification numbergender:string | nullPerson's gender, represented asMorF, ornullif not presentdateOfBirth:string | nullPerson's date of birth, represented asYYYY-MM-DDyearOfBirth:string | nullPerson's year of birth, represented asYYYYplaceOfBirth:string | nullPerson's place of birthnationality:string | nullPerson's nationality, represented as ISO 3166alpha-2oralpha-3codepepSanctionMatch:string | nullLegacy field, may return incorrect results. Ignore this field
document:objectVerified document. No data is extracted from documents in this flow. Fields reflect data passed during session creation, ornullif not providednumber:string | nullDocument number,[a-zA-Z0-9]characters onlytype:string | nullDocument type, one ofPASSPORT,ID_CARD,RESIDENCE_PERMIT,DRIVERS_LICENSE,VISA,OTHERcountry:string | nullDocument issuing country, represented as ISO 3166alpha-2codevalidFrom:string | nullDocument validity start date, represented asYYYY-MM-DDvalidUntil:string | nullDocument expiry date, represented asYYYY-MM-DDstate:string | nullDocument issuing state, represented as ISO 3166alpha-2oralpha-3code
comments:arrayAlways[]additionalVerifiedData:objectAlways{}registryValidations:objectRegistry validation results for this sessionMX_NOM_151:objectNOM-151 Certification result (see Parameters inMX_NOM_151explained)
technicalData:objectTechnical data objectip:string | nullIP address of the device from which the session was created
API call
Sample response
The API response payload is identical to the decision webhook payload.
Response properties explained
The API response payload is identical to the decision webhook payload.
Veriff Customer Portal
You can find the verification session related info, including the decision, in the Veriff Customer Portal, in the webhooks view.
→ See Review verification in Veriff Customer Portal about how to view the session info in the Veriff Customer portal
Retrieve the signed certificate
The signed CMS/PKCS#7 certificate is not inlined in the webhook. After receiving MX_NOM_151.status: success, retrieve it using the certificateId from the webhook payload via GET /v1/sessions/{sessionId}/certificates.
Note: This is a dedicated endpoint specific to NOM-151 Certification. It is separate from the standard decision webhook and GET /decision endpoint. The certificate can only be retrieved via this API endpoint.
Get certificates for a session
See List session certificates article in the Public API v1 documentation for more info.
GET /v1/sessions/{sessionId}/certificatesSample response
{
"status": "success",
"certificates": [
{
"id": "c4a6b5e2-1dfa-4d6b-a9e7-2c0b3f8e1d42",
"kind": "nom-151-certificate",
"format": "pkcs7",
"value": "MIIFr...",
"createdAt": "2026-05-15T06:26:12Z",
"metadata": {
"certificateNumber": "02377f31",
"issueDate": "2026-05-15T06:26:12Z",
"hashAlgorithm": "sha256",
"hash": "eJ8olhK7cR5v2iKnbFuRKngydS1Si6KVevSycRN6/dg="
},"sourceDocuments": [
{
"id": "<pdf-uuid>",
"url": "/v1/sessions/{id}/certificates/{certificateId}/files/{fileId}"
}
]
}
]
}
Response properties explained
certificates:arrayCertificate entries for this session. One entry per certified PDFid:string (UUID)Certificate IDkind:stringAlways"nom-151-certificate"format:stringAlways"pkcs7"value:stringBase64-encoded CMS/PKCS#7 token. Treat as opaque: Veriff returns this verbatim from FIMPE and does not decode or validate itcreatedAt:stringISO-8601 creation timemetadata.certificateNumber:string | nullCertificate serial number.nullwhen not provided by the certificate authoritymetadata.issueDate:string | nullCertified issuance timestamp.nullwhen not provided by the certificate authoritymetadata.hashAlgorithm:string | nullDigest algorithm.nullwhen not provided by the certificate authoritymetadata.hash:string | nullBase64-encoded digest that was timestamped.nullwhen not provided by the certificate authoritysourceDocuments[].id:string (UUID)Source PDF IDsourceDocuments[].url:stringRelative URL to stream the raw PDF bytes
Download the source PDF
See Download certificate source document article in Public API v1 documentation for more info.
GET /v1/sessions/{sessionId}/certificates/{certificateId}/files/{fileId}Returns the raw PDF as a binary stream. These are the exact bytes that were hashed. Store them as-is and do not re-encode.
Important: Mexican law (NOM-151 retention requirement) requires you to store the certificate together with the source PDF.
Status and reason codes
For a successful NOM-151 session, verification.status is approved and verification.code is 9001. For all other outcomes, verification.status is declined. See the table below.
If the NOM-151 session was declined, you can find additional information by checking:
verification.reasonCodeand cross-reference it with Granular reason codes (table)If
MX_NOM_151.statusisfailure(PDF not uploaded), checkMX_NOM_151.validations.is_input_valid.reasonfor the specific input failure reason. Note:validationsisnullwhenMX_NOM_151.statusiserrorIf
MX_NOM_151.statusiserror, checkMX_NOM_151.error.codeto tell the cause apart
|
|
|
|
|
| What does it mean? |
|---|---|---|---|---|---|---|
|
|
|
| - | - | Certificate issued. Retrieve via |
|
|
|
|
|
| FIMPE was unreachable, or returned a certificate Veriff could not validate against the submitted hash. Retry certification. |
|
|
|
|
|
| FIMPE timed out. Retry certification. |
|
|
|
|
|
| FIMPE rejected the request, or an internal error occurred. Retry once. If it persists, contact Veriff support. |
|
|
|
| - | - | No PDF was uploaded before submission. Upload the PDF and resubmit. |
The table above lists outcomes specific to NOM-151 Certification. The session may also reach other statuses for reasons unrelated to the certification step. To find info about other codes, refer to:
Additional information
FAQ
Is there an SDK flow?
No. NOM-151 Certification is available via API only. You are responsible for capturing or generating the PDF and uploading it.
Does FIMPE see the document?
No. Veriff sends FIMPE only a cryptographic hash of the PDF.
What documents can be certified?
NOM-151 Certification can be applied to any digital document that has been captured through a controlled, auditable process. Eligible document classes include business agreements, financial records, operational documents, legal and HR filings, real-estate deeds, and digitised originals that follow a controlled capture process. The input must be a single PDF file of maximum 15 pages.
What are typical use cases?
Common scenarios include contract disputes, SAT/tax audits, court evidence, inheritance and wills, corporate compliance records, real-estate transactions, intellectual-property priority claims, and KYC/AML verification records.
Who is the data controller and who is the data processor?
Your organisation (the Veriff customer) is the data controller: you determine the purpose of processing, for example meeting Mexican AML or archiving requirements. Veriff acts as the data processor, processing data solely on your behalf. FIMPE is the sub-processor: it issues the NOM-151 certificate by signing a hash, but per its contract with Veriff it never has knowledge of the contents of the original files.
Does NOM-151 Certification guarantee the document is authentic?
No. The certificate proves the document has not changed since the timestamp was applied. It does not validate what was in the document at that moment.
Can I verify the certificate myself?
Yes, base64-decode hashValue, compare against the hash of the downloaded PDF, and validate the CMS/PKCS#7 token against the CA chain, with no call back to FIMPE.
Troubleshooting
Session declined with reason code 586
The PDF was not uploaded before the session was submitted. Confirm the media upload returned a 2xx response before you call PATCH /sessions/{sessionId}, and that it used the generic-document-front context.
Session declined with reason code 566
The certification step did not complete. Check MX_NOM_151.error.code to tell the causes apart:
registry_unavailableandregistry_timeoutare provider-side, so retrytechnical_issuescan mean a rejected request as well as a transient error, so retry once and contact Veriff support if it persists.
verification.reason says "Registry provider is unavailable" but the connection to FIMPE is working
That reason also covers a certificate Veriff could not validate against the submitted hash, not only an unreachable provider. Retry the certification.
The certificate is not in the webhook
Expected. The certificate is only available via GET /v1/sessions/{sessionId}/certificates, never inlined in the decision payload.
Not receiving webhooks
Check the callback URL, that your endpoint is reachable over HTTPS, and your HMAC signature validation. Webhook delivery can be reviewed in the Veriff Customer Portal.
data.* fields missing on a successful session
Expected. All data.* fields are individually optional and are omitted rather than returned as null.
Best practices
Upload the PDF before submitting: ensure the PDF upload succeeds before calling
PATCH /sessions/{id}. A missing PDF causes adeclinedoutcome. Validate client-side that the file is a single PDF of 15 pages or fewer.Session declined due to third-party provider issues: when
MX_NOM_151.statusiserrorwitherror.coderegistry_unavailableorregistry_timeout, the session isdeclinedbut the failure is on the provider side. Implement a retry or re-certification path rather than treating these as permanent failures.Handle
technical_issuesdifferently: this code can mean a rejected request as well as a transient internal error, so an identical retry may fail identically. Retry once, and contact Veriff support if it persists.Store both the certificate and the source PDF: Mexican law (NOM-151 retention requirement) requires retaining the signed certificate alongside the exact hashed PDF. Use GET /v1/sessions/{sessionId}/certificates to retrieve the byte-faithful PDF binary.
Treat the certificate blob as opaque: Veriff returns the raw CMS/PKCS#7 token verbatim and does not decode or validate it. Store and transmit it without modification.
Integrity expectation: NOM-151 Certification proves integrity and time only, not identity or document authenticity. Ensure a trusted chain of custody before certifying: anything stamped was trusted at the moment of stamping.
Webhook security: secure your webhook endpoint and verify request signatures. See HMAC Authentication and Endpoint Security for more info.
Ensure backwards compatibility for webhooks and API connections.
Changelog
Date | Description |
|---|---|
Sep 4, 2026 | Documentation published |