> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.vlenseg.com/llms.txt.
> For full documentation content, see https://docs.vlenseg.com/llms-full.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.vlenseg.com/_mcp/server.

# Quick Start

This guide walks through the minimal path to register a user and verify their identity. You'll need your `ApiKey` — get it from the [Vlens dashboard](https://dashboard.buildwithfern.com).

```mermaid
flowchart LR
    A[1. Get admin token] --> B[2. Register user]
    B --> C[3. Scan ID front]
    C --> D[4. Scan ID back]
    D --> E[5. Liveness check]
    E --> F([User verified ✓])
```

***

## 1. Get an admin token

```bash
curl -X POST https://api.vlenseg.com/api/credentials/Login \
  -H "ApiKey: YOUR_API_KEY" \
  -H "TenancyName: YOUR_TENANT" \
  -H "Content-Type: application/json" \
  -d '{
    "tenancyName": "YOUR_TENANT",
    "userNameOrEmailAddress": "admin@yourtenant.com",
    "password": "YOUR_PASSWORD"
  }'
```

```javascript
const res = await fetch("https://api.vlenseg.com/api/credentials/Login", {
  method: "POST",
  headers: {
    "ApiKey": "YOUR_API_KEY",
    "TenancyName": "YOUR_TENANT",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    tenancyName: "YOUR_TENANT",
    userNameOrEmailAddress: "admin@yourtenant.com",
    password: "YOUR_PASSWORD"
  })
});
const { data } = await res.json();
const adminToken = data.accessToken;
```

```python
import requests

res = requests.post(
    "https://api.vlenseg.com/api/credentials/Login",
    headers={
        "ApiKey": "YOUR_API_KEY",
        "TenancyName": "YOUR_TENANT"
    },
    json={
        "tenancyName": "YOUR_TENANT",
        "userNameOrEmailAddress": "admin@yourtenant.com",
        "password": "YOUR_PASSWORD"
    }
)
admin_token = res.json()["data"]["accessToken"]
```

**Response:**

```json
{
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expireInSeconds": 86400,
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}
```

***

## 2. Register a user

Registration is a two-step OTP flow: **send OTP → validate OTP → complete registration**.

```bash
# 2a — Send phone OTP
curl -X POST https://api.vlenseg.com/api/DigitalIdentity/Register/StepVerifyPhone \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber": "+201234567890"}'

# 2b — Validate OTP (use phoneNumberOtpRequestId from above response)
curl -X POST https://api.vlenseg.com/api/DigitalIdentity/Register/StepVerifyPhone \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+201234567890",
    "phoneNumberOtpRequestId": "SAVED_REQUEST_ID",
    "phoneNumberOtp": "123456"
  }'

# 2c — Complete registration
curl -X POST https://api.vlenseg.com/api/DigitalIdentity/Register \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+201234567890",
    "phoneNumberOtp": "123456",
    "phoneNumberOtpRequestId": "SAVED_REQUEST_ID"
  }'
```

```javascript
// 2a — Send OTP
const sendRes = await fetch(
  "https://api.vlenseg.com/api/DigitalIdentity/Register/StepVerifyPhone",
  {
    method: "POST",
    headers: { "ApiKey": API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ phoneNumber: "+201234567890" })
  }
);
const { data: sendData } = await sendRes.json();
const otpRequestId = sendData.phoneNumberOtpRequestId;

// 2b — Validate OTP
await fetch(
  "https://api.vlenseg.com/api/DigitalIdentity/Register/StepVerifyPhone",
  {
    method: "POST",
    headers: { "ApiKey": API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({
      phoneNumber: "+201234567890",
      phoneNumberOtpRequestId: otpRequestId,
      phoneNumberOtp: "123456"  // code entered by user
    })
  }
);

// 2c — Complete registration
const regRes = await fetch(
  "https://api.vlenseg.com/api/DigitalIdentity/Register",
  {
    method: "POST",
    headers: { "ApiKey": API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({
      phoneNumber: "+201234567890",
      phoneNumberOtp: "123456",
      phoneNumberOtpRequestId: otpRequestId
    })
  }
);
const { data: regData } = await regRes.json();
const userToken = regData.accessToken; // use this for verification calls
```

```python
BASE = "https://api.vlenseg.com"
HEADERS = {"ApiKey": API_KEY}

# 2a — Send OTP
send = requests.post(
    f"{BASE}/api/DigitalIdentity/Register/StepVerifyPhone",
    headers=HEADERS,
    json={"phoneNumber": "+201234567890"}
)
otp_request_id = send.json()["data"]["phoneNumberOtpRequestId"]

# 2b — Validate OTP
requests.post(
    f"{BASE}/api/DigitalIdentity/Register/StepVerifyPhone",
    headers=HEADERS,
    json={
        "phoneNumber": "+201234567890",
        "phoneNumberOtpRequestId": otp_request_id,
        "phoneNumberOtp": "123456"
    }
)

# 2c — Complete registration
reg = requests.post(
    f"{BASE}/api/DigitalIdentity/Register",
    headers=HEADERS,
    json={
        "phoneNumber": "+201234567890",
        "phoneNumberOtp": "123456",
        "phoneNumberOtpRequestId": otp_request_id
    }
)
user_token = reg.json()["data"]["accessToken"]
```

The registration response includes `data.accessToken` — use this as `Authorization: Bearer <token>` for all verification calls.

***

## 3 – 5. Verify identity

With the user token, submit the national ID and liveness images.

```bash
# 3 — ID front (omit transaction_id to start a new transaction)
curl -X POST https://api.vlenseg.com/api/DigitalIdentity/verify/id/front \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"image": "BASE64_ID_FRONT", "getExtractedData": true}'

# 4 — ID back (use transaction_id from previous response)
curl -X POST https://api.vlenseg.com/api/DigitalIdentity/verify/id/back \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"image": "BASE64_ID_BACK", "transaction_id": "TX_ID"}'

# 5 — Liveness (3 images captured within 0.5 seconds of each other)
curl -X POST https://api.vlenseg.com/api/DigitalIdentity/verify/liveness/multi \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "BASE64_ID_FRONT",
    "face_1": "BASE64_FACE_1",
    "face_2": "BASE64_FACE_2",
    "face_3": "BASE64_FACE_3",
    "transaction_id": "TX_ID"
  }'
```

```javascript
const AUTH = {
  "ApiKey": API_KEY,
  "Authorization": `Bearer ${userToken}`,
  "Content-Type": "application/json"
};

// 3 — ID front
const frontRes = await fetch(
  "https://api.vlenseg.com/api/DigitalIdentity/verify/id/front",
  { method: "POST", headers: AUTH,
    body: JSON.stringify({ image: base64Front, getExtractedData: true }) }
);
const txId = (await frontRes.json()).data.idFrontData.transaction_id;

// 4 — ID back
await fetch(
  "https://api.vlenseg.com/api/DigitalIdentity/verify/id/back",
  { method: "POST", headers: AUTH,
    body: JSON.stringify({ image: base64Back, transaction_id: txId }) }
);

// 5 — Liveness
const liveRes = await fetch(
  "https://api.vlenseg.com/api/DigitalIdentity/verify/liveness/multi",
  { method: "POST", headers: AUTH,
    body: JSON.stringify({
      image: base64Front,
      face_1: face1, face_2: face2, face_3: face3,
      transaction_id: txId
    }) }
);
const { data } = await liveRes.json();
console.log("Verified:", data.isDigitalIdentityVerified);
```

```python
AUTH = {"ApiKey": API_KEY, "Authorization": f"Bearer {user_token}"}

# 3 — ID front
front = requests.post(
    f"{BASE}/api/DigitalIdentity/verify/id/front",
    headers=AUTH,
    json={"image": base64_front, "getExtractedData": True}
)
tx_id = front.json()["data"]["idFrontData"]["transaction_id"]

# 4 — ID back
requests.post(
    f"{BASE}/api/DigitalIdentity/verify/id/back",
    headers=AUTH,
    json={"image": base64_back, "transaction_id": tx_id}
)

# 5 — Liveness
live = requests.post(
    f"{BASE}/api/DigitalIdentity/verify/liveness/multi",
    headers=AUTH,
    json={
        "image": base64_front,
        "face_1": face1, "face_2": face2, "face_3": face3,
        "transaction_id": tx_id
    }
)
verified = live.json()["data"]["isDigitalIdentityVerified"]
print(f"User verified: {verified}")
```

When `data.isDigitalIdentityVerified` is `true`, the user is fully verified and eligible to create contracts.

***

## Next steps

Token types, refresh flow, and security best practices

Full guide with error handling and edge cases

Create and sign FRA-compliant contracts

Complete error reference