Skip to main content

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"
}
}
FieldDescription
codeMachine-readable error code for programmatic handling
messageHuman-readable error description
detailsAdditional context (optional, varies by error type)
request_idUnique request identifier for support inquiries

HTTP Status Codes​

Status CodeMeaningCommon Causes
400Bad RequestInvalid parameters, malformed JSON
401UnauthorizedMissing or invalid API key
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist
413Payload Too LargeFile exceeds size limit
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error
503Service UnavailableTemporary 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 requests
from 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
# Usage
try:
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 time
import requests
from 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)
# Usage
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 = 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 time
from 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
# Usage
breaker = 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 logging
import requests
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
# Log HTTP requests
import http.client as http_client
http_client.HTTPConnection.debuglevel = 1
# Your API calls will now show detailed logs
response = 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​

  1. Always implement retry logic with exponential backoff
  2. Respect Retry-After headers for rate limits
  3. Log request IDs for support inquiries
  4. Set reasonable timeouts (30-60 seconds for file uploads)
  5. Use circuit breakers for high-volume integrations
  6. Monitor error rates and set up alerts
  7. Don't retry 4xx errors (except 429) - they won't succeed
  8. Implement graceful degradation - cache results when possible

Next Steps​

Need Help?​