Skip to navigation

Iframe Integration

Embed the full Vlens flow inside your app without exposing your API key
View as Markdown

The Identity User Session API lets you embed the complete Vlens verification and contracting UX inside your own application using an iframe or WebView — without exposing your ApiKey or admin credentials to the client.

Sessions are device-bound and user-bound. Each session is tied to a single device (via RSA public key) and expires after 30 minutes. A device is identified by its public key — store generated key pairs securely to avoid repeated mobile verification at each login.


How it works

sessionStartingPath postMessage events Your servercreates session Client loads iframe<tenancy>-onboarding.vlenseg.com User registersverifies IDsigns contract Your app responds
  1. Your server calls Vlens with the user’s phone/email and session config
  2. The server passes sessionStartingPath to the client app
  3. The client loads the Vlens iframe at <tenancy_name>-onboarding.vlenseg.com/<sessionStartingPath>
  4. The user completes registration, KYC, and/or contract signing
  5. Your app receives completion events via postMessage

Create Auth Session

A session that guides the user through whatever steps are needed based on their current state. Requires only ApiKey — no admin token.

curl -X POST "https://api.vlenseg.com/api/IdentityUserSession/CreateAuthSession" \
-H "ApiKey: YOUR_API_KEY" \
-H "TenancyName: YOUR_TENANT" \
-H "Content-Type: application/json" \
-d '{
"UserPublicKey": "DEVICE_RSA_PUBLIC_KEY",
"PhoneNumber": "+201234567890",
"Email": "user@example.com",
"Language": "AR",
"redirectUrl": "https://your-app.com/done",
"sessionPermissions": {
"allowedContractTypeIds": [414],
"minimalSignatureFlow": true,
"DigitalIdentityOnly": false,
"SendInvitationsForCosigners": false
},
"CustomerSigners": [
{
"customerSignerIdentifier": "+201234567891",
"shouldSign": true,
"signOrder": 0
}
],
"RequestFieldsValues": {
"414": {
"fullName": "Ahmed Mohamed",
"monthlyIncome": "5000"
}
}
}'

Request fields

FieldRequiredDescription
UserPublicKeyYesRSA public key generated on the device. The private key never leaves the device.
PhoneNumberNoUser’s phone number — pre-fills registration
EmailNoUser’s email address
LanguageNoUI language — "AR" or "EN"
redirectUrlNoWhere to send the user after session completion
sessionPermissions.allowedContractTypeIdsNoList of contract type IDs the user may create in this session
sessionPermissions.minimalSignatureFlowNotrue = streamlined signing UX; false = full application experience
sessionPermissions.DigitalIdentityOnlyNotrue = KYC only, no contracting
sessionPermissions.SendInvitationsForCosignersNotrue = co-signers receive an invitation link via SMS
sessionPermissions.preventNewRequestOnRejectionNotrue = the user can’t start a new request for a contract type that was already rejected for them
CustomerSignersNoList of co-signers to add to contracts in this session
RequestFieldsValuesNoPre-filled contract form values, keyed by contract type ID then field key

Response

{
"data": {
"sessionId": "af72ed47-7db3-40e6-acbd-e6efe01ca849",
"sessionEnd": "2026-05-05T13:55:14.7043492Z",
"sessionStartingPath": "/session/start?token=...",
"sessionPermissions": { "..." },
"redirectUrl": null,
"sessionAllowedTypesSignedContracts": {
"allTypesSigned": false,
"signedContracts": [
{
"id": "4325a38b-02f7-4437-a3da-6526cb33711c",
"typeId": 201,
"status": "CustomerSigned",
"statusId": 4
}
]
}
},
"error_code": null
}

sessionStartingPath is the path to append to your tenant’s base URL. If null, no session was created.


Create Invitation Session

A session with pre-filled data and an invitation notification (SMS or email) sent to the user. Requires admin bearer token + ApiKey.

Use this when you have already collected the customer’s information and want to minimize the steps they must complete.

curl -X POST "https://api.vlenseg.com/api/IdentityUserSession/CreateInvitation" \
-H "ApiKey: YOUR_API_KEY" \
-H "TenancyName: YOUR_TENANT" \
-H "Authorization: Bearer ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sessionInput": {
"UserPublicKey": "DEVICE_RSA_PUBLIC_KEY",
"PhoneNumber": "+201234567890",
"Language": "AR",
"sessionPermissions": {
"allowedContractTypeIds": [414],
"minimalSignatureFlow": true,
"DigitalIdentityOnly": false
},
"RequestFieldsValues": {
"414": {
"fullName": "Ahmed Mohamed",
"monthlyIncome": "5000"
}
}
},
"smsProvider": 0
}'

smsProvider controls which SMS gateway sends the invitation. 0 = default from tenant settings.

Invitation links are short-lived (10 minutes) but the session itself lasts 30 minutes from when the user opens it. The link acts as a one-time OTP:

  • Sent via SMS → no mobile verification required at login or registration
  • Sent via email → no email verification required at registration

Change Phone Number Session

A session in which an existing user changes their registered phone number. It is loaded in the iframe the same way as the sessions above.

No Yes Admin: CreateInvitation(emailed link) SendOtpSMS code to the new number Your server: CreateSession VerifyOtp needsFaceMatching? ✅ Phone number updated ValidateFaceMatchselfie vs. stored biometrics
  • Invitation — POST /api/ChangePhoneNumberSession/CreateInvitation emails the user an invitation link. Requires an admin bearer token with the Change Phone Number Invitation permission, and the user’s email must be confirmed. Admins can also send it from the portal’s Users page.
  • Session — POST /api/ChangePhoneNumberSession/CreateSession returns a sessionStartingPath to load in the iframe, like CreateAuthSession. UserPublicKey is required.
  • The user confirms the new number with an SMS code (SendOtp, then VerifyOtp).
  • Users with a verified digital identity must also pass a face match against their stored biometric data (ValidateFaceMatch). For other users, phone ownership is checked and the number is updated right after the OTP is verified.
  • The new number can’t be the same as the current number.

The invitation email has English and Arabic templates. To send the invitation from the portal, see Users & invitations.

EndpointPurpose
POST /api/ChangePhoneNumberSession/CreateInvitationEmail a change-phone invitation (admin)
POST /api/ChangePhoneNumberSession/CreateSessionCreate a change-phone session
GET /api/ChangePhoneNumberSession/GetUserSessionSettingsSession config (new phone number, return URL, starting path)
POST /api/ChangePhoneNumberSession/SendOtpSend the SMS code to the new number
POST /api/ChangePhoneNumberSession/VerifyOtpVerify the code — returns needsFaceMatching and isCompleted
POST /api/ChangePhoneNumberSession/ValidateFaceMatchFace match for verified digital identities

Loading the iframe

Concatenate sessionStartingPath to your tenant’s base URL:

https://<tenancy_name>-onboarding.vlenseg.com<sessionStartingPath>
<iframe
src="https://YOUR_TENANT-onboarding.vlenseg.com/session/start?token=..."
width="100%"
height="700"
allow="camera; microphone"
/>

The allow="camera; microphone" attribute is required for liveness detection to work in the browser.


postMessage integration

The iframe communicates with the parent app via window.postMessage. This is required for device-bound signing — the parent app holds the private key.

Iframe → Parent (signing request):

window.postMessage({
type: "NATIVE_CALL",
method: "signContent",
requestId: "123",
args: { signingBody: "..." }
}, "*");

Parent → Iframe (signing response):

window.postMessage({
type: "NATIVE_RESPONSE",
requestId: "123",
success: true,
result: "signed-value",
source: "native"
}, "*");

Key storage

The private key must never leave the device. Store it using each platform’s secure enclave:

PlatformStorage
AndroidAndroid Keystore
iOSKeychain with Secure Enclave
Webwindow.crypto (non-exportable)

Security features

Every session request includes three layers of protection:

FeatureDescription
NonceEach request is processed only once — replay attacks are rejected
TimestampRequests are only processed in real-time — intercepted requests expire immediately
Body signatureAll request data is signed with the device private key, preventing MITM tampering

Session permissions reference

PermissionTypeDescription
allowedContractTypeIdsint[]Contract type IDs the user may create in this session
minimalSignatureFlowbooleantrue = streamlined UX; false = full application
DigitalIdentityOnlybooleanRestrict session to KYC only — no contracting
SendInvitationsForCosignersbooleanSend invitation links to co-signers via SMS instead of regular notification
preventNewRequestOnRejectionbooleanBlock a new request for a contract type that was already rejected for this user. See Prevent new request on rejection.

Prevent new request on rejection

Set sessionPermissions.preventNewRequestOnRejection: true when you create the session or the invitation. Inside the iframe:

  • The user can’t start a new request for a contract type that was previously rejected for them.
  • Rejected requests no longer count as signed contracts.
  • If every allowed contract type is already signed or rejected, the session is treated as fulfilled.

The option is shown in the invitation and session details in the portal. To set it from the portal, see Users & invitations.


Web app (no-code access)

Users can access the Vlens web app directly at:

https://<tenancy_name>-onboarding.vlenseg.com

No developer configuration is required. The web app manages keys and sessions securely — each browser is treated as a separate device with its own key pair.

To restrict access to invited users only, enable Invitation Only in the portal under Feature Control → Main Feature.


When to use each flow

ScenarioRecommended flow
Mobile app with native ID captureNative API flow
Embed Vlens in a web page with minimal integrationAuth Session (iframe)
Pre-fill customer data server-sideInvitation Session
Let a user change their phone numberChange Phone Number Session
Redirect user to Vlens-hosted register/login pageUser Profile — Hosted links
KYC only — no contractingAuth Session with DigitalIdentityOnly: true
Restrict to invited usersEnable Invitation Only in portal

Session API endpoints

Your server creates the session with CreateAuthSession or CreateInvitation. The embedded iframe then calls the endpoints below (you do not call these directly from your backend in most integrations).

EndpointPurpose
GET /api/IdentityUserSession/GetUserSessionSettingsSession config (redirect URL, starting path)
GET /api/IdentityUserSession/GetSessionThemeSettingsBranding colors and logo
POST /api/IdentityUserSession/LoginLogin inside the session
POST /api/IdentityUserSession/RegisterStepVerifyPhoneRegistration phone OTP
POST /api/IdentityUserSession/RegisterStepVerifyEmailRegistration email OTP
POST /api/IdentityUserSession/RegisterStepCreateComplete registration
POST /api/IdentityUserSession/CheckExistenceOfEmailOrPhoneCheck if email/phone exists
GET /api/IdentityUserSession/CheckEligibilityCan user create a contract?
GET /api/IdentityUserSession/GetAllRequestTypesList contract types
POST /api/IdentityUserSession/Create/{typeId}Create a business request
GET /api/IdentityUserSession/HasMoreToSignPending signatures remaining
GET /api/IdentityUserSession/CurrentListThe user’s current requests, including rejected ones
POST /api/IdentityUserSession/CustomerSign/StepValidateOtpSign — validate OTP
POST /api/IdentityUserSession/CustomerSign/StepValidatePaymentSign — validate payment

For the native API equivalents (outside the iframe), see Digital Identity and E-Contracting. To associate a pre-login OCR transaction with a user after native login, see Link an existing transaction — that flow does not apply inside an iframe session.