Error codes

Every non-2xx response from the /v1 API carries the same body shape — branch on error.code, never on message text:

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded: 600 requests per minute per API key. Retry after 12s.",
    "doc_url": "https://serp-agent.com/docs/errors#rate_limited"
  }
}

429 responses additionally carry a Retry-After header (seconds); every /v1 response carries X-RateLimit-Limit / -Remaining / -Reset. See also the REST reference for per-endpoint error codes.

invalid_requestHTTP 400

Malformed JSON body or a field failed validation. The message names the offending field.

key_limit_reachedHTTP 400

The account already has 5 active API keys. Revoke one (DELETE /v1/api-keys/{id}) before creating another.

cannot_revoke_last_keyHTTP 400

Refusing to revoke the only active API key — the account would be locked out of the API. Create a replacement key first, then revoke.

unauthorizedHTTP 401

Missing or malformed Authorization header, or the key is unknown. Expected: Authorization: Bearer sk_sandbox_... or sk_live_...

key_revokedHTTP 401

The API key was revoked. Authenticate with another active key.

key_expiredHTTP 401

The (sandbox) key passed its expiry date. Create a new account or upgrade to a paid plan.

payment_requiredHTTP 402

The project has no active subscription and the key cannot pay per unit (sandbox keys after the trial budget). Subscribe the project (POST /v1/subscriptions) or complete payment at https://serp-agent.com/pricing.

insufficient_creditsHTTP 402

Pay-per-unit charge failed: the prepaid credit balance is below the unit price. The body carries required_credits and balance_credits. Buy a pack (POST /v1/credits/purchases) or subscribe the project (POST /v1/subscriptions).

sandbox_limit_reachedHTTP 403

A sandbox trial budget is exhausted (1 project, 1 audit, 2 articles per trial). Upgrade to a paid plan to continue.

sandbox_not_billableHTTP 403

Sandbox keys cannot make purchases — the trial is free by design. Purchases require a live key (sk_live_); a human completes the upgrade at https://serp-agent.com/pricing.

not_foundHTTP 404

No such resource on this account. Foreign ids are indistinguishable from missing ones.

account_existsHTTP 409

An account with this email already exists. Log in to the dashboard or authenticate with an existing API key.

already_subscribedHTTP 409

The project already has an active subscription — no second checkout is created. Check GET /v1/subscription?project_id=...

article_in_progressHTTP 409

An article is already generating for this project. Poll it and retry once it finishes.

idempotency_conflictHTTP 409

This Idempotency-Key was previously used for a different endpoint.

limit_reachedHTTP 409

A structural resource cap was hit (e.g. 20 webhook endpoints per account). Delete one first.

rate_limitedHTTP 429

Rate limit exceeded. Honor the Retry-After header (seconds) before retrying. Authenticated routes: 600 requests/minute per API key. Signup: 5 requests/hour per IP.

internal_errorHTTP 500

Something went wrong server-side. Safe to retry (creating POSTs: reuse the same Idempotency-Key).

billing_not_configuredHTTP 503

The requested purchase is not configured on this server yet (the operator has not created the Creem product / set its env var). Not the caller's fault — try again later or use the alternative purchase path named in the message.