Error Codes

This page documents all error responses returned by the SerpWatch API, including HTTP status codes, error formats, and troubleshooting guidance.

Error Response Format

All error responses include a JSON body with details about the error. The format varies slightly depending on the error type.

Standard Error

{
  "detail": "Error message describing what went wrong"
}

Validation Error (422)

{
  "detail": [
    {
      "loc": ["body", "keyword"],
      "msg": "field required",
      "type": "value_error.missing"
    },
    {
      "loc": ["body", "depth"],
      "msg": "ensure this value is less than or equal to 100",
      "type": "value_error.number.not_le"
    }
  ]
}

Rate Limit Error (429)

{
  "code": "ThrottlingException",
  "message": "Retry your request, preferably using backoff algorithm."
}

HTTP Status Codes

Code Name Description
200 OK Request succeeded
201 Created Resource created successfully
400 Bad Request Invalid request format (e.g., malformed JSON)
401 Unauthorized Missing or invalid authentication
403 Forbidden Valid auth but insufficient permissions
404 Not Found Resource doesn't exist
422 Unprocessable Entity Validation error in request body
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error (contact support)
503 Service Unavailable Temporary outage (retry later)

Common Errors

Authentication Errors

401 Unauthorized

Message: "Could not validate credentials"

Causes:

  • Missing Authorization header
  • Invalid API key
  • Malformed Bearer token format

Solution:

# Correct format
curl -H "Authorization: Bearer YOUR_API_KEY" ...

# Common mistakes:
# - Missing "Bearer " prefix
# - Extra spaces in header
# - Using expired or revoked key

Validation Errors

422 Unprocessable Entity

Message: Field-specific validation errors

Common Validation Errors:

Field Error Solution
keyword field required Include the keyword field in your request
depth ensure this value is less than or equal to 100 Use a depth value between 1 and 100
device value is not a valid enumeration member Use "desktop" or "mobile"
postback_url invalid or malformed url Use a valid HTTPS URL

Rate Limit Errors

429 Too Many Requests

Message: "Retry your request, preferably using backoff algorithm."

Causes:

  • Too many requests per second
  • Exceeded daily/monthly quota
  • DynamoDB throttling (internal)

Solution: Implement exponential backoff:

import time
import random

def request_with_backoff(func, max_retries=5):
    """Execute request with exponential backoff on 429 errors."""
    for attempt in range(max_retries):
        response = func()

        if response.status_code != 429:
            return response

        # Exponential backoff with jitter
        wait_time = (2 ** attempt) + random.uniform(0, 1)
        print(f"Rate limited. Retrying in {wait_time:.1f}s...")
        time.sleep(wait_time)

    raise Exception("Max retries exceeded")

Not Found Errors

404 Not Found

Message: "Task not found" or "Not Found"

Causes:

  • Task ID doesn't exist
  • Task ID belongs to different user
  • Task has been deleted or expired

Solution:

  • Verify the task ID is correct
  • Check that you're using the right API key
  • Ensure the task was created successfully

Task-Level Errors

Even when the API request succeeds (200), the task itself may fail during processing. Check the task's status field:

{
  "id": "task_abc123",
  "status": "error",
  "keyword": "search query",
  "error_message": "Failed to fetch search results after 6 attempts"
}

Common Task Errors

Error Message Cause Solution
Failed to fetch search results Crawling failed after max retries Retry the task; may be temporary
Invalid search engine configuration Invalid se_id parameter Use a valid search engine ID or omit
Location not supported Invalid location_name Check location spelling
Insufficient credits Account has no remaining credits Add credits to your account

Error Handling Best Practices

import requests
from requests.exceptions import RequestException

def make_api_request(endpoint, method="GET", **kwargs):
    """Make API request with comprehensive error handling."""
    try:
        response = requests.request(
            method,
            f"https://engine.v2.serpwatch.io{endpoint}",
            headers={"Authorization": f"Bearer {API_KEY}"},
            **kwargs
        )

        # Check for HTTP errors
        if response.status_code == 401:
            raise AuthenticationError("Invalid API key")
        elif response.status_code == 422:
            errors = response.json().get("detail", [])
            raise ValidationError(f"Validation failed: {errors}")
        elif response.status_code == 429:
            raise RateLimitError("Rate limit exceeded")
        elif response.status_code >= 500:
            raise ServerError("Server error, please retry")

        response.raise_for_status()
        return response.json()

    except RequestException as e:
        raise NetworkError(f"Network error: {e}")

# Usage with specific error handling
try:
    result = make_api_request("/api/v2/serp/crawl", method="POST", json=data)
except AuthenticationError:
    print("Check your API key")
except ValidationError as e:
    print(f"Fix request: {e}")
except RateLimitError:
    print("Slow down requests")
except (ServerError, NetworkError):
    print("Retry later")
async function makeApiRequest(endpoint, options = {}) {
  try {
    const response = await fetch(
      `https://engine.v2.serpwatch.io${endpoint}`,
      {
        ...options,
        headers: {
          "Authorization": `Bearer ${API_KEY}`,
          "Content-Type": "application/json",
          ...options.headers
        }
      }
    );

    // Handle specific status codes
    if (response.status === 401) {
      throw new Error("Authentication failed: Invalid API key");
    }
    if (response.status === 422) {
      const data = await response.json();
      throw new Error(`Validation error: ${JSON.stringify(data.detail)}`);
    }
    if (response.status === 429) {
      throw new Error("Rate limit exceeded");
    }
    if (response.status >= 500) {
      throw new Error("Server error, please retry");
    }

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    return await response.json();

  } catch (error) {
    if (error.name === "TypeError") {
      throw new Error("Network error: Unable to connect");
    }
    throw error;
  }
}

// Usage
try {
  const result = await makeApiRequest("/api/v2/serp/crawl", {
    method: "POST",
    body: JSON.stringify(data)
  });
} catch (error) {
  console.error("API Error:", error.message);
}

Getting Help

If you encounter errors not covered here:

  • Check the Swagger UI for interactive testing
  • Review the OpenAPI spec for exact schema requirements
  • Contact support with your request details and error response