> 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 AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.vlenseg.com/_mcp/server.

# User Profile

This page covers all user-facing account management flows: login (with OTP), token refresh, email and phone updates, password change, and password reset.

---

## Registration paths

Vlens has **two separate registration flows**. Choose one per user based on `CheckExistenceOfEmailOrPhone`:

| Flow         | When to use                                                        | User-facing steps                                                                            | Documented in                                                           |
| ------------ | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| **Standard** | `hasCDI` is `false` or absent — new user                           | 8 — phone OTP (send + enter), email OTP (send + enter), account, ID front, ID back, liveness | This page → [Standard registration flow](#standard-registration-flow)   |
| **CDI**      | `hasCDI: true` — network identity eligible for consent-based reuse | 2 — phone OTP (consent), liveness                                                            | [Consent-based Digital Identity (CDI)](/consent-based-digital-identity) |

Do not combine steps from both flows (for example, do not call `verify/id/front` after a CDI `StepCreate`).

---

## Standard registration flow

Phone OTP → optional email OTP → `StepCreate` → then ID scan and liveness on the [Digital Identity](/digital-identity#identity-verification-standard-registration-only) page. Login only repeats the phone OTP step afterward.

```mermaid
flowchart TD
    A([Start]) --> B["CheckExistenceOfEmailOrPhone\nphone + email"]
    B --> C{Already\nregistered?}
    C -- Yes --> D(["❌ Phone or email already in use\nAsk user to login instead"])
    C -- No --> E["StepVerifyPhone\nSend OTP to phone"]
    E --> F[User enters phone OTP]
    F --> G["StepVerifyPhone\nValidate OTP"]
    G --> H{Email\nrequired?}
    H -- "No — skipEmail: true" --> J
    H -- Yes --> I["StepVerifyEmail\nSend OTP to email"]
    I --> I2[User enters email OTP]
    I2 --> I3["StepVerifyEmail\nValidate OTP"]
    I3 --> J

    J["StepCreate\ngeoLocation, imei, password, OTP IDs\n→ Returns accessToken"]

    J --> K

    subgraph KYC["Identity Verification — required once at registration"]
        K["① POST /verify/id/front\nimage: ID front photo\n→ Returns transaction_id"]
        K --> L["② POST /verify/id/back\ntransaction_id + image: ID back photo"]
        L --> M["③ POST /verify/liveness/multi\ntransaction_id + face_1, face_2, face_3"]
    end

    M --> N(["✅ isDigitalIdentityVerified: true\nUser can now sign contracts"])
```

This diagram is the **standard** path only. If `CheckExistenceOfEmailOrPhone` returns `hasCDI: true`, stop here and follow [Consent-based Digital Identity (CDI)](/consent-based-digital-identity) instead — no `verify/*` steps afterward.

After standard registration, **login does not repeat** the ID or liveness steps. The user only enters phone + password and validates the SMS OTP.

---

## Login

Login calls the same endpoint twice — first to trigger the OTP SMS, then to validate it and receive tokens.

```mermaid
sequenceDiagram
    actor User
    participant App
    participant Vlens

    Note over User,Vlens: Login — no ID scanning or liveness required

    User->>App: Enter phone + password
    App->>+Vlens: POST /Login<br />{ phone, password, geoLocation, imei }
    Vlens-->>-App: { phoneNumberOtpRequestId }
    Vlens--)User: SMS OTP sent

    User->>App: Enter OTP code
    App->>+Vlens: POST /Login<br />{ phone, password, phoneNumberOtpRequestId, phoneNumberOtp }
    Vlens-->>-App: { accessToken, refreshToken, isDigitalIdentityVerified }
    App->>User: Logged in ✓
```

### Step 1 — Submit credentials (triggers SMS OTP)

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/Login" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "geoLocation": { "latitude": 30.0444, "longitude": 31.2357 },
    "imei": "DEVICE_ID",
    "phoneNumber": "+201234567890",
    "password": "USER_PASSWORD",
    "smsProviders": 0
  }'
```

Save `data.phoneNumberOtpRequestId` from the response.

### Step 2 — Validate OTP and receive tokens

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/Login" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "geoLocation": { "latitude": 30.0444, "longitude": 31.2357 },
    "imei": "DEVICE_ID",
    "phoneNumber": "+201234567890",
    "password": "USER_PASSWORD",
    "smsProviders": 0,
    "phoneNumberOtpRequestId": "OTP_REQUEST_ID",
    "phoneNumberOtp": "123456"
  }'
```

**Response:**

```json
{
  "data": {
    "accessToken": "eyJ...",
    "refreshToken": "eyJ...",
    "expireInSeconds": 86400,
    "isDigitalIdentityVerified": true,
    "hasPendingRequest": false,
    "user": {
      "fullName": "Ahmed Mohamed",
      "phoneNumber": "+201234567890",
      "idNumber": "29901234567890"
    }
  },
  "error_code": null
}
```

`smsProviders` values: `0` = default, `1` = Infobip, `2` = Vodafone, `3` = Cequens, `4` = Victory Link, `5` = BroadNet, `6` = Ezagel, `7` = Orange.

---

## Hosted registration and login links

When you do not want to build a registration or login UI, generate a signed Vlens web URL server-side and redirect the user to it. This is a **browser redirect** flow — not the same as [Iframe Integration](/iframe-session) and not related to [linking a pre-login transaction](/digital-identity#alternative-link-an-existing-transaction).

| Endpoint                                         | Purpose                  |
| ------------------------------------------------ | ------------------------ |
| `POST /api/DigitalIdentity/GenerateRegisterLink` | Hosted registration flow |
| `POST /api/DigitalIdentity/GenerateLoginLink`    | Hosted login flow        |

Both accept optional `phoneNumber`, `email`, `latitude`, `longitude`, `imei`, and `returnUrl`. The response `data` field is the URL to open in a browser.

```bash
curl -X POST https://api.vlenseg.com/api/DigitalIdentity/GenerateRegisterLink \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+201234567890",
    "returnUrl": "https://yourapp.com/registration-complete"
  }'
```

---

## Refresh token

```mermaid
flowchart LR
    A{Token\nexpired?} -- User token --> B["POST /DigitalIdentity/RefreshToken\n{ refreshToken }"]
    A -- Admin token --> C["POST /credentials/RefreshToken\n{ refreshToken }"]
    B --> D(["New accessToken\n+ refreshToken"])
    C --> D
```

#### User token

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/RefreshToken" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer CURRENT_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"refreshToken": "YOUR_REFRESH_TOKEN"}'
```

#### Admin token

```bash
curl -X POST "https://api.vlenseg.com/api/credentials/RefreshToken" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer CURRENT_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"refreshToken": "YOUR_REFRESH_TOKEN"}'
```

Both return `data.accessToken` and `data.refreshToken`.

---

## Log out

Invalidate the current user session. Requires `ApiKey` and a user bearer token.

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/Logout" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN"
```

---

## Update email

```mermaid
flowchart LR
    A["UpdateEmailRequest\n{ email: new@example.com }"] -->|emailOtpRequestId| B["ValidateUpdateEmailRequestOtp\n{ emailOtpRequestId, emailOtp }"]
    B --> C(["✅ Email updated"])
```

### Step 1 — Request email OTP

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/UpdateEmailRequest" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "new@example.com"}'
```

Save `data.emailOtpRequestId` from the response.

### Step 2 — Validate OTP

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ValidateUpdateEmailRequestOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "emailOtpRequestId": "OTP_REQUEST_ID",
    "emailOtp": "123456"
  }'
```

---

## Verify email (post-registration)

If email verification was skipped during registration (`skipEmail: true`), the user can verify later.

```mermaid
flowchart LR
    A["VerifyEmail\n{ email }"] -->|emailOtpRequestId| B["VerifyEmail\n{ email, emailOtpRequestId, emailOtp }"]
    B --> C(["✅ Email verified"])
```

### Step 1 — Request email OTP

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/VerifyEmail" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'
```

Save `data.emailOtpRequestId`.

### Step 2 — Validate OTP

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/VerifyEmail" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "emailOtpRequestId": "OTP_REQUEST_ID",
    "emailOtp": "123456"
  }'
```

---

## Update phone number

Changing a phone number requires liveness re-validation before the OTP is sent.

```mermaid
flowchart TD
    A["SendPhoneOtp\n{ newPhone, password }"] --> B{Liveness\nrequired?}
    B -- No --> C["phoneNumberOtpRequestId returned"]
    B -- Yes --> D["ReValidateLiveness\n{ phone, password, image: face }"]
    D --> E["New phoneNumberOtpRequestId"]
    C --> F["ValidatePhoneOtp\n{ phoneNumberOtpRequestId, OTP }"]
    E --> F
    F --> G(["✅ Phone number updated"])
```

### Step 1 — Send OTP to new number

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/UpdatePhone/SendPhoneOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+201234567891",
    "password": "USER_PASSWORD",
    "smsProviders": 0
  }'
```

Save `data.phoneNumberOtpRequestId`.

### Step 2 — Re-validate liveness *(if required)*

If the response indicates liveness re-validation is needed:

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/UpdatePhone/ReValidateLiveness" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+201234567891",
    "password": "USER_PASSWORD",
    "image": "BASE64_FACE_IMAGE"
  }'
```

Save the new `data.phoneNumberOtpRequestId` from this response.

### Step 3 — Validate OTP

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/UpdatePhone/ValidatePhoneOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumberOtpRequestId": "OTP_REQUEST_ID",
    "phoneNumberOtp": "123456"
  }'
```

---

## Change password

Changing the current password sends an OTP to the registered email to confirm the change.

```mermaid
flowchart LR
    A["ChangePasswordRequest\n{ currentPassword, newPassword }"] -->|emailOtpRequestId| B["ValidateChangePasswordRequest\n{ passwords, emailOtpRequestId, emailOtp }"]
    B --> C(["✅ Password changed"])
```

### Step 1 — Request password change

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ChangePasswordRequest" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "currentPassword": "CURRENT_PASSWORD",
    "newPassword": "NEW_PASSWORD"
  }'
```

Save `data.emailOtpRequestId`.

### Step 2 — Validate OTP and confirm change

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ValidateChangePasswordRequest" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "currentPassword": "CURRENT_PASSWORD",
    "newPassword": "NEW_PASSWORD",
    "emailOtpRequestId": "OTP_REQUEST_ID",
    "emailOtp": "123456"
  }'
```

---

## Reset password

```mermaid
flowchart TD
    A([Forgot password]) --> B{Have\nemail access?}
    B -- Yes --> C[Via email + phone\n4 steps]
    B -- No --> D[Via phone only\n3 steps]

    C --> C1["ForgetPassword/SendEmailOtp"]
    C1 --> C2["ForgetPassword/ValidateEmailOtp\n→ triggers phone OTP"]
    C2 --> C3["ForgetPassword/ValidatePhoneOtp\n→ returns userId + resetCode"]
    C3 --> C4["ForgetPassword/Reset\n{ userId, resetCode, newPassword }"]
    C4 --> E(["✅ Password reset"])

    D --> D1["ForgetPasswordByPhone/SendPhoneOtp"]
    D1 --> D2["ForgetPasswordByPhone/ValidatePhoneOtp\n→ returns userId + resetCode"]
    D2 --> D3["ForgetPasswordByPhone/Reset\n{ userId, resetCode, newPassword }"]
    D3 --> E
```

V2 variants (`SendEmailOtpV2`, `ValidateEmailOtpV2`, `ValidatePhoneOtpV2`, `ResetV2`) follow the same steps with updated validation rules.

### Via email + phone (4 steps)

**Step 1 — Send OTP to email**

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ForgetPassword/SendEmailOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emailOrPhoneNumber": "+201234567890",
    "idNumber": ""
  }'
```

Save `data.emailOtpRequestId`.

**Step 2 — Validate email OTP (triggers phone OTP)**

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ForgetPassword/ValidateEmailOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emailOrPhoneNumber": "+201234567890",
    "idNumber": "",
    "emailOtpRequestId": "EMAIL_OTP_REQUEST_ID",
    "emailOtp": "123456",
    "smsProviders": 0
  }'
```

Save `data.phoneNumberOtpRequestId`.

**Step 3 — Validate phone OTP**

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ForgetPassword/ValidatePhoneOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emailOrPhoneNumber": "+201234567890",
    "idNumber": "",
    "phoneNumberOtpRequestId": "PHONE_OTP_REQUEST_ID",
    "phoneNumberOtp": "123456"
  }'
```

Save `data.userId` and `data.passwordResetCode`.

**Step 4 — Set new password**

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ForgetPassword/Reset" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 12345,
    "resetCode": "RESET_CODE",
    "password": "NEW_PASSWORD"
  }'
```

### Via phone only (3 steps)

**Step 1 — Send OTP to phone**

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ForgetPasswordByPhone/SendPhoneOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber": "+201234567890"}'
```

Save `data.phoneNumberOtpRequestId`.

**Step 2 — Validate phone OTP**

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ForgetPasswordByPhone/ValidatePhoneOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+201234567890",
    "phoneNumberOtpRequestId": "OTP_REQUEST_ID",
    "phoneNumberOtp": "123456"
  }'
```

Save `data.userId` and `data.passwordResetCode`.

**Step 3 — Set new password**

```bash
curl -X POST "https://api.vlenseg.com/api/DigitalIdentity/ForgetPasswordByPhone/Reset" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 12345,
    "resetCode": "RESET_CODE",
    "password": "NEW_PASSWORD"
  }'
```