AI Quick Start: Partner Platform Integration Guide
This guide covers how partner ecosystems need to integrate to enable customers to verify their end users
What This Guide Covers (and What It Doesn't)
What This Guide Provides
Complete CLEAR Integration Functionality:
- How to create verification sessions (User Profile Matching and Known User Key flows)
- How to retrieve and process verification results
- How to route users to the correct flow based on stored data
- How to validate credentials
- How to correlate verification data back to your user records
- Working code samples for Node.js/Express and Python/Flask
- Complete API reference with real request/response examples
- Decision logic and flow routing patterns
- Security best practices (userID validation, mismatch handling)
This guide will get you to a functional CLEAR integration.
What This Guide Does NOT Provide
You Will Need to Build/Decide:
-
Database Architecture
- Where to store employee/user data
- How to structure your
employees,tenants,sessionstables - Which database technology to use (PostgreSQL, MySQL, MongoDB, etc.)
- Database migrations and schema management
-
Data Storage Layer
- How to connect to your data storage systems
- Where to push CLEAR verification data after processing
- How to encrypt and secure stored credentials
- Your ORM or database access patterns
-
Application Integration
- How this fits into your existing application architecture
- Your authentication/authorization system
- Your frontend framework and UI components
- Your admin dashboard structure
- Your existing user management flows
-
Infrastructure & Deployment
- How to deploy your application (Docker, Kubernetes, serverless, etc.)
- Environment variable management
- Secrets management (API keys, database credentials)
- Logging, monitoring, and alerting infrastructure
- Load balancing and scaling strategies
-
User Interface
- Admin configuration screens (we provide requirements, not code)
- User verification screens (pre/post verification)
- Error handling UI
- Success/failure messaging
-
Business Logic
- Multi-tenancy implementation (if applicable)
- Billing/usage tracking
- User permissions and role-based access
- Workflow customization beyond CLEAR integration
This guide provides the CLEAR-specific integration logic. You own how it connects to your existing systems and infrastructure.
Intended Audience
This guide is for:
- Platform partners building integrations where their customers will configure CLEAR credentials
- Technical architects planning CLEAR integration approach
- Engineering teams implementing identity verification flows
- Developers familiar with REST APIs and backend development
You should be comfortable with:
- Backend API development
- Database design and management
- Authentication and security concepts
- Your chosen programming language/framework
For AI-Assisted Development
This guide is optimized for use with AI coding assistants (ChatGPT, Claude, Cursor, GitHub Copilot, etc.).
How to Use This Guide with AI:
-
Load this entire document into your AI tool's context (paste the full markdown or provide the file path)
-
Use these prompts to understand the integration:
"Explain the difference between Establish Identity Flow and Known User Key Flow" "How does User Profile Matching work in CLEAR's verification process?" "What are the two integration layers I need to build?" "Walk me through the complete verification process from capture to storage" "What's the difference between CLEAR Network and Customer Ecosystem Identity?" "Show me how to implement the decision logic for routing users to the correct flow" -
Generate code for your stack:
"Generate the admin configuration UI for Bring Your Own Keys in [React/Vue/Angular]" "Create a Node.js Express endpoint to initiate a CLEAR verification session" "Write Python/Flask code to handle the redirect callback and process results" "Build a complete integration in [your language/framework] with error handling" "Show me how to implement User Profile Matching in [your language]" "Create database schema for storing CLEAR userIDs in [PostgreSQL/MySQL/MongoDB]" -
Get specific code examples:
"Show me the complete API request to create an Establish Identity session" "How do I poll for session results with proper error handling?" "Give me a complete example of processing Known User Key results" "Show me how to validate CLEAR credentials before saving" "Create a webhook handler for CLEAR session completion events" -
Understand edge cases:
"What should I do when User Profile Matching returns no_match?" "How do I handle userID mismatches in Known User Key flow?" "What error scenarios do I need to handle and how?" "How should I handle session expiration?"
CLEAR Basics
Before building a CLEAR integration, it's important to understand how CLEAR's identity platform works and the distinction between Networked Identity and Ecosystem Identity.
Networked Identity: The CLEAR Network
CLEAR operates a nationwide network of identity verification nodes across physical and digital locations. These nodes include airports, stadiums, arenas, as well as digital experiences like LinkedIn, consumer applications like The Home Depot, and other partner platforms. When a user signs up in the CLEAR network for the first time at any node, they create a reusable identity that works across all network nodes.
First-Time Sign-Up (CLEAR Network)
When a user first joins CLEAR at any network node (e.g., airport, stadium, LinkedIn, The Home Depot), they complete a one-time sign-up:
- Provide Contact Information: Phone number and email
- Document Verification: Scan a valid ID document:
- U.S. Driver's License
- U.S. Passport or Passport Card
- Permanent Resident Card (Green Card)
- Other accepted government-issued IDs from supported countries
- Biometric Capture: Take a selfie
- Verification Complete: CLEAR verifies the document and links the user's biometric to their verified identity
Result: User now has a verified identity in the CLEAR network.
Returning to Any Network Node
Once signed up, the user can access any CLEAR network location with a streamlined experience:
- Enter Phone Number: Input the phone number associated with their CLEAR account
- Biometric Verification: Take a selfie
- Instant Access: Identity confirmed in seconds
No need to re-scan ID or sign up again. The user's verified identity travels with them across the entire CLEAR network.
CLEAR Verification Basics: How Identity Proofing Works
Whether it's a user's first time, a repeat visit to a CLEAR network node, or verification within a customer ecosystem, CLEAR follows a rigorous multi-layered verification process to proof identity. Understanding this process is critical for partners building integrations.
The Verification Process
1. Capture
CLEAR captures the necessary components for identity verification:
- Biometric Selfie: Facial capture via device camera
- Document Image: Scan of government-issued ID (driver's license, passport, etc.)
- Phone Number: User's mobile number
- Email Address: User's email (typically on first-time verification)
- One-Time Passcode (OTP): Sent to phone or email for additional verification in many cases
2. Extract
CLEAR extracts information from each captured component:
- From Selfie: Facial biometric data, feature measurements, liveness indicators
- From Document: Personal information (name, DOB, address), document details (issue date, expiration, document number), security features (holograms, patterns, fonts)
- From Phone/Email: Contact verification, ownership confirmation via OTP
3. Biometric Verification
CLEAR performs advanced facial biometric analysis:
- Anti-Spoofing Detection: Check for image injection attempts or AI deepfake attacks
- Liveness Detection: Ensure a live person is present, not a photo, video, or synthetic image
- Facial Matching: Compare the selfie against:
- The photo on the ID document (first-time verification)
- The existing biometric template on file (returning users)
- Customer employee data image (ecosystem verification with User Profile Matching)
- Feature Analysis: Identify irregularities and facial imperfections that assure no AI deepfake attacks
- Geometric Measurement: Measure the distance between facial features (eyes, nose, mouth, etc.) and compare those measurements to templates stored on file for returning users
Result: High-confidence match that the live person presenting the selfie is the same person in the document and/or stored biometric template.
4. Document Verification
CLEAR validates the authenticity of the ID document:
- Liveness Detection: Ensure the document is physically present, not a photo or printout
- Image Attack Detection: Check for spoofing attempts (photos of photos, screen displays, manipulated images)
- Document Vintage Validation: Compare the document to the expected template for documents minted in a given year
- Example: If the document issuance is 2026, CLEAR validates that holograms, security features, fonts, layouts, and all design trends match the 2026 vintage
- Ensures the document is genuine and not forged or altered
- Security Feature Analysis: Validate holograms, microprinting, UV features, and other security elements specific to the issuing authority
Result: Confirmation that the document is authentic, valid, and has not been tampered with.
5. Data Extraction & Validation
CLEAR extracts verified data from the document to enable system population and user matching:
- Demographic Data: Name, date of birth, address, document number, expiration date
- Document Metadata: Issuing authority, document type, issue date
- Verified Attributes: Data confirmed as authentic through document validation
This data is passed back to the integrating partner to:
- Populate user records and systems
- Facilitate user matching (comparing verified data to employee records)
- Enable downstream workflows (account creation, access provisioning, etc.)
6. Source Validation (Baseline Identity)
CLEAR corroborates the information extracted from the document across authoritative sources:
- Authoritative Database Checks: Cross-reference data with trusted identity databases and government sources
- Consistency Validation: Ensure information is consistent across multiple data points
- Baseline Identity Approach: By default, CLEAR performs source validation during each verification session as a key component of user verification
This step provides an additional layer of assurance that the identity presented is legitimate and matches authoritative records.
7. Device Telemetry (Optional)
Partners can optionally enable device telemetry to assess device risk:
- VPN Detection: Determine if the user is connecting through a VPN or proxy
- Device Risk Assessment: Analyze device characteristics, browser fingerprinting, and behavioral signals
- Trustworthiness Score: Provide a risk score indicating whether the device is trustworthy
This helps ensure that the device the user is verifying from is legitimate and not associated with fraudulent activity.
Verification Across All CLEAR Contexts
This comprehensive verification process applies consistently across:
- CLEAR Network (Networked Identity): Airport security, stadium entry, event access, LinkedIn verification, consumer experiences (The Home Depot, etc.)
- Customer Ecosystem (Ecosystem Identity): Employee verification, password reset, conditional access, building entry, device provisioning
Key Distinction by Context:
| Verification Step | First-Time (Network or Ecosystem) | Returning User (Network) | Returning User (Ecosystem - Known User Key) |
|---|---|---|---|
| Document Capture | ✓ Required | ✗ Not required | ✗ Not required |
| Selfie Capture | ✓ Required | ✓ Required | ✓ Required (selfie-only) |
| Phone/Email | ✓ Required | ✓ Required (phone) | ✗ Not required |
| Biometric Match | Match selfie to document | Match selfie to stored template | Match selfie to stored template |
| Document Verification | ✓ Full validation | ✓ Proof on file | ✓ Proof on file |
| Data Extraction | ✓ Extract and store | ✗ Not required | ✗ Not required |
| Source Validation | ✓ Corroborate data | ✓ Corroborate against stored data | ✓ Corroborate against stored data |
| User Profile Matching | ✗ Not applicable | ✗ Not applicable | ✓ Match to customer employee data (first time only) |
Security Note: Even on returning user flows where only a selfie is required, CLEAR still performs rigorous anti-spoofing, liveness detection, biometric matching, document proofing (against document on file), and source validation to ensure the highest level of security.
Ecosystem Identity: Customer-Specific Verification
While the CLEAR network serves a broad range of locations and experiences, Ecosystem Identity extends CLEAR's verification capabilities to enterprise customers within their own specific environments—both digital and physical. This is where partners integrate.
How Ecosystem Identity Works
When a user verifies their identity for a specific customer (e.g., a company, organization, or platform), they are issued a customer-specific CLEAR userID (PSUID - Person-Specific Unique Identifier). This userID represents the verified identity relationship between that user and that customer.
Key Characteristics:
- Customer-Scoped: The userID is unique to the user-customer relationship
- Ecosystem-Bound: Only valid within that customer's ecosystem (does NOT work at airports or other CLEAR network nodes)
- Reusable: Once the user receives their userID, it enables fast re-verification across all use cases within that customer's ecosystem
- Privacy-Preserving: Customer A cannot access or use userIDs issued by Customer B
Customer Ecosystem Touchpoints
Enterprise customers typically have multiple touchpoints where identity verification is critical. Once a user completes their first verification for a customer and receives their customer-specific CLEAR userID, they can use it for streamlined verification across ALL of these scenarios:
Workforce Identity & Access:
- Employee Onboarding: Verify new hire identity during account creation
- Laptop/Device Provisioning: Confirm identity before issuing hardware
- Physical Access: Verify identity for building entry, secure facility access, or equipment checkout
- VPN/Network Access: Authenticate access to corporate networks
- High-Risk Login: Step-up authentication for suspicious activity or sensitive systems
- Conditional Access: Re-verify when accessing from new device or location
- Account Recovery: Prove identity to regain account access
- MFA Reset: Verify user before resetting multi-factor authentication
HR & Recruiting:
- Candidate Verification: Verify job applicant identity during hiring process
- Contractor Onboarding: Verify identity for temporary or contract workers
Operational Security:
- Password Reset: Verify identity before allowing password changes
- Role Changes: Re-verify when changing access permissions or roles
- Offboarding Verification: Confirm identity during exit procedures
Compliance & Audit:
- General Employee Verification: Periodic identity checks for compliance
- Access Recertification: Re-verify identity during access reviews
Example: User's Journey Across Customer Ecosystem
Day 1 - Onboarding (First Verification):
- New employee logs in for the first time
- Completes CLEAR verification (ID + Selfie) with User Profile Matching
- Customer receives and stores CLEAR userID to employee record
- Employee gains access to systems
Week 2 - Laptop Provisioning (Known User Key):
- Employee requests new laptop
- Takes 3-5 second selfie to verify identity
- Laptop provisioning approved and logged
Week 4 - Building Access Setup (Known User Key):
- Employee requests badge for secure facility
- Takes quick selfie to verify identity
- Physical access badge issued
Month 3 - Password Reset (Known User Key):
- Employee forgets password
- Takes quick selfie to verify identity
- Password reset authorized
Month 6 - High-Risk Login Alert (Known User Key):
- System detects login from new location
- Employee takes selfie for step-up authentication
- Access granted after verification
All of these verifications—both digital and physical—use the same customer-specific CLEAR userID received on Day 1.
Network vs. Ecosystem: Key Differences
| Aspect | CLEAR Network (Networked Identity) | Customer Ecosystem (Ecosystem Identity) |
|---|---|---|
| Scope | Physical locations (airports, stadiums) and digital experiences (LinkedIn, consumer apps) | Digital and physical touchpoints within a specific customer's environment |
| Setup | User signs up directly with CLEAR | User completes first verification through customer integration |
| Identifier | CLEAR network account (phone number + biometric) | Customer-specific userID (PSUID) |
| Reusability | Works across all CLEAR network nodes | Works only within that customer's ecosystem |
| Use Cases | Airport security, stadium entry, event access, LinkedIn verification, consumer retail experiences | Employee verification, password reset, digital access control, physical access control (building entry) |
| User Experience | Phone number + biometric verification | Selfie-only verification (after first verification) |
Critical Distinction: A user's customer-specific CLEAR userID issued by Company A does not grant access to Company B's systems, nor does it work at CLEAR network nodes like airports. Each customer ecosystem is isolated and has unique userIDs for each user relationship.
Why This Matters for Integration
As a partner building a CLEAR integration, you are enabling Ecosystem Identity for your customers. Your integration will:
- Create customer-specific ecosystems where users complete their first verification and then verify quickly across multiple touchpoints
- Issue customer-scoped userIDs that work only within each customer's environment
- Enable progressive enhancement where first-time verification leads to fast re-verification on all subsequent interactions
This guide focuses exclusively on building Ecosystem Identity integrations for enterprise customers.
Overview
This guide enables partners to build identity verification solutions that are use case agnostic and support both initial identity establishment and fast re-verification flows. The integration uses CLEAR's User Profile Matching technology to bind verified identity to customer employee records, enabling seamless authentication across multiple use cases.
Key Outcome: Once a user completes identity establishment, all subsequent verifications across any use case become fast, friction-reduced selfie-only flows.
Integration Layers: What Partners Must Build
A complete CLEAR integration requires partners to build two critical layers:
Layer 1: Admin Configuration Experience
The backend configuration and setup that enables customers to connect their CLEAR environment to your platform. This includes:
- CLEAR Environment Provisioning: How customers obtain CLEAR credentials
- Credential Management: Where customers input and manage their Project IDs and API keys
- Workflow Configuration: Defining which use cases trigger CLEAR verification
- Data Mapping Configuration: Specifying which customer fields map to CLEAR data
Layer 2: Customer End User Experience
The actual verification flow that your customer's end users (their employees/users) experience. Once your customer configures CLEAR credentials (Layer 1), their end users can verify their identity. This layer is about facilitating the standard CLEAR integration experience for your customers:
Core Integration Components:
- Create Verification Session (API Docs): Initiate CLEAR verification with the right project and data
- Get Verification Results (API Docs): Retrieve session results and map data back to user records
- User Profile Matching Logic: Check if CLEAR userID exists, route to appropriate flow (Project A with UPM or Project B with known user key)
- Result Retrieval Mechanism: Define redirect path to pull verification results (redirect, polling, or button-triggered)
What Partners Must Build:
- Data System Check: Mechanism to check if CLEAR userID exists on user record
- Flow Routing:
- If no userID → Create session with Project A (User Profile Matching), send
employee_idincustom_fields - If userID exists → Create session with Project B (Known User Key), send
user_idin request
- If no userID → Create session with Project A (User Profile Matching), send
- Redirect Path Definition: Specify
redirect_urlin both create session API calls - Result Processing: When user redirects back, call Get Verification endpoint to retrieve results
- Data Correlation: Map returned data back to correct user record using
employee_idfromcustom_fields - UserID Storage: Store CLEAR
user_idwhen User Profile Matching returnsmatch_result: "match"
User Experience Patterns:
- Traditional Web Application: Pre-verification screen → CLEAR verification → Post-verification landing screen
- Terminal Screen: CLEAR ends on final screen, results retrieved via polling or agent-triggered button
- Call Center Assisted: Agent helps user verify, retrieves results manually
Key Point: The end goal is to create the session, retrieve results, and map the verified identity back to the correct user record by correlating data.
Both layers must work together seamlessly to deliver a complete identity verification solution.
Layer 1: Admin Configuration Experience
Overview
Before any end user can verify their identity with CLEAR, your platform must enable customers (admins/IT teams) to configure CLEAR within your system. This configuration determines:
- Which CLEAR environment and projects power the verification
- Who owns and controls the verification data
- Which workflows and use cases trigger CLEAR
- Where and how data is stored
Configuration Options for Partners
Partners must implement at minimum Option A (Bring Your Own Keys). Option B (Self-Service Procurement) is optional but recommended for a seamless customer experience.
Option A: Bring Your Own Keys (BYOK) - REQUIRED
What It Is: A configuration interface that allows customers to input their own CLEAR environment credentials (Project IDs and API keys) obtained directly from CLEAR.
Why It's Critical: Ensures customers own and control their verification data. Data flows through customer-specific CLEAR tenants, not shared infrastructure. This is a fundamental requirement for enterprise security and compliance.
What Partners Must Build:
-
Admin Configuration UI - A secure settings page where authorized admins can input:
- Establish Identity Project ID: For first-time verification with User Profile Matching
- Known User Key Project ID: For fast re-verification flows
- API Key: Authentication credential (supports both projects)
- Environment Selection: Production vs. Sandbox
-
Credential Storage - Secure backend storage for customer-specific CLEAR credentials:
- Encrypted at rest
- Scoped per customer/tenant
- Accessible only to authorized platform services
-
Credential Validation - Test connectivity before saving:
async function validateClearCredentials(projectId, apiKey) { try { // Validate by attempting to create a test session const response = await fetch('https://verified.clearme.com/v1/verification_sessions', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ project_id: projectId, redirect_url: 'https://yourapp.com/test', custom_fields: { test: 'validation' } }) }); // Valid credentials return 200/201 return response.ok; } catch (error) { return false; } }Note: There is no dedicated
/validateendpoint. Validate credentials by creating a test session and checking for a successful response (200/201 status).
Implementation Checklist:
- Secure settings page accessible only to authorized admins
- Input fields for both Project IDs and API Key
- Credential validation before saving
- Encrypted storage of credentials
- Credential rotation support
- Audit logging of configuration changes
Option B: Self-Service Procurement (OPTIONAL)
What It Is: Enable customers to provision CLEAR environments, create projects, and generate credentials directly through your platform using CLEAR's provisioning APIs. Credentials are automatically populated into the BYOK configuration UI.
Why Consider It:
- Reduces customer friction (no need to contact CLEAR separately)
- Faster time-to-value (instant provisioning vs. manual setup)
- Seamless customer experience (never leave your platform)
- Automatic credential management
How to Implement:
Self-service procurement requires access to CLEAR's provisioning APIs, which are not yet publicly available.
To enable Option B, please contact CLEAR:
- Email: [email protected]
- Request: Access to provisioning APIs, code samples, and API reference documentation
- What You'll Receive:
- Provisioning API credentials
- Complete API reference for environment and project creation
- Code samples for orchestrating the provisioning workflow
- Integration guide for automatic credential population
- Testing environment access
Workflow Configuration
Once CLEAR credentials are configured, admins must define where and when CLEAR verification is triggered.
Key Configuration Points:
-
Use Case Selection: Which workflows require CLEAR verification?
- Employee onboarding
- Password reset
- Account recovery
- High-risk transactions
- Conditional access (new device/location)
- VPN/network access
- Application access
-
Trigger Conditions: When should verification be required?
- Always (every login)
- Conditional (risk-based triggers)
- On-demand (user-initiated)
- Periodic (time-based re-verification)
-
Flow Routing Logic: Which CLEAR project to use?
- If
clear_user_idexists → Known User Key Project - If
clear_user_idnull → Establish Identity Project
- If
Data Mapping Configuration
Admins must specify which fields from their user database map to CLEAR's expected fields for User Profile Matching.
Required Mappings:
| CLEAR Field | Customer Field (Example) | Required For |
|---|---|---|
employee_id | employee_id or user_id | Establish Identity |
first_name | first_name or given_name | Establish Identity |
last_name | last_name or family_name | Establish Identity |
date_of_birth | dob or birth_date | Establish Identity |
email | email or work_email | Optional |
Layer 2: Customer End User Experience
Overview
This layer enables your customer's end users (their employees) to complete identity verification through CLEAR. Once customers configure their CLEAR credentials in Layer 1, their end users can verify. This layer implements the core CLEAR integration workflow.
What This Layer Does:
Partners facilitate the standard CLEAR verification flow documented at:
- Create Verification Session: Initiate verification
- Get Verification: Retrieve results
The Critical Addition: User Profile Matching (UPM)
When creating a session, partners must check if the user has a stored CLEAR userID:
- No CLEAR userID exists → Use Project A (configured for User Profile Matching):
- Send
employee_id,first_name,last_name,date_of_birthincustom_fields - CLEAR performs biometric verification AND matches verified data against the data you sent
- Result includes
match_result: "match"ormatch_result: "no_match" - If match succeeds, store the returned CLEAR
user_idto the user record
- Send
- CLEAR userID exists → Use Project B (re-verification):
- Send the stored CLEAR
user_idin the request - User completes selfie-only flow (3-5 seconds)
- Verify returned
user_idmatches storeduser_id
- Send the stored CLEAR
CLEAR Owns the Matching: When using User Profile Matching, CLEAR determines if the verified identity data matches the employee data you sent. The verification result tells you two things:
- Did the user pass CLEAR verification? (document valid, selfie matches ID)
- Did the verified data match the employee data you sent? (
match_result)
Three Core Components Partners Must Build:
- End User Experience Design: Where CLEAR is triggered, what the user sees before/during/after verification, error handling, and success paths
- User Matching & Verification Logic: Check for CLEAR userID, route to correct project, process match results, store userID
- Data Storage & Correlation: Store CLEAR userID, map results back to correct user record using
employee_id, retrieve verification data
Component 1: End User Experience Design
Partners must design and implement the following UX touchpoints:
1. Verification Trigger Points
Question: Where and how is CLEAR verification initiated?
Common Trigger Patterns:
A. Button/Link Click
User explicitly clicks a button to start verification.
When to Use: Password reset, account recovery, on-demand verification
B. Automatic Redirect
System automatically redirects user to CLEAR when conditions are met.
async function handleLogin(username, password) {
const user = await authenticateCredentials(username, password);
// Check if conditional access verification required
if (isNewDevice(user.id) || isHighRiskLogin(user.id)) {
// Automatic redirect to CLEAR
const sessionUrl = await initiateVerification(user.id, 'conditional_access');
return redirect(sessionUrl);
}
// Normal login flow
return redirect('/dashboard');
}When to Use: Conditional access, risk-based authentication
C. Workflow Step
CLEAR verification as part of a multi-step process.
Step 1: Create Account → Step 2: Verify Identity → Step 3: Set Preferences
(CLEAR verification)
When to Use: Employee onboarding, account setup flows
D. SMS/Email Link
User receives a message with a link to start verification.
SMS: "To complete your account recovery, verify your identity:
https://yourapp.com/verify/abc123"
When to Use: Async verification requests, out-of-band authentication
2. Pre-Verification Experience
Question: What does the user see immediately before entering CLEAR?
Design Considerations:
A. Context Setting
Explain why verification is needed and what will happen (e.g., "We need to verify your identity to reset your password. You'll scan a photo ID and take a quick selfie. Verification completes in under 60 seconds.").
B. Returning User (Known User Key)
Provide a different message for users who have already completed their first verification (e.g., "Welcome back! We just need a quick selfie to verify it's you. This will only take 3-5 seconds.").
Implementation:
async function showPreVerificationScreen(userId) {
const user = await getUserProfile(userId);
if (user.clear_user_id) {
// Returning user - show Known User Key message
return renderScreen('quick_verification_prompt');
} else {
// New user - show full Establish Identity message
return renderScreen('full_verification_prompt');
}
}3. CLEAR Session Flow
Question: How does the user navigate to and from CLEAR?
Required Pattern: Full Redirect
CLEAR verification must redirect the user outside of the partner application. Popups and iframe embeds are not supported.
User leaves partner app entirely, completes CLEAR verification, and is redirected back to partner app.
Partner App → CLEAR Verification → Partner App
(redirect) (verify.clearme.com) (redirect_url callback)
Implementation:
async function initiateVerification(userId) {
// 1. Create session and get token
const session = await createClearSession(userId);
// 2. Construct CLEAR verification URL with token
const verificationUrl = `https://verified.clearme.com/verify?token=${session.token}`;
// 3. Full page redirect to CLEAR
window.location.href = verificationUrl;
}
// User completes verification on CLEAR's site, then CLEAR redirects back
// to the redirect_url you specified during session creation
// Callback endpoint handles the return
app.get('/verify/confirmation', async (req, res) => {
const sessionId = req.query.session_id;
const results = await getSessionResults(sessionId);
await processResults(results);
res.redirect('/verification/success');
});Why Full Redirect Is Required:
- Ensures consistent user experience across all devices
- Avoids popup blocker issues
- Works reliably on mobile devices
- Maintains CLEAR's security and verification integrity
- No complex iframe or postMessage handling needed
4. Post-Verification Experience
Question: What happens after CLEAR returns the user?
Critical Steps:
A. Loading/Processing State
Show user that verification is being processed (e.g., loading spinner with message "Verifying your identity... This may take a few seconds.").
B. Retrieve Session Results
Fetch verification data from CLEAR.
app.get('/clear/callback', async (req, res) => {
const sessionId = req.query.session_id;
try {
// Show loading screen
res.send(renderLoadingScreen());
// Fetch results (redirect or polling)
const results = await getSessionResults(sessionId);
// Process based on flow type
if (results.mode === 'user_profile_matching') {
await handleEstablishIdentityResults(results);
} else {
await handleKnownUserKeyResults(results);
}
// Redirect to success
res.redirect('/verification/success');
} catch (error) {
res.redirect(`/verification/error?reason=${error.message}`);
}
});C. Success Path
User verification succeeded - grant access and provide confirmation (e.g., "Identity Verified Successfully. Your identity has been confirmed. You can now proceed with your password reset.").
Implementation:
async function handleEstablishIdentityResults(results) {
if (results.status === 'completed' && results.match_result === 'match') {
// Store CLEAR userID
await updateUserProfile(results.custom_fields.employee_id, {
clear_user_id: results.user_id,
identity_verified_at: new Date()
});
// Grant access
await grantWorkflowAccess(results.custom_fields.employee_id);
// Log success event
await logEvent('verification_success', {
employee_id: results.custom_fields.employee_id,
session_id: results.session_id,
flow_type: 'establish_identity'
});
}
}D. Failure Paths
Handle various failure scenarios gracefully:
Scenario 1: Verification Failed - Unable to verify identity (e.g., unclear ID, poor lighting, information mismatch). Provide retry option and support contact.
Scenario 2: User Profile Match Failed (Establish Identity) - Verified identity doesn't match employee record on file. Direct user to contact IT/HR to update employee information. Include session reference code.
Scenario 3: UserID Mismatch (Known User Key) - Verified identity doesn't match stored userID. This is a security event - log it, notify administrators, and provide clear messaging about potential unauthorized access attempt.
Scenario 4: Session Expired - Verification session timed out. Provide option to start new verification.
Error Handling Implementation:
async function processVerificationResults(results) {
// Handle different statuses
switch (results.status) {
case 'completed':
if (results.match_result === 'match') {
return handleSuccess(results);
} else if (results.match_result === 'no_match') {
return handleProfileMismatch(results);
}
break;
case 'failed':
return handleVerificationFailed(results);
case 'expired':
return handleSessionExpired(results);
case 'cancelled':
return handleUserCancelled(results);
default:
return handleUnknownError(results);
}
}
async function handleVerificationFailed(results) {
// Log failure
await logEvent('verification_failed', {
employee_id: results.custom_fields?.employee_id,
session_id: results.session_id,
reason: results.failure_reason
});
// Show user-friendly error
return renderErrorScreen('verification_failed', {
canRetry: true,
supportContact: '[email protected]'
});
}Component 2: User Matching & Verification Logic
Overview
This component handles how users are matched to their records during verification and how the system validates identity on subsequent verifications.
First-Time Verification: User Profile Matching (UPM)
Purpose: Match the verified identity data from CLEAR against the customer's employee/user records to ensure the right person is accessing the right account.
How It Works:
-
Customer sends employee data in the session creation request:
{ project_id: "proj_abc123", redirect_url: "https://yourapp.com/verify/confirmation", custom_fields: { employeeID: "EMP12345" // For correlation only }, user_profile_information: { // Biographic data for matching name: { first_name: "Jane", last_name: "Smith" }, dob: "1990-05-15" } }Important:
custom_fieldsis for correlation data only (e.g., employeeID, department, etc.)user_profile_informationcontains the biographic data CLEAR will match against
-
User completes CLEAR verification (ID scan + selfie)
-
CLEAR performs biometric matching:
- Extracts data from government-issued ID
- Matches selfie to ID photo using facial biometrics
- Compares verified data to employee data sent in
user_profile_information - If data matches, returns
user_idin the response - If data doesn't match, no
user_idis returned
-
Partner validates the match:
if (results.user_id) { // Success: Verified identity matches employee record // Store CLEAR userID to employee profile await updateUserProfile(employeeId, { clear_user_id: results.user_id }); } else { // No match: Verified identity doesn't match employee data // Flag for manual review await flagForReview(employeeId, results); }
Key Point: User Profile Matching ensures the person verifying is the same person as the employee record, preventing account takeover or identity confusion.
Subsequent Verifications: UserID-to-UserID Matching
Purpose: On subsequent verifications, match the CLEAR userID returned from the session against the stored userID on the employee profile.
How It Works:
-
Partner sends stored userID in the session creation request:
{ project_id: "known_user_key_project_id", user_id: "psuid_abc123def456" // From employee profile } -
User completes selfie-only verification (3-5 seconds)
-
CLEAR matches selfie to stored biometric using the provided userID
-
Partner validates userID match:
const storedUserId = userProfile.clear_user_id; const returnedUserId = results.user_id; if (returnedUserId === storedUserId) { // Success: UserIDs match await grantAccess(employeeId); } else { // SECURITY ALERT: UserID mismatch await logSecurityAlert({ employee_id: employeeId, stored_user_id: storedUserId, returned_user_id: returnedUserId }); throw new Error('Unauthorized access attempt'); }
Key Point: UserID-to-userID matching prevents unauthorized users from accessing accounts even if they bypass initial verification flows.
Component 3: Data Storage Strategy
Overview
After verification, partners must decide what data from the CLEAR session to store on user profiles. The requirements vary based on your system's capabilities and compliance needs.
Required Data (Minimum)
Always store these fields:
await updateUserProfile(employeeId, {
// REQUIRED: Enables Known User Key flow
clear_user_id: results.user_id, // e.g., "psuid_abc123def456"
// REQUIRED: Audit and troubleshooting
verification_session_id: results.session_id, // e.g., "session_xyz789"
// REQUIRED: Timestamps for compliance
identity_verified_at: new Date()
});Why Required:
- clear_user_id: Without this, you cannot use Known User Key flow. Every verification would require full ID + selfie.
- verification_session_id: Essential for audit trails, troubleshooting, and linking back to CLEAR session data.
- identity_verified_at: Compliance requirement for tracking when identity was last verified.
Recommended Data (If Your System Supports PII Storage)
If your system can store PII, we recommend also storing verified data from the CLEAR session:
await updateUserProfile(employeeId, {
// Required minimum
clear_user_id: results.user_id,
verification_session_id: results.session_id,
identity_verified_at: new Date(),
// RECOMMENDED: Verified PII from government-issued ID
verified_first_name: results.verified_data.first_name,
verified_last_name: results.verified_data.last_name,
verified_dob: results.verified_data.date_of_birth,
verified_address: results.verified_data.address,
// RECOMMENDED: Document metadata
document_type: results.verified_data.document_type, // "drivers_license", "passport"
document_number: results.verified_data.document_number,
document_expiration: results.verified_data.document_expiration,
// RECOMMENDED: Contact information
verified_phone_number: results.verified_data.phone_number,
verified_email: results.verified_data.email,
// RECOMMENDED: Audit metadata
match_result: results.match_result, // "match" or "no_match"
verification_method: 'clear_user_profile_matching'
});Why Recommended:
- System of Record: Your platform becomes the authoritative source for verified employee data
- Compliance: Meets regulatory requirements for identity verification documentation
- Audit Trail: Complete record of what data was verified and when
- Reconciliation: Compare stored data against employee records to detect discrepancies
- User Profile Enhancement: Populate or update employee profiles with verified, authoritative data
Optional Data (Not Required If PII Storage Is Not Allowed)
If your system cannot store PII (due to data minimization policies, GDPR, or security constraints):
await updateUserProfile(employeeId, {
// Only store required minimum
clear_user_id: results.user_id,
verification_session_id: results.session_id,
identity_verified_at: new Date(),
// NO verified PII stored
});When to Use This Approach:
- Data minimization requirements
- Systems with limited PII storage capabilities
- Environments where PII storage increases compliance burden
- Known User Key flow still works (only requires
clear_user_id)
Trade-offs:
- Cannot use verified data for profile updates or reconciliation
- Must rely on session_id to look up historical verification data if needed
- Limited audit trail visibility without accessing CLEAR API
Known User Key Flow: Event Logging Only
On subsequent verifications (Known User Key), DO NOT update stored data. Only log the verification event:
// DO NOT update clear_user_id (already stored)
// Only log the verification event
await logVerificationEvent({
employee_id: employeeId,
session_id: results.session_id,
clear_user_id: results.user_id,
verification_type: 'known_user_key',
verified_at: new Date(),
use_case: 'password_reset', // Or 'conditional_access', etc.
result: 'success'
});Why: The userID never changes, so no profile updates are needed. Only track that verification occurred.
Data Retention Guidelines
| Data Type | Retention Period | Purpose |
|---|---|---|
| clear_user_id | Permanent | Required for all future verifications |
| verification_session_id | 90 days minimum | Audit and troubleshooting |
| Verified PII | Per compliance policy | System of record, reconciliation |
| Verification logs | 1-7 years typical | Compliance and security audit |
| Session metadata | 90 days minimum | Debugging and support |
Component 4: Result Retrieval & Data Correlation
Overview
After the user completes CLEAR verification, partners MUST retrieve the session results and map the data back to the correct user record. This is a required step to complete the verification workflow.
Critical Requirement: Define a redirect_url in BOTH create session API calls (User Profile Matching and Known User Key). This enables the system to retrieve results when the user is redirected back to your application.
Three Methods to Retrieve Results
Partners must implement at least one method to retrieve verification results:
Method 1: Redirect (RECOMMENDED - Most Common)
How It Works:
- When creating the session, include
redirect_url:{ "project_id": "proj_abc123", "redirect_url": "https://yourapp.com/clear/callback?employee_id={employee_id}" } - User completes CLEAR verification
- User is redirected back to your callback URL with
session_idparameter - Your system calls Get Verification to retrieve results
- Map results back to user record using
employee_idfromcustom_fields
When to Use:
- Standard web application flows (most common pattern)
- User-present verification (login, password reset, onboarding)
- Browser-based experiences
- Real-time user feedback required
Implementation:
// Helper function to create verification session
async function createVerificationSession(
apiKey,
projectId,
redirectUrl,
employeeId,
pii, // { first_name, last_name, dob } for User Profile Matching
userId // CLEAR user_id for re-verification
) {
const body = {
project_id: projectId,
redirect_url: redirectUrl,
custom_fields: { employeeID: employeeId },
};
// If userId provided, this is re-verification
if (userId) {
body.user_id = userId;
} else if (pii) {
// Otherwise, use User Profile Matching for initial verification
body.user_profile_information = {
name: {
first_name: pii.first_name,
last_name: pii.last_name,
},
dob: pii.dob,
};
}
const response = await fetch('https://verified.clearme.com/v1/verification_sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Failed to create CLEAR verification session');
}
return data; // { id, token, status }
}
// 1. Create session with redirect_url
app.post('/create-session', async (req, res) => {
const { employeeId } = req.body;
// Look up employee
const employee = await getEmployeeById(employeeId);
// Determine if this is initial verification or re-verification
const isReverification = !!employee.clear_user_id;
const redirectUrl = `https://yourapp.com/verify/confirmation`;
let clearSession;
if (isReverification) {
// Re-verification with Known User Key
clearSession = await createVerificationSession(
apiKey,
reverificationProjectId,
redirectUrl,
employee.employee_id,
undefined,
employee.clear_user_id // Pass stored userID
);
} else {
// Initial verification with User Profile Matching
const pii = {
first_name: employee.first_name,
last_name: employee.last_name,
dob: employee.date_of_birth
};
clearSession = await createVerificationSession(
apiKey,
initialProjectId,
redirectUrl,
employee.employee_id,
pii,
undefined
);
}
// Save session to database
await saveSession({
employee_id: employee.id,
clear_session_id: clearSession.id,
status: 'pending'
});
// Return token to frontend
res.json({ token: clearSession.token });
});
// 2. Frontend redirects user to CLEAR
// window.location.href = `https://verified.clearme.com/verify?token=${token}`;
// 3. Handle redirect callback
app.get('/verify/confirmation', async (req, res) => {
// User was redirected back from CLEAR
// Now retrieve results using Get Verification endpoint
const { sessionId } = req.query; // Your internal session ID
// Look up session
const session = await getSessionById(sessionId);
// Get results from CLEAR
const response = await fetch(
`https://verified.clearme.com/v1/verification_sessions/${session.clear_session_id}`,
{
method: 'GET',
headers: {
'Authorization': `Bearer ${apiKey}`,
},
}
);
const clearData = await response.json();
// Extract employee_id from custom_fields to map back to correct record
const employeeId = clearData.custom_fields.employeeID;
// Process and store results
await processResults(employeeId, clearData);
// Show success screen
res.redirect('/verification/success');
});User Experience Pattern:
[Pre-Verification Screen] → [CLEAR Verification] → [Post-Verification Landing Screen]
Your Application CLEAR Your Application (with results)
Method 2: Polling
How It Works:
- Create session and redirect user to CLEAR
- Periodically poll Get Verification endpoint
- When
statuschanges tocompleted,failed, orexpired, retrieve results - Map results back to user record
When to Use:
- Terminal screen flows (CLEAR ends on final screen)
- Call center assisted verification (agent triggers result retrieval)
- Async workflows (background verification)
- Mobile apps with deep linking
- SMS/Email initiated flows
Implementation:
// Helper function to get verification session
async function getVerificationSession(apiKey, clearSessionId) {
const response = await fetch(
`https://verified.clearme.com/v1/verification_sessions/${clearSessionId}`,
{
method: 'GET',
headers: {
'Authorization': `Bearer ${apiKey}`,
},
}
);
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Failed to get CLEAR verification session');
}
return data;
}
// Polling implementation
async function pollForResults(apiKey, clearSessionId, employeeId) {
const maxAttempts = 60; // 2 minutes with 2-second intervals
for (let i = 0; i < maxAttempts; i++) {
const clearData = await getVerificationSession(apiKey, clearSessionId);
// Check for completion
const isComplete = clearData.status === 'complete' ||
clearData.status === 'success' ||
clearData.status === 'completed';
if (isComplete) {
console.log('Verification complete!');
console.log('Status:', clearData.status);
console.log('user_id:', clearData.user_id);
// Map results back using employee_id from custom_fields
const employeeIdFromClear = clearData.custom_fields.employeeID;
await processResults(employeeIdFromClear, clearData);
return clearData;
} else if (clearData.status === 'failed' || clearData.status === 'expired') {
throw new Error(`Session ${clearData.status}`);
}
console.log(`Polling attempt ${i + 1}/${maxAttempts}, status: ${clearData.status}`);
// Wait 2 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 2000));
}
throw new Error('Polling timeout - verification took too long');
}
// Usage
app.get('/poll-status/:sessionId', async (req, res) => {
const { sessionId } = req.params;
// Look up session
const session = await getSessionById(sessionId);
try {
const results = await pollForResults(
apiKey,
session.clear_session_id,
session.employee_id
);
res.json({ success: true, results });
} catch (error) {
res.status(500).json({ error: error.message });
}
});Method 3: Agent/Button-Triggered Retrieval
How It Works:
- User completes CLEAR verification (ends on terminal screen)
- Agent or automated system clicks button to retrieve results
- System calls Get Verification endpoint
- Results mapped back to user record
When to Use:
- Call center scenarios (agent assists user with verification)
- Administrative workflows (manual review required)
- Kiosk or in-person verification scenarios
Implementation:
// Agent clicks "Retrieve Results" button
app.post('/admin/retrieve-verification', async (req, res) => {
const { sessionId } = req.body;
try {
// Look up session
const session = await getSessionById(sessionId);
// Retrieve results from CLEAR
const clearData = await getVerificationSession(apiKey, session.clear_session_id);
console.log('=== VERIFICATION RESULTS ===');
console.log('Status:', clearData.status);
console.log('user_id:', clearData.user_id);
console.log('Custom fields:', clearData.custom_fields);
// Extract employee_id to map back to correct record
const employeeId = clearData.custom_fields.employeeID;
// Process and store results
await processResults(employeeId, clearData);
res.json({ success: true, clearData });
} catch (error) {
console.error('Error retrieving verification:', error);
res.status(500).json({ error: error.message });
}
});Data Correlation: Mapping Results to User Records
Critical Step: After retrieving results, map the verified identity data back to the correct user record.
How to Correlate:
-
Use
employee_idfromcustom_fields:const employeeId = results.custom_fields.employee_id; const userRecord = await getUserProfile(employeeId); -
For User Profile Matching (first-time):
- Check
match_result === "match" - If match, store
results.user_idto user record - If no match, flag for manual review
- Check
-
For Known User Key (returning):
- Verify
results.user_id === userRecord.clear_user_id - If mismatch, trigger security alert
- Verify
Example Complete Flow (from real production code):
async function processResults(clearSessionId, apiKey) {
// 1. Get verification data from CLEAR
const clearData = await getVerificationSession(apiKey, clearSessionId);
console.log('=== PROCESSING VERIFICATION RESULTS ===');
console.log('CLEAR Status:', clearData.status);
console.log('CLEAR user_id:', clearData.user_id);
// 2. Extract employee_id from custom_fields to map back
const employeeId = clearData.custom_fields.employeeID;
console.log('Employee ID:', employeeId);
// 3. Fetch user record
const employee = await getEmployeeById(employeeId);
console.log('Current employee clear_user_id:', employee.clear_user_id);
// 4. Route based on flow type
const isComplete = clearData.status === 'complete' ||
clearData.status === 'success' ||
clearData.status === 'completed';
if (isComplete && clearData.user_id) {
if (!employee.clear_user_id) {
// First-time verification with User Profile Matching
console.log('🔄 First-time verification complete! Saving user_id...');
// Store CLEAR userID to employee record
await updateEmployee(employee.id, {
clear_user_id: clearData.user_id,
identity_verified_at: new Date()
});
console.log('✅ Successfully saved user_id to employee record');
// Log verification event
await logVerificationEvent({
employee_id: employee.id,
clear_user_id: clearData.user_id,
verification_type: 'initial',
status: 'success'
});
} else {
// Returning user verification (Known User Key)
console.log('🔄 Re-verification complete. Validating user_id...');
if (clearData.user_id === employee.clear_user_id) {
console.log('✅ user_id matches! Re-verification successful');
// Log verification event (don't update employee record)
await logVerificationEvent({
employee_id: employee.id,
clear_user_id: clearData.user_id,
verification_type: 'reverification',
status: 'success'
});
} else {
// SECURITY ALERT - userID mismatch
console.error('❌ SECURITY ALERT: user_id mismatch!');
console.error('Expected:', employee.clear_user_id);
console.error('Received:', clearData.user_id);
await triggerSecurityAlert({
employee_id: employee.id,
stored_user_id: employee.clear_user_id,
returned_user_id: clearData.user_id,
alert_type: 'user_id_mismatch'
});
throw new Error('UserID mismatch - unauthorized access attempt');
}
}
} else {
console.log('⏸️ Verification not complete. Status:', clearData.status);
}
console.log('=== END PROCESSING ===');
return clearData;
}Key Takeaways
✅ Always define redirect_url in create session requests (required for traditional web flows)
✅ Choose a retrieval method that matches your use case (redirect, polling, or button-triggered)
✅ Retrieve results using Get Verification endpoint: https://docs.clearme.com/reference/get_verification
✅ Map results back to user records using employee_id from custom_fields
✅ Store CLEAR userID when User Profile Matching returns match_result: "match"
✅ Validate userID match on subsequent verifications to prevent unauthorized access
End User Experience Checklist
Use this checklist to ensure complete end user experience implementation:
Pre-Verification:
- Clear context explaining why verification is required
- Different messaging for new vs. returning users
- Instructions on what to expect
- Cancel/back option if verification is optional
Verification Flow:
- Seamless navigation to CLEAR (redirect/popup/iframe)
- Consistent branding throughout journey
- Mobile-responsive design
- Loading states during transitions
Post-Verification:
- Loading indicator while processing results
- Clear success confirmation message
- Appropriate error messages for all failure scenarios
- Retry mechanism for recoverable errors
- Support contact information for unrecoverable errors
Data Handling:
- Store clear_user_id to user profile immediately
- Log all verification events for audit
- Handle session expiration gracefully
- Implement proper error logging and monitoring
Security:
- Verify userID match on Known User Key flows
- Log suspicious activity (userID mismatches)
- Implement rate limiting on verification attempts
- Secure credential storage and transmission
Architecture: Two-Flow Model
Flow 1: Establish Identity
Purpose: First-time identity binding with User Profile Matching
When: User has no CLEAR userID stored in their profile
User Experience: Full CLEAR verification (ID + Selfie)
Technical: Biometric matching between customer employee data and CLEAR-verified data
Flow 2: Known User Key Flow
Purpose: Fast re-verification for established users
When: User has CLEAR userID already stored in their profile
User Experience: Selfie-only verification (3-5 seconds)
Technical: userID-to-userID matching
Integration Requirements
1. Customer Configuration (Federated Mode)
Partners must provide a configuration interface for customers to input their CLEAR environment credentials:
Required Input Fields
| Field | Description | Usage |
|---|---|---|
| Establish Identity Project ID | CLEAR Project ID for full verification with User Profile Matching | Used when no CLEAR userID exists on user profile |
| Known User Key Project ID | CLEAR Project ID for selfie-only re-verification | Used when CLEAR userID exists on user profile |
| API Key | CLEAR API authentication key | Shared across both flows |
Configuration Example:
{
"clear_config": {
"establish_identity_project_id": "proj_abc123_establish",
"known_user_key_project_id": "proj_xyz789_kukf",
"api_key": "clear_api_key_prod_***",
"environment": "production"
}
}2. User Profile Schema
Your system must store CLEAR userID on each user/employee record.
Required Field:
{
"employee_id": "EMP12345",
"first_name": "Jane",
"last_name": "Smith",
"email": "[email protected]",
"clear_user_id": null // Populated after Establish Identity flow
}Implementation Guide
Step 1: Decision Logic - Route to Appropriate Flow
Before initiating any CLEAR verification, check the user's profile for an existing CLEAR userID.
async function initiateVerification(employeeId, useCase) {
// 1. Fetch user profile from your database
const userProfile = await getUserProfile(employeeId);
// 2. Check if CLEAR userID exists
if (userProfile.clear_user_id) {
// User has established identity → Use Known User Key Flow
return await createKnownUserKeySession(userProfile);
} else {
// New user → Use Establish Identity Flow
return await createEstablishIdentitySession(userProfile);
}
}Step 2: Establish Identity Flow Implementation
When to Use
- First time user interacts with CLEAR
- User profile has
clear_user_id = null - Can be triggered from ANY use case (onboarding, password reset, system access, etc.)
API Call: Create Session with User Profile Matching
async function createEstablishIdentitySession(userProfile) {
const sessionPayload = {
project_id: config.establish_identity_project_id,
redirect_url: "https://yourapp.com/verify/confirmation",
custom_fields: {
employeeID: userProfile.employee_id // For correlation only
},
user_profile_information: { // Biographic data for matching
name: {
first_name: userProfile.first_name,
last_name: userProfile.last_name
},
dob: userProfile.date_of_birth // Format: "YYYY-MM-DD"
}
};
const response = await fetch('https://verified.clearme.com/v1/verification_sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${config.api_key}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(sessionPayload)
});
const session = await response.json();
// Construct verification URL with token
const verificationUrl = `https://verified.clearme.com/verify?token=${session.token}`;
return verificationUrl;
}Important:
- Use
user_profile_informationfor biographic data that CLEAR will match against (name, DOB) - Use
custom_fieldsonly for correlation data (employeeID, department, etc.) - Response includes
token- use it to construct the verification URL
What Happens During Establish Identity
- User completes full CLEAR verification (ID scan + selfie)
- CLEAR matches verified data against employee data sent in
user_profile_information - If match succeeds, CLEAR returns
user_id(PSUID) in the response - Partner stores CLEAR
user_idto employee profile
Step 3: Known User Key Flow Implementation
When to Use
- User has completed Establish Identity
- User profile has
clear_user_idpopulated - Works across ALL use cases (password reset, conditional access, high-risk transactions, etc.)
API Call: Create Session with Known User Key
async function createKnownUserKeySession(userProfile) {
const sessionPayload = {
project_id: config.known_user_key_project_id,
user_id: userProfile.clear_user_id, // Pass stored CLEAR userID
redirect_url: "https://yourapp.com/verify/confirmation",
custom_fields: {
employeeID: userProfile.employee_id // For correlation only
}
};
const response = await fetch('https://verified.clearme.com/v1/verification_sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${config.api_key}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(sessionPayload)
});
const session = await response.json();
// Construct verification URL with token
const verificationUrl = `https://verified.clearme.com/verify?token=${session.token}`;
return verificationUrl;
}What Happens During Known User Key
- User completes selfie-only verification (3-5 seconds)
- CLEAR matches selfie to stored biometric using
user_id - Partner verifies returned
user_idmatches storedclear_user_id - No additional data storage required
Step 4: Retrieve Verification Results
Partners must implement one of two methods to retrieve session results:
Option A: Redirect (Recommended for User-Present Flows)
// 1. Include redirect_url in session creation
const sessionPayload = {
project_id: config.project_id,
redirect_url: "https://yourapp.com/clear/callback?session_id={{session_id}}"
};
// 2. Handle callback
app.get('/clear/callback', async (req, res) => {
const sessionId = req.query.session_id;
// Fetch session results
const results = await getSessionResults(sessionId);
// Process results and complete flow
await processVerificationResults(results);
res.redirect('/dashboard');
});Option B: Polling (For Async or Background Flows)
async function pollForResults(sessionId, maxAttempts = 30) {
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(`https://verified.clearme.com/v1/verification_sessions/${sessionId}`, {
headers: {
'Authorization': `Bearer ${config.api_key}`
}
});
const session = await response.json();
if (session.status === 'completed') {
return session;
} else if (session.status === 'failed' || session.status === 'expired') {
throw new Error(`Session ${session.status}`);
}
// Wait 2 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 2000));
}
throw new Error('Polling timeout');
}Step 5: Process Results and Store CLEAR userID
For Establish Identity Flow
async function processEstablishIdentityResults(sessionResults) {
const {
session_id,
status,
user_id, // CLEAR userID (PSUID)
custom_fields,
match_result,
verified_data
} = sessionResults;
// 1. Verify session succeeded
if (status !== 'completed') {
throw new Error(`Verification failed: ${status}`);
}
// 2. Verify User Profile Match succeeded
if (match_result !== 'match') {
// Handle no match - may require manual review
await flagForReview(custom_fields.employee_id, sessionResults);
return;
}
// 3. Store CLEAR userID to employee profile
await updateUserProfile(custom_fields.employee_id, {
clear_user_id: user_id,
identity_verified_at: new Date(),
verification_session_id: session_id
});
// 4. Grant access or complete workflow
await grantAccess(custom_fields.employee_id);
}For Known User Key Flow
async function processKnownUserKeyResults(sessionResults, employeeId) {
const {
status,
user_id, // CLEAR userID returned from session
} = sessionResults;
// 1. Verify session succeeded
if (status !== 'completed') {
throw new Error(`Re-verification failed: ${status}`);
}
// 2. Fetch stored userID from user profile
const userProfile = await getUserProfile(employeeId);
// 3. Match userID to userID
if (user_id !== userProfile.clear_user_id) {
throw new Error('UserID mismatch - possible unauthorized access attempt');
}
// 4. Grant access or complete workflow
await grantAccess(employeeId);
// 5. Log verification event (optional)
await logVerificationEvent(employeeId, sessionResults);
}Complete Flow Diagrams
Establish Identity Flow
Customer System Partner Platform CLEAR API
| | |
| 1. User initiates action | |
|------------------------------>| |
| | |
| | 2. Check user profile |
| | clear_user_id = null |
| | |
| | 3. POST /sessions |
| | (with UPM + custom |
| | fields: employee_id) |
| |------------------------->|
| | |
| | 4. Session created |
| |<-------------------------|
| | |
| 5. Redirect to CLEAR | |
|<------------------------------| |
| | |
| 6. Complete verification | |
| (ID + Selfie) | |
|---------------------------------------------->| |
| | |
| | 7. Biometric matching |
| | against custom_fields |
| | |
| 8. Redirect with session_id | |
|------------------------------>| |
| | |
| | 9. GET /sessions/{id} |
| |------------------------->|
| | |
| | 10. Results (user_id) |
| |<-------------------------|
| | |
| | 11. Store user_id to |
| | employee profile |
| | |
| 12. Access granted | |
|<------------------------------| |
Known User Key Flow
Customer System Partner Platform CLEAR API
| | |
| 1. User initiates action | |
|------------------------------>| |
| | |
| | 2. Check user profile |
| | clear_user_id exists |
| | |
| | 3. POST /sessions |
| | (with user_id) |
| |------------------------->|
| | |
| | 4. Session created |
| |<-------------------------|
| | |
| 5. Redirect to CLEAR | |
|<------------------------------| |
| | |
| 6. Complete selfie-only | |
| verification (3-5 sec) | |
|---------------------------------------------->| |
| | |
| 7. Redirect with session_id | |
|------------------------------>| |
| | |
| | 8. GET /sessions/{id} |
| |------------------------->|
| | |
| | 9. Results (user_id) |
| |<-------------------------|
| | |
| | 10. Verify user_id match |
| | to stored value |
| | |
| 11. Access granted | |
|<------------------------------| |
Use Case Examples
Use Case 1: Employee Onboarding
// First time employee logs in - no CLEAR userID on profile
async function onboardEmployee(employeeId) {
const sessionUrl = await initiateVerification(employeeId, 'onboarding');
// → Routes to Establish Identity Flow
// → User completes full verification
// → CLEAR userID stored to profile
// → Employee gains access
}Use Case 2: Password Reset
// Employee forgot password - already has CLEAR userID
async function resetPassword(employeeId) {
const sessionUrl = await initiateVerification(employeeId, 'password_reset');
// → Routes to Known User Key Flow (selfie-only)
// → User verified in 3-5 seconds
// → Password reset authorized
}Use Case 3: High-Risk Transaction
// Step-up authentication for sensitive action
async function authorizeTransaction(employeeId, transactionId) {
const sessionUrl = await initiateVerification(employeeId, 'transaction_auth');
// → If CLEAR userID exists: Known User Key Flow
// → If no CLEAR userID: Establish Identity Flow
// → Transaction authorized after verification
}Use Case 4: Conditional Access
// Accessing sensitive system from new device
async function grantConditionalAccess(employeeId, deviceInfo) {
const sessionUrl = await initiateVerification(employeeId, 'conditional_access');
// → Uses Known User Key Flow for fast re-verification
// → Device access granted
}Key Benefits for Partners
- Use Case Agnostic: One integration supports unlimited verification scenarios
- Progressive Enhancement: Identity established once, fast flows everywhere
- Reduced Friction: Selfie-only verification takes 3-5 seconds
- Strong Security: Biometric matching eliminates credential-based attacks
- Simplified Logic: Single decision point (userID exists?) routes to appropriate flow
Best Practices
1. Always Check for Existing userID
// DON'T: Assume user is new
await createEstablishIdentitySession(user);
// DO: Check profile and route appropriately
const hasUserId = user.clear_user_id !== null;
const session = hasUserId
? await createKnownUserKeySession(user)
: await createEstablishIdentitySession(user);2. Store userID Immediately After Establish Identity
// DON'T: Delay storage
if (results.status === 'completed') {
// ... other logic
// TODO: store userID later
}
// DO: Store immediately
if (results.status === 'completed' && results.match_result === 'match') {
await updateUserProfile(employeeId, {
clear_user_id: results.user_id
});
}3. Verify userID Match on Known User Key Flow
// DON'T: Trust without verification
if (results.status === 'completed') {
grantAccess(employeeId);
}
// DO: Verify userID matches stored value
if (results.status === 'completed') {
const storedUserId = await getUserProfile(employeeId).clear_user_id;
if (results.user_id === storedUserId) {
grantAccess(employeeId);
} else {
throw new Error('UserID mismatch');
}
}4. Handle Edge Cases
async function initiateVerification(employeeId) {
try {
const userProfile = await getUserProfile(employeeId);
// Edge case 1: Profile not found
if (!userProfile) {
throw new Error('User profile not found');
}
// Edge case 2: CLEAR userID was revoked/reset
if (userProfile.clear_user_id && userProfile.clear_id_revoked) {
// Treat as new user
return await createEstablishIdentitySession(userProfile);
}
// Normal flow
return userProfile.clear_user_id
? await createKnownUserKeySession(userProfile)
: await createEstablishIdentitySession(userProfile);
} catch (error) {
await logError('verification_initiation_failed', { employeeId, error });
throw error;
}
}Testing Recommendations
Test Scenario 1: New User Journey
- Create test user with no
clear_user_id - Initiate verification
- Verify Establish Identity flow triggered
- Complete verification
- Verify
clear_user_idstored to profile
Test Scenario 2: Returning User Journey
- Use test user with existing
clear_user_id - Initiate verification
- Verify Known User Key flow triggered
- Complete selfie-only verification
- Verify access granted
Test Scenario 3: Cross-Use Case Flow
- Establish identity via onboarding use case
- Verify
clear_user_idstored - Initiate password reset use case
- Verify Known User Key flow triggered (not re-establishing)
- Complete verification
- Verify same
clear_user_idused across use cases
Complete API Reference
Official CLEAR API Documentation
- Create Verification Session: https://docs.clearme.com/reference/create_verification_session
- Get Verification Results: https://docs.clearme.com/reference/get_verification
cURL Examples
Create Establish Identity Session (User Profile Matching)
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": "proj_abc123_establish",
"redirect_url": "https://yourapp.com/verify/confirmation",
"custom_fields": {
"employeeID": "EMP12345"
},
"user_profile_information": {
"name": {
"first_name": "Jane",
"last_name": "Smith"
},
"dob": "1990-05-15"
}
}'Important: Use user_profile_information (not custom_fields) to send employee data for User Profile Matching. The custom_fields.employeeID is used to correlate the results back to your employee record.
Note: Use the token to construct the verification URL: https://verified.clearme.com/verify?token={token}
Create Known User Key Session (Re-verification)
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": "proj_def456_kukf",
"user_id": "psuid_abc123def456",
"redirect_url": "https://yourapp.com/verify/confirmation",
"custom_fields": {
"employeeID": "EMP12345"
}
}'Important: Include the stored user_id from the employee's initial verification. This enables the selfie-only Known User Key flow.
Note: Use the token to construct the verification URL: https://verified.clearme.com/verify?token={token}
Get Session Results
curl --request GET \
--url https://verified.clearme.com/v1/verification_sessions/vs_1a2b3c4d5e6f7g8h \
--header 'Authorization: Bearer YOUR_API_KEY'Note: Replace vs_1a2b3c4d5e6f7g8h with the id returned from the create session response.
Key Fields:
id: The verification session IDstatus: Session status (complete,pending,failed,expired)user_id: The CLEAR userID (PSUID) - store this to enable Known User Key flowverification_id: Unique verification ID for this sessioncustom_fields.employeeID: Your employee ID passed during session creationtraits.document: Verified data extracted from the government-issued ID
Key Points:
- No
traits.documentdata on re-verification (selfie-only, no document scan) user_idreturned must match theuser_idyou stored from initial verification- Verification completes in 3-5 seconds
Possible Status Values:
pending: Verification in progresscomplete: Verification successfulsuccess: Verification successful (alternative status)failed: Verification failedexpired: Session timed out
Note: When User Profile Matching fails, the session status is still complete (user verified successfully with CLEAR), but the verified data doesn't match the employee data you sent. No user_id is returned. This requires manual review to reconcile the mismatch.
Error Handling Reference
Common Error Responses
Understanding error responses is critical for building robust error handling and user messaging.
Note: All error response examples below are actual responses from the CLEAR API, captured from live testing. Your application will encounter these exact error formats.
Authentication Errors
401 Unauthorized - Invalid API Key
curl --request POST \
--url https://verified.clearme.com/v1/verification_sessions \
--header 'Authorization: Bearer invalid_api_key' \
--header 'Content-Type: application/json' \
--data '{
"project_id": "proj_abc123",
"redirect_url": "https://yourapp.com/callback"
}'Response (actual from CLEAR API):
{
"error_type": "unauthenticated",
"fields": [],
"message": "Invalid authentication"
}HTTP Status: 401
How to Handle:
- Log the error with full context
- Alert administrators (API key may be rotated or expired)
- Return user-friendly message: "Unable to connect to verification service. Please contact support."
- Check environment variables and credential storage
Validation Errors
400 Bad Request - Invalid Project ID
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": "proj_nonexistent",
"redirect_url": "https://yourapp.com/callback"
}'Response (actual from CLEAR API):
{
"error_type": "invalid_argument",
"fields": [],
"message": "The project_id does not exist or is archived."
}HTTP Status: 400
How to Handle:
- Verify project IDs in your configuration (environment variables or database)
- Check that you're using the correct project ID (User Profile Matching vs Known User Key)
- Ensure project hasn't been archived in CLEAR dashboard
- Validate project ID format before API call
400 Bad Request - Missing Required User Profile Information
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": "proj_abc123",
"redirect_url": "https://yourapp.com/callback",
"user_profile_information": {
"name": {
"first_name": "Jane"
}
}
}'Response (actual from CLEAR API):
{
"error_type": "invalid_argument",
"fields": [],
"message": "Traits for user profile matching do not match project configuration. Missing traits: {'last_name'}"
}HTTP Status: 400
How to Handle:
- Ensure all required UPM fields configured in your project are present
- Common required fields:
first_name,last_name - Validate employee data completeness before API call
- Check project configuration in CLEAR dashboard for required traits
400 Bad Request - Extra/Unconfigured Traits
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": "proj_abc123",
"redirect_url": "https://yourapp.com/callback",
"user_profile_information": {
"name": {
"first_name": "Jane",
"last_name": "Smith"
},
"dob": "1990-01-15"
}
}'Response (actual from CLEAR API):
{
"error_type": "invalid_argument",
"fields": [],
"message": "Traits for user profile matching do not match project configuration. Extra traits: {'dob'}"
}HTTP Status: 400
How to Handle:
- Only send traits (fields) that are configured in your CLEAR project
- Check project configuration in CLEAR dashboard
- Remove unconfigured fields from
user_profile_information - Common configured traits:
first_name,last_name(DOB is optional and must be enabled in project)
Session Retrieval Errors
404 Not Found - Invalid Session ID
curl --request GET \
--url https://verified.clearme.com/v1/verification_sessions/vs_nonexistent \
--header 'Authorization: Bearer YOUR_API_KEY'Response (actual from CLEAR API):
{
"error_type": "not_found",
"fields": [],
"message": "Invalid verification_session.id"
}HTTP Status: 404
How to Handle:
- Verify session ID is correct (should start with
verify_notvs_) - Check that session hasn't expired (sessions typically expire after 10 days)
- Ensure you're using the
idfield from the create session response - Log error with session ID for debugging
Rate Limiting
429 Too Many Requests
{
"error": {
"type": "rate_limit_error",
"message": "Too many requests. Please retry after 60 seconds"
}
}How to Handle:
- Implement exponential backoff
- Cache session results to reduce API calls
- Contact CLEAR if you need higher rate limits
Server Errors
500 Internal Server Error
{
"error": {
"type": "api_error",
"message": "An internal error occurred. Please try again later"
}
}How to Handle:
- Retry with exponential backoff (3 retries recommended)
- Log error with full context (request ID, timestamp, parameters)
- If persistent, contact CLEAR support
503 Service Unavailable
{
"error": {
"type": "api_error",
"message": "Service temporarily unavailable. Please try again"
}
}How to Handle:
- Retry after brief delay
- Show user-friendly message
- Monitor for extended outages
Error Handling Best Practices
1. Implement Retry Logic with Exponential Backoff
async function createSessionWithRetry(payload, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch('https://verified.clearme.com/v1/verification_sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const data = await response.json();
if (!response.ok) {
// Don't retry client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new Error(data.error?.message || 'Client error');
}
// Retry server errors (5xx)
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
}
return data;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
}
}
}2. Log All Errors with Context
async function logError(error, context) {
console.error('CLEAR API Error', {
timestamp: new Date().toISOString(),
errorType: error.type,
message: error.message,
statusCode: context.statusCode,
endpoint: context.endpoint,
employeeId: context.employeeId,
sessionId: context.sessionId,
requestId: context.requestId,
});
// Send to monitoring service (Sentry, Datadog, etc.)
// monitoringService.captureError(error, context);
}3. User-Friendly Error Messages
Map technical errors to user-friendly messages:
function getUserMessage(errorType) {
const messages = {
'authentication_error': 'Unable to connect to verification service. Please contact support.',
'permission_error': 'Configuration error. Please contact your administrator.',
'invalid_request_error': 'Invalid request. Please try again or contact support.',
'rate_limit_error': 'Too many requests. Please wait a moment and try again.',
'api_error': 'Service temporarily unavailable. Please try again in a few moments.',
};
return messages[errorType] || 'An unexpected error occurred. Please try again.';
}4. Validation Before API Calls
function validateSessionPayload(payload) {
const errors = [];
if (!payload.project_id) {
errors.push('project_id is required');
}
if (!payload.redirect_url) {
errors.push('redirect_url is required');
}
if (payload.user_profile_information) {
if (!payload.user_profile_information.name?.first_name) {
errors.push('first_name is required for User Profile Matching');
}
if (!payload.user_profile_information.name?.last_name) {
errors.push('last_name is required for User Profile Matching');
}
if (payload.user_profile_information.dob) {
// Validate YYYY-MM-DD format
if (!/^\d{4}-\d{2}-\d{2}$/.test(payload.user_profile_information.dob)) {
errors.push('dob must be in YYYY-MM-DD format');
}
}
}
if (errors.length > 0) {
throw new Error(`Validation failed: ${errors.join(', ')}`);
}
}5. Circuit Breaker Pattern (Advanced)
For high-volume applications, implement a circuit breaker to prevent cascading failures:
class CircuitBreaker {
constructor(threshold = 5, timeout = 60000) {
this.failureCount = 0;
this.threshold = threshold;
this.timeout = timeout;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
this.nextAttempt = Date.now();
}
async execute(fn) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttempt) {
throw new Error('Circuit breaker is OPEN');
}
this.state = 'HALF_OPEN';
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failureCount++;
if (this.failureCount >= this.threshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.timeout;
}
}
}
const clearApiCircuitBreaker = new CircuitBreaker();
async function createSessionWithCircuitBreaker(payload) {
return await clearApiCircuitBreaker.execute(() =>
createVerificationSession(payload)
);
}Implementation Sequence
Follow these steps in order to build a working integration. Each step builds on the previous one.
Phase 1: Setup & Configuration (30-45 minutes)
Step 1: Database Setup (10 min)
- Create your database schema with the three core tables:
tenants,employees,sessions - Add indexes for performance
- Add
clear_user_idto employees table (critical for Known User Key flow) - Add
initial_project_idandreverification_project_idto tenants table - Success criteria: Can query all tables without errors
- Dependency: None - start here
Step 2: Environment Configuration (5 min)
- Add CLEAR credentials to
.env.local - Get
CLEAR_API_KEYand project IDs from CLEAR - Add database connection string
- Success criteria: API key validates with CLEAR (test with create_session call)
- Dependency: Step 1 complete
Step 3: Seed Test Data (10 min)
- Add a test tenant to
tenantstable with your CLEAR project IDs - Add 2-3 test employees with employee IDs and matching first/last names
- Leave
clear_user_idNULL for first-time verification test - Success criteria: Can query tenant and employees by slug/employee_id
- Dependency: Steps 1-2 complete
Step 4: API Integration Layer (15 min)
- Copy
/lib/clear-api.ts(see Complete Working Examples below) - Implement
createVerificationSession()andgetVerificationSession() - Success criteria: Can make test API call to CLEAR and get back session token
- Dependency: Step 2 complete
Phase 2: Core Flows (60-90 minutes)
Step 5: Create Session Endpoint (30 min)
- Build
POST /api/[company]/create-sessionendpoint - Implement routing logic: if
clear_user_idexists → Known User Key, else → User Profile Matching - Return session token to frontend
- Success criteria: Endpoint returns valid CLEAR session token, routing logic works correctly
- Dependency: Steps 1-4 complete
- Cannot test: Step 6 (without frontend to call this endpoint)
Step 6: Verification UI (20 min)
- Build verification start page with employee ID input
- Call create-session endpoint
- Redirect to
https://verified.clearme.com/verify?token={token} - Success criteria: User enters employee ID, gets redirected to CLEAR
- Dependency: Step 5 complete
- Cannot test: Step 7 (without results endpoint)
Step 7: Results Endpoint (20 min)
- Build
GET /api/[company]/verification/[sessionId]endpoint - Poll CLEAR API for session status
- Save
clear_user_idto employee record when verification complete - Success criteria: After CLEAR redirect, can fetch results and see status='complete', user_id saved to DB
- Dependency: Steps 5-6 complete
Step 8: Confirmation UI (20 min)
- Build confirmation page that polls results endpoint
- Show success state when complete
- Success criteria: After CLEAR verification, see "Thank you" page with verified name
- Dependency: Step 7 complete
Phase 3: Testing & Validation (30-45 minutes)
Step 9: Test User Profile Matching (15 min)
- Use test employee WITHOUT clear_user_id
- Complete verification flow
- Verify user_id saved to database
- Success criteria: See all test scenarios pass (see Testing & Validation section)
- Dependency: Steps 1-8 complete
Step 10: Test Known User Key (15 min)
- Use same employee (now has clear_user_id)
- Complete verification flow again
- Verify faster selfie-only flow
- Success criteria: Second verification uses reverification_project_id, completes faster
- Dependency: Step 9 complete (need user_id from first verification)
Step 11: Error Handling (15 min)
- Test invalid employee ID
- Test invalid API credentials
- Test missing project IDs
- Add proper error messages to UI
- Success criteria: All error scenarios show user-friendly messages (see Troubleshooting section)
- Dependency: Steps 1-10 complete
Phase 4: Production Readiness (Optional - 30 minutes)
Step 12: Multi-tenant Support (if needed)
- Add tenant lookup by slug
- Support multiple tenants with different CLEAR credentials
- Dependency: Steps 1-11 complete
Step 13: Admin UI (if needed)
- Build tenant configuration page
- Allow admins to input their own CLEAR credentials (BYOK)
- Dependency: Step 12 complete
Step 14: Monitoring & Logging
- Add structured logging for verification events
- Track success/failure rates
- Set up alerts for API errors
- Dependency: Steps 1-11 complete
Testing & Validation
Pre-Flight Checklist
Before going live, verify each integration point:
-
Database
- All three tables exist (tenants, employees, sessions)
- Indexes created for performance
-
clear_user_idcolumn exists on employees table -
initial_project_idandreverification_project_idexist on tenants table
-
API Credentials
- CLEAR API key validates (test with create_session call)
- Initial project ID exists and is not archived
- Reverification project ID exists and is not archived
- Environment variables load correctly
-
Test Data
- Test tenant exists with valid CLEAR credentials
- Test employees exist with matching first/last names
- At least one employee has
clear_user_idNULL (for UPM test) - At least one employee has
clear_user_idpopulated (for Known User Key test)
-
Endpoints
-
POST /api/[company]/create-sessionreturns token -
GET /api/[company]/verification/[sessionId]returns status - Error responses include helpful messages
-
-
UI
- Verification page loads tenant logo
- Employee ID input validates format
- CLEAR redirect works with token
- Confirmation page polls for results
Test Scenarios
Scenario 1: First-Time Verification (User Profile Matching)
Setup:
- Employee record with
clear_user_id = NULL - First name: "John"
- Last name: "Doe"
- Employee ID: "123456"
Steps:
- Navigate to
/{company}/verify - Enter employee ID: "123456"
- Click "Verify with CLEAR"
- Complete CLEAR verification with selfie + ID
- Redirected to confirmation page
Expected Results:
- ✅ Session created with
initial_project_id - ✅
user_profile_informationsent with first_name and last_name - ✅ CLEAR matches biometric to provided name
- ✅ Status changes from
pending→complete - ✅
user_idreturned from CLEAR (e.g.,user_abc123) - ✅
clear_user_idsaved to employee record in database - ✅ Confirmation page shows "Thank you, John!"
How to Verify:
-- Check employee record
SELECT employee_id, clear_user_id FROM employees WHERE employee_id = '123456';
-- Should show: clear_user_id = 'user_abc123' (not NULL)
-- Check session record
SELECT status, clear_user_id FROM sessions WHERE employee_id = (SELECT id FROM employees WHERE employee_id = '123456') ORDER BY created_at DESC LIMIT 1;
-- Should show: status = 'complete', clear_user_id = 'user_abc123'Scenario 2: Return Verification (Known User Key)
Setup:
- Same employee from Scenario 1 (now has
clear_user_id = 'user_abc123')
Steps:
- Navigate to
/{company}/verify - Enter employee ID: "123456"
- Click "Verify with CLEAR"
- Complete CLEAR verification (selfie only, faster)
- Redirected to confirmation page
Expected Results:
- ✅ Session created with
reverification_project_id - ✅
user_idsent (not user_profile_information) - ✅ CLEAR skips ID capture, only takes selfie
- ✅ Verification completes faster (~10-15 seconds vs 30-45 seconds)
- ✅ Status changes from
pending→complete - ✅ Same
user_idreturned - ✅ Confirmation page shows "Thank you, John!"
How to Verify:
-- Check routing logic worked
SELECT clear_session_id FROM sessions WHERE employee_id = (SELECT id FROM employees WHERE employee_id = '123456') ORDER BY created_at DESC LIMIT 1;
-- Then use CLEAR API to check which project_id was usedScenario 3: Employee Not Found
Steps:
- Navigate to
/{company}/verify - Enter employee ID: "999999" (doesn't exist)
- Click "Verify with CLEAR"
Expected Results:
- ✅ Error message: "Employee not found. Please contact your administrator."
- ✅ No CLEAR session created
- ✅ No redirect happens
Scenario 4: Invalid API Credentials
Setup:
- Temporarily change API key to invalid value
Expected Results:
- ✅ Error message: "Failed to create verification session"
- ✅ Error logged with 401 response from CLEAR
- ✅ User sees helpful error message
Scenario 5: Biometric Mismatch
Setup:
- Employee with first_name "Jane", last_name "Smith"
- User completes CLEAR verification but name on ID is "John Doe"
Expected Results:
- ✅ CLEAR returns
status: 'failed' - ✅ No
user_idreturned - ✅
clear_user_idremains NULL on employee record - ✅ User sees error message explaining verification failed
Scenario 6: User Abandons Verification
Setup:
- User starts verification but closes browser before completing
Expected Results:
- ✅ Session status remains
pending - ✅ When user returns and starts new session, old session stays pending
- ✅ New session can be created without issues
Common Integration Bugs
| Bug | Symptom | Root Cause | Fix |
|---|---|---|---|
| user_id not saving | Second verification still requires ID | Results endpoint not saving user_id to employee record | Check that clear_user_id update happens after status='complete' |
| Wrong project used | Always shows ID capture, even on second verification | Routing logic not checking clear_user_id | Ensure isReverification = !!employee.clear_user_id check works |
| Biometric matching fails | Status returns 'failed' on valid verification | First/last name mismatch between employee record and ID | Ensure employee.first_name and employee.last_name match ID exactly |
| API returns 401 | "Invalid authentication" error | Wrong API key or missing Bearer prefix | Check Authorization header: Bearer ${apiKey} |
| API returns 400 | "Project does not exist" | Wrong project_id or project archived | Verify project_id in CLEAR dashboard, check for typos |
| Redirect fails | User stuck on verification page | Invalid redirect_url or CORS issue | Ensure redirect_url is publicly accessible, matches protocol (http/https) |
| Polling times out | Confirmation page never loads | Results endpoint not polling CLEAR API | Check that getVerificationSession() is called in polling loop |
| Duplicate employees | Same employee_id exists twice | No UNIQUE constraint on (tenant_id, employee_id) | Add constraint: UNIQUE(tenant_id, employee_id) |
| Session status stuck | Status never changes from pending | CLEAR session never completed | Check CLEAR dashboard for session status, verify user completed flow |
| No traits returned | Verified data missing from response | Project configuration doesn't request traits | Update project settings in CLEAR dashboard to request specific traits |
Troubleshooting Decision Trees
Decision Tree 1: Verification Session Creation Fails
Session creation fails
├─ HTTP 401 "Invalid authentication"
│ ├─ Check: API key correct in .env?
│ ├─ Check: Authorization header includes "Bearer " prefix?
│ └─ Fix: Verify credentials in CLEAR dashboard
│
├─ HTTP 400 "Project does not exist or is archived"
│ ├─ Check: Project ID matches CLEAR dashboard?
│ ├─ Check: Project archived or deleted?
│ └─ Fix: Use correct project_id or create new project
│
├─ HTTP 400 "Traits for user profile matching do not match project configuration"
│ ├─ Check: Sending first_name and last_name?
│ ├─ Check: Project configured for User Profile Matching?
│ └─ Fix: Update project settings or send correct traits
│
└─ HTTP 500 or network error
├─ Check: Can reach https://verified.clearme.com?
├─ Check: Firewall/proxy blocking requests?
└─ Fix: Check network connectivity, update firewall rules
Decision Tree 2: user_id Not Saving to Employee Record
Second verification still requires ID capture
├─ Check database: Does employee.clear_user_id have value?
│ ├─ YES → Routing logic broken
│ │ ├─ Check: isReverification = !!employee.clear_user_id?
│ │ ├─ Check: Sending user_id instead of user_profile_information?
│ │ └─ Fix: Update create-session routing logic
│ │
│ └─ NO → user_id never saved
│ ├─ Check: First verification completed successfully?
│ │ ├─ Query sessions table: status = 'complete'?
│ │ └─ If pending: User never finished CLEAR flow
│ │
│ ├─ Check: CLEAR returned user_id in response?
│ │ ├─ Call GET /verification_sessions/{id}
│ │ └─ If no user_id: CLEAR session failed
│ │
│ └─ Check: Results endpoint saving user_id?
│ ├─ Add logging to update query
│ ├─ Check for SQL errors
│ └─ Fix: Ensure update happens when status='complete' AND user_id exists
Decision Tree 3: Biometric Matching Fails
Verification returns status='failed'
├─ Check CLEAR response for failure reason
│ ├─ "Biometric match failed"
│ │ ├─ Name on ID doesn't match user_profile_information
│ │ ├─ Check: employee.first_name exactly matches ID?
│ │ ├─ Check: employee.last_name exactly matches ID?
│ │ └─ Fix: Update employee record or ask user to use correct ID
│ │
│ ├─ "ID verification failed"
│ │ ├─ ID expired or invalid
│ │ ├─ ID photo quality too low
│ │ └─ Fix: Ask user to use valid government-issued ID
│ │
│ └─ "Liveness detection failed"
│ ├─ Selfie appeared to be photo of photo
│ ├─ Multiple faces detected
│ └─ Fix: Ask user to complete selfie in good lighting, alone
│
└─ No failure reason in response
├─ Check project configuration
├─ Contact CLEAR support
└─ Provide session_id for debugging
Debug Logging Recommendations
Add these logs to help diagnose issues:
In create-session endpoint:
console.log('=== VERIFICATION FLOW DEBUG ===');
console.log('Employee ID:', employee.employee_id);
console.log('Employee Name:', employee.first_name, employee.last_name);
console.log('clear_user_id:', employee.clear_user_id);
console.log('Flow type:', isReverification ? 'REVERIFICATION' : 'INITIAL VERIFICATION');
console.log('Project ID:', projectId);
console.log('Sending user_id?', !!employee.clear_user_id);
console.log('Sending PII?', !!pii);In results endpoint:
console.log('=== CHECKING VERIFICATION STATUS ===');
console.log('Session ID:', sessionId);
console.log('CLEAR Session ID:', session.clear_session_id);
console.log('CLEAR Status:', clearData.status);
console.log('CLEAR user_id:', clearData.user_id);
console.log('Saving user_id?', isComplete && !!clearData.user_id);In frontend:
console.log('Redirecting to CLEAR with token:', token);
console.log('Redirect URL:', redirectUrl);
console.log('Polling session:', sessionId);
console.log('Verification status:', result.status);How to Validate Each Integration Point
1. Database Connection
SELECT * FROM tenants WHERE slug = 'test-company';
-- Should return tenant with api_key and project IDs2. API Credentials
curl -X POST https://verified.clearme.com/v1/verification_sessions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "project_abc123",
"redirect_url": "https://example.com/callback"
}'
# Should return: {"id": "...", "token": "...", "status": "pending"}3. Create Session Endpoint
curl -X POST http://localhost:3000/api/test-company/create-session \
-H "Content-Type: application/json" \
-d '{"employeeId": "123456"}'
# Should return: {"token": "...", "sessionId": "..."}4. Routing Logic
// Test in code or with console.log
const hasUserId = !!employee.clear_user_id;
console.log('Will use Known User Key?', hasUserId);
// First time: false (User Profile Matching)
// Second time: true (Known User Key)5. Results Endpoint
curl http://localhost:3000/api/test-company/verification/SESSION_ID
# Should return: {"sessionId": "...", "status": "complete", "clearData": {...}}Success Criteria
User Profile Matching (UPM) Success
You know UPM is working correctly when:
-
Session Creation
- API returns
tokenandid - Request includes
user_profile_information(notuser_id) -
custom_fieldsincludes employeeID for mapping
- API returns
-
CLEAR Verification
- User completes selfie capture
- User completes ID capture (government-issued ID)
- CLEAR performs biometric matching
- Process takes 30-45 seconds total
-
Results
- Status changes to
complete - Response includes
user_id(PSUID) - Response includes
traits.documentwith verified data -
user_idmatches biometric to name on ID
- Status changes to
-
Database
- Session status updated to
complete -
clear_user_idsaved to employee record -
clear_user_idis NOT null after completion
- Session status updated to
-
User Experience
- Redirected from partner app to CLEAR
- Clear instructions during verification
- Redirected back to partner app with success message
- Confirmation page shows verified name
Known User Key Success
You know Known User Key is working correctly when:
-
Session Creation
- API returns
tokenandid - Request includes
user_id(notuser_profile_information) - Routing logic detected existing
clear_user_id
- API returns
-
CLEAR Verification
- User only completes selfie capture (no ID)
- CLEAR performs biometric matching to existing user_id
- Process takes 10-15 seconds (faster than UPM)
-
Results
- Status changes to
complete - Same
user_idreturned as before - No need to update
clear_user_id(already stored)
- Status changes to
-
User Experience
- Noticeably faster than first verification
- No ID capture step
- Same confirmation experience
Metrics to Track
Operational Metrics:
- Verification Success Rate:
completesessions / total sessions (target: >95%) - Average Verification Time: Time from session creation to completion
- UPM: 30-45 seconds
- Known User Key: 10-15 seconds
- Error Rate: Failed sessions / total sessions (target: <5%)
- Abandonment Rate: Pending sessions that never complete (target: <10%)
Technical Metrics:
- API Response Time: Time for create_session call (target: <500ms)
- Database Query Time: Time to lookup employee (target: <100ms)
- Polling Success Rate: Results endpoint successfully fetches CLEAR data (target: >99%)
Support & Resources
- Official API Documentation: https://docs.clearme.com/reference/create_verification_session
- Get Verification Results: https://docs.clearme.com/reference/get_verificatio
Appendix: Three Pillars of Identity Binding
- Matching: Align employee data with CLEAR-verified demographics using biometric matching
- Mapping: Use unique company identifier (employee_id) to map to correct employee record
- Storing: Persist CLEAR userID (PSUID) on employee record
Result: Authorization becomes userID ↔ userID, eliminating need for biographic matching on every session.
Updated 5 days ago