> 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.

# Request OTP

Sends the customer an SMS with a one-time password, then confirms the action using that OTP. The OTP type (`otpTypeId`) determines what's being verified and which `parameters` the SMS template fills in — for example, `otpTypeId: 1` is Purchase Authorization, confirming a purchase with its amount, tenor, and installment details.

## Flow

#### Request OTP

Call `POST /api/OtpRequests/RequestOtp` with the `otpTypeId` and any parameters for that type. VLens sends the SMS and returns a `phoneNumberOtpRequestId`.

#### Customer receives the SMS

The SMS includes the OTP and the relevant details, using the template configured for that OTP type.

#### Confirm OTP

Call `POST /api/OtpRequests/ConfirmOtp` with the same request details, the `phoneNumberOtpRequestId`, and the OTP the customer received.

---

## Step 1 — Request OTP

`POST /api/OtpRequests/RequestOtp`

#### cURL

```bash
curl -X POST https://api.vlenseg.com/api/OtpRequests/RequestOtp \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "otpTypeId": 1,
    "transactionId": "YOUR_TRANSACTION_ID",
    "phoneNumber": "PHONE_NUMBER",
    "lang": "ar",
    "parameters": {
      "amount": "5000",
      "tenor": "12",
      "installment_amount": "450"
    }
  }'
```

| Field           | Required | Description                                                                                           |
| --------------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `otpTypeId`     | Yes      | The OTP type, e.g. `1` = Purchase Authorization.                                                      |
| `transactionId` | Yes      | Caller-supplied identifier for this request. Echoed back in step 2.                                   |
| `phoneNumber`   | Yes      | The phone number to send the SMS and OTP to.                                                          |
| `lang`          | No       | Language of the SMS template, e.g. `ar` or `en`.                                                      |
| `parameters`    | No       | Values substituted into the SMS template for that OTP type — see [SMS template](#sms-template) below. |

```json
{
  "data": {
    "phoneNumberOtpRequestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "error_code": 0,
  "error_message": null,
  "error_descriptions": null
}
```

Keep the `phoneNumberOtpRequestId` — you send it back in step 3.

---

## Step 2 — Confirm OTP

`POST /api/OtpRequests/ConfirmOtp`

#### cURL

```bash
curl -X POST https://api.vlenseg.com/api/OtpRequests/ConfirmOtp \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "otpTypeId": 1,
    "transactionId": "YOUR_TRANSACTION_ID",
    "phoneNumber": "PHONE_NUMBER",
    "phoneNumberOtpRequestId": "OTP_REQUEST_ID",
    "phoneNumberOtp": "123456"
  }'
```

| Field                     | Required | Description                                 |
| ------------------------- | -------- | ------------------------------------------- |
| `otpTypeId`               | Yes      | Must match the value sent in step 1.        |
| `transactionId`           | Yes      | Must match the value sent in step 1.        |
| `phoneNumber`             | Yes      | Must match the value sent in step 1.        |
| `phoneNumberOtpRequestId` | Yes      | Returned by step 1.                         |
| `phoneNumberOtp`          | Yes      | The OTP code the customer received via SMS. |

A successful confirmation returns no `error_code`:

```json
{
  "data": null,
  "error_code": null,
  "error_message": null,
  "error_descriptions": null
}
```

> **Note**
>
> The full shape of a successful `data` response hasn't been confirmed yet — only that `error_code` is absent on success. This page will be updated once that's available.

---

## SMS template

Each OTP type has its own template, configured per-tenant from the portal:

**Administration → Settings → Messages Management**

Every template must include `{OTP}`. Other placeholders depend on the OTP type and are filled from the `parameters` you send in step 1.

### Example: Purchase Authorization (`otpTypeId: 1`)

Portal entry: **Purchase Authorization OTP SMS** — the template must include `{OTP}` and `{AMOUNT}`.

| Placeholder            | `parameters` key                |
| ---------------------- | ------------------------------- |
| `{Amount}`             | `amount`                        |
| `{Tenor}`              | `tenor`                         |
| `{Installment_Amount}` | `installment_amount`            |
| `{OTP}`                | — filled automatically by VLens |

Example template (Arabic):

> عزيزي العميل، لقد استقبلنا طلبك لعملية شراء بقيمة \{Amount} جنيه ومدة التمويل \{Tenor} شهر بقسط شهري \{Installment_Amount} جنيه. لتأكيد عملية الشراء برجاء استخدام كود: \{OTP}

> **Note**
>
> Which `parameters` keys are supported for `otpTypeId` values other than `1` hasn't been confirmed yet.

---

## Portal: OTP Requests screen

A dedicated OTP Requests screen in the portal lets users view and track sent OTPs. Access requires the **OTP Requests** permission.

---

## Error codes

| Code | Meaning                                                                        |
| ---- | ------------------------------------------------------------------------------ |
| 6101 | OTP already used, attempts exhausted, or request not found                     |
| 6105 | OTP Code Expired — see [Error codes](/errors#identity--contract-errors-6xxx)   |
| 6106 | OTP Code Incorrect — see [Error codes](/errors#identity--contract-errors-6xxx) |