Documentation Index

Fetch the complete documentation index at: https://devdocs.veriff.com/llms.txt

Use this file to discover all available pages before exploring further.

Mexico - INE Biometric Database Verification

Prev Next

Available via API

Available via SDK

Needs configuration on Veriff's side

Needs a separate integration

Needs a solution-specific webhook

Mexico - INE Biometric Database Verification validates the authenticity of an end-user's identity by comparing their selfie against the biometric portrait held in the Mexican National Electoral Institute (INE) registry. It confirms identity and performs a biometric face match against government-held records to provide the highest level of assurance for Mexican identity verification.

INE Biometric Database Verification can be used as a standalone and is available only via API.

You need a separate integration for this solution, meaning existing integrations cannot be used.

All session-related info is returned via decision webhook and can be polled from different API endpoints. The results of the verification can also be viewed in the Veriff Customer Portal, under the Webhooks tab.

Contact your solutions engineer for info and configuration.


Prerequisites

  • You have an integration set up with Veriff

  • The INE Biometric Registry step is configured for that integration by your Solutions Engineer

  • You have registered directly with Instituto Nacional Electoral (Veriff can help facilitate the registration, see below for more info)

  • You have configured the decision webhook to get responses from Veriff (see the how-to in webhooks' Set up webhooks section)

  • You are ready to collect and send Veriff your end-user's data and selfie

  • Because the solution is available only over API:

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

Key terminology

Term

Description

CIC

Código de Identificación de la Credencial , the 9-digit Credential Identification Code printed on the voter card

CURP

Clave Única de Registro de Población , the 18-character unique citizen identification code

FIMPE

Fideicomiso de Infraestructura de Mercados y Pagos Electrónicos , a third-party provider that relays verification requests to the INE registry

INE

Instituto Nacional Electoral, Mexico's National Electoral Institute, custodian of the biometric voter registry

Validation

An umbrella term that refers to any individual check performed during the verification process. Includes field-validations (the per-data-point comparisons), and system-level validations (infrastructure and business-logic checks).
In this documentation, validation_check is used as its placeholder value.

Validation cascade

Sequential evaluation of validations where a core validation failure causes downstream validations to be set to not_applicable

Voter card

Mexican INE credential (Credencial para Votar) , the only document type supported by this solution

How to register with INE?

Veriff can help facilitate the registration with our partner FIMPE. After registration you must share with us one time the following data points:

  • Encryption key

  • FIMPE endpoint URL (Base URL of the FIMPE API endpoint)

  • Institution ID (Institution identifier issued by FIMPE)

  • Station ID (Station identifier for the FIMPE connection)

  • Latitude (Latitude of the station location)

  • Longitude (Longitude of the station location)

  • Postal code (Postal code of the station location)

  • City (City of the station location)

  • State (State of the station location, a 2 digit code)


End-user data sources

The "end-user data sources" refer to the origins from where the end-user's information can be collected for the registry check. INE Biometric Database Verification uses initData exclusively.

The minimum data combination to run a successful check is:

  • CIC (voter card credential identification code) + document country code + document type + end-user consent + selfie image

InitData

This is data that you provide when creating a verification session, i.e. the parameters you specify in the POST /sessions request.

Optional fields are matched against the INE registry only when the corresponding validation has been enabled for your integration by your Solutions Engineer. If a validation is not enabled, the field is accepted but has no effect on the verification result and no corresponding entry appears in validations.

See the Available validation_check values table below for which checks require SE enablement.

Parameters that can be sent via initData:

  • verification: object Root object containing all session parameters

    • person: object Object containing person information

      • idNumber: string 18-character CURP [OPTIONAL]

      • firstName: string End-user's first name. Matched against INE registry records [OPTIONAL]

      • lastName: string End-user's father's last name (apellido paterno). Matched against INE registry records [OPTIONAL]

      • secondLastName: string End-user's mother's last name (apellido materno). Matched against INE registry records [OPTIONAL]

    • document: object Object containing document information

      • number: string 9-digit CIC from the voter card [REQUIRED]

      • country: string Must be MX [REQUIRED]

      • type: string Document type, must be ID_CARD [REQUIRED]

      • firstIssue: string Document registration date in YYYY-MM-DD format (only the year portion is used for matching) [OPTIONAL]

      • validFrom: string Document issue date in YYYY-MM-DD format (only the year portion is used for matching) [OPTIONAL]

    • consents: array Required array containing the end-user's consent for INE biometric data processing [REQUIRED]

      • type: string Must be ine [REQUIRED]

      • approved: boolean Must be true [REQUIRED]


Flow overview

INE Biometric Database Verification is available only via API. You are responsible for the selfie capture interface and image quality.

Use via API

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

    • Make sure to pass the mandatory verification.document.number parameter with the end-user's 9-digit CIC value

    • Make sure to pass the mandatory verification.document.country parameter with the MX value

    • Make sure to pass the mandatory verification.document.type parameter with the ID_CARD value

    • Make sure to pass the mandatory verification.consents array with type: "ine" and approved: true

    • 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",
        "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
        "person": {
            "idNumber": "GARJ000000HMCRLP00",
            "firstName": "JUAN",
            "lastName": "GARCIA",
            "secondLastName": "LOPEZ"
        },
        "document": {
            "type": "ID_CARD",
            "number": "000000000",
            "country": "MX",
            "validFrom": "2020-03-10",
            "firstIssue": "2018-06-15"
        },
        "consents": [
            {
                "type": "ine",
                "approved": true
            }
        ]
    }
}'

{
    "verification": {
        "callback": "https://veriff.com",
        "vendorData": "12345678",
        "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
        "person": {
            "idNumber": "GARJ000000HMCRLP00",
            "firstName": "JUAN",
            "lastName": "GARCIA",
            "secondLastName": "LOPEZ"
        },
        "document": {
            "type": "ID_CARD",
            "number": "000000000",
            "country": "MX",
            "validFrom": "2020-03-10",
            "firstIssue": "2018-06-15"
        },
        "consents": [
            {
                "type": "ine",
                "approved": true
            }
        ]
    }
}

  1. Upload the end-user's selfie via POST /sessions/{sessionId}/media[↗] call. This is matched against the portrait stored in the INE registry.

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": "face",
        "content": "data:image/jpeg;base64,...",
        "timestamp": "2026-04-01T10:00:00.000Z"
    }
}'

{
    "image": {
        "context": "face",
        "content": "data:image/jpeg;base64,...",
        "timestamp": "2026-04-01T10:00:00.000Z"
    }
}

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

Session update example

curl -X PATCH \
  --url '/v1/sessions/fd5c1563-1d23-4b1a-ae46-7ba429927ed8' \
  -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 and/or session related info 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.


You can get the data from three sources:

  • Receive the decision webhook (full examples 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 tab

Note that the decision webhook and GET /sessions/{sessionId}/decision API response payloads are identical.

Solution-specific parameters

Info related to INE Biometric Database Verification is returned in the registryValidations.MX_INE object. This object contains the overall registry check result, the individual validation outcomes, and error details when applicable.

Structure of MX_INE object

{
  "MX_INE": {
    "status": "success | failure | error",
    "data": null,
    "validations": { ... } | null,
    "error": { ... } | null,
    "timestamp": "ISO-8601 string" | null
  }
}

Parameters in MX_INE explained

  • verification: object Verification results object

  • registryValidations: object Registry validation results object

    • MX_INE: object Registry validation result for Mexico INE

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

      • data: null Always null . The INE registry does not return person data, it only confirms or denies matches

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

        • <validation_check>: object A specific validation check result. See below for available values.

          • result: string Outcome of the validation. One of: success (passed), failure (failed), not_applicable (could not run due to an upstream failure)

          • reason: string | null Machine-readable reason for the result. null on result: success . See below for more info.

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

        • code: string Machine-readable error code, always registry_error

        • message: string Human-readable error description. One of: REGISTRY_UNAVAILABLE, TECHNICAL_ISSUES

      • timestamp: string | null ISO-8601 timestamp of when the registry responded. null when the registry was not reached

Possible status values

Status

Description

success

All checks passed or are not applicable

failure

One or more validations failed

error

Registry could not be reached or returned an unexpected response

Available validation_check values

Validation check

Description

Needs enablement by the SE?

consent_obtained

Whether the end-user's INE consent was provided

No

person_registered

Whether the person was found in the INE registry

No

selfie_registry_match

Whether the submitted selfie matches the registry portrait (default threshold: 80%)

No

not_reported_lost_or_stolen

Whether the voter card has not been reported lost or stolen

No

first_name_match

Whether the provided first name matches the INE registry

Yes

father_last_name_match

Whether the provided father's last name matches the INE registry

Yes

mother_last_name_match

Whether the provided mother's last name matches the INE registry

Yes

personal_number_match

Whether the provided CURP matches the INE registry

Yes

registration_year_match

Whether the provided document registration year matches the INE registry

Yes

issue_year_match

Whether the provided document issue year matches the INE registry

Yes

Possible reason values

reason

When it appears?

null

Validation passed

PERSON_NOT_FOUND

CIC not found in INE registry, downstream of person_registered failure

SELFIE_MISMATCH

Face match failed, downstream of selfie_registry_match failure

VALUE_MISMATCH

Data field did not match registry record, or voter card reported as lost or stolen

INPUT_NOT_PROVIDED

End-user declined consent (approved: false); or optional input was not sent

REGISTRY_UNAVAILABLE

Registry was unreachable

TECHNICAL_ISSUES

Internal processing error

OUTPUT_NOT_RECEIVED

Registry did not return the specific field needed for comparison

Note about object and field visibility

Some objects and fields within the registryValidations.MX_INE object are optional.

You should expect that any key may be omitted from the payload or return a null value.

A field is included in the response only when:

  • The registry check was successfully performed

  • The specific validation (e.g., first_name_match) is enabled in your configuration

  • The input data required for that specific check was provided

Validations that have been disabled by your Solutions Engineer are not included in the webhook output. Validations that are not_applicable due to a cascade failure are included.

Because the response schema is dynamic and based on both your specific configuration and the quality of the data provided, your application logic must account for omitted keys and null values as a standard part of the verification workflow.

Note on session outcomes

An approved session is identified by a verification.status of approved. For a clean result, all four core validations must pass: consent_obtained, person_registered, selfie_registry_match, and not_reported_lost_or_stolen.

Any enabled optional field validations must also pass or return not_applicable (when the corresponding input was not provided).

If optional field validations are not enabled, they are omitted from the payload and do not impact the approved status.

Validation cascade

The INE registry uses a validation cascade: if a core validation fails, downstream validations are automatically set to not_applicable. The reason value of a not_applicable validation reflects the upstream failure that caused it to be omitted, not a result of the validation itself.

Do not use the reason of a not_applicable validation to diagnose that specific check.

Cascade order

Session submitted
│
└── Consent provided?
      ├─ NO → consent_obtained = FAIL
      │       reasonCode: 640
      │       All remaining validations = N/A
      │
      └─ YES → consent_obtained = PASS
               │
               └── Registry contacted
                     │
                     ├── Registry error (unavailable, timeout, or invalid response)
                     │     → status: "error"
                     │     → validations: null
                     │
                     └── Registry responds successfully
                           │
                           └── Person found in INE registry?
                                 ├─ NO → person_registered = FAIL
                                 │       reasonCode: 902
                                 │       All remaining validations = N/A
                                 │
                                 └─ YES → person_registered = PASS
                                          │
                                          └── Face match score ≥ threshold?
                                                ├─ NO → selfie_registry_match = FAIL
                                                │       reasonCode: 581
                                                │       not_reported_lost_or_stolen = N/A
                                                │       All optional validations = N/A
                                                │
                                                └─ YES → selfie_registry_match = PASS
                                                         │
                                                         └── Document reported lost or stolen?
                                                               ├─ YES → not_reported_lost_or_stolen = FAIL
                                                               │        reasonCode: 904
                                                               │        All optional validations = N/A
                                                               │
                                                               └─ NO → not_reported_lost_or_stolen = PASS
                                                                        │
                                                                        └── Each enabled optional validation runs independently
                                                                              ├─ first_name_match
                                                                              ├─ father_last_name_match
                                                                              ├─ mother_last_name_match
                                                                              ├─ personal_number_match
                                                                              ├─ registration_year_match
                                                                              └─ issue_year_match
                                                                                    FAIL → reasonCode: 903

Cascade rules

  1. If consent is not passed in the session creation or consent_obtained fails, the session submission fails.

  2. If the registry is unavailable, validations is null and error is populated. No individual validation results are returned.

  3. If person_registered fails, all remaining validations are set to not_applicable.

  4. If selfie_registry_match fails, all remaining mandatory and optional validations are set to not_applicable.

  5. If not_reported_lost_or_stolen fails, all optional validations are set to not_applicable.

  6. For not_applicable validations, the reason value shows what caused the skip, not a result of the validation itself.

  7. If all core validations pass, each enabled optional validation is evaluated independently. A failure in one does not block the others.

Click to open an example of a declined session where person not found caused a cascading failure

{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "status": "declined",
    "code": 9102,
    "reason": "Person not found",
    "reasonCode": 902,
    "decisionTime": "2026-04-01T10:01:05.916Z",
    "acceptanceTime": "2026-04-01T10:00:27.000Z",
    "submissionTime": "2026-04-01T10:01:00.736Z",
    "person": {
      "firstName": "JUAN",
      "lastName": "GARCIA",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": "GARJ000000HMCRLP00",
      "yearOfBirth": null,
      "placeOfBirth": null
    },
    "document": {
      "number": "000000000",
      "type": "ID_CARD",
      "country": "MX",
      "state": null
    },
    "registryValidations": {
      "MX_INE": {
        "status": "failure",
        "data": null,
        "validations": {
          "consent_obtained": {
            "result": "success",
            "reason": null
          },
          "person_registered": {
            "result": "failure",
            "reason": "PERSON_NOT_FOUND"
          },
          "selfie_registry_match": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          },
          "not_reported_lost_or_stolen": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          },
          "first_name_match": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          },
          "father_last_name_match": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          },
          "mother_last_name_match": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          },
          "personal_number_match": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          },
          "registration_year_match": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          },
          "issue_year_match": {
            "result": "not_applicable",
            "reason": "PERSON_NOT_FOUND"
          }
        },
        "error": null,
        "timestamp": "2026-04-01T10:01:05.000Z"
      }
    },
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": null
  }
}

Sample payload of registryValidations.MX_INE object

The following is a sample response for an approved session with all possible registryValidations.MX_INE object values. All strings and IDs are placeholder values used for illustrative purposes only. Your production payload will contain real-time data from the registry check.

{
  "verification": {
    "registryValidations": {
      "MX_INE": {
        "status": "success",
        "data": null,
        "validations": {
          "consent_obtained": {
            "result": "success",
            "reason": null
          },
          "person_registered": {
            "result": "success",
            "reason": null
          },
          "selfie_registry_match": {
            "result": "success",
            "reason": null
          },
          "not_reported_lost_or_stolen": {
            "result": "success",
            "reason": null
          },
          "first_name_match": {
            "result": "success",
            "reason": null
          },
          "father_last_name_match": {
            "result": "success",
            "reason": null
          },
          "mother_last_name_match": {
            "result": "success",
            "reason": null
          },
          "personal_number_match": {
            "result": "success",
            "reason": null
          },
          "registration_year_match": {
            "result": "success",
            "reason": null
          },
          "issue_year_match": {
            "result": "success",
            "reason": null
          }
        },
        "error": null,
        "timestamp": "2026-04-01T10:01:05.000Z"
      }
    }
  }
}

Webhook payload

The examples below use placeholder data to show all mandatory parameters and possible Mexico - INE Biometric Database Verification fields. While mandatory fields are always present, solution-specific keys are omitted if a feature is disabled or data extraction fails. 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 (all validations passed)

{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "status": "approved",
    "code": 9001,
    "reason": null,
    "reasonCode": null,
    "decisionTime": "2026-04-01T10:01:05.916Z",
    "acceptanceTime": "2026-04-01T10:00:27.000Z",
    "submissionTime": "2026-04-01T10:01:00.736Z",
    "person": {
      "firstName": "JUAN",
      "lastName": "GARCIA",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": "GARJ000000HMCRLP00",
      "yearOfBirth": null,
      "placeOfBirth": null
    },
    "document": {
      "number": "000000000",
      "type": "ID_CARD",
      "country": "MX",
      "state": null
    },
    "registryValidations": {
      "MX_INE": {
        "status": "success",
        "data": null,
        "validations": {
          "consent_obtained": {
            "result": "success",
            "reason": null
          },
          "person_registered": {
            "result": "success",
            "reason": null
          },
          "selfie_registry_match": {
            "result": "success",
            "reason": null
          },
          "not_reported_lost_or_stolen": {
            "result": "success",
            "reason": null
          },
          "first_name_match": {
            "result": "success",
            "reason": null
          },
          "father_last_name_match": {
            "result": "success",
            "reason": null
          },
          "mother_last_name_match": {
            "result": "success",
            "reason": null
          },
          "personal_number_match": {
            "result": "success",
            "reason": null
          },
          "registration_year_match": {
            "result": "success",
            "reason": null
          },
          "issue_year_match": {
            "result": "success",
            "reason": null
          }
        },
        "error": null,
        "timestamp": "2026-04-01T10:01:05.000Z"
      }
    },
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": null
  }
}

Click to open an example of an approved session where optional field data was not provided (approved with not_applicable)

{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "status": "approved",
    "code": 9001,
    "reason": null,
    "reasonCode": null,
    "decisionTime": "2026-04-01T10:01:05.916Z",
    "acceptanceTime": "2026-04-01T10:00:27.000Z",
    "submissionTime": "2026-04-01T10:01:00.736Z",
    "person": {
      "firstName": "JUAN",
      "lastName": null,
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": null,
      "yearOfBirth": null,
      "placeOfBirth": null
    },
    "document": {
      "number": "000000000",
      "type": "ID_CARD",
      "country": "MX",
      "state": null
    },
    "registryValidations": {
      "MX_INE": {
        "status": "success",
        "data": null,
        "validations": {
          "consent_obtained": {
            "result": "success",
            "reason": null
          },
          "person_registered": {
            "result": "success",
            "reason": null
          },
          "selfie_registry_match": {
            "result": "success",
            "reason": null
          },
          "not_reported_lost_or_stolen": {
            "result": "success",
            "reason": null
          },
          "first_name_match": {
            "result": "success",
            "reason": null
          },
          "father_last_name_match": {
            "result": "NOT_APPLICABLE",
            "reason": "input_not_provided"
          },
          "personal_number_match": {
            "result": "NOT_APPLICABLE",
            "reason": "input_not_provided"
          }
        },
        "error": null,
        "timestamp": "2026-04-01T10:01:05.000Z"
      }
    },
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": "127.0.0.1"
  }
}

Click to open an example of a declined session where consent was declined

{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "status": "declined",
    "code": 9102,
    "reason": "Consent not obtained",
    "reasonCode": 640,
    "decisionTime": "2026-04-01T10:01:05.916Z",
    "acceptanceTime": "2026-04-01T10:00:27.000Z",
    "submissionTime": "2026-04-01T10:01:00.736Z",
    "person": {
      "firstName": "JUAN",
      "lastName": "GARCIA",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": null,
      "yearOfBirth": null,
      "placeOfBirth": null
    },
    "document": {
      "number": "000000000",
      "type": "ID_CARD",
      "country": "MX",
      "state": null
    },
    "registryValidations": {
      "MX_INE": {
        "status": "failure",
        "data": null,
        "validations": {
          "consent_obtained": {
            "result": "failure",
            "reason": "INPUT_NOT_PROVIDED"
          },
          "person_registered": {
            "result": "not_applicable",
            "reason": "INPUT_NOT_PROVIDED"
          },
          "selfie_registry_match": {
            "result": "not_applicable",
            "reason": "INPUT_NOT_PROVIDED"
          },
          "not_reported_lost_or_stolen": {
            "result": "not_applicable",
            "reason": "INPUT_NOT_PROVIDED"
          }
        },
        "error": null,
        "timestamp": null
      }
    },
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": null
  }
}

Click to open an example of a declined session where selfie mismatch caused a cascading failure

{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "status": "declined",
    "code": 9102,
    "reason": "Selfie mismatch",
    "reasonCode": 581,
    "decisionTime": "2026-04-01T10:01:05.916Z",
    "acceptanceTime": "2026-04-01T10:00:27.000Z",
    "submissionTime": "2026-04-01T10:01:00.736Z",
    "person": {
      "firstName": "JUAN",
      "lastName": "GARCIA",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": "GARJ000000HMCRLP00",
      "yearOfBirth": null,
      "placeOfBirth": null
    },
    "document": {
      "number": "000000000",
      "type": "ID_CARD",
      "country": "MX",
      "state": null
    },
    "registryValidations": {
      "MX_INE": {
        "status": "failure",
        "data": null,
        "validations": {
          "consent_obtained": {
            "result": "success",
            "reason": null
          },
          "person_registered": {
            "result": "success",
            "reason": null
          },
          "selfie_registry_match": {
            "result": "failure",
            "reason": "SELFIE_MISMATCH"
          },
          "not_reported_lost_or_stolen": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          },
          "first_name_match": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          },
          "father_last_name_match": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          },
          "mother_last_name_match": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          },
          "personal_number_match": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          },
          "registration_year_match": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          },
          "issue_year_match": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          }
        },
        "error": null,
        "timestamp": "2026-04-01T10:01:05.000Z"
      }
    },
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": null
  }
}

Click to open an example of a declined session where the voter card was reported as lost or stolen

{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "status": "declined",
    "code": 9102,
    "reason": "Value mismatch",
    "reasonCode": 904,
    "decisionTime": "2026-04-01T10:01:05.916Z",
    "acceptanceTime": "2026-04-01T10:00:27.000Z",
    "submissionTime": "2026-04-01T10:01:00.736Z",
    "person": {
      "firstName": "JUAN",
      "lastName": "GARCIA",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": "GARJ000000HMCRLP00",
      "yearOfBirth": null,
      "placeOfBirth": null
    },
    "document": {
      "number": "000000000",
      "type": "ID_CARD",
      "country": "MX",
      "state": null
    },
    "registryValidations": {
      "MX_INE": {
        "status": "failure",
        "data": null,
        "validations": {
          "consent_obtained": {
            "result": "success",
            "reason": null
          },
          "person_registered": {
            "result": "success",
            "reason": null
          },
          "selfie_registry_match": {
            "result": "not_applicable",
            "reason": "SELFIE_MISMATCH"
          },
          "not_reported_lost_or_stolen": {
            "result": "failure",
            "reason": "VALUE_MISMATCH"
          },
          "first_name_match": {
            "result": "not_applicable",
            "reason": "VALUE_MISMATCH"
          },
          "father_last_name_match": {
            "result": "not_applicable",
            "reason": "VALUE_MISMATCH"
          },
          "mother_last_name_match": {
            "result": "not_applicable",
            "reason": "VALUE_MISMATCH"
          },
          "personal_number_match": {
            "result": "not_applicable",
            "reason": "VALUE_MISMATCH"
          },
          "registration_year_match": {
            "result": "not_applicable",
            "reason": "VALUE_MISMATCH"
          },
          "issue_year_match": {
            "result": "not_applicable",
            "reason": "VALUE_MISMATCH"
          }
        },
        "error": null,
        "timestamp": "2026-04-01T10:01:05.000Z"
      }
    },
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": null
  }
}

Click to open an example of a declined session where the INE registry was unavailable

{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "status": "declined",
    "code": 9102,
    "reason": "Registry unavailable",
    "reasonCode": 901,
    "decisionTime": "2026-04-01T10:01:05.916Z",
    "acceptanceTime": "2026-04-01T10:00:27.000Z",
    "submissionTime": "2026-04-01T10:01:00.736Z",
    "person": {
      "firstName": "JUAN",
      "lastName": "GARCIA",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": null,
      "yearOfBirth": null,
      "placeOfBirth": null
    },
    "document": {
      "number": "000000000",
      "type": "ID_CARD",
      "country": "MX",
      "state": null
    },
    "registryValidations": {
      "MX_INE": {
        "status": "error",
        "data": null,
        "validations": null,
        "error": {
          "code": "registry_error",
          "message": "REGISTRY_UNAVAILABLE"
        },
        "timestamp": null
      }
    },
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": null
  }
}

Request properties explained

  • status: string Status of the response

  • verification: object Verification request decision object. null if decision is not available yet

    • id: string UUID v4 which identifies the verification session

    • attemptId: string UUID v4 of the attempt which received a status (as shown in verification.status field)

    • vendorData: string | null The unique identifier that you created for your end-user. null if not specified

    • endUserId: string | null The UUID that you created for your end-user. 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. For more info, see the verification session decision codes article

    • reason: string | null Reason why the verification failed. For more info, see the status and reason codes section below

    • reasonCode: integer | null Reason code of the failed verification

    • decisionTime: string | null Timestamp of the decision, represented as UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset (ISO 8601)

    • acceptanceTime: string Timestamp of the session generation, represented as UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset (ISO 8601)

    • submissionTime: string Timestamp of when the session was submitted, represented as UTC YYYY-MM-DDTHH:MM:SS.SSSSSS+Timezone Offset (ISO 8601)

    • person: object Data about the verified person

      • firstName: string | null Person's first name

      • lastName: string | null Person's father's last name

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

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

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

      • idNumber: string | null Person's CURP

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

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

    • document: object Data about verified document

      • number: string | null The 9-digit CIC, [0-9] characters only

      • type: string | null Document type, always ID_CARD

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

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

    • registryValidations: object Registry validation results for this session

      • MX_INE: object Results of the Mexican INE registry check

        • status: string Overall result of the registry check: success, failure, or error

        • data: null Always null because the INE registry does not return person data, it only confirms or denies matches

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

          • consent_obtained: object Whether the end-user's INE consent was provided

            • result: string Validation result

            • reason: string | null Reason for the result

          • person_registered: object Whether the person was found in the INE registry

            • result: string Validation result

            • reason: string | null Reason for the result

          • selfie_registry_match: object Whether the submitted selfie matches the registry portrait

            • result: string Validation result

            • reason: string | null Reason for the result

          • not_reported_lost_or_stolen: object Whether the voter card has not been reported as lost or stolen

            • result: string Validation result

            • reason: string | null Reason for the result

          • first_name_match: object Whether the provided first name matches the INE registry

            • result: string Validation result

            • reason: string | null Reason for the result

          • father_last_name_match: object Whether the provided father's last name matches the INE registry

            • result: string Validation result

            • reason: string | null Reason for the result

          • mother_last_name_match: object Whether the provided mother's last name matches the INE registry

            • result: string Validation result

            • reason: string | null Reason for the result

          • personal_number_match: object Whether the provided CURP matches the INE registry

            • result: string Validation result

            • reason: string | null Reason for the result

          • registration_year_match: object Whether the provided document registration year matches the INE registry

            • result: string Validation result

            • reason: string | null Reason for the result

          • issue_year_match: object Whether the provided document issue year matches the INE registry

            • result: string Validation result

            • reason: string | null Reason for the result

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

          • code: string Machine-readable error code, always registry_error

          • message: string Error description, one of REGISTRY_UNAVAILABLE, TECHNICAL_ISSUES

        • timestamp: string | null ISO-8601 timestamp of when the registry responded. null when the registry was not reached

    • additionalVerifiedData: object Data that has been optionally verified for the session. Returns empty {} if no additional data was verified

    • comments: array (Deprecated) Always returns empty []

  • technicalData: object Technical data object

    • ip: string | null IP address of the device from which the verification was made

API call

Sample response

The GET /v1/sessions/{sessionId}/decision API endpoint’s response payload is identical to decision webhook payload.

Response properties explained

The GET /v1/sessions/{sessionId}/decision API endpoint’s response payload is identical to decision webhook payload.

Veriff Customer Portal

You can find the verification session related info, including the decision, in the Veriff Customer Portal, under the Webhooks tab.

See Review verification in Veriff Customer Portal about how to view the session info in the Veriff Customer portal


Status and reason codes

Veriff runs a series of automated checks on the submitted data and biometric information. At the end, a decision is produced and delivered via webhook.

As the primary decision signal see:

  • verification.code for verification session decision code, one of 9001, 9102, 9103, 9104, 9121

  • verification.status for verification decision status, one of approved, declined, resubmission_requested, expired, abandoned

If the INE Biometric Database Verification session was declined, you can find additional information by checking:

  • verification.reason for the reason why the verification failed

  • verification.reasonCode for the reason code of the failed verification and cross-reference it with Granular reason codes (table)

How to interpret reasonCode and reason fields?

Use the verification.reasonCode to determine what kind of problem occurred and to create programmatic actions based on rejection outcomes.

Use the verification.reason for logging, display, and human interpretation only.

The verification.reasonCode is produced by registry match validations aka validations that run against the actual registry response (e.g., "did the selfie match?"). These come from a flat list of integer constants, meaning they are deliberate, stable, machine-readable signals that can be used for integration logic.

The verification.reason is a human-readable text string that describes why a verification was not approved.

  • The value is derived from the specific reason behind the registry validation that failed: for example, a name match check or a selfie match check. Each of these validations can fail for multiple different reasons (e.g., a name match can fail because the value did not match, or because the registry was unavailable). The reason field surfaces whichever specific reason applied in that session.

  • Because of this, there is no 1:1 relationship between reasonCode and reason. Values like registry_unavailable or technical_issues can appear under any reasonCode because they indicate that the relevant validation could not complete, not that the match itself failed. For more detail on how validation failure reasons propagate, see the Validation cascade → Cascade rules section.

verification.reasonCode

What it means

Default behavior*

Typical verification.reason values**

218

You have exceeded the upload limit of number the selfie images

resubmission_requested

Upload limit is exceeded

581

Selfie did not match the portrait in the INE registry

declined

Selfie mismatch with registry

640

End-user consent for the INE biometric check was not provided

declined

Consent not obtained

901

Registry provider error, meaning the INE/FIMPE registry was unreachable

declined

Technical issues
Registry unavailable

902

Person not found in the INE registry

declined

Person not found in registry

903

Personal information verification failed (name, CURP, or document date checks)

declined

Value mismatch
Output not received

904

Voter card reported as lost or stolen in the INE registry

declined

Value mismatch

* The "default behavior" column reflects the session outcome on a default configuration. Veriff can configure some of these validations differently per your request (e.g., turning a decline into a resubmission, or ignoring a check entirely).

** The "typical value" reflects the core failure condition of that validation. Other values can appear when the validation could not complete normally — for example, due to registry unavailability, missing input, or a disabled validation.


Additional information

Best practices

  1. CIC format validation: validate the CIC format client-side before creating a session. The CIC must be exactly digits. Passing an invalid CIC will result in a session failure.

  2. CURP format validation: if you send the CURP (verification.person.idNumber), validate its format client-side. A valid CURP is 18 characters in the format AAAA######AAAAAA##. Passing an incorrectly formatted CURP will cause the the whole session to fail with and person_registered.result: failure and person_registered.reason: INPUT_NOT_PROVIDED.

  3. Consent validation: ensure consents includes {"type": "ine", "approved": true} before creating the session. A missing or false value causes an immediate decline with reasonCode 640.

  4. Selfie image quality: ensure the end-user's selfie is a good quality, front-facing image with adequate lighting. The face similarity threshold is 80% by default, and poor image quality increases the risk of false negatives.

  5. Error handling: implement proper error handling for all three MX_INE.status values: success, failure, and error. When status is error, check error.code and error.message to determine whether to retry.

  6. Session declined due to third-party provider issues: implement proper session handling when a legitimate end-user's session is declined due to third-party service provider issues, as indicated by reasonCode 901. In case of upstream INE/FIMPE connectivity issues, Veriff retries up to 2 times internally before returning this error. Consider implementing retry logic with exponential backoff on your side for 901 errors.

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

  8. User experience: provide clear feedback to users about validation results. Inform end-users what their INE consent covers (biometric data processing against the INE registry) before session creation.

  9. Ensure backwards compatibility for webhooks and API connections


Changelog

Date

Description

Jun 16, 2026

validation_code changed to validaction_check for consistency

Jun 11, 2026

Added support for Mexican voter card validation

May 25, 2026

Article title and intro text updated

Availability matrix added

Feb 3, 2026

Documentation published