v1.0 • Lead Management
Comprehensive guide to API errors and troubleshooting
All API errors follow a consistent response structure
{
"success": false,
"error": "Human-readable error message",
"code": "MACHINE_READABLE_ERROR_CODE",
"details": {
"field": "Additional context about the error",
"value": "Invalid value that caused the error",
"expected": "What was expected instead"
},
"timestamp": "2024-01-16T10:30:00.000Z",
"requestId": "req_1234567890abcdef"
}successAlways false for error responses
errorHuman-readable error description
codeMachine-readable error identifier
detailsAdditional context and debugging info
timestampWhen the error occurred
requestIdUnique identifier for support
Errors caused by invalid requests
The request is malformed or contains invalid data.
{
"success": false,
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"details": {
"field": "email",
"value": "invalid-email",
"message": "Must be a valid email address"
}
}The requested resource doesn't exist.
{
"success": false,
"error": "Lead not found",
"code": "LEAD_NOT_FOUND",
"details": {
"leadId": "lead_nonexistent123",
"message": "No lead found with this ID in your workspace"
}
}The request conflicts with existing data.
{
"success": false,
"error": "Email already exists",
"code": "DUPLICATE_EMAIL",
"details": {
"email": "john.doe@example.com",
"existingLeadId": "lead_existing123",
"message": "A lead with this email already exists in your workspace"
}
}Production-ready error handling patterns
class LeadAPIClient {
constructor(apiKey, baseURL = 'https://your-domain.com/api/v1') {
this.apiKey = apiKey;
this.baseURL = baseURL;
}
async makeRequest(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
...options.headers
},
...options
};
try {
const response = await fetch(url, config);
// Handle rate limiting
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
throw new RateLimitError(
'Rate limit exceeded',
parseInt(retryAfter),
response.headers
);
}
// Parse response
const data = await response.json();
// Handle API errors
if (!response.ok) {
throw new APIError(
data.error || 'Unknown error',
response.status,
data.code,
data.details
);
}
return data;
} catch (error) {
// Handle network errors
if (error.name === 'TypeError' || error.name === 'NetworkError') {
throw new NetworkError('Network connection failed', error);
}
throw error;
}
}
async createLead(leadData) {
return this.makeRequest('/leads', {
method: 'POST',
body: JSON.stringify(leadData)
});
}
}
// Custom error classes
class APIError extends Error {
constructor(message, status, code, details) {
super(message);
this.name = 'APIError';
this.status = status;
this.code = code;
this.details = details;
}
}
class RateLimitError extends APIError {
constructor(message, retryAfter, headers) {
super(message, 429, 'RATE_LIMIT_EXCEEDED');
this.retryAfter = retryAfter;
this.headers = headers;
}
}
class NetworkError extends Error {
constructor(message, originalError) {
super(message);
this.name = 'NetworkError';
this.originalError = originalError;
}
}
// Usage with error handling
async function createLeadSafely(apiClient, leadData) {
try {
const result = await apiClient.createLead(leadData);
return result;
} catch (error) {
if (error instanceof RateLimitError) {
// Implement retry logic
} else if (error instanceof APIError) {
console.error(`API Error (${error.status}): ${error.message}`);
if (error.details) {
console.error('Details:', error.details);
}
} else if (error instanceof NetworkError) {
console.error('Network error. Please check your connection.');
} else {
console.error('Unexpected error:', error);
}
throw error;
}
}import requests
import time
from typing import Dict, Any, Optional
class LeadAPIError(Exception):
def __init__(self, message: str, status: int, code: str = None, details: Dict = None):
super().__init__(message)
self.status = status
self.code = code
self.details = details or {}
class RateLimitError(LeadAPIError):
def __init__(self, message: str, retry_after: int, headers: Dict):
super().__init__(message, 429, 'RATE_LIMIT_EXCEEDED')
self.retry_after = retry_after
self.headers = headers
class LeadAPIClient:
def __init__(self, api_key: str, base_url: str = 'https://your-domain.com/api/v1'):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
})
def make_request(self, endpoint: str, method: str = 'GET', data: Dict = None) -> Dict[str, Any]:
url = f'{self.base_url}{endpoint}'
try:
response = self.session.request(method, url, json=data)
# Handle rate limiting
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
raise RateLimitError(
'Rate limit exceeded',
retry_after,
dict(response.headers)
)
# Parse JSON response
try:
json_data = response.json()
except ValueError:
raise LeadAPIError(f'Invalid JSON response', response.status_code)
# Handle API errors
if not response.ok:
raise LeadAPIError(
json_data.get('error', 'Unknown error'),
response.status_code,
json_data.get('code'),
json_data.get('details')
)
return json_data
except requests.exceptions.RequestException as e:
raise LeadAPIError(f'Network error: {str(e)}', 0)
def create_lead(self, lead_data: Dict[str, Any]) -> Dict[str, Any]:
return self.make_request('/leads', 'POST', lead_data)
def create_lead_with_retry(self, lead_data: Dict[str, Any], max_retries: int = 3) -> Dict[str, Any]:
for attempt in range(max_retries + 1):
try:
return self.create_lead(lead_data)
except RateLimitError as e:
if attempt < max_retries:
print(f'Rate limited. Waiting {e.retry_after} seconds... (attempt {attempt + 1})')
time.sleep(e.retry_after)
else:
raise
except LeadAPIError as e:
if e.status >= 500 and attempt < max_retries:
# Retry server errors with exponential backoff
wait_time = 2 ** attempt
print(f'Server error. Retrying in {wait_time} seconds... (attempt {attempt + 1})')
time.sleep(wait_time)
else:
raise
# Usage example
def create_lead_safely(api_client: LeadAPIClient, lead_data: Dict[str, Any]):
try:
result = api_client.create_lead_with_retry(lead_data)
print(f"Lead created: {result['data']['id']}")
return result
except LeadAPIError as e:
print(f"API Error ({e.status}): {e}")
if e.details:
print(f"Details: {e.details}")
raise
except Exception as e:
print(f"Unexpected error: {e}")
raiseCommon issues and their solutions
Check API key format and Authorization header
Validate required fields (name, email)
Verify the lead ID exists in your workspace
Wait for the Retry-After time and implement backoff
Verify rate limit headers in responses
Include requestId when contacting support
Isolate issues by testing with command line
Track API usage in your workspace dashboard
You now know how to handle all API errors gracefully. Ready to see complete code examples in action?