VerifyMX Docs

Getting started

Create an account, exchange a token, run your first verification in minutes.

This guide walks through the complete integration lifecycle from account creation to receiving your first verification result.

Two ways to integrate

For Node.js / TypeScript backends we recommend the official SDK — it handles auth caching, retries, idempotency, webhook signatures, and polling for you:

import { VerifyMXClient } from '@verifymx/sdk-node';
import { readFileSync } from 'node:fs';

const vmx = new VerifyMXClient({
  clientId: process.env.VERIFYMX_CLIENT_ID!,
  clientSecret: process.env.VERIFYMX_CLIENT_SECRET!,
});

const ver = await vmx.createVerification({ workflowId: 'wf_default' });
await vmx.uploadDocument(ver.id, readFileSync('./ine-front.jpg'), 'ine-front.jpg', 'front');
const result = await vmx.waitUntilTerminal(ver.id);
// result.status: APPROVED | REJECTED | MANUAL_REVIEW | EXPIRED

See the Node.js SDK page for full reference. For every other language, use the REST API directly — examples below all use curl, and they translate 1:1 to fetch / requests / Faraday / Guzzle in your language of choice. Replace http://localhost:3001 with https://api.verifymx.xyz in production.


Step 1 — Create an Account

POST /v1/auth/register creates your organization, admin user, and first API key in a single call. The raw API key is returned exactly once — store it in a secrets manager immediately.

curl -s -X POST http://localhost:3001/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "orgName": "Acme Corp",
    "email": "dev@acme.mx",
    "password": "supersecretpass123"
  }'

Response 201:

{
  "org": {
    "id": "org_01HXYZ...",
    "name": "Acme Corp",
    "slug": "acme-corp"
  },
  "user": {
    "id": "usr_01HXYZ...",
    "email": "dev@acme.mx",
    "role": "OWNER"
  },
  "apiKey": {
    "id": "key_01HXYZ...",
    "name": "Default key",
    "key": "vmx_a1b2c3d4e5f6...",
    "prefix": "vmx_a1b2c3d4",
    "createdAt": "2026-04-08T12:00:00.000Z"
  }
}

Save org.id as your client_id and apiKey.key as your client_secret. You will need both to obtain access tokens.


Step 2 — Get an Access Token

Tokens use the OAuth 2.0 client_credentials grant. They expire in 1 hour.

TOKEN=$(curl -s -X POST http://localhost:3001/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "org_01HXYZ...",
    "client_secret": "vmx_a1b2c3d4e5f6..."
  }' | jq -r '.access_token')

echo "Token: $TOKEN"

Response 200:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Use the token in all subsequent requests as Authorization: Bearer <token>.


Step 3 — Create a Workflow

A workflow defines which verification steps are executed and in what order.

Available step types:

TypeDescription
DOCUMENT_OCRExtract data from INE, passport, driver's licence via OCR
FACE_MATCHCompare selfie against the document photo
LIVENESSPassive/active liveness detection
GOVERNMENT_VERIFYCross-reference against RENAPO/INE government databases
curl -s -X POST http://localhost:3001/v1/workflows \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "INE + Selfie",
    "description": "Standard INE OCR with face match",
    "steps": [
      { "type": "DOCUMENT_OCR", "order": 0 },
      { "type": "FACE_MATCH",   "order": 1 }
    ]
  }'

Response 201:

{
  "workflow": {
    "id": "wf_01HXYZ...",
    "name": "INE + Selfie",
    "isActive": true,
    "steps": [
      { "id": "ws_01...", "type": "DOCUMENT_OCR", "order": 0 },
      { "id": "ws_02...", "type": "FACE_MATCH",   "order": 1 }
    ],
    "createdAt": "2026-04-08T12:00:00.000Z"
  }
}

Save the workflow.id — you will use it when creating verifications.


Step 4 — Create a Verification

A verification is a single identity check session for one end-user.

curl -s -X POST http://localhost:3001/v1/verifications \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workflowId": "wf_01HXYZ...",
    "metadata": { "userId": "internal-user-42" },
    "externalId": "user-42"
  }'

Response 201:

{
  "verification": {
    "id": "ver_01HXYZ...",
    "status": "PENDING",
    "workflowId": "wf_01HXYZ...",
    "externalId": "user-42",
    "metadata": { "userId": "internal-user-42" },
    "createdAt": "2026-04-08T12:00:00.000Z"
  }
}

The verification starts in PENDING status and moves to IN_PROGRESS once documents are uploaded.


Step 5 — Upload Documents

Send document images and selfies as multipart form fields. Field names determine the document type (e.g. front, back, selfie). Supported formats: JPEG, PNG, WebP, PDF. Maximum file size: 10 MB per file, up to 10 files per request.

# Upload INE front + back + selfie in one request
curl -s -X POST "http://localhost:3001/v1/verifications/ver_01HXYZ.../inputs" \
  -H "Authorization: Bearer $TOKEN" \
  -F "front=@/path/to/ine_front.jpg;type=image/jpeg" \
  -F "back=@/path/to/ine_back.jpg;type=image/jpeg" \
  -F "selfie=@/path/to/selfie.jpg;type=image/jpeg"

Response 202:

{
  "uploaded": [
    { "id": "doc_01...", "type": "front",  "mimeType": "image/jpeg" },
    { "id": "doc_02...", "type": "back",   "mimeType": "image/jpeg" },
    { "id": "doc_03...", "type": "selfie", "mimeType": "image/jpeg" }
  ],
  "message": "Documents queued for processing"
}

Document processing runs asynchronously in the background. Poll the verification or listen for webhooks.


Step 6 — Check Results

Poll the verification endpoint, or better yet, subscribe to webhooks (see Webhooks).

curl -s "http://localhost:3001/v1/verifications/ver_01HXYZ..." \
  -H "Authorization: Bearer $TOKEN"

Response 200:

{
  "verification": {
    "id": "ver_01HXYZ...",
    "status": "APPROVED",
    "workflowId": "wf_01HXYZ...",
    "steps": [
      {
        "id": "vs_01...",
        "type": "DOCUMENT_OCR",
        "status": "PASSED",
        "result": {
          "name": "JUAN PÉREZ GARCÍA",
          "curp": "PEGJ800101HMCRRN09",
          "clave": "IDMEXABC123456"
        }
      },
      {
        "id": "vs_02...",
        "type": "FACE_MATCH",
        "status": "PASSED",
        "result": { "similarity": 0.97 }
      }
    ],
    "createdAt": "2026-04-08T12:00:00.000Z",
    "updatedAt": "2026-04-08T12:00:45.000Z"
  },
  "documents": [
    { "id": "doc_01...", "type": "front", "mimeType": "image/jpeg" }
  ]
}

Verification statuses:

StatusMeaning
PENDINGCreated, waiting for document uploads
IN_PROGRESSDocuments received, steps executing
APPROVEDAll steps passed
REJECTEDOne or more steps failed decisively
MANUAL_REVIEWFlagged for human review
EXPIREDVerification timed out without completion

Next Steps

On this page