API Integration (No Matching)

Integrate CLEAR through 2 API calls

The Standard Integration gives you full control via API calls and is the most flexible way to work with CLEAR. At a high level, the flow is:

  1. Create a verification session
  2. Invoke CLEAR’s hosted UI
  3. Decide how your system will know when the session is finished
  4. Retrieve and use the verification data

Phase 1: 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
curl -X POST https://verified.clearme.com/v1/verification_sessions \
  -H 'Authorization: Bearer <API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
        "project_id": "<YOUR_PROJECT_ID>",
        "redirect_url": "https://yourapp.com/verified-callback?state=<SERVER_GENERATED_UUID>"
      }'

Phase 2: Invoke CLEAR

Direct the user to CLEAR’s hosted UI by embedding the 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
  • Biometrics (face scan, selfie match)
  • 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: Add a unique token to https://verified.clearme.com/verify?to immediately begin session

Phase 3: 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 three common strategies:

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, you can ask your backend for the latest verification status whenever the user returns to a relevant screen (e.g., onboarding, access request, settings). You correlate by your own user session, then your backend 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 verificationID

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

Frontend example (page load check):

Backend example:

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

This method is simple but less efficient. Use with exponential backoff or only as a fallback.

Phase 4: 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 \
     --H 'accept: application/json' \
     --H 'authorization: Bearer {{API_KEY}}'

Response includes:

status — one of: not_started, awaiting_user_input, success, failed, expired, canceled

traits — Specifically traits.document --verified user attributes as JSON

psuid — or userID persistent identifier for the verified user

verification_id — identifier for the specific verification session

🚧

Do not use verified_info from the response

Do not use the verified_info field, as this 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 of the users 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 back is not suspicious",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Gov ID captured image is acceptable",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Gov ID country is not blocklisted",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Gov ID front is not suspicious",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Gov ID full name was extracted",
   "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": "Gov ID last name matches phone number",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Gov ID type is an eligible document type",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Gov ID was processed",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Selfie matches portrait on Gov ID",
   "value": true,
   "status": "completed"
  },
  {
   "name": "Selfie passes liveness check",
   "value": true,
   "status": "completed"
  }
 ],
 "collected_traits": null,
 "completed_at": 1757337785,
 "created_at": 1757337702,
 "custom_fields": {
  "smartVerify": "9922292929292"
 },
 "email": "[email protected]",
 "expires_at": 1758201702,
 "fields_to_collect": [],
 "idv_status": "success",
 "ip": [
  "208.252.193.210"
 ],
 "is_data_granted": null,
 "legacy_clear_partner_information": {
  "preferred_username": "verify_HUQgjLoNLnhHlbtEBJJ305JMKG2pFoVt"
 },
 "phone": "+19172222222",
 "project_id": "project_9C4eCAstPDUwfIjkZlUcIZcYm8uCA9NGE5AWSqHNac",
 "redirect_url": null,
 "report_id": null,
 "sessions": [
  {
   "location": {
    "country": "United States",
    "country_iso": "US",
    "subdivision": "New York",
    "subdivision_type": "State",
    "city": "New York City",
    "lat": "40.71427",
    "lon": "-74.00597",
    "ip": "208.252.193.210"
   },
   "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
   "created_at": 1757337760,
   "ip": "208.252.193.210",
   "locale": "en-US",
   "zoneinfo": "America/New_York"
  }
 ],
 "status": "success",
 "status_details": null,
 "token": "verify_token_NO12MWMiwXhXdRJLhkjN7sqNNMGULbaT",
 "traits": {
  "address": null,
  "dob": null,
  "email": "[email protected]",
  "first_name": null,
  "last_name": null,
  "middle_name": null,
  "second_family_name": null,
  "full_last_name": null,
  "phone": "+19172222222",
  "ssn4": null,
  "ssn9": null,
  "identification_number": null,
  "identification_type": null,
  "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",
  "member_type": null,
  "health_insurance": {
    "payer_id": "87726",
    "payer_name": "UnitedHealthcare",
    "plan_status": "ACTIVE",
    "group_name": "Group DDD",
    "group_id": "DDD123",
    "insurance_member_id": "DEDUCTIBLEMET",
    "policy_holder_first_name": "DEDUCTIBLEMET",
    "policy_holder_last_name": "Arnoldson"
   }
 },
 "updated_at": 1757337785,
 "user_agent": [
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
 ],
 "user_created": true,
 "user_id": "3mfsPYduiyY4l04EB5z1IXumxc4XFV6wQlgAUptW44",
 "user_profile_information": null,
 "user_profile_match_status": "not_applicable",
 "verified_info": null
}%  

More details on the responses can be found in the API Reference.

Best Practices

  • Use Webhooks + Redirect or Redirect + UUID together for best reliability and UX.
  • Treat state values as single-use to prevent replay attacks.
  • Never trust redirects alone — always confirm via API.
  • Secure all endpoints with HTTPS, Bearer token, and (optionally) HMAC signatures.
  • Store what you need: psuid, verification_id, PII (if needed).

Did this page help you?