Documentation Index Fetch the complete documentation index at: https://docs.fraudiant.com/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Proper error handling ensures your application remains resilient and provides a great user experience even when issues occur. This guide covers common errors, best practices, and implementation patterns.
HTTP Status Codes
The Fraudiant API uses standard HTTP status codes to indicate success or failure:
Status Code Meaning Description
200Success Request completed successfully 400Bad Request Invalid input (malformed email, invalid domain) 401Unauthorized Missing or invalid API key 403Forbidden Feature requires Pro account or insufficient permissions 404Not Found Resource not found (e.g., domain not in blocklist) 422Unprocessable Entity Validation failed (e.g., duplicate blocklist entry) 429Too Many Requests Rate limit exceeded 500Internal Server Error Unexpected server error 503Service Unavailable Temporary service outage
Common Error Responses
Invalid Email (400)
Returned when the email address format is invalid:
{
"status" : 400 ,
"error" : "The email address is invalid."
}
Cause: Malformed email address (missing @, invalid characters, etc.)
Solution:
function validateEmailFormat ( email ) {
const regex = / ^ [ ^ \s@ ] + @ [ ^ \s@ ] + \. [ ^ \s@ ] + $ / ;
if ( ! regex . test ( email )) {
return { valid: false , error: 'Invalid email format' };
}
return { valid: true };
}
Unauthorized (401)
Returned when API key is missing, invalid, or expired:
{
"status" : 401 ,
"error" : "Unauthorized. Please provide a valid API key."
}
Common causes:
Missing Authorization header
Invalid API key format
Expired or revoked API key
Typo in API key
Solution:
async function validateWithAuth ( email ) {
const apiKey = process . env . FRAUDIANT_API_KEY ;
if ( ! apiKey ) {
throw new Error ( 'FRAUDIANT_API_KEY environment variable not set' );
}
try {
const response = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ apiKey } `
}
}
);
if ( response . status === 401 ) {
console . error ( 'Invalid API key. Please check your credentials.' );
// Alert admin or rotate key
throw new Error ( 'Authentication failed' );
}
return response . json ();
} catch ( error ) {
console . error ( 'Authentication error:' , error );
throw error ;
}
}
Pro Feature Required (403)
Returned when attempting to use Pro-only features (like blocklist management):
{
"status" : 403 ,
"error" : "This feature requires a Pro account."
}
Solution:
async function addToBlocklist ( domain ) {
try {
const response = await fetch (
'https://api.fraudiant.com/blocklist' ,
{
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({ domain })
}
);
if ( response . status === 403 ) {
return {
success: false ,
error: 'Pro account required. Upgrade at https://app.fraudiant.com/upgrade'
};
}
return { success: true };
} catch ( error ) {
console . error ( 'Blocklist error:' , error );
return { success: false , error: error . message };
}
}
Rate Limit Exceeded (429)
Returned when you exceed your rate limit:
{
"status" : 429 ,
"error" : "Too many requests" ,
"retry_after" : 30
}
Solution with exponential backoff:
async function validateWithRetry ( email , maxRetries = 3 ) {
for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
try {
const response = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
}
}
);
if ( response . status === 429 ) {
const retryAfter = response . headers . get ( 'Retry-After' ) || Math . pow ( 2 , attempt );
console . log ( `Rate limited. Retrying after ${ retryAfter } s...` );
await new Promise ( resolve => setTimeout ( resolve , retryAfter * 1000 ));
continue ; // Retry
}
if ( ! response . ok ) {
throw new Error ( `HTTP ${ response . status } : ${ response . statusText } ` );
}
return await response . json ();
} catch ( error ) {
if ( attempt === maxRetries - 1 ) {
console . error ( 'Max retries exceeded:' , error );
throw error ;
}
// Exponential backoff
const delay = Math . pow ( 2 , attempt ) * 1000 ;
console . log ( `Attempt ${ attempt + 1 } failed. Retrying in ${ delay } ms...` );
await new Promise ( resolve => setTimeout ( resolve , delay ));
}
}
}
Service Unavailable (503)
Returned during temporary service outages:
{
"status" : 503 ,
"error" : "Service temporarily unavailable. Please try again later."
}
Solution: Fail Open Strategy
async function validateEmailSafe ( email ) {
try {
const response = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
},
timeout: 5000 // 5 second timeout
}
);
if ( response . status === 503 ) {
console . warn ( 'Fraudiant service unavailable. Failing open.' );
return {
valid: true ,
failedOpen: true ,
message: 'Validation service temporarily unavailable'
};
}
const validation = await response . json ();
return {
valid: ! validation . disposable && ! validation . spam && validation . mx ,
data: validation
};
} catch ( error ) {
console . error ( 'Service error:' , error );
// Fail open - don't block users
return {
valid: true ,
failedOpen: true ,
error: error . message
};
}
}
Network & Timeout Errors
Timeout Handling
async function validateWithTimeout ( email , timeoutMs = 5000 ) {
const controller = new AbortController ();
const timeoutId = setTimeout (() => controller . abort (), timeoutMs );
try {
const response = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
},
signal: controller . signal
}
);
clearTimeout ( timeoutId );
return await response . json ();
} catch ( error ) {
clearTimeout ( timeoutId );
if ( error . name === 'AbortError' ) {
console . error ( 'Request timeout after' , timeoutMs , 'ms' );
// Fail open
return { disposable: false , spam: false , mx: true , timeout: true };
}
throw error ;
}
}
Connection Errors
async function validateWithConnectionHandling ( email ) {
try {
const response = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
}
}
);
return await response . json ();
} catch ( error ) {
// Network errors
if ( error . code === 'ENOTFOUND' || error . code === 'ECONNREFUSED' ) {
console . error ( 'Cannot reach Fraudiant API. Check network connection.' );
return { valid: true , networkError: true };
}
// DNS errors
if ( error . code === 'EAI_AGAIN' ) {
console . error ( 'DNS resolution failed. Temporary network issue.' );
return { valid: true , dnsError: true };
}
// SSL/TLS errors
if ( error . code === 'CERT_HAS_EXPIRED' ) {
console . error ( 'SSL certificate error' );
return { valid: true , sslError: true };
}
throw error ;
}
}
Error Logging & Monitoring
Structured Error Logging
class ErrorLogger {
static log ( context , error , metadata = {}) {
const logEntry = {
timestamp: new Date (). toISOString (),
context ,
error: {
message: error . message ,
stack: error . stack ,
code: error . code
},
metadata ,
severity: this . getSeverity ( error )
};
console . error ( JSON . stringify ( logEntry ));
// Send to monitoring service (e.g., Sentry, DataDog)
// this.sendToMonitoring(logEntry);
}
static getSeverity ( error ) {
if ( error . code === 401 ) return 'critical' ; // Auth failure
if ( error . code === 429 ) return 'warning' ; // Rate limit
if ( error . code === 503 ) return 'warning' ; // Service down
return 'error' ;
}
}
// Usage
async function validateWithLogging ( email ) {
try {
const validation = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
}
}
). then ( r => r . json ());
return validation ;
} catch ( error ) {
ErrorLogger . log ( 'email_validation' , error , { email: email . split ( '@' )[ 1 ] });
// Fail open
return { valid: true , error: true };
}
}
Circuit Breaker Pattern
Prevent cascading failures by implementing a circuit breaker:
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 ;
console . error ( 'Circuit breaker opened' );
}
}
}
// Usage
const breaker = new CircuitBreaker ( 5 , 60000 );
async function validateWithCircuitBreaker ( email ) {
try {
return await breaker . execute ( async () => {
const response = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
}
}
);
if ( ! response . ok ) throw new Error ( `HTTP ${ response . status } ` );
return response . json ();
});
} catch ( error ) {
console . error ( 'Validation failed:' , error . message );
// Fail open when circuit is open
return { valid: true , circuitOpen: true };
}
}
Error Recovery Strategies
Graceful Degradation
async function validateWithFallback ( email ) {
try {
// Primary: Full validation
const validation = await fetch (
`https://api.fraudiant.com/email/ ${ email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
},
timeout: 3000
}
). then ( r => r . json ());
return {
valid: ! validation . disposable && ! validation . spam && validation . mx ,
quality: 'full' ,
data: validation
};
} catch ( error ) {
console . warn ( 'Full validation failed, using fallback' );
// Fallback: Basic format check only
const isValidFormat = / ^ [ ^ \s@ ] + @ [ ^ \s@ ] + \. [ ^ \s@ ] + $ / . test ( email );
return {
valid: isValidFormat ,
quality: 'basic' ,
fallback: true ,
error: error . message
};
}
}
Queue Failed Requests
class ValidationQueue {
constructor () {
this . queue = [];
this . processing = false ;
}
async add ( email ) {
return new Promise (( resolve , reject ) => {
this . queue . push ({ email , resolve , reject , retries: 0 });
this . process ();
});
}
async process () {
if ( this . processing || this . queue . length === 0 ) return ;
this . processing = true ;
while ( this . queue . length > 0 ) {
const item = this . queue [ 0 ];
try {
const validation = await fetch (
`https://api.fraudiant.com/email/ ${ item . email } ` ,
{
headers: {
'Authorization' : `Bearer ${ process . env . FRAUDIANT_API_KEY } `
}
}
). then ( r => r . json ());
this . queue . shift (); // Remove from queue
item . resolve ( validation );
} catch ( error ) {
item . retries ++ ;
if ( item . retries >= 3 ) {
this . queue . shift (); // Remove after max retries
item . reject ( error );
} else {
// Move to back of queue
this . queue . push ( this . queue . shift ());
await new Promise ( r => setTimeout ( r , 1000 * item . retries ));
}
}
}
this . processing = false ;
}
}
Testing Error Scenarios
Mock Error Responses
// test-helpers/fraudiant-mock.js
class FraudiantMock {
constructor ( mode = 'success' ) {
this . mode = mode ;
}
async validate ( email ) {
switch ( this . mode ) {
case 'rate_limit' :
throw { status: 429 , error: 'Too many requests' };
case 'auth_error' :
throw { status: 401 , error: 'Unauthorized' };
case 'service_down' :
throw { status: 503 , error: 'Service unavailable' };
case 'timeout' :
await new Promise ( r => setTimeout ( r , 10000 )); // Simulate timeout
throw new Error ( 'Timeout' );
case 'network_error' :
throw { code: 'ECONNREFUSED' , message: 'Connection refused' };
default :
return {
disposable: email . includes ( 'temp' ),
spam: false ,
mx: true
};
}
}
}
// Usage in tests
describe ( 'Error Handling' , () => {
it ( 'should handle rate limit errors' , async () => {
const mock = new FraudiantMock ( 'rate_limit' );
const result = await validateWithRetry ( '[email protected]' , mock );
expect ( result . valid ). toBe ( true );
expect ( result . failedOpen ). toBe ( true );
});
});
Best Practices Summary
Always implement timeout handling
Set reasonable timeouts (3-5 seconds) to prevent hanging requests.
When errors occur, allow users to proceed rather than blocking them completely.
Include request metadata, timestamps, and error details for debugging.
Use exponential backoff for transient failures like rate limits and network issues.
Track error patterns to identify systemic issues early.
Use mocks to test how your application handles various error conditions.
Next Steps
Best Practices Learn optimization and performance strategies
Rate Limits Understand rate limits and quotas
Integration Examples View framework-specific implementations
API Reference Complete API documentation