Error Handling
Comprehensive guide to handling errors when integrating with the BotsKYC API.
HTTP Status Codes
The BotsKYC API uses standard HTTP status codes to indicate success or failure:
Code Status Meaning 200 OK Request successful 400 Bad Request Invalid request parameters or malformed request 401 Unauthorized Invalid or missing API key 403 Forbidden Valid API key but insufficient permissions 404 Not Found Resource not found (e.g., session ID) 422 Unprocessable Entity Request valid but failed validation (e.g., low confidence) 429 Too Many Requests Rate limit exceeded 500 Internal Server Error Server error - contact support 503 Service Unavailable Service temporarily unavailable
Error Response Format
All error responses follow a consistent JSON structure:
{
"errorCode" : 1004 ,
"message" : "Document validation failed: Low confidence score" ,
"status" : 422 ,
"timestamp" : "2025-11-24T12:35:00Z" ,
"details" : {
"confidence" : 65.5 ,
"threshold" : 80.0 ,
"reason" : "Poor image quality"
}
}
Fields:
errorCode - Internal error code for specific error types
message - Human-readable error description
status - HTTP status code
timestamp - When the error occurred
details - Additional context (optional)
Error Codes
General Errors (1000-1999)
Code Message Resolution 1000 Invalid request parameters Check request body and parameters 1001 Missing required field Include all required fields 1002 Invalid file format Use supported formats (JPG, PNG, PDF) 1003 File too large Reduce file size to under 10MB 1004 Low confidence score Improve image quality, retake photo 1005 No documents provided Include at least one document
Liveness Errors (1006-1020)
Code Message Resolution 1006 Liveness session creation failed Retry or contact support 1007 Liveness session expired Create a new session 1008 Liveness session not found Verify session ID 1009 Liveness confidence too low Improve lighting, retry 1010 Face matching failed Check image quality 1011 Face similarity too low Verify same person in images 1012 Multiple faces detected Ensure only one face in frame 1013 No face detected Ensure face is visible and centered
Document Processing Errors (2000-2999)
Code Message Resolution 2001 Document type not supported Use supported document types 2002 Document unreadable Provide clearer image 2003 Missing document pages Include all pages 2004 Document expired Provide current document 2005 Document data inconsistent Verify document authenticity
Service Errors (5000-5999)
Code Message Resolution 5001 Liveness service error Retry or contact support 5002 Document processing service error Retry or contact support 5003 External service unavailable Wait and retry
Handling Errors in Code
JavaScript/TypeScript
async function callBotsKycApi ( endpoint , options ) {
try {
const response = await fetch ( `https://api.botskyc.com${ endpoint }` , options);
// Check if response is OK
if ( ! response.ok) {
const error = await response. json ();
throw new BotsKycError (error);
}
return response. json ();
} catch (error) {
if (error instanceof BotsKycError ) {
handleBotsKycError (error);
} else {
// Network or other errors
console. error ( 'Network error:' , error);
throw error;
}
}
}
class BotsKycError extends Error {
constructor ( errorData ) {
super (errorData.message);
this .errorCode = errorData.errorCode;
this .status = errorData.status;
this .details = errorData.details;
this .timestamp = errorData.timestamp;
}
}
function handleBotsKycError ( error ) {
switch (error.status) {
case 400 :
alert ( 'Invalid request. Please check your input.' );
break ;
case 401 :
alert ( 'Authentication failed. Please check your API key.' );
// Redirect to login
break ;
case 422 :
if (error.errorCode === 1004 ) {
alert ( 'Image quality too low. Please retake photo in better lighting.' );
}
break ;
case 429 :
const retryAfter = error.details?.retryAfter || 60 ;
alert ( `Rate limit exceeded. Please wait ${ retryAfter } seconds.` );
break ;
case 500 :
case 503 :
alert ( 'Service temporarily unavailable. Please try again later.' );
break ;
default :
alert ( `Error: ${ error . message }` );
}
}
Python
import requests
from typing import Dict, Any
import time
class BotsKycError ( Exception ):
def __init__ (self, error_data: Dict[ str , Any]):
self .error_code = error_data.get( 'errorCode' )
self .message = error_data.get( 'message' )
self .status = error_data.get( 'status' )
self .details = error_data.get( 'details' , {})
self .timestamp = error_data.get( 'timestamp' )
super (). __init__ ( self .message)
def call_botskyc_api (endpoint: str , ** kwargs) -> Dict[ str , Any]:
"""Call BotsKYC API with error handling"""
try :
response = requests.request(
url = f 'https://api.botskyc.com { endpoint } ' ,
** kwargs
)
# Raise HTTP errors
response.raise_for_status()
return response.json()
except requests.HTTPError as e:
# Parse error response
try :
error_data = e.response.json()
raise BotsKycError(error_data)
except ValueError :
# Response not JSON
raise Exception ( f 'HTTP { e.response.status_code } : { e.response.text } ' )
except requests.RequestException as e:
# Network errors
raise Exception ( f 'Network error: {str (e) } ' )
def handle_botskyc_error (error: BotsKycError):
"""Handle specific BotsKYC errors"""
if error.status == 422 and error.error_code == 1004 :
print ( 'Image quality too low. Please retake photo.' )
return 'RETRY'
elif error.status == 429 :
retry_after = error.details.get( 'retryAfter' , 60 )
print ( f 'Rate limited. Waiting { retry_after } seconds...' )
time.sleep(retry_after)
return 'RETRY'
elif error.status in [ 500 , 503 ]:
print ( 'Service unavailable. Retrying...' )
return 'RETRY'
else :
print ( f 'Error { error.error_code } : { error.message } ' )
return 'FAIL'
# Usage
def scan_document_with_retry (file_path: str , max_retries: int = 3 ):
"""Scan document with automatic retry logic"""
retries = 0
while retries < max_retries:
try :
with open (file_path, 'rb' ) as f:
result = call_botskyc_api(
'/v1/identity/scan' ,
method = 'POST' ,
headers = { 'Authorization' : f 'Bearer {API_KEY} ' },
files = { 'documents' : f}
)
return result
except BotsKycError as e:
action = handle_botskyc_error(e)
if action == 'RETRY' :
retries += 1
continue
else :
raise
raise Exception ( f 'Max retries ( { max_retries } ) exceeded' )
Retry Strategies
Exponential Backoff
Implement exponential backoff for transient errors:
async function fetchWithRetry ( url , options , maxRetries = 3 ) {
let retries = 0 ;
let delay = 1000 ; // Start with 1 second
while (retries < maxRetries) {
try {
const response = await fetch (url, options);
// Success or non-retryable error
if (response.ok || response.status < 500 ) {
return response;
}
// Server error - retry
retries ++ ;
if (retries < maxRetries) {
console. log ( `Retry ${ retries }/${ maxRetries } after ${ delay }ms` );
await new Promise ( resolve => setTimeout (resolve, delay));
delay *= 2 ; // Exponential backoff
}
} catch (error) {
// Network error - retry
retries ++ ;
if (retries >= maxRetries) throw error;
await new Promise ( resolve => setTimeout (resolve, delay));
delay *= 2 ;
}
}
throw new Error ( 'Max retries exceeded' );
}
Rate Limit Handling
Respect rate limits with proper retry logic:
async function handleRateLimitedRequest ( url , options ) {
const response = await fetch (url, options);
if (response.status === 429 ) {
const retryAfter = parseInt (
response.headers. get ( 'Retry-After' ) || '60'
);
console. log ( `Rate limited. Waiting ${ retryAfter }s...` );
await new Promise ( resolve => setTimeout (resolve, retryAfter * 1000 ));
// Retry request
return handleRateLimitedRequest (url, options);
}
return response;
}
Validation Errors
Client-Side Validation
Validate inputs before sending to API:
function validateDocumentUpload ( file ) {
const errors = [];
// Check file type
const validTypes = [ 'image/jpeg' , 'image/png' , 'application/pdf' ];
if ( ! validTypes. includes (file.type)) {
errors. push ( 'Invalid file type. Use JPG, PNG, or PDF.' );
}
// Check file size (10MB max)
const maxSize = 10 * 1024 * 1024 ;
if (file.size > maxSize) {
errors. push ( 'File too large. Maximum size is 10MB.' );
}
// Check file name
if ( ! file.name || file.name. length === 0 ) {
errors. push ( 'File name is required.' );
}
return errors;
}
// Usage
const errors = validateDocumentUpload (file);
if (errors. length > 0 ) {
alert ( 'Validation errors: \n ' + errors. join ( ' \n ' ));
return ;
}
// Proceed with upload
await uploadDocument (file);
Server Response Validation
Validate API responses:
function validateApiResponse ( response ) {
// Check required fields
if ( ! response.status) {
throw new Error ( 'Invalid response: missing status field' );
}
if (response.status === 'success' ) {
if ( ! response.extractedData) {
throw new Error ( 'Invalid response: missing extractedData' );
}
if (response.confidence < 50 ) {
console. warn ( 'Low confidence score:' , response.confidence);
}
}
return response;
}
Debugging
Enable Debug Logging
const DEBUG = process.env. NODE_ENV === 'development' ;
async function debugFetch ( url , options ) {
if ( DEBUG ) {
console. log ( 'Request:' , {
url,
method: options.method,
headers: options.headers
});
}
const response = await fetch (url, options);
if ( DEBUG ) {
console. log ( 'Response:' , {
status: response.status,
headers: Object. fromEntries (response.headers. entries ())
});
}
return response;
}
Log Error Details
function logError ( error ) {
console. error ( 'BotsKYC API Error:' , {
errorCode: error.errorCode,
message: error.message,
status: error.status,
timestamp: error.timestamp,
details: error.details
});
// Send to error tracking service
if (window.Sentry) {
window.Sentry. captureException (error, {
extra: {
errorCode: error.errorCode,
details: error.details
}
});
}
}
Common Scenarios
Low Confidence Score
async function handleLowConfidence ( result ) {
if (result.confidence < 80 ) {
// Show helpful message to user
const tips = [
'Ensure good lighting' ,
'Hold camera steady' ,
'Make sure all text is visible' ,
'Avoid glare and shadows'
];
alert ( 'Image quality could be improved: \n ' + tips. join ( ' \n ' ));
// Offer to retry
const retry = confirm ( 'Would you like to try again?' );
if (retry) {
return 'RETRY' ;
}
}
return 'CONTINUE' ;
}
Session Expiration
async function handleSessionExpiration ( sessionId ) {
try {
const results = await getLivenessResults (sessionId);
return results;
} catch (error) {
if (error.errorCode === 1007 ) {
// Session expired - create new one
console. log ( 'Session expired. Creating new session...' );
const newSession = await createLivenessSession ();
return newSession;
}
throw error;
}
}
Network Errors
async function handleNetworkError ( error ) {
if ( ! navigator.onLine) {
alert ( 'No internet connection. Please check your network.' );
return 'OFFLINE' ;
}
// Retry with exponential backoff
return 'RETRY' ;
}
Best Practices
Always validate inputs before sending to API
Implement retry logic for transient errors (500, 503)
Respect rate limits and use exponential backoff
Log errors for debugging and monitoring
Provide helpful error messages to users
Handle low confidence gracefully with user guidance
Test error scenarios in development
Monitor error rates in production
Support
If you encounter errors not covered in this guide:
Include error details when contacting support:
Error code
Timestamp
Request details (without sensitive data)
Steps to reproduce
Related Documentation:
Last modified on November 30, 2025