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

# E-Contracting

The e-contracting flow replaces paper contracts with end-to-end digital agreements — legally compliant under the Financial Regulatory Authority (FRA) of Egypt. Vlens handles form collection, document generation, OTP-based customer signing, and service-provider countersignature.

***

## Prerequisites

Before creating a contract, the user must:

* Be **registered** in Vlens (have a user access token)
* Have a **verified digital identity** (`isDigitalIdentityVerified: true`)

***

## Contract lifecycle

```mermaid
flowchart TD
    A[GetAllRequestTypes] --> B[GetBusinessRequestTypeTemplateFields]
    B --> C[CheckEligibility]
    C --> D{isEligible?}
    D -- No --> E[Surface blocking reason to user]
    D -- Yes --> F["Create/{typeId}"]
    F --> G[Pending Approval]
    G --> H{Admin approval}
    H -- Rejected --> I[Status: Rejected]
    H -- Approved --> J[StepRequestOtp]
    J --> K{Location check}
    K -- within 80km --> L[StepValidateOtp]
    K -- over 80km --> M[StepReValidateLiveness]
    M --> L
    L --> N[StepValidatePayment]
    N --> O[Status: Customer Signed]
    O --> P[Provider countersigns]
    P --> Q[Status: Service Provider Signed]
```

***

## Step 1 — Discover product types

```bash
curl "https://api.vlenseg.com/api/BusinessRequest/GetAllRequestTypes" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN"
```

```javascript
const res = await fetch(
  "https://api.vlenseg.com/api/BusinessRequest/GetAllRequestTypes",
  { headers: { "ApiKey": API_KEY, "Authorization": `Bearer ${token}` } }
);
const { data } = await res.json();
// data is an array of { id, name, type, typeName }
```

```python
res = requests.get(
    "https://api.vlenseg.com/api/BusinessRequest/GetAllRequestTypes",
    headers={"ApiKey": API_KEY, "Authorization": f"Bearer {token}"}
)
types = res.json()["data"]
```

Use the returned `id` (e.g. `414`) in steps 2 and 4.

***

## Step 2 — Get form fields

```bash
curl "https://api.vlenseg.com/api/BusinessRequest/GetBusinessRequestTypeTemplateFields\
?requestTypeId=414" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN"
```

The response contains `requestsFields` — an array of fields the user must fill in. Each field has:

| Property               | Description                                                              |
| ---------------------- | ------------------------------------------------------------------------ |
| `key`                  | Machine identifier — use this as the key in `requestFieldsValues`        |
| `displayText`          | English label                                                            |
| `displayArText`        | Arabic label                                                             |
| `type`                 | Field type: `text`, `dropdown`, `date`, `table`, etc.                    |
| `availableValuesItems` | Options for dropdown fields                                              |
| `parentQuestionKey`    | Shows this field only when the parent field equals `parentQuestionValue` |

***

## Step 3 — Check eligibility

```bash
curl "https://api.vlenseg.com/api/BusinessRequest/CheckEligibility" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN"
```

```javascript
const { data } = await (await fetch(
  "https://api.vlenseg.com/api/BusinessRequest/CheckEligibility",
  { headers: { "ApiKey": API_KEY, "Authorization": `Bearer ${token}` } }
)).json();

if (!data.isEligible) {
  if (!data.isDigitalIdentityVerified) showError("Please verify your identity first.");
  if (data.hasPendingRequest)          showError("You already have a pending request.");
  if (!data.isEmailConfirmed)          showError("Please confirm your email address.");
}
```

`isEligible` is `true` only when all checks pass simultaneously.

***

## Step 4 — Create the request

```bash
curl -X POST "https://api.vlenseg.com/api/BusinessRequest/Create/414" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "geoLocation": { "latitude": 30.0444, "longitude": 31.2357 },
    "userDeviceUtcTime": "2025-01-15T10:30:00Z",
    "requestFieldsValues": {
      "fullName": "Ahmed Mohamed",
      "nationalId": "29901234567890",
      "monthlyIncome": "5000"
    }
  }'
```

```javascript
const res = await fetch(
  "https://api.vlenseg.com/api/BusinessRequest/Create/414",
  {
    method: "POST",
    headers: {
      "ApiKey": API_KEY,
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      geoLocation: { latitude: 30.0444, longitude: 31.2357 },
      userDeviceUtcTime: new Date().toISOString(),
      requestFieldsValues: {
        fullName: "Ahmed Mohamed",
        nationalId: "29901234567890",
        monthlyIncome: "5000"
      }
    })
  }
);
const { data } = await res.json();
const requestId = data.id; // save this for the signing steps
```

```python
from datetime import datetime, timezone

res = requests.post(
    "https://api.vlenseg.com/api/BusinessRequest/Create/414",
    headers={"ApiKey": API_KEY, "Authorization": f"Bearer {token}"},
    json={
        "geoLocation": {"latitude": 30.0444, "longitude": 31.2357},
        "userDeviceUtcTime": datetime.now(timezone.utc).isoformat(),
        "requestFieldsValues": {
            "fullName": "Ahmed Mohamed",
            "nationalId": "29901234567890",
            "monthlyIncome": "5000"
        }
    }
)
request_id = res.json()["data"]["id"]
```

**Save the returned `id`** — this is the request ID required for all signing steps.

***

## Step 5 — Admin approval

After creation, the request enters **Pending Approval** status. An admin must approve it via:

* The Vlens portal (manual review)
* Auto-approval (if configured for your tenant)

Subscribe to the `App.BusinessRequestStatusChange` webhook in the portal to receive real-time status updates instead of polling.

**Webhook payload example:**

```json
{
  "WebhookEvent": "App.BusinessRequestStatusChange",
  "Data": {
    "Id": "81f404b3-d7dc-4f08-b4fe-934853c86282",
    "NewStatus": "Approved"
  },
  "CreationTimeUtc": "2025-01-15T10:35:00Z"
}
```

***

## Step 6 — Customer signing flow

Once approved, the user activates the contract via a location-checked OTP flow.

### 6a — Request OTP

```bash
curl -X POST "https://api.vlenseg.com/api/BusinessRequest/CustomerSign/StepRequestOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "REQUEST_ID",
    "geoLocation": { "latitude": 30.0444, "longitude": 31.2357 },
    "userDeviceUtcTime": "2025-01-15T10:30:00Z"
  }'
```

**Location check:** The system compares the submitted location against the user's last active device location.

```mermaid
flowchart LR
    A[StepRequestOtp] --> B{Distance from\nlast location}
    B -- within 80km --> C[OTP sent\nSave otpRequestId]
    B -- over 80km --> D[Error: liveness required]
    D --> E[StepReValidateLiveness]
    E --> A
```

### 6b — Handle location change *(if needed)*

If the location check fails, call `StepReValidateLiveness` with new liveness images. Use the **same `transactionId`** as the original KYC verification.

```bash
curl -X POST "https://api.vlenseg.com/api/BusinessRequest/CustomerSign/StepReValidateLiveness" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "REQUEST_ID",
    "transactionId": "ORIGINAL_KYC_TRANSACTION_ID",
    "geoLocation": { "latitude": 25.0444, "longitude": 35.2357 },
    "userDeviceUtcTime": "2025-01-15T10:30:00Z",
    "scanTransaction": {
      "image": "BASE64_ID_FRONT",
      "face_1": "BASE64_FACE_1",
      "face_2": "BASE64_FACE_2",
      "face_3": "BASE64_FACE_3",
      "transaction_id": "ORIGINAL_KYC_TRANSACTION_ID"
    }
  }'
```

### 6c — Validate OTP

```bash
curl -X POST "https://api.vlenseg.com/api/BusinessRequest/CustomerSign/StepValidateOtp" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "REQUEST_ID",
    "otpRequestId": "OTP_REQUEST_ID",
    "otpCode": "123456",
    "geoLocation": { "latitude": 30.0444, "longitude": 31.2357 },
    "userDeviceUtcTime": "2025-01-15T10:31:00Z"
  }'
```

### 6d — Validate payment and activate

```bash
curl -X POST "https://api.vlenseg.com/api/BusinessRequest/CustomerSign/StepValidatePayment" \
  -H "ApiKey: YOUR_API_KEY" \
  -H "Authorization: Bearer USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "REQUEST_ID",
    "geoLocation": { "latitude": 30.0444, "longitude": 31.2357 },
    "userDeviceUtcTime": "2025-01-15T10:32:00Z"
  }'
```

On success the contract moves to **Customer Signed** (`requeststatus: 4`).

***

## Request statuses

| Value | Status                            | Description                                   |
| ----- | --------------------------------- | --------------------------------------------- |
| `1`   | Pending Approval                  | Awaiting admin review                         |
| `2`   | Approved                          | Admin approved — user can now sign            |
| `3`   | Rejected                          | Rejected by admin                             |
| `4`   | Customer Signed                   | User completed the OTP signing flow           |
| `5`   | Service Provider Partially Signed | Not all designated signers have countersigned |
| `6`   | Service Provider Signed           | All signers countersigned — fully executed    |
| `7`   | Cancelled                         | Cancelled before completion                   |
| `8`   | Expired                           | Contract expired before completion            |

***

## Retrieve contracts

```bash
# Most recent active request (full details)
curl "https://api.vlenseg.com/api/BusinessRequest/Current" \
  -H "ApiKey: YOUR_API_KEY" -H "Authorization: Bearer USER_TOKEN"

# All requests — IDs and statuses only (lightweight, good for list views)
curl "https://api.vlenseg.com/api/BusinessRequest/CurrentListIds" \
  -H "ApiKey: YOUR_API_KEY" -H "Authorization: Bearer USER_TOKEN"

# Specific request by ID
curl "https://api.vlenseg.com/api/BusinessRequest/GetBusinessRequestById/REQUEST_ID" \
  -H "ApiKey: YOUR_API_KEY" -H "Authorization: Bearer USER_TOKEN"
```

***

## Service provider countersigning

Once the customer signs, a user with the `BusinessRequestContractSigner` role must countersign. This can be done:

* **Manually** in the Vlens portal: navigate to *Manage request traffic* → select the contract → **Actions → Sign Contract**
* **Automatically** using the `serviceprovider_sign_api` tool, which polls for Customer Signed contracts at a configured interval

For auto-signing, configure the tool's `.env` with `VLENS_USERNAME`, `VLENS_PASSWORD`, `VLENS_TENANCY`, `VLENS_APIKEY`, `VLENS_BASEURL`, `RequestType`, and `SignEvery_X_Minutes`.