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:
| Type | Description |
|---|---|
DOCUMENT_OCR | Extract data from INE, passport, driver's licence via OCR |
FACE_MATCH | Compare selfie against the document photo |
LIVENESS | Passive/active liveness detection |
GOVERNMENT_VERIFY | Cross-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:
| Status | Meaning |
|---|---|
PENDING | Created, waiting for document uploads |
IN_PROGRESS | Documents received, steps executing |
APPROVED | All steps passed |
REJECTED | One or more steps failed decisively |
MANUAL_REVIEW | Flagged for human review |
EXPIRED | Verification timed out without completion |
Next Steps
- Set up webhooks to receive real-time events instead of polling
- Explore all endpoints — OTP, AML screening, workflow management
- Embed the Web SDK so end-users can upload documents from their browser
- Use the Node.js SDK for type-safe server-side integration