Error Response Format

All errors follow a consistent JSON structure:

json
{
  "success": false,
  "message": "Human-readable error description",
  "errors": {},
  "doc_url": null,
  "timestamp": "2026-05-03T10:30:00Z"
}

API controller errors carry this envelope — success is always false, message is human-readable, errors holds machine context (an error code plus per-endpoint details where applicable), and doc_url points to relevant documentation (null when none applies). The edge-level per-IP throttle uses the smaller envelope documented below because it rejects the request before the API controller runs.

Request Deadlines

Most requests return immediately. Resolve requests that refresh include[] data can wait up to 240 seconds. Configure the client timeout to allow at least 300 seconds. This is an outer cutoff, not expected latency.

When refresh reaches its wait budget, resolve returns its normal HTTP 200 response with the data it can deliver. An optional section that is not available stays unavailable and adds no charge. Source timestamps show the freshness of delivered data. A check of the site that is already running can still help a later request.

HTTP Status Codes

Status Meaning When
200 Success Request completed
201 Created Resource created
202 Accepted Async operation started (exports)
400 Bad Request Invalid public parameters or filter values
401 Unauthorized Missing or invalid API key
402 Payment Required Feature needs a higher plan, account credits, or connected-app Spending limit
403 Forbidden Demo key used outside documented templates, or the authenticated account or connected app lacks the required scope
404 Not Found Domain or resource doesn't exist
409 Conflict Request identity or lookup inputs conflict
422 Unprocessable Entity Validation failed
429 Too Many Requests Credit quota exhausted, or 100 requests/minute/IP throttle exceeded
500 Internal Server Error Unexpected server error
503 Service Unavailable Public capability or dependency is temporarily unavailable

A 402 response from a connected app includes a recovery URL. Follow it to Account → AI integrations to inspect or increase that app's Spending limit.

Authentication Errors (401)

json
{
  "success": false,
  "message": "Unauthorized",
  "errors": {},
  "doc_url": "https://igamingfinder.com/docs/authentication.md",
  "timestamp": "2026-05-03T10:30:00Z"
}

Check that your API key is valid and passed via X-API-Key or Authorization: Bearer header.

Plan Upgrade Required (402)

Returned when your plan doesn't include the requested feature (e.g. exports require Starter or higher). The machine context lives in errors.code / errors.details:

json
{
  "success": false,
  "message": "This feature requires the Starter plan or higher",
  "errors": {
    "code": "plan_upgrade_required",
    "details": {
      "feature": "exports",
      "current_plan": "free",
      "required_plan": "starter"
    }
  },
  "doc_url": "https://igamingfinder.com/pricing",
  "timestamp": "2026-05-03T10:30:00Z"
}
$ help --topic=tip
See pricing for what each plan includes. 402 means your plan does not include the feature. A quota 429 has errors.code: quota_exceeded. A throttle 429 has retry_after and rate-limit headers.

Quota Exceeded (429)

Returned when your credit balance is exhausted (credits are granted upfront and never expire — see pricing). Machine context lives in errors.code / errors.details:

json
{
  "success": false,
  "message": "Credit balance exhausted — top up or upgrade your plan",
  "errors": {
    "code": "quota_exceeded",
    "details": {
      "granted": 2500,
      "used": 2500,
      "reserved": 0
    }
  },
  "doc_url": "https://igamingfinder.com/docs/errors.md",
  "timestamp": "2026-05-03T10:30:00Z"
}
$ help --topic=tip
Check your remaining credits with GET /v1/account before a paid search, resolve, or export.

Per-IP Throttle (429)

Public /v1 requests are limited to 100 requests per minute per IP. This throttle is separate from credits and can apply to any plan.

json
{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Limit: 100 per 60 seconds",
  "retry_after": 60
}

Every matching public /v1 response includes the draft-11 RateLimit-Policy and RateLimit fields. Draft-11 is work in progress, so clients should parse the named parameters rather than depend on field ordering.

http
RateLimit-Policy: "public-api";q=100;w=60
RateLimit: "public-api";r=99;t=42

q is the request limit, w is the fixed-window size in seconds, r is the remaining request count, and t is the number of seconds until the window resets. These fields describe the per-IP request throttle, not the credit balance.

Throttle responses include r=0 plus these recovery headers:

Header Meaning
Retry-After Seconds until the current fixed window resets
RateLimit-Policy Draft-11 named policy, request limit, and window
RateLimit Draft-11 remaining requests (0) and reset delay
X-RateLimit-Limit Request limit (older header)
X-RateLimit-Remaining Remaining requests (older header); 0 on the throttle response
X-RateLimit-Reset Unix time when the window resets (older header)

Handling Errors

Retry Strategy

For a quota 429 with errors.code: quota_exceeded, top up credits or upgrade the plan. For a throttle 429, wait for Retry-After and retry. Credits are a prepaid balance — granted never expires and does not reset monthly.

For 500 responses, retry with exponential backoff:

python
import time
import requests

def api_call_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        r = requests.get(url, headers=headers)
        if r.status_code == 500:
            time.sleep(2 ** attempt)
            continue
        return r
    raise Exception(f"Failed after {max_retries} retries")

Validation Errors (422)

Field-level errors include the field name and description:

json
{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "domain": ["can't be blank"]
  },
  "timestamp": "2026-05-03T10:30:00Z"
}

Self-Correction for AI Agents

Error responses include a doc_url field linking to relevant documentation:

json
{
  "success": false,
  "message": "Unauthorized",
  "doc_url": "https://igamingfinder.com/docs/authentication.md"
}
Error doc_url
401 Unauthorized /docs/authentication.md
400 Bad Request /docs/errors.md
429 Too Many Requests /docs/errors.md