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:
- Create a verification session
- Invoke CLEAR’s hosted UI
- Decide how your system will know when the session is finished
- 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 laterverification_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:
- Generate a UUID on your backend.
- Store a mapping: state → verification_session.id.
- When the user returns to verified-callback, read state from 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, 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 responseDo not use the
verified_infofield, as this is a deprecated value. Usetraitsto get a user's demographics.Within
traitsCLEAR requires usingtraits.documentas the place to retrieve information pulled of the users 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 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).
Updated 2 days ago