Error Handling
Learn how to handle errors gracefully when integrating with the CallCov API. This guide covers common error scenarios, retry strategies, and debugging techniques.
Error Response Formatβ
All API errors follow a consistent JSON format:
{
"error": {
"code": "error_code_here",
"message": "Human-readable error message",
"details": {
"field": "additional_context"
},
"request_id": "req_1a2b3c4d5e"
}
}
| Field | Description |
|---|---|
code | Machine-readable error code for programmatic handling |
message | Human-readable error description |
details | Additional context (optional, varies by error type) |
request_id | Unique request identifier for support inquiries |
HTTP Status Codesβ
| Status Code | Meaning | Common Causes |
|---|---|---|
400 | Bad Request | Invalid parameters, malformed JSON |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Insufficient permissions |
404 | Not Found | Resource doesn't exist |
413 | Payload Too Large | File exceeds size limit |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side error |
503 | Service Unavailable | Temporary service outage |
Common Errors & Solutionsβ
401 Unauthorizedβ
Error Response:
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key"
}
}
Solutions:
- Verify API key is correct and active
- Check header name is exactly
X-API-Key - Ensure no extra whitespace in the key value
- Regenerate key if potentially compromised
400 Bad Requestβ
Common Scenarios:
Invalid File Format:
{
"error": {
"code": "invalid_file_format",
"message": "Audio file must be in WAV, MP3, M4A, FLAC, or OGG format",
"details": {
"provided_format": "pdf"
}
}
}
Missing Required Field:
{
"error": {
"code": "validation_error",
"message": "Missing required fields",
"details": {
"missing_fields": ["agent_id", "contact_id"]
}
}
}
413 Payload Too Largeβ
{
"error": {
"code": "file_too_large",
"message": "Audio file exceeds maximum size of 100 MB",
"details": {
"file_size_mb": 150,
"max_size_mb": 100
}
}
}
Solutions:
- Compress audio file (reduce bitrate while maintaining quality)
- Split long recordings into segments
- Use URL submission for very large files
429 Rate Limit Exceededβ
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please try again in 32 seconds.",
"details": {
"retry_after": 32,
"limit": "60/minute"
}
}
}
Response Headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1699564832
Retry-After: 32
Implementing Error Handlingβ
Basic Error Handlingβ
import requestsfrom requests.exceptions import RequestException
def analyze_call(audio_file_path, agent_id, contact_id, api_key): """Submit call with proper error handling""" try: files = {"audio_file": open(audio_file_path, "rb")} data = {"agent_id": agent_id, "contact_id": contact_id} headers = {"X-API-Key": api_key}
response = requests.post( "https://api.callcov.com/api/v1/calls/analyze", headers=headers, files=files, data=data, timeout=30 )
# Raise exception for 4xx/5xx status codes response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e: status_code = e.response.status_code error_data = e.response.json().get("error", {})
if status_code == 401: print(f"Authentication failed: {error_data.get('message')}") elif status_code == 400: print(f"Invalid request: {error_data.get('message')}") print(f"Details: {error_data.get('details')}") elif status_code == 429: retry_after = e.response.headers.get('Retry-After', 60) print(f"Rate limited. Retry after {retry_after} seconds") elif status_code >= 500: print(f"Server error: {error_data.get('message')}") else: print(f"HTTP error {status_code}: {error_data.get('message')}")
raise
except requests.exceptions.Timeout: print("Request timed out after 30 seconds") raise
except RequestException as e: print(f"Network error: {e}") raise
# Usagetry: result = analyze_call("call.wav", "AGENT_001", "CONTACT_001", "your_api_key") print(f"Success: {result['analysis_id']}")except Exception as e: print(f"Failed to analyze call: {e}")Retry Strategiesβ
Exponential Backoffβ
Implement exponential backoff for transient errors (rate limits, server errors):
import timeimport requestsfrom typing import Optional
def exponential_backoff_retry( func, max_retries=5, initial_delay=1, max_delay=60, backoff_factor=2): """Execute function with exponential backoff retry logic""" for attempt in range(max_retries): try: return func()
except requests.exceptions.HTTPError as e: status_code = e.response.status_code
# Don't retry client errors (except rate limits) if 400 <= status_code < 500 and status_code != 429: raise
if attempt == max_retries - 1: raise # Last attempt failed
# Calculate delay with exponential backoff delay = min(initial_delay * (backoff_factor ** attempt), max_delay)
# Use Retry-After header if available if status_code == 429: retry_after = e.response.headers.get('Retry-After') if retry_after: delay = int(retry_after)
print(f"Attempt {attempt + 1} failed. Retrying in {delay}s...") time.sleep(delay)
except requests.exceptions.RequestException as e: if attempt == max_retries - 1: raise
delay = min(initial_delay * (backoff_factor ** attempt), max_delay) print(f"Network error. Retrying in {delay}s...") time.sleep(delay)
# Usagedef submit_call(): return requests.post( "https://api.callcov.com/api/v1/calls/analyze", headers={"X-API-Key": "your_api_key"}, files={"audio_file": open("call.wav", "rb")}, data={"agent_id": "AGENT_001", "contact_id": "CONTACT_001"} )
try: response = exponential_backoff_retry(submit_call) print(f"Success: {response.json()['analysis_id']}")except Exception as e: print(f"All retries failed: {e}")Circuit Breaker Patternβ
Prevent cascading failures by temporarily halting requests after repeated failures:
import timefrom enum import Enum
class CircuitState(Enum): CLOSED = "closed" # Normal operation OPEN = "open" # Blocking requests HALF_OPEN = "half_open" # Testing if service recovered
class CircuitBreaker: def __init__(self, failure_threshold=5, timeout=60): self.failure_threshold = failure_threshold self.timeout = timeout self.failures = 0 self.last_failure_time = None self.state = CircuitState.CLOSED
def call(self, func): """Execute function with circuit breaker protection""" if self.state == CircuitState.OPEN: if time.time() - self.last_failure_time > self.timeout: # Try transitioning to half-open self.state = CircuitState.HALF_OPEN else: raise Exception("Circuit breaker is OPEN. Service unavailable.")
try: result = func()
# Success - reset failures if self.state == CircuitState.HALF_OPEN: self.state = CircuitState.CLOSED self.failures = 0
return result
except Exception as e: self.failures += 1 self.last_failure_time = time.time()
if self.failures >= self.failure_threshold: self.state = CircuitState.OPEN print(f"Circuit breaker opened after {self.failures} failures")
raise
# Usagebreaker = CircuitBreaker(failure_threshold=3, timeout=30)
def submit_call(): return requests.post( "https://api.callcov.com/api/v1/calls/analyze", headers={"X-API-Key": "your_api_key"}, files={"audio_file": open("call.wav", "rb")}, data={"agent_id": "AGENT_001", "contact_id": "CONTACT_001"} )
try: response = breaker.call(submit_call) print(f"Success: {response.json()['analysis_id']}")except Exception as e: print(f"Request failed: {e}")Debugging Tipsβ
Enable Request Loggingβ
import loggingimport requests
# Enable debug logginglogging.basicConfig(level=logging.DEBUG)
# Log HTTP requestsimport http.client as http_clienthttp_client.HTTPConnection.debuglevel = 1
# Your API calls will now show detailed logsresponse = requests.post(...)Save Request IDsβ
Always log the request_id from error responses - it helps support diagnose issues:
try:
response = requests.post(...)
except requests.exceptions.HTTPError as e:
error_data = e.response.json().get("error", {})
request_id = error_data.get("request_id")
print(f"Request failed. Support reference: {request_id}")
Best Practicesβ
- Always implement retry logic with exponential backoff
- Respect Retry-After headers for rate limits
- Log request IDs for support inquiries
- Set reasonable timeouts (30-60 seconds for file uploads)
- Use circuit breakers for high-volume integrations
- Monitor error rates and set up alerts
- Don't retry 4xx errors (except 429) - they won't succeed
- Implement graceful degradation - cache results when possible
Next Stepsβ
Need Help?β
- Email: support@callcov.com
- Include the
request_idfrom error responses - Documentation: docs.callcov.com