Standard Integration (Recommended)
Integrate CLEAR through 2 API calls
Overview
Integrate CLEAR through 2 API calls, orchestrated by a lightweight logic layer that routes each user down one of two paths — Known User Key (returning users) or Establish Identity (first-time users).
CLEAR doesn't just verify — CLEAR matches.The purpose of a verification isn't only to prove someone is real. It's to prove that the person completing the flow is the specific user you expected to verify, and to bind that verified identity back to the correct record in your system. Every Standard Integration is designed around this principle: verify + match + link.
The Standard Integration gives you full control via API calls and is the most flexible way to work with CLEAR. It is designed as one orchestration with two paths, routed by whether a CLEAR userID is already stored on the customer record.
Two paths = two projects in CLEAR Console.Each path is powered by its own project in CLEAR Console — one for Establish Identity (document + selfie) and one for Known User Key (selfie-only reverification). Both projects share the same API key; your backend picks the right
project_idbased on whether the user record already has aclear_user_idstored.
At a high level, the flow is:
- Logic layer: check whether a CLEAR
userIDexists on the user record - Create a verification session — against the Establish Identity project or the Known User Key project
- Invoke CLEAR's hosted UI
- Decide how your system will know when the session is finished
- Retrieve and use the verification data — match the response back to your record (Match Identified for known users, Mint + Write for new users)
Identifying the User Before You Start
Before you can route to either path, your system needs to know which user is requesting verification. There are two shapes this takes:
1. The user is already authenticated (recommended)
If the user has an active session in your app (SSO, logged in, etc.), you already have a concept of who this is. Your backend can:
- Look up the user record silently — no input from the user
- Pull the stored
clear_user_id(if any) and the PII fields needed for User Profile Matching - Pass those directly into the CLEAR session
This is the smoothest UX — the user never has to type anything to prove which record they map to.
2. The user is not authenticated
If your system doesn't already know who the user is (pre-onboarding, password reset from a logged-out state, help-desk-initiated flows, etc.), we recommend collecting a single identifier — typically an employee ID, member number, or email — that your backend can use to query your internal data store.
That identifier tells your system:
- Whether a
clear_user_idalready exists on the record → route to Known User Key - Or what PII to send in
user_profile_information→ route to Establish Identity
The identifier is used only to look up the record on your side. CLEAR never sees it unless you choose to pass it through
custom_fieldsfor reconciliation.
Why This Is Our Standard Integration
We recommend this pattern for one reason: it builds a durable ecosystem of identity around your existing user records.
- Your records stay the source of truth. CLEAR verifies and returns an identity; your system decides how that identity maps to the user. The
userIDlives on your record, not the other way around. - Existing users get the fastest possible experience. Once a user is established, every future verification is a 3–5 second selfie — no ID scan, no PII re-entry. That's what the Known User Key path buys you across every touchpoint: onboarding, password reset, device provisioning, MFA reset, conditional access, account recovery.
- Every verification is a matched verification. Because you always know which record you're verifying against — either through User Profile Matching (Establish Identity) or a stored
user_id(Known User Key) — you never end up with a "verified stranger" that doesn't correspond to a real user in your system. - One orchestration, one API key, two payloads. The routing logic is trivial; the payload difference is small; the operational surface stays clean.
Looking for a different integration style?If you'd rather have CLEAR create user rows in your system (rather than matching against records you already own), take a look at the additional integration paths in the docs. Standard Integration assumes you own the user record and want CLEAR to verify and link — other patterns invert that ownership model.
UX and Data Flow
One orchestration. Two paths — routed by whether a CLEAR userID is already on the customer record.
Key mental model:
- YES path (Known User Key): stored
userID→ session created withuser_id→ user completes selfie-only → returneduserIDmatched against stored value → user is identified (3–5s). - NO path (Establish Identity): no
userIDyet → session created withuser_profile_information→ user completes ID + selfie → CLEAR mints a newuserID→ write it back to the user record for all future flows (30–60s).
Both paths share the same API endpoints, the same hosted UI, and the same completion-notification strategies (webhooks, redirect, session-aware check, or polling).
Prerequisites
Before you write a single line of integration code, make sure you have the following in place:
- ✅ Access to CLEAR Console — the admin portal where you configure projects, manage API keys, and inspect verification sessions.
- ✅ Establish Identity project created — this is the project users are routed to the first time they verify (document + selfie). Configure it in Console before you start building.
- ✅ Known User Key project created — this is the project users are routed to on every subsequent verification (selfie-only). It must exist alongside your Establish Identity project.
- ✅ API key available — a single environment-scoped API key is used to authenticate calls to both projects.
- ✅ You understand CLEAR's identity product — you've reviewed CLEAR's identity verification product overview and watched the demo video below covering both journeys (Establish Identity + Known User Key). This is essential context; the integration decisions downstream only make sense once you understand the two user journeys and how they differ.
Getting Started
This section walks you through how to integrate CLEAR and embed CLEAR's identity verification into every workflow that needs a verified user — onboarding, password reset, device provisioning, MFA reset, conditional access, account recovery, help-desk-initiated flows, and any other high-assurance moment across your ecosystem.
The integration is deliberately small: one logic-layer check, one Create Session call, one Retrieve Session call. Everything else — which project to use, what payload to send, what to do with the response — is decided by that first check.
Step-by-step
-
Identify the user (Step 0 of every workflow).
- Authenticated: pull the user record silently from your session.
- Unauthenticated: prompt for an identifier (employee ID, member number, email) and query your internal data store.
-
Run the logic layer.
- Does the user record have a
clear_user_id?- Yes → route to the Known User Key project.
- No → route to the Establish Identity project.
- Does the user record have a
-
Create the verification session (Phase 2 below).
- Known User Key path: send the stored
user_id. - Establish Identity path: send
user_profile_information(for User Profile Matching) plus anycustom_fieldsyou need for reconciliation.
- Known User Key path: send the stored
-
Invoke CLEAR's hosted UI (Phase 3) using the
verification_session.tokenreturned from step 3. -
Wait for completion (Phase 4). Pick your notification strategy — webhooks, redirect + UUID, session-aware check, or polling. Webhooks + redirect is the recommended pairing.
-
Retrieve the session and act on it (Phase 5).
- Establish Identity → Mint + Write: save the newly minted
user_idto your user record. - Known User Key → Match Identified: confirm the returned
user_idequals the one you sent in.
- Establish Identity → Mint + Write: save the newly minted
-
Reuse this same 6-step flow everywhere. Once the pattern is wired up, embedding CLEAR into a new workflow is a matter of calling the same integration from the surface that needs it — the routing, session creation, and matching are already built.
What "embedding into all workflows" looks like
Once the Standard Integration is live, every downstream surface reuses the same primitive:
| Workflow | Trigger | Path used (most of the time) |
|---|---|---|
| First-time onboarding | User does not exist yet in the ecosystem | Establish Identity |
| Password reset | Existing user | Known User Key |
| Device / laptop provisioning | Existing user | Known User Key |
| MFA reset | Existing user | Known User Key |
| Conditional access step-up | Existing user | Known User Key |
| Account recovery | Existing user | Known User Key |
| Help-desk-initiated verification | Existing user | Known User Key |
Every one of these calls the same Create Session → Invoke → Retrieve → Match/Mint sequence. The logic layer decides which project handles it based on whether a clear_user_id is already on the record.
Phase 1: The Logic Layer — Route the User
Before creating a session, your backend checks the user record:
if (user.clear_user_id) {
// YES → Known User Key path
createSession({ project_id: PROJECT_ID, user_id: user.clear_user_id })
} else {
// NO → Establish Identity path
createSession({
project_id: PROJECT_ID,
user_profile_information: { name: { first_name, last_name }, dob }
})
}
Rules of thumb:
- The check runs on every verification request — onboarding, password reset, device provisioning, MFA reset, account recovery, conditional access.
- The same
userIDis reusable across every touchpoint in your ecosystem for the lifetime of the user relationship. userIDis ecosystem-scoped: auserIDissued by Company A does not work for Company B (privacy-preserving by design).
Phase 2: Create a Verification Session
From your backend, call the Create Verification Session API. You'll need:
project_id(from CLEAR Console)api_key(environment-specific)
The API will return:
verification_session.id→ used by your backend to retrieve results laterverification_session.token→ passed to your frontend to launch the hosted UI
Path A — Establish Identity (no userID on record)
userID on record)Send user_profile_information so CLEAR can bind the new verification to your existing user record via User Profile Matching (UPM).
curl --request POST \
--url https://verified.clearme.com/v1/verification_sessions \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"project_id": "<YOUR_PROJECT_ID>",
"redirect_url": "https://yourapp.com/verified-callback?state=<SERVER_GENERATED_UUID>",
"user_profile_information": {
"name": {
"first_name": "Jane",
"last_name": "Smith"
},
"dob": "1990-05-15"
},
"custom_fields": {
"employeeID": "EMP12345"
}
}'What happens:
- User scans ID + takes a selfie (30–60s).
- CLEAR matches the extracted PII against
user_profile_information(if UPM is enabled). - CLEAR mints a new
userIDand returns it in the session response. - Mint + Write: your backend saves
userIDto the user record.
UPM is optional. Include
user_profile_informationwhen you want CLEAR to guarantee the returned identity matches the record you initiated the session for.
Path B — Known User Key (stored userID on record)
userID on record)Send the stored user_id. The user completes a selfie-only flow (3–5s).
curl --request POST \
--url https://verified.clearme.com/v1/verification_sessions \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"project_id": "<YOUR_PROJECT_ID>",
"redirect_url": "https://yourapp.com/verified-callback?state=<SERVER_GENERATED_UUID>",
"user_id": "UxBm6T2KkJxHgXlM7gaZrboYpwLIAnAh4lausdqO68",
"custom_fields": {
"employeeID": "EMP12345"
}
}'What happens:
- User takes a selfie only — no document scan.
- CLEAR matches the live selfie against the stored biometric associated with
user_id. - CLEAR returns the same
userIDyou sent in. - Match Identified: your backend verifies
response.user_id === stored.clear_user_id.
Phase 3: Invoke CLEAR
Direct the user to CLEAR's hosted UI by embedding verification_session.token into the verification URL:
https://verified.clearme.com/verify?token=<VERIFICATION_TOKEN>
This URL launches the CLEAR experience, which securely collects identity information such as:
- Government-issued IDs (Establish Identity path only)
- Biometrics (face scan, selfie match — both paths)
- Other project-specific data (e.g., phone number, SSN, insurance card)
You can open this URL in:
- A redirect (common for web apps)
- An embedded webview (common for mobile apps)
- A kiosk browser (for in-person flows)
- Direct: append a unique token to
https://verified.clearme.com/verify?to immediately begin a session
Phase 4: Decide How to Know When Verification Is Complete
Once a session has started, your system needs to know when to make the final Get Verification Session call. There are four common strategies — pick one, or combine webhooks with a redirect for maximum reliability.
Option A — Webhooks (recommended)
CLEAR sends a server-to-server request to your webhook endpoint when events occur, such as verification_session.completed.
Example webhook payload:
{
"event_id": "event_12345",
"event_type": "event_verification_session_completed_v1",
"object_name": "event",
"created_at": 1679707372,
"data": {
"verification_session_id": "verify_ABC123XYZ"
}
}Your webhook handler should:
- Validate the request (Bearer token, HMAC if enabled)
- Extract the
verification_session_id - Fetch the session via API to confirm status
Option B — Redirect + UUID (state)
When creating the session, include a redirect_url with a caller-generated UUID (e.g., state):
"redirect_url": "https://yourapp.com/verified-callback?state=<UUID>"
Flow:
- Generate a UUID on your backend.
- Store a mapping:
state → verification_session.id. - When the user returns to
verified-callback, readstatefrom the URL. - Look up the mapping, then fetch the session with
verification_session.id.
Redirects are great for UX, but always confirm status via API. A redirect alone is not proof of successful verification.
Option C — Session-Aware Status Check
If your app has a logged-in user, ask your backend for the latest verification status whenever the user returns to a relevant screen (e.g., onboarding, access request, settings). Correlate by your own user session; your backend then calls GET /v1/verification_sessions/id.
How to implement
When you create a verification session for a logged-in user, save:
- Your internal
userId - The
verification_session.id
Later, when the user returns to your app (e.g. /onboarding/verify), the frontend calls /api/verification-status.
The backend:
- Looks up the saved
verification_session.id - Calls CLEAR's
GET /verification_sessions/{id} - Returns the normalized status to the frontend
Common trigger points (pick 1):
- On page load / view mount (e.g., React
useEffecton/onboarding/verify) - On CTA click ("I've completed verification" → check status)
- Timed re-check while a relevant page is open (debounced every 5–10s)
- Background listener after a webhook updates your DB (client polls your API once to refresh UI)
- Route guard (optional) if your framework already uses guards for gated routes
When to use this pattern
- You have authenticated sessions and know which user is viewing the page.
- You want a simple, reliable check even if the user closed the CLEAR tab or skipped the redirect.
- You already store the pending
verification_session_idper user.
Tip: Pair this with webhooks (backend gets the event first; the client-side check just refreshes UI). Use route guards only if they fit your framework — they're optional.
Option D — Polling
Your backend periodically checks the session status via API until it reaches a terminal state (success, failed, expired, canceled). Simple but less efficient. Use with exponential backoff or only as a fallback.
Phase 5: Retrieve and Use the Verification Data
Once you know the session is complete, call the Get Verification Session API from your backend with the verification_session.id.
curl --request GET \
--url https://verified.clearme.com/v1/verification_sessions/id \
--header 'accept: application/json' \
--header 'authorization: Bearer {{API_KEY}}'Response includes:
status— one of:not_started,awaiting_user_input,success,failed,expired,canceledtraits— verified user attributes as JSON (specificallytraits.document)user_id— persistent identifier for the verified user (also referred to aspsuid)verification_id— identifier for the specific verification session
What to do with the response — by path
YES path (Known User Key) → Match Identified
1. Verification completes successfully
2. Compare response.user_id to the user_id you sent in
3. If match → user is identified; complete the use case
(password reset, conditional access, MFA reset, etc.)
4. If mismatch → do NOT overwrite the stored user_id;
log a security alert and deny access
NO path (Establish Identity) → Mint + Write
1. Verification completes successfully
2. Read response.user_id (freshly minted by CLEAR)
3. Correlate to your record via custom_fields.employeeID (or state/UUID mapping)
4. Write user_id to the user record
5. Complete the use case
Do not useverified_infofrom the response — it is a deprecated value. Usetraitsto get a user's demographics.Within
traits, CLEAR requires usingtraits.documentas the place to retrieve information pulled off the user's government-issued ID.
traitswill only be populated if the use case leverages "user info" within the project configuration.traits.documentis used to retrieve information extracted from government-issued ID. Most projects, including IAL2 projects, will only have "user info" data when data required for a verification (e.g. residential address) is not available on a document (e.g. passport).
Example Response
{
"id": "verify_HUQgjLoNLnhHlbtEBJJ305JMKG2pFoVt",
"object_name": "verification_session",
"activated_authentication_methods": [],
"authenticated": true,
"authentication_methods": ["sms"],
"checks": [
{ "name": "Age on Gov ID is 18 or over", "value": true, "status": "completed" },
{ "name": "Device is trustworthy", "value": true, "status": "completed" },
{ "name": "Gov ID is likely authentic", "value": true, "status": "completed" },
{ "name": "Gov ID is not expired", "value": true, "status": "completed" },
{ "name": "Selfie matches portrait on Gov ID", "value": true, "status": "completed" },
{ "name": "Selfie passes liveness check", "value": true, "status": "completed" }
],
"completed_at": 1757337785,
"created_at": 1757337702,
"custom_fields": { "employeeID": "EMP12345" },
"email": "[email protected]",
"expires_at": 1758201702,
"idv_status": "success",
"phone": "+19172222222",
"project_id": "project_9C4eCAstPDUwfIjkZlUcIZcYm8uCA9NGE5AWSqHNac",
"status": "success",
"token": "verify_token_NO12MWMiwXhXdRJLhkjN7sqNNMGULbaT",
"traits": {
"address": null,
"dob": null,
"email": "[email protected]",
"first_name": null,
"last_name": null,
"phone": "+19172222222",
"document": {
"nationality": null,
"document_type": "drivers_license",
"issuing_country": "USA",
"issuing_subdivision": "NJ",
"document_number": "1537331",
"date_of_expiry": { "day": 24, "month": 12, "year": 2031 },
"gender": "M",
"address": {
"line1": "123 Test St",
"line2": "Apt A",
"city": "Test City",
"state": "NJ",
"postal_code": "12345",
"country": "US"
},
"date_of_birth": { "day": 1, "month": 1, "year": 1990 },
"first_name": "JOHN",
"last_name": "DOE",
"middle_name": null
},
"document_front": "REDACTED",
"document_back": "REDACTED",
"parsed_fields": ["name", "dob", "address"],
"face_scan_preview": "c3GCjdcqrSAZqHxyk8qySg"
},
"updated_at": 1757337785,
"user_id": "3mfsPYduiyY4l04EB5z1IXumxc4XFV6wQlgAUptW44",
"user_created": true,
"user_profile_match_status": "not_applicable",
"verified_info": null
}More details on the responses can be found in the API Reference.
Error Handling
Error: user_id Not Found (Known User Key path)
user_id Not Found (Known User Key path)Causes: revoked/deleted, invalid, or wrong stored ID.
1. Catch the error from CLEAR API
2. Fall back to the Establish Identity path
3. Include user_profile_information for UPM
4. Overwrite the old user_id with the new user_id returned from CLEAR
5. Save the new user_id to the user record
Error: Biographic Mismatch (Establish Identity + UPM)
Causes: wrong employee selected, outdated info, wrong ID scanned.
1. CLEAR completes verification successfully (status: success)
2. But no user_id is returned (UPM match failed)
3. Flag for manual review
4. DO NOT save user_id to the user record
5. Notify an administrator to reconcile the data
Error: user_id Mismatch on Reverification (Known User Key path)
user_id Mismatch on Reverification (Known User Key path)Causes: potential security issue, database corruption, or rare CLEAR system error.
1. Verification completes successfully
2. Compare returned user_id to stored user_id
3. If mismatch:
- Log security alert
- Deny access
- Trigger security review
- DO NOT overwrite the stored user_id
Best Practices
- Always run the logic layer first. No verification session should be created without checking
user.clear_user_id— this is what decides Known User Key vs. Establish Identity. - Save
user_idimmediately after a successful Establish Identity session — this is the "Mint + Write" step that enables every future selfie-only flow. - Always validate the returned
user_idon reverification. Never blindly trust the response. - Use Webhooks + Redirect together for the best reliability and UX. Never trust a redirect alone.
- Treat
statevalues as single-use to prevent replay attacks. - Secure all endpoints with HTTPS, Bearer token, and (optionally) HMAC signatures on webhooks.
- Store what you need:
user_id(akapsuid),verification_id, and any PII your compliance model requires. - One API key, one integration. Both paths share the same project pattern, endpoints, and completion strategies — the only difference is the payload you send at session creation.
Updated 2 days ago