Mexico - NOM-151 Certification

Prev Next

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

certificateId

Opaque UUID referencing the stored certificate, used to retrieve it via /certificates endpoints

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

MX_NOM_151

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.

  1. Generate a verification session using the API keys and the baseURL of your integration (see the API Documentation and API Reference how to find these).

    • Veriff strongly recommends you create and send the endUserId or vendorData

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

  1. Upload the PDF via POST /sessions/{sessionId}/media call.

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

  1. Patch session status to submitted status using PATCH /sessions/{sessionId} call.

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

  1. 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 URL

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 URL


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: object Verification results object

  • registryValidations: object Registry validation results object

    • MX_NOM_151: object NOM-151 Certification result

      • status: string Overall result of the certification step. One of: success, failure, or error. See below for more info.

      • data: object | null Certificate metadata returned by FIMPE. Present on success; null on failure or error

        • certificateId: string (UUID) Opaque identifier of the stored certificate. Use this to retrieve the full certificate and source PDF via /certificates endpoints in Public API v1 documentation

        • serialNumber: string Certificate serial number from the issuing CA

        • authorityName: string Distinguished name of the accredited PSC CA

        • issuerName: string Distinguished name of the NOM-151 notary

        • hashValue: string Base64-encoded digest that was timestamped by FIMPE

        • hashAlgorithm: string Digest algorithm used (e.g., sha256)

        • issueDate: string ISO-8601 UTC legally certified issuance timestamp

        • rsaSignature: string Base64 RSA signature of the certificate by the CA

        • policy: string Object identifier (OID) of the PSC issuance policy under NOM-151

      • validations: object | null Map of validation check results. null when status is error

        • processed: object Overall execution and FIMPE connectivity check

          • result: string Always success . If the check fails, this field is not returned

          • reason: string | null Machine-readable reason, null on success

        • is_input_valid: object Input precondition check (confirms the PDF was uploaded)

          • result: string One of: success, failure

          • reason: string | null Machine-readable reason. null on success. See reason codes table below

      • error: object | null Error details when status is error. null otherwise

        • code: string Machine-readable error code

        • message: string Human-readable error description

      • timestamp: string | null ISO-8601 UTC legally certified issuance timestamp. null when no certificate was issued.

Validations object

processed shows the overall execution and FIMPE connectivity check:

processed.result

processed.reason

Meaning

success

null

FIMPE returned a valid certificate

N/A

N/A

Check failed. MX_NOM_151.status is error, validations is null, cause is in error.code

is_input_valid shows whether the input precondition check (the PDF was uploaded) passed or not:

is_input_valid.result

is_input_valid.reason

Meaning

success

null

PDF was uploaded and passed precondition checks

failure

input_not_provided

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 in MX_NOM_151.error object and at the top level via verification.reason and verification.reasonCode. See the table below for more info.

  • PDF not uploaded (MX_NOM_151.status: failure): error surfaces in MX_NOM_151.validations.is_input_valid object and at the top level via verification.reason and verification.reasonCode. See the table below for more info.

Outcome

verification.status

verification.reasonCode

MX_NOM_151.status

Certificate issued

approved

null

success

FIMPE unreachable or invalid certificate

declined

566

error

FIMPE timed out

declined

566

error

Request rejected or internal error

declined

566

error

No PDF uploaded

declined

586

failure

→ 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

  • data is present. All data.* fields are individually optional, and fields with no value are omitted rather than returned as null. Do not assume any individual data.* field is present.

  • validations lists the checks that ran, each with reason: null

  • error is null

  • timestamp carries the certified issuance time

When MX_NOM_151.status is failure or error

  • data is null

  • On failure, validations lists the checks, including the one that failed and its reason. error is null.

  • On error, validations is null and the cause is in error.code instead

  • timestamp is null, 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)

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

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

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

{
  "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: string Status of the response

  • verification: object Verification request decision object

    • id: string UUID v4 identifying the verification session

    • attemptId: string UUID v4 of the attempt which received a status

    • vendorData: string | null The unique identifier you created for the session. null if not specified

    • status: string Verification status, one of approved, declined, resubmission_requested, expired, abandoned

    • code: integer Verification session decision code, one of 9001, 9102, 9103, 9104, 9121

    • reason: string | null Human-readable reason for the decision. Examples: "Registry provider is unavailable", "Internal error". null on approved

    • reasonCode: integer | null Numeric reason code. null on approved

    • acceptanceTime: string ISO-8601 timestamp of session creation

    • submissionTime: string ISO-8601 timestamp of when the session was submitted

    • decisionTime: string | null ISO-8601 timestamp of the decision

    • person: object Data about the verified person. No data is extracted from documents in this flow. Fields reflect data passed during session creation, or null if not provided

      • firstName: string | null Person's first name

      • lastName: string | null Person's last name

      • citizenship: null Deprecated, always returns null

      • idNumber: string | null National identification number

      • gender: string | null Person's gender, represented as M or F, or null if not present

      • dateOfBirth: string | null Person's date of birth, represented as YYYY-MM-DD

      • yearOfBirth: string | null Person's year of birth, represented as YYYY

      • placeOfBirth: string | null Person's place of birth

      • nationality: string | null Person's nationality, represented as ISO 3166 alpha-2 or alpha-3 code

      • pepSanctionMatch: string | null Legacy field, may return incorrect results. Ignore this field

    • document: object Verified document. No data is extracted from documents in this flow. Fields reflect data passed during session creation, or null if not provided

      • number: string | null Document number, [a-zA-Z0-9] characters only

      • type: string | null Document type, one of PASSPORT, ID_CARD, RESIDENCE_PERMIT, DRIVERS_LICENSE, VISA, OTHER

      • country: string | null Document issuing country, represented as ISO 3166 alpha-2 code

      • validFrom: string | null Document validity start date, represented as YYYY-MM-DD

      • validUntil: string | null Document expiry date, represented as YYYY-MM-DD

      • state: string | null Document issuing state, represented as ISO 3166 alpha-2 or alpha-3 code

    • comments: array Always []

    • additionalVerifiedData: object Always {}

    • registryValidations: object Registry validation results for this session

  • technicalData: object Technical data object

    • ip: string | null IP 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}/certificates

Sample 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: array Certificate entries for this session. One entry per certified PDF

    • id: string (UUID) Certificate ID

    • kind: string Always "nom-151-certificate"

    • format: string Always "pkcs7"

    • value: string Base64-encoded CMS/PKCS#7 token. Treat as opaque: Veriff returns this verbatim from FIMPE and does not decode or validate it

    • createdAt: string ISO-8601 creation time

    • metadata.certificateNumber: string | null Certificate serial number. null when not provided by the certificate authority

    • metadata.issueDate: string | null Certified issuance timestamp. null when not provided by the certificate authority

    • metadata.hashAlgorithm: string | null Digest algorithm. null when not provided by the certificate authority

    • metadata.hash: string | null Base64-encoded digest that was timestamped. null when not provided by the certificate authority

    • sourceDocuments[].id: string (UUID) Source PDF ID

    • sourceDocuments[].url: string Relative 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.reasonCode and cross-reference it with Granular reason codes (table)

  • If MX_NOM_151.status is failure (PDF not uploaded), check MX_NOM_151.validations.is_input_valid.reason for the specific input failure reason. Note: validations is null when MX_NOM_151.status is error

  • If MX_NOM_151.status is error, check MX_NOM_151.error.code to tell the cause apart

verification.status

verification.reason

verification.reasonCode

MX_NOM_151.status

MX_NOM_151.error.code

MX_NOM_151.error.message

What does it mean?

approved

null

null

success

-

-

Certificate issued. Retrieve via /certificates.

declined

"Registry provider is unavailable"

566

error

registry_unavailable

"Provider returned unexpected response"

FIMPE was unreachable, or returned a certificate Veriff could not validate against the submitted hash. Retry certification.

declined

“Timeout while connecting to registry provider”

566

error

registry_timeout

"Registry request timed out"

FIMPE timed out. Retry certification.

declined

"Internal error"

566

error

technical_issues

"Internal error occurred"

FIMPE rejected the request, or an internal error occurred. Retry once. If it persists, contact Veriff support.

declined

"No PDF was uploaded for certification"

586

failure

-

-

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_unavailable and registry_timeout are provider-side, so retry

  • technical_issues can 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

  1. Upload the PDF before submitting: ensure the PDF upload succeeds before calling PATCH /sessions/{id}. A missing PDF causes a declined outcome. Validate client-side that the file is a single PDF of 15 pages or fewer.

  2. Session declined due to third-party provider issues: when MX_NOM_151.status is error with error.code registry_unavailable or registry_timeout, the session is declined but the failure is on the provider side. Implement a retry or re-certification path rather than treating these as permanent failures.

    Handle technical_issues differently: 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.

  3. 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.

  4. 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.

  5. 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.

  6. Webhook security: secure your webhook endpoint and verify request signatures. See HMAC Authentication and Endpoint Security for more info.

  7. Ensure backwards compatibility for webhooks and API connections.


Changelog

Date

Description

Sep 4, 2026

Documentation published