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:

  1. Database Architecture

    • Where to store employee/user data
    • How to structure your employees, tenants, sessions tables
    • Which database technology to use (PostgreSQL, MySQL, MongoDB, etc.)
    • Database migrations and schema management
  2. 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
  3. 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
  4. 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
  5. User Interface

    • Admin configuration screens (we provide requirements, not code)
    • User verification screens (pre/post verification)
    • Error handling UI
    • Success/failure messaging
  6. 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:

  1. Load this entire document into your AI tool's context (paste the full markdown or provide the file path)

  2. 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"
  3. 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]"
  4. 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"
  5. 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:

  1. Provide Contact Information: Phone number and email
  2. 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
  3. Biometric Capture: Take a selfie
  4. 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:

  1. Enter Phone Number: Input the phone number associated with their CLEAR account
  2. Biometric Verification: Take a selfie
  3. 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 StepFirst-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 MatchMatch selfie to documentMatch selfie to stored templateMatch 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

AspectCLEAR Network (Networked Identity)Customer Ecosystem (Ecosystem Identity)
ScopePhysical locations (airports, stadiums) and digital experiences (LinkedIn, consumer apps)Digital and physical touchpoints within a specific customer's environment
SetupUser signs up directly with CLEARUser completes first verification through customer integration
IdentifierCLEAR network account (phone number + biometric)Customer-specific userID (PSUID)
ReusabilityWorks across all CLEAR network nodesWorks only within that customer's ecosystem
Use CasesAirport security, stadium entry, event access, LinkedIn verification, consumer retail experiencesEmployee verification, password reset, digital access control, physical access control (building entry)
User ExperiencePhone number + biometric verificationSelfie-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:

  1. Create customer-specific ecosystems where users complete their first verification and then verify quickly across multiple touchpoints
  2. Issue customer-scoped userIDs that work only within each customer's environment
  3. 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:

  1. Data System Check: Mechanism to check if CLEAR userID exists on user record
  2. Flow Routing:
    • If no userID → Create session with Project A (User Profile Matching), send employee_id in custom_fields
    • If userID exists → Create session with Project B (Known User Key), send user_id in request
  3. Redirect Path Definition: Specify redirect_url in both create session API calls
  4. Result Processing: When user redirects back, call Get Verification endpoint to retrieve results
  5. Data Correlation: Map returned data back to correct user record using employee_id from custom_fields
  6. UserID Storage: Store CLEAR user_id when User Profile Matching returns match_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:

  1. 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
  2. Credential Storage - Secure backend storage for customer-specific CLEAR credentials:

    • Encrypted at rest
    • Scoped per customer/tenant
    • Accessible only to authorized platform services
  3. 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 /validate endpoint. 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:

  1. 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
  2. Trigger Conditions: When should verification be required?

    • Always (every login)
    • Conditional (risk-based triggers)
    • On-demand (user-initiated)
    • Periodic (time-based re-verification)
  3. Flow Routing Logic: Which CLEAR project to use?

    • If clear_user_id exists → Known User Key Project
    • If clear_user_id null → Establish Identity Project

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 FieldCustomer Field (Example)Required For
employee_idemployee_id or user_idEstablish Identity
first_namefirst_name or given_nameEstablish Identity
last_namelast_name or family_nameEstablish Identity
date_of_birthdob or birth_dateEstablish Identity
emailemail or work_emailOptional

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:

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_birth in custom_fields
    • CLEAR performs biometric verification AND matches verified data against the data you sent
    • Result includes match_result: "match" or match_result: "no_match"
    • If match succeeds, store the returned CLEAR user_id to the user record
  • CLEAR userID exists → Use Project B (re-verification):
    • Send the stored CLEAR user_id in the request
    • User completes selfie-only flow (3-5 seconds)
    • Verify returned user_id matches stored user_id

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:

  1. Did the user pass CLEAR verification? (document valid, selfie matches ID)
  2. Did the verified data match the employee data you sent? (match_result)

Three Core Components Partners Must Build:

  1. End User Experience Design: Where CLEAR is triggered, what the user sees before/during/after verification, error handling, and success paths
  2. User Matching & Verification Logic: Check for CLEAR userID, route to correct project, process match results, store userID
  3. 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:

  1. 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_fields is for correlation data only (e.g., employeeID, department, etc.)
    • user_profile_information contains the biographic data CLEAR will match against
  2. User completes CLEAR verification (ID scan + selfie)

  3. 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_id in the response
    • If data doesn't match, no user_id is returned
  4. 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:

  1. Partner sends stored userID in the session creation request:

    {
      project_id: "known_user_key_project_id",
      user_id: "psuid_abc123def456"  // From employee profile
    }
  2. User completes selfie-only verification (3-5 seconds)

  3. CLEAR matches selfie to stored biometric using the provided userID

  4. 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 TypeRetention PeriodPurpose
clear_user_idPermanentRequired for all future verifications
verification_session_id90 days minimumAudit and troubleshooting
Verified PIIPer compliance policySystem of record, reconciliation
Verification logs1-7 years typicalCompliance and security audit
Session metadata90 days minimumDebugging 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:

  1. When creating the session, include redirect_url:
    {
      "project_id": "proj_abc123",
      "redirect_url": "https://yourapp.com/clear/callback?employee_id={employee_id}"
    }
  2. User completes CLEAR verification
  3. User is redirected back to your callback URL with session_id parameter
  4. Your system calls Get Verification to retrieve results
  5. Map results back to user record using employee_id from custom_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:

  1. Create session and redirect user to CLEAR
  2. Periodically poll Get Verification endpoint
  3. When status changes to completed, failed, or expired, retrieve results
  4. 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:

  1. User completes CLEAR verification (ends on terminal screen)
  2. Agent or automated system clicks button to retrieve results
  3. System calls Get Verification endpoint
  4. 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:

  1. Use employee_id from custom_fields:

    const employeeId = results.custom_fields.employee_id;
    const userRecord = await getUserProfile(employeeId);
  2. For User Profile Matching (first-time):

    • Check match_result === "match"
    • If match, store results.user_id to user record
    • If no match, flag for manual review
  3. For Known User Key (returning):

    • Verify results.user_id === userRecord.clear_user_id
    • If mismatch, trigger security alert

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

FieldDescriptionUsage
Establish Identity Project IDCLEAR Project ID for full verification with User Profile MatchingUsed when no CLEAR userID exists on user profile
Known User Key Project IDCLEAR Project ID for selfie-only re-verificationUsed when CLEAR userID exists on user profile
API KeyCLEAR API authentication keyShared 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_information for biographic data that CLEAR will match against (name, DOB)
  • Use custom_fields only for correlation data (employeeID, department, etc.)
  • Response includes token - use it to construct the verification URL

What Happens During Establish Identity

  1. User completes full CLEAR verification (ID scan + selfie)
  2. CLEAR matches verified data against employee data sent in user_profile_information
  3. If match succeeds, CLEAR returns user_id (PSUID) in the response
  4. Partner stores CLEAR user_id to employee profile

Step 3: Known User Key Flow Implementation

When to Use

  • User has completed Establish Identity
  • User profile has clear_user_id populated
  • 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

  1. User completes selfie-only verification (3-5 seconds)
  2. CLEAR matches selfie to stored biometric using user_id
  3. Partner verifies returned user_id matches stored clear_user_id
  4. 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

  1. Use Case Agnostic: One integration supports unlimited verification scenarios
  2. Progressive Enhancement: Identity established once, fast flows everywhere
  3. Reduced Friction: Selfie-only verification takes 3-5 seconds
  4. Strong Security: Biometric matching eliminates credential-based attacks
  5. 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

  1. Create test user with no clear_user_id
  2. Initiate verification
  3. Verify Establish Identity flow triggered
  4. Complete verification
  5. Verify clear_user_id stored to profile

Test Scenario 2: Returning User Journey

  1. Use test user with existing clear_user_id
  2. Initiate verification
  3. Verify Known User Key flow triggered
  4. Complete selfie-only verification
  5. Verify access granted

Test Scenario 3: Cross-Use Case Flow

  1. Establish identity via onboarding use case
  2. Verify clear_user_id stored
  3. Initiate password reset use case
  4. Verify Known User Key flow triggered (not re-establishing)
  5. Complete verification
  6. Verify same clear_user_id used across use cases


Complete API Reference

Official CLEAR API Documentation


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 ID
  • status: Session status (complete, pending, failed, expired)
  • user_id: The CLEAR userID (PSUID) - store this to enable Known User Key flow
  • verification_id: Unique verification ID for this session
  • custom_fields.employeeID: Your employee ID passed during session creation
  • traits.document: Verified data extracted from the government-issued ID

Key Points:

  • No traits.document data on re-verification (selfie-only, no document scan)
  • user_id returned must match the user_id you stored from initial verification
  • Verification completes in 3-5 seconds

Possible Status Values:

  • pending: Verification in progress
  • complete: Verification successful
  • success: Verification successful (alternative status)
  • failed: Verification failed
  • expired: 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_ not vs_)
  • Check that session hasn't expired (sessions typically expire after 10 days)
  • Ensure you're using the id field 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_id to employees table (critical for Known User Key flow)
  • Add initial_project_id and reverification_project_id to 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_KEY and 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 tenants table with your CLEAR project IDs
  • Add 2-3 test employees with employee IDs and matching first/last names
  • Leave clear_user_id NULL 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() and getVerificationSession()
  • 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-session endpoint
  • Implement routing logic: if clear_user_id exists → 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_id to 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_id column exists on employees table
    • initial_project_id and reverification_project_id exist 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_id NULL (for UPM test)
    • At least one employee has clear_user_id populated (for Known User Key test)
  • Endpoints

    • POST /api/[company]/create-session returns 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:

  1. Navigate to /{company}/verify
  2. Enter employee ID: "123456"
  3. Click "Verify with CLEAR"
  4. Complete CLEAR verification with selfie + ID
  5. Redirected to confirmation page

Expected Results:

  • ✅ Session created with initial_project_id
  • user_profile_information sent with first_name and last_name
  • ✅ CLEAR matches biometric to provided name
  • ✅ Status changes from pendingcomplete
  • user_id returned from CLEAR (e.g., user_abc123)
  • clear_user_id saved 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:

  1. Navigate to /{company}/verify
  2. Enter employee ID: "123456"
  3. Click "Verify with CLEAR"
  4. Complete CLEAR verification (selfie only, faster)
  5. Redirected to confirmation page

Expected Results:

  • ✅ Session created with reverification_project_id
  • user_id sent (not user_profile_information)
  • ✅ CLEAR skips ID capture, only takes selfie
  • ✅ Verification completes faster (~10-15 seconds vs 30-45 seconds)
  • ✅ Status changes from pendingcomplete
  • ✅ Same user_id returned
  • ✅ 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 used

Scenario 3: Employee Not Found

Steps:

  1. Navigate to /{company}/verify
  2. Enter employee ID: "999999" (doesn't exist)
  3. 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_id returned
  • clear_user_id remains 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

BugSymptomRoot CauseFix
user_id not savingSecond verification still requires IDResults endpoint not saving user_id to employee recordCheck that clear_user_id update happens after status='complete'
Wrong project usedAlways shows ID capture, even on second verificationRouting logic not checking clear_user_idEnsure isReverification = !!employee.clear_user_id check works
Biometric matching failsStatus returns 'failed' on valid verificationFirst/last name mismatch between employee record and IDEnsure employee.first_name and employee.last_name match ID exactly
API returns 401"Invalid authentication" errorWrong API key or missing Bearer prefixCheck Authorization header: Bearer ${apiKey}
API returns 400"Project does not exist"Wrong project_id or project archivedVerify project_id in CLEAR dashboard, check for typos
Redirect failsUser stuck on verification pageInvalid redirect_url or CORS issueEnsure redirect_url is publicly accessible, matches protocol (http/https)
Polling times outConfirmation page never loadsResults endpoint not polling CLEAR APICheck that getVerificationSession() is called in polling loop
Duplicate employeesSame employee_id exists twiceNo UNIQUE constraint on (tenant_id, employee_id)Add constraint: UNIQUE(tenant_id, employee_id)
Session status stuckStatus never changes from pendingCLEAR session never completedCheck CLEAR dashboard for session status, verify user completed flow
No traits returnedVerified data missing from responseProject configuration doesn't request traitsUpdate 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 IDs

2. 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:

  1. Session Creation

    • API returns token and id
    • Request includes user_profile_information (not user_id)
    • custom_fields includes employeeID for mapping
  2. CLEAR Verification

    • User completes selfie capture
    • User completes ID capture (government-issued ID)
    • CLEAR performs biometric matching
    • Process takes 30-45 seconds total
  3. Results

    • Status changes to complete
    • Response includes user_id (PSUID)
    • Response includes traits.document with verified data
    • user_id matches biometric to name on ID
  4. Database

    • Session status updated to complete
    • clear_user_id saved to employee record
    • clear_user_id is NOT null after completion
  5. 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:

  1. Session Creation

    • API returns token and id
    • Request includes user_id (not user_profile_information)
    • Routing logic detected existing clear_user_id
  2. 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)
  3. Results

    • Status changes to complete
    • Same user_id returned as before
    • No need to update clear_user_id (already stored)
  4. User Experience

    • Noticeably faster than first verification
    • No ID capture step
    • Same confirmation experience

Metrics to Track

Operational Metrics:

  • Verification Success Rate: complete sessions / 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


Appendix: Three Pillars of Identity Binding

  1. Matching: Align employee data with CLEAR-verified demographics using biometric matching
  2. Mapping: Use unique company identifier (employee_id) to map to correct employee record
  3. Storing: Persist CLEAR userID (PSUID) on employee record

Result: Authorization becomes userID ↔ userID, eliminating need for biographic matching on every session.


Did this page help you?