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_id based on whether the user record already has a clear_user_id stored.

At a high level, the flow is:

  1. Logic layer: check whether a CLEAR userID exists on the user record
  2. Create a verification session — against the Establish Identity project or the Known User Key project
  3. Invoke CLEAR's hosted UI
  4. Decide how your system will know when the session is finished
  5. 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_id already 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_fields for 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 userID lives 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 with user_id → user completes selfie-only → returned userID matched against stored value → user is identified (3–5s).
  • NO path (Establish Identity): no userID yet → session created with user_profile_information → user completes ID + selfie → CLEAR mints a new userIDwrite 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.
🎥

Watch the journeys first


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

  1. 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.
  2. 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.
  3. 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 any custom_fields you need for reconciliation.
  4. Invoke CLEAR's hosted UI (Phase 3) using the verification_session.token returned from step 3.

  5. Wait for completion (Phase 4). Pick your notification strategy — webhooks, redirect + UUID, session-aware check, or polling. Webhooks + redirect is the recommended pairing.

  6. Retrieve the session and act on it (Phase 5).

    • Establish Identity → Mint + Write: save the newly minted user_id to your user record.
    • Known User Key → Match Identified: confirm the returned user_id equals the one you sent in.
  7. 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:

WorkflowTriggerPath used (most of the time)
First-time onboardingUser does not exist yet in the ecosystemEstablish Identity
Password resetExisting userKnown User Key
Device / laptop provisioningExisting userKnown User Key
MFA resetExisting userKnown User Key
Conditional access step-upExisting userKnown User Key
Account recoveryExisting userKnown User Key
Help-desk-initiated verificationExisting userKnown 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 userID is reusable across every touchpoint in your ecosystem for the lifetime of the user relationship.
  • userID is ecosystem-scoped: a userID issued 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 later
  • verification_session.token → passed to your frontend to launch the hosted UI

Path A — Establish Identity (no 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 userID and returns it in the session response.
  • Mint + Write: your backend saves userID to the user record.

UPM is optional. Include user_profile_information when 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)

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 userID you 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:

  1. Generate a UUID on your backend.
  2. Store a mapping: state → verification_session.id.
  3. When the user returns to verified-callback, read state from the URL.
  4. 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 useEffect on /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_id per 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, canceled
  • traits — verified user attributes as JSON (specifically traits.document)
  • user_id — persistent identifier for the verified user (also referred to as psuid)
  • 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 use verified_info from the response — it is a deprecated value. Use traits to get a user's demographics.

Within traits, CLEAR requires using traits.document as the place to retrieve information pulled off the user's government-issued ID.

  • traits will only be populated if the use case leverages "user info" within the project configuration.
  • traits.document is 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)

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)

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_id immediately after a successful Establish Identity session — this is the "Mint + Write" step that enables every future selfie-only flow.
  • Always validate the returned user_id on reverification. Never blindly trust the response.
  • Use Webhooks + Redirect together for the best reliability and UX. Never trust a redirect alone.
  • Treat state values 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 (aka psuid), 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.


Did this page help you?