Skip to main content

Error Handling

All Descripio API errors return a JSON response with an error field.

Error Response Format

{
  "error": "Human-readable error message",
  "limit": 10,
  "used": 10
}
Additional fields may be included depending on the error type.

Common Errors

401 Unauthorized

Cause: Invalid or revoked API key
{
  "error": "Invalid API key"
}
Solution:
  1. Verify your API key is correct (starts with dscr_)
  2. Check if key was revoked in the dashboard
  3. Create a new key if needed

402 Payment Required

Cause: Monthly quota exceeded
{
  "error": "Monthly quota exceeded",
  "used": 10,
  "limit": 10
}
Solution:
  1. Wait for quota reset (1st of each month)
  2. Upgrade to a higher plan

403 Forbidden

Cause: Marketplace not authorized for your account
{
  "error": "Marketplace not authorized for this store",
  "hint": "Configure marketplace access in your account settings"
}
Solution:
  1. Go to Dashboard → Settings → Marketplaces
  2. Add the marketplace you’re trying to access
  3. Retry the request

429 Rate Limit Exceeded

Cause: Too many requests or concurrent jobs
{
  "error": "Rate limit exceeded",
  "limit": 1
}
Solution: Implement retry with backoff:
import time
import requests

def api_call_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        
        if response.status_code == 429:
            wait_time = (2 ** attempt) * 10  # 10s, 20s, 40s
            print(f"Rate limited. Waiting {wait_time}s...")
            time.sleep(wait_time)
            continue
        
        return response
    
    raise Exception("Max retries exceeded")

429 ASIN Cooldown

Cause: ASIN was refreshed recently
{
  "error": "ASIN cooldown active",
  "cooldownHours": 24
}
Solution: Wait for cooldown period to expire, or use cached data via GET /reviews.

Best Practices

1. Always check status codes

response = requests.post(url, headers=headers, json=data)

if response.status_code == 202:
    job = response.json()
    # Success - process job
elif response.status_code == 429:
    # Rate limited - wait and retry
elif response.status_code == 402:
    # Quota exceeded - alert user
else:
    # Log unexpected error
    print(f"Error {response.status_code}: {response.json()}")

2. Implement exponential backoff

async function fetchWithBackoff(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);
    
    if (response.status === 429) {
      const waitTime = Math.pow(2, attempt) * 10000; // 10s, 20s, 40s
      await new Promise(r => setTimeout(r, waitTime));
      continue;
    }
    
    return response;
  }
  
  throw new Error('Max retries exceeded');
}

3. Set polling timeout

Never poll forever. Always set a maximum timeout:
max_attempts = 24  # 2 minutes at 5s intervals
timeout_seconds = 120

for attempt in range(max_attempts):
    # ... poll job status
    time.sleep(5)
else:
    raise TimeoutError("Job did not complete in time")

4. Log errors for debugging

Include relevant context when logging errors:
import logging

logging.error(
    "API Error",
    extra={
        "status_code": response.status_code,
        "error": response.json().get("error"),
        "asin": asin,
        "timestamp": datetime.now().isoformat()
    }
)

5. Handle network errors

import requests
from requests.exceptions import Timeout, ConnectionError

try:
    response = requests.post(url, headers=headers, json=data, timeout=30)
except Timeout:
    print("Request timed out - check your connection")
except ConnectionError:
    print("Connection failed - check if service is available")

Support

If you encounter persistent errors: