Documentation

Errors & Limits

Standard HTTP status codes, async job envelopes, and per-key limits help you build reliable integrations.

AgentSEO uses normal HTTP status codes for request-level failures and a structured job status envelope for async work. Rate limits are split between workload traffic and higher-budget control traffic such as job polling and SSE streams.

HTTP Status Codes

CodeMeaningDescription
200OKRequest succeeded. Result is in the body.
202AcceptedJob queued or still processing. Poll /jobs/{id} or stream /jobs/{id}/events.
400Bad RequestInvalid parameters. check details field.
401UnauthorizedInvalid or missing API key.
402Payment RequiredCredits are exhausted for the API key or workspace budget path in use.
403ForbiddenKey is revoked, expired, or blocked by an allowed-domain policy.
404Not FoundResource or endpoint does not exist.
429Too Many RequestsRate limit exceeded. Read RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset to decide when to retry.
5xxServer ErrorSomething went wrong on our end or in an upstream provider path. Retry transient failures and inspect job-level error codes on async workflows.

Error Response Format

{
  "error": {
    "code": "INVALID_PARAMETERS",
    "message": "The request parameters are invalid.",
    "details": {
      "domain": {
        "_errors": ["Domain or Business Name is required"]
      }
    },
    "request_id": "req_123xyz"
  }
}
{
  "error": {
    "code": "CREDITS_EXHAUSTED",
    "message": "Insufficient credits to run this request.",
    "details": {
      "credits_remaining": 0
    },
    "request_id": "req_456abc"
  }
}

Async Job Status Format

Most workflow endpoints are async-first. A queued or in-flight job can be polled through /jobs/{id} or streamed through /jobs/{id}/events. Completed jobs return result; failed jobs return a structured error block with a retryable flag.

{
  "jobId": "123e4567-e89b-12d3-a456-426614174000",
  "status": "processing",
  "phase": "waiting_upstream",
  "progress": {
    "percent": 55,
    "indeterminate": true,
    "eta_seconds": 12
  },
  "attempt": 1,
  "max_attempts": 3,
  "message": "Waiting for upstream provider results.",
  "poll_url": "/api/v1/jobs/123e4567-e89b-12d3-a456-426614174000",
  "events_url": "/api/v1/jobs/123e4567-e89b-12d3-a456-426614174000/events",
  "retry_after_seconds": 2,
  "upstream": {
    "provider": "dataforseo",
    "task_id": "0228...",
    "status_code": 40602,
    "status_message": "Task In Queue.",
    "next_poll_at": "2026-02-28T12:00:10.000Z"
  }
}
{
  "jobId": "123e4567-e89b-12d3-a456-426614174000",
  "status": "failed",
  "phase": "finalizing",
  "progress": {
    "percent": 100,
    "indeterminate": false,
    "eta_seconds": null
  },
  "attempt": 3,
  "max_attempts": 3,
  "message": "Job failed.",
  "error": {
    "code": "UPSTREAM_FETCH_FAILED",
    "message": "UPSTREAM_FETCH_FAILED: fetch failed",
    "retryable": true
  },
  "poll_url": "/api/v1/jobs/123e4567-e89b-12d3-a456-426614174000",
  "events_url": "/api/v1/jobs/123e4567-e89b-12d3-a456-426614174000/events",
  "retry_after_seconds": 2
}

Rate Limits

Limits are applied per API key. AgentSEO uses a lower budget for workload requests that create or run SEO work, and a higher budget for control-plane requests such as /jobs/{id} polling and /jobs/{id}/events SSE connections.

PlanWorkloadControl
Hobby60 / minute600 / minute
Starter120 / minute1200 / minute
Pro300 / minute3000 / minute
Agency1000 / minute10000 / minute

On rate-limit responses, read RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. Retry-After is used on some sync-pending job responses, not as the main rate-limit signal.