Platform Error Handling
Error Handling Reference
Common Error Responses
Understanding error responses is critical for building robust error handling and user messaging.
Note: All error response examples below are actual responses from the CLEAR API, captured from live testing. Your application will encounter these exact error formats.
Authentication Errors
401 Unauthorized - Invalid API Key
curl --request POST \
--url https://verified.clearme.com/v1/verification_sessions \
--header 'Authorization: Bearer invalid_api_key' \
--header 'Content-Type: application/json' \
--data '{
"project_id": "proj_abc123",
"redirect_url": "https://yourapp.com/callback"
}'Response (actual from CLEAR API):
{
"error_type": "unauthenticated",
"fields": [],
"message": "Invalid authentication"
}HTTP Status: 401
How to Handle:
- Log the error with full context
- Alert administrators (API key may be rotated or expired)
- Return user-friendly message: "Unable to connect to verification service. Please contact support."
- Check environment variables and credential storage
Validation Errors
400 Bad Request - Invalid Project ID
curl --request POST \
--url https://verified.clearme.com/v1/verification_sessions \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"project_id": "proj_nonexistent",
"redirect_url": "https://yourapp.com/callback"
}'Response (actual from CLEAR API):
{
"error_type": "invalid_argument",
"fields": [],
"message": "The project_id does not exist or is archived."
}HTTP Status: 400
How to Handle:
- Verify project IDs in your configuration (environment variables or database)
- Check that you're using the correct project ID (User Profile Matching vs Known User Key)
- Ensure project hasn't been archived in CLEAR dashboard
- Validate project ID format before API call
400 Bad Request - Missing Required User Profile Information
curl --request POST \
--url https://verified.clearme.com/v1/verification_sessions \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"project_id": "proj_abc123",
"redirect_url": "https://yourapp.com/callback",
"user_profile_information": {
"name": {
"first_name": "Jane"
}
}
}'Response (actual from CLEAR API):
{
"error_type": "invalid_argument",
"fields": [],
"message": "Traits for user profile matching do not match project configuration. Missing traits: {'last_name'}"
}HTTP Status: 400
How to Handle:
- Ensure all required UPM fields configured in your project are present
- Common required fields:
first_name,last_name - Validate employee data completeness before API call
- Check project configuration in CLEAR dashboard for required traits
400 Bad Request - Extra/Unconfigured Traits
curl --request POST \
--url https://verified.clearme.com/v1/verification_sessions \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"project_id": "proj_abc123",
"redirect_url": "https://yourapp.com/callback",
"user_profile_information": {
"name": {
"first_name": "Jane",
"last_name": "Smith"
},
"dob": "1990-01-15"
}
}'Response (actual from CLEAR API):
{
"error_type": "invalid_argument",
"fields": [],
"message": "Traits for user profile matching do not match project configuration. Extra traits: {'dob'}"
}HTTP Status: 400
How to Handle:
- Only send traits (fields) that are configured in your CLEAR project
- Check project configuration in CLEAR dashboard
- Remove unconfigured fields from
user_profile_information - Common configured traits:
first_name,last_name(DOB is optional and must be enabled in project)
Session Retrieval Errors
404 Not Found - Invalid Session ID
curl --request GET \
--url https://verified.clearme.com/v1/verification_sessions/vs_nonexistent \
--header 'Authorization: Bearer YOUR_API_KEY'Response (actual from CLEAR API):
{
"error_type": "not_found",
"fields": [],
"message": "Invalid verification_session.id"
}HTTP Status: 404
How to Handle:
- Verify session ID is correct (should start with
verify_notvs_) - Check that session hasn't expired (sessions typically expire after 10 days)
- Ensure you're using the
idfield from the create session response - Log error with session ID for debugging
Rate Limiting
429 Too Many Requests
{
"error": {
"type": "rate_limit_error",
"message": "Too many requests. Please retry after 60 seconds"
}
}How to Handle:
- Implement exponential backoff
- Cache session results to reduce API calls
- Contact CLEAR if you need higher rate limits
Server Errors
500 Internal Server Error
{
"error": {
"type": "api_error",
"message": "An internal error occurred. Please try again later"
}
}How to Handle:
- Retry with exponential backoff (3 retries recommended)
- Log error with full context (request ID, timestamp, parameters)
- If persistent, contact CLEAR support
503 Service Unavailable
{
"error": {
"type": "api_error",
"message": "Service temporarily unavailable. Please try again"
}
}How to Handle:
- Retry after brief delay
- Show user-friendly message
- Monitor for extended outages
Error Handling Best Practices
1. Implement Retry Logic with Exponential Backoff
async function createSessionWithRetry(payload, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch('https://verified.clearme.com/v1/verification_sessions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const data = await response.json();
if (!response.ok) {
// Don't retry client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new Error(data.error?.message || 'Client error');
}
// Retry server errors (5xx)
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
}
return data;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
}
}
}2. Log All Errors with Context
async function logError(error, context) {
console.error('CLEAR API Error', {
timestamp: new Date().toISOString(),
errorType: error.type,
message: error.message,
statusCode: context.statusCode,
endpoint: context.endpoint,
employeeId: context.employeeId,
sessionId: context.sessionId,
requestId: context.requestId,
});
// Send to monitoring service (Sentry, Datadog, etc.)
// monitoringService.captureError(error, context);
}3. User-Friendly Error Messages
Map technical errors to user-friendly messages:
function getUserMessage(errorType) {
const messages = {
'authentication_error': 'Unable to connect to verification service. Please contact support.',
'permission_error': 'Configuration error. Please contact your administrator.',
'invalid_request_error': 'Invalid request. Please try again or contact support.',
'rate_limit_error': 'Too many requests. Please wait a moment and try again.',
'api_error': 'Service temporarily unavailable. Please try again in a few moments.',
};
return messages[errorType] || 'An unexpected error occurred. Please try again.';
}4. Validation Before API Calls
function validateSessionPayload(payload) {
const errors = [];
if (!payload.project_id) {
errors.push('project_id is required');
}
if (!payload.redirect_url) {
errors.push('redirect_url is required');
}
if (payload.user_profile_information) {
if (!payload.user_profile_information.name?.first_name) {
errors.push('first_name is required for User Profile Matching');
}
if (!payload.user_profile_information.name?.last_name) {
errors.push('last_name is required for User Profile Matching');
}
if (payload.user_profile_information.dob) {
// Validate YYYY-MM-DD format
if (!/^\d{4}-\d{2}-\d{2}$/.test(payload.user_profile_information.dob)) {
errors.push('dob must be in YYYY-MM-DD format');
}
}
}
if (errors.length > 0) {
throw new Error(`Validation failed: ${errors.join(', ')}`);
}
}5. Circuit Breaker Pattern (Advanced)
For high-volume applications, implement a circuit breaker to prevent cascading failures:
class CircuitBreaker {
constructor(threshold = 5, timeout = 60000) {
this.failureCount = 0;
this.threshold = threshold;
this.timeout = timeout;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
this.nextAttempt = Date.now();
}
async execute(fn) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttempt) {
throw new Error('Circuit breaker is OPEN');
}
this.state = 'HALF_OPEN';
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failureCount++;
if (this.failureCount >= this.threshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.timeout;
}
}
}
const clearApiCircuitBreaker = new CircuitBreaker();
async function createSessionWithCircuitBreaker(payload) {
return await clearApiCircuitBreaker.execute(() =>
createVerificationSession(payload)
);
}Updated 5 days ago