Skip to main content

Error Response Format

All API errors follow a consistent JSON structure to make error handling predictable:
Error Response Structure
{
  "status": "error",
  "error": "Brief error description",
  "message": "Human-readable error details",
  "code": "MACHINE_READABLE_CODE",
  "details": {
    "field": "Additional context when applicable"
  }
}
status
string
Always “error” for error responses
error
string
Brief, human-readable error summary
message
string
Detailed error description with actionable guidance
code
string
Machine-readable error code for programmatic handling
details
object
Additional context specific to the error (optional)

HTTP Status Codes

400 Bad Request

Invalid request format, missing required fields, or invalid parameters

401 Unauthorized

Authentication failed - invalid or missing API key

403 Forbidden

Valid authentication but insufficient permissions

404 Not Found

Endpoint or resource doesn’t exist

429 Too Many Requests

Rate limit exceeded - too many requests in time window

500 Internal Server Error

Unexpected server error - contact support if persistent

Authentication Errors

{
  "status": "error",
  "error": "Invalid API key",
  "message": "The provided API key is invalid or has been revoked",
  "code": "INVALID_API_KEY"
}
Common Causes:
  • API key doesn’t start with ap_
  • Typo in API key
  • API key has been revoked
  • Using wrong environment’s key
Solutions:
  • Verify API key format and spelling
  • Generate a new API key from your dashboard
  • Ensure you’re using the correct environment
{
  "status": "error",
  "error": "Missing authorization",
  "message": "Authorization header is required",
  "code": "MISSING_AUTH_HEADER"
}
Common Causes:
  • Forgot to include Authorization header
  • Header name is incorrect (should be Authorization)
  • Missing “Bearer ” prefix
Solutions:
  • Add Authorization: Bearer ap_your_key_here header
  • Check header spelling and format
{
  "status": "error",
  "error": "API key expired",
  "message": "Your API key has expired. Please generate a new one",
  "code": "EXPIRED_API_KEY"
}
Solutions:
  • Generate a new API key from your dashboard
  • Update your application with the new key
  • Set up key rotation reminders

Rate Limiting Errors

{
  "status": "error",
  "error": "Rate limit exceeded",
  "message": "You have exceeded your rate limit of 60 requests per minute. Please try again in 23 seconds.",
  "code": "RATE_LIMIT_EXCEEDED",
  "retry_after": 23
}
Response Headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1708185623
Retry-After: 23
Solutions:
  • Wait for the time specified in retry_after
  • Implement exponential backoff
  • Upgrade to a higher plan for increased limits
  • Use multiple API keys to distribute load

Request Validation Errors

{
  "status": "error",
  "error": "Missing required field",
  "message": "The 'domain' field is required but was not provided",
  "code": "MISSING_REQUIRED_FIELD",
  "details": {
    "field": "domain",
    "required_fields": ["domain", "topic", "country"]
  }
}
Solutions:
  • Check API documentation for required fields
  • Ensure all required parameters are included
  • Verify request body structure
{
  "status": "error",
  "error": "Invalid field format",
  "message": "Country code must be a 2-letter ISO code (e.g., 'US', 'UK')",
  "code": "INVALID_FIELD_FORMAT",
  "details": {
    "field": "country",
    "provided_value": "USA",
    "expected_format": "2-letter ISO code"
  }
}
Solutions:
  • Check the expected format in API documentation
  • Validate input data before making requests
  • Use proper data types and formats
{
  "status": "error",
  "error": "Invalid domain format",
  "message": "Domain must be in format 'example.com' without protocol or path",
  "code": "INVALID_DOMAIN_FORMAT",
  "details": {
    "field": "domain",
    "provided_value": "https://example.com/blog",
    "expected_format": "example.com"
  }
}
Solutions:
  • Remove protocol (http://, https://)
  • Remove paths, subdomains (www.), ports
  • Use just the root domain: example.com

Business Logic Errors

{
  "status": "error",
  "error": "Insufficient credits",
  "message": "This request requires 15 credits but you only have 8 remaining",
  "code": "INSUFFICIENT_CREDITS",
  "details": {
    "required_credits": 15,
    "available_credits": 8,
    "upgrade_url": "https://platform.agenticpencil.com/billing"
  }
}
Solutions:
  • Wait for next billing cycle (free/monthly plans)
  • Upgrade to a higher plan
  • Monitor credit usage with /v1/usage endpoint
{
  "status": "error",
  "error": "Domain not found",
  "message": "Unable to analyze domain 'nonexistent-domain.xyz' - domain may not exist or be accessible",
  "code": "DOMAIN_NOT_FOUND",
  "details": {
    "domain": "nonexistent-domain.xyz"
  }
}
Solutions:
  • Verify the domain exists and is accessible
  • Check for typos in domain name
  • Ensure domain has sufficient content to analyze
  • Try again later if domain is temporarily unavailable
{
  "status": "error",
  "error": "Sitemap not found",
  "message": "Could not find or access sitemap at 'https://example.com/sitemap.xml'",
  "code": "SITEMAP_NOT_FOUND",
  "details": {
    "sitemap_url": "https://example.com/sitemap.xml",
    "attempted_locations": [
      "https://example.com/sitemap.xml",
      "https://example.com/sitemap_index.xml",
      "https://example.com/robots.txt"
    ]
  }
}
Solutions:
  • Verify sitemap URL is correct and accessible
  • Check robots.txt for sitemap location
  • Ensure sitemap is publicly accessible (not behind authentication)
  • Omit sitemap_url to let us auto-discover it

Plan and Billing Errors

{
  "status": "error",
  "error": "Plan limit exceeded",
  "message": "Your Free plan allows maximum 10 keywords per request. Upgrade to Pro for up to 100 keywords.",
  "code": "PLAN_LIMIT_EXCEEDED",
  "details": {
    "current_plan": "free",
    "limit_type": "keywords_per_request",
    "current_limit": 10,
    "requested": 25,
    "upgrade_plans": ["pro", "scale"]
  }
}
Solutions:
  • Reduce request size to fit plan limits
  • Upgrade to a higher plan
  • Split large requests into multiple smaller ones
{
  "status": "error",
  "error": "Subscription required",
  "message": "This feature requires a paid subscription. Please upgrade to Pro or Scale plan.",
  "code": "SUBSCRIPTION_REQUIRED",
  "details": {
    "required_plans": ["pro", "scale", "enterprise"],
    "current_plan": "free"
  }
}
Solutions:
  • Upgrade to a paid plan
  • Use alternative endpoints available on your plan

Server Errors

{
  "status": "error",
  "error": "Internal server error",
  "message": "An unexpected error occurred. Our team has been notified. Please try again later.",
  "code": "INTERNAL_SERVER_ERROR",
  "details": {
    "incident_id": "inc_1234567890abcdef",
    "timestamp": "2024-02-17T17:10:32Z"
  }
}
Solutions:
  • Try the request again after a short delay
  • Contact support with the incident_id if problem persists
  • Check our status page for known issues
{
  "status": "error",
  "error": "Service temporarily unavailable",
  "message": "The service is temporarily unavailable due to maintenance. Please try again in a few minutes.",
  "code": "SERVICE_UNAVAILABLE",
  "details": {
    "retry_after": 300,
    "maintenance_window": "2024-02-17T18:00:00Z - 2024-02-17T18:30:00Z"
  }
}
Solutions:
  • Wait for the specified retry_after time
  • Check our status page for maintenance schedules
  • Implement retry logic with exponential backoff

Error Handling Best Practices

1. Implement Proper Error Handling

import requests
import time

def handle_api_call(url, headers, data, max_retries=3):
    for attempt in range(max_retries + 1):
        try:
            response = requests.post(url, headers=headers, json=data)
            
            # Handle success
            if response.status_code == 200:
                return response.json()
            
            # Parse error response
            error_data = response.json()
            error_code = error_data.get('code')
            
            # Handle specific errors
            if error_code == 'RATE_LIMIT_EXCEEDED':
                retry_after = error_data.get('retry_after', 60)
                if attempt < max_retries:
                    print(f"Rate limited, retrying after {retry_after} seconds")
                    time.sleep(retry_after)
                    continue
                    
            elif error_code == 'INSUFFICIENT_CREDITS':
                print("❌ Insufficient credits - please upgrade your plan")
                return None
                
            elif error_code in ['INVALID_API_KEY', 'EXPIRED_API_KEY']:
                print("❌ Authentication error - check your API key")
                return None
                
            elif error_code == 'INTERNAL_SERVER_ERROR':
                if attempt < max_retries:
                    delay = 2 ** attempt  # Exponential backoff
                    print(f"Server error, retrying in {delay} seconds")
                    time.sleep(delay)
                    continue
            
            # For other errors, don't retry
            print(f"❌ API Error: {error_data.get('message')}")
            return None
            
        except requests.RequestException as e:
            if attempt == max_retries:
                print(f"❌ Request failed: {e}")
                return None
                
            time.sleep(2 ** attempt)
    
    return None

2. Log Errors for Debugging

Always log error details for debugging and monitoring:
Python Error Logging
import logging
import json

def log_api_error(error_response, request_data):
    logger = logging.getLogger('agenticpencil_api')
    
    error_info = {
        'timestamp': datetime.now().isoformat(),
        'error_code': error_response.get('code'),
        'error_message': error_response.get('message'),
        'request_endpoint': request_data.get('endpoint'),
        'request_params': request_data.get('params', {}),
        'incident_id': error_response.get('details', {}).get('incident_id')
    }
    
    logger.error(f"AgenticPencil API Error: {json.dumps(error_info)}")

3. User-Friendly Error Messages

Transform technical errors into user-friendly messages:
User-Friendly Error Mapping
ERROR_MESSAGES = {
    'INVALID_API_KEY': 'Your API key is invalid. Please check your configuration.',
    'RATE_LIMIT_EXCEEDED': 'You\'re sending requests too quickly. Please wait a moment and try again.',
    'INSUFFICIENT_CREDITS': 'You don\'ve used all your credits this month. Consider upgrading your plan.',
    'DOMAIN_NOT_FOUND': 'We couldn\'t analyze this domain. Please check the URL and try again.',
    'INTERNAL_SERVER_ERROR': 'Something went wrong on our end. Please try again in a few minutes.'
}

def get_user_friendly_error(error_code, default_message):
    return ERROR_MESSAGES.get(error_code, default_message)
Never expose raw error details to end users - always sanitize error messages to prevent information leakage.
Monitor error patterns - Frequent specific errors might indicate issues with your integration that need addressing.