Verification Sessions
A verification session represents a single identity verification attempt.
When do I need this?
If you're using the widget with a publishable key, sessions are created automatically — you don't need this API. Use the Verification Sessions API when you need server-side control over session creation, or want to retrieve, cancel, or list sessions programmatically.
All examples on this page assume you've initialized the Node.js SDK. See Installation for setup.
Session statuses
| Status | Description |
|---|---|
created | Session created, waiting for the user to start verification. |
pending | User has opened the verification UI. |
processing | Verification is actively being processed by a method. |
requires_input | A method requires additional user input. |
verified | Verification succeeded. Terminal state. |
failed | All methods were exhausted without success. Terminal state. |
cancelled | Cancelled by your server or the user. Terminal state. |
expired | The 24-hour expiry passed before completion. Terminal state. |
Create a session
/v1/verification_sessions| Parameter | Type | Description |
|---|---|---|
typerequired | "identity" | "age" | "student" | The type of verification to perform. Determines the default method waterfall. |
methods | VerificationMethod[] | Override the default method waterfall. E.g. ["mdl", "facial_age"] to try MDL first then facial age estimation. |
return_url | string | URL to redirect to after successful verification. |
cancel_url | string | URL to redirect to if the user cancels. |
client_reference_id | string | Your internal ID for this user or transaction. Returned in webhook events. |
metadata | object | Up to 50 key-value pairs of arbitrary data. Values must be strings. |
idempotency_key | string | A unique key to prevent duplicate session creation. If a session was already created with this key, the existing session is returned. |
use_case | string | Compliance use-case. Automatically resolves jurisdiction rules, filters allowed methods, and enforces the correct age tier. One of: alcohol_delivery, alcohol_in_person, gambling_online, gambling_in_person, cannabis_dispensary, cannabis_delivery, tobacco_nicotine, adult_content, social_media, firearms, general. |
jurisdiction | string | Explicit jurisdiction override (e.g. "US-CA", "US-TX"). If omitted, derived from request geo headers. |
custom_user_message | string | Override the default user-facing message shown in the widget. Max 500 characters. |
email | string | User email for Verified Person lookup. Enables cross-site verification reuse when accept_existing is true. |
phone | string | User phone for Verified Person lookup. Used alongside or instead of email. |
accept_existing | boolean | When true, accepts existing cross-site verifications instead of requiring a new one. Requires email or phone. |
min_strength | string | Minimum credential strength for existing verifications. E.g. "document_capture" to only accept doc capture or stronger. |
max_age | string | Maximum age of existing verification. Format: "<number>d" (e.g. "30d" for 30 days). |
required_methods | string[] | Require ALL of these methods to be previously verified when reusing existing credentials. |
const session = await stile.verificationSessions.create({
type: "age",
methods: ["mdl", "facial_age"],
return_url: "https://yourapp.com/done",
client_reference_id: "user_123",
use_case: "alcohol_delivery",
});
// Returns:
// {
// id: "vks_abc123",
// object: "verification_session",
// status: "created",
// type: "age",
// client_secret: "eyJ...", ← pass to frontend
// already_verified: false, ← true if reusing an existing credential
// expires_at: 1741651200,
// livemode: false,
// created: 1741564800,
// compliance: { ← present when use_case is set
// jurisdiction: "US-CA",
// use_case: "alcohol_delivery",
// age_tier: "over_21",
// mdl_acceptance_status: "full",
// },
// }curl https://api.stile.dev/v1/verification_sessions \
-H "Authorization: Bearer vk_test_..." \
-H "Content-Type: application/json" \
-d '{
"type": "age",
"methods": ["mdl", "facial_age"],
"return_url": "https://yourapp.com/done",
"client_reference_id": "user_123"
}'Retrieve a session
/v1/verification_sessions/:idPass expand[]=results to include the full verification results array in the response.
const session = await stile.verificationSessions.retrieve("vks_abc123", {
expand: ["results"],
});
// session.results — array of VerificationResult objectscurl "https://api.stile.dev/v1/verification_sessions/vks_abc123?expand[]=results" \
-H "Authorization: Bearer vk_test_..."Cancel a session
/v1/verification_sessions/:id/cancelCancels a session that is in created, pending, or requires_input status. Cannot cancel a session that is already processing, verified, failed, or expired.
const session = await stile.verificationSessions.cancel("vks_abc123");
// session.status === "cancelled"curl -X POST https://api.stile.dev/v1/verification_sessions/vks_abc123/cancel \
-H "Authorization: Bearer vk_test_..."List sessions
/v1/verification_sessionsReturns a paginated list of sessions for your organization, newest first.
| Parameter | Type | Description |
|---|---|---|
limit | number= 10 | Number of sessions to return. Between 1 and 100. |
starting_after | string | Session ID to start after (cursor-based pagination). Returns sessions created before this ID. |
status | string | Filter by session status (e.g. "verified", "failed", "created"). |
const { data, has_more } = await stile.verificationSessions.list({
limit: 20,
});
for (const session of data) {
console.log(session.id, session.status);
}curl "https://api.stile.dev/v1/verification_sessions?limit=20" \
-H "Authorization: Bearer vk_test_..."Verification methods
Each verification type has a default method waterfall. You can override it by passing a methods array when creating the session.
| Method | Value | Description |
|---|---|---|
| Mobile Driver's License | mdl | ISO 18013-5 mDL via OID4VP. Highest assurance. |
| Mobile Identity | mid | Government-issued digital identity credential. |
| EUDI PID | eudi_pid | European Digital Identity credential. |
| Facial Age Estimation | facial_age | AI age estimate from a selfie. No document required. |
| Selfie Liveness | selfie_liveness | Confirms a real person is present via a live selfie check. |
| Selfie Match | selfie_match | Matches a selfie against a previously verified photo. |
| Self Attestation | self_attestation | User self-declares their age or identity. Lowest assurance. |
| Document Capture | document_capture | Extracts and verifies data from a physical ID document photo. |
| Carrier Lookup | carrier_lookup | Phone carrier verification for age signals. |
| Open Banking | open_banking | Bank account data for identity signals. |
| Parental Consent | parental_consent | Collects consent from a parent or guardian. |
| Student Verification | student | Academic enrollment verification. |
The default waterfall for identity is: mdl → mid → facial_age → carrier_lookup → open_banking.
For age: mdl → mid → facial_age → parental_consent → carrier_lookup → open_banking.