Serpex

Errors

Error codes and retry guidance

Stealth mode will no longer be available from 1 November 2026. Search and Extract are unchanged.

Errors are never charged. Credits are deducted for searches that return results, and for searches whose query genuinely has no results (confirmed across multiple search sources). An empty response we could not confirm as genuinely empty is never charged; see When are empty results charged?. Your organization's own repeats of the same request within 5 minutes are free.

HTTP Status Codes

StatusMeaningRetryable
400Bad requestNo
401Invalid or missing API keyNo
402Insufficient creditsNo
403Stealth mode is not included in your planNo
410Stealth mode has ended (from 1 November 2026)No
429Rate limit exceededYes
500Internal server errorYes
502Extraction service error (not charged)Yes
503Temporarily unavailableYes
504Extract timed out (not charged)Yes

400 Bad Request

Returned when the request is malformed or missing required parameters.

Common causes:

  • Missing q parameter on the Search endpoint
  • Query exceeds 500 characters
  • include_content is not true or false, or content_results is not 5 or 10
  • Missing urls, more than 10 URLs, or a URL that cannot be parsed on the Extract endpoint
  • days on the Usage endpoint is not a whole number of at least 1
{
  "error": "Query parameter (q or query) is required",
  "example": "/api/search?q=javascript"
}

An Extract request with URLs that cannot be parsed lists them:

{
  "error": "Invalid URLs provided",
  "invalid_urls": ["not a url"]
}

401 Unauthorized

Returned when the API key is missing, invalid, or inactive.

{
  "error": "Invalid or inactive API key"
}

When no key is sent at all, the message is "API key required".

Check that you are sending Authorization: Bearer sk_... and that the key is active in your dashboard.

402 Insufficient Credits

Returned when your account does not have enough credits to cover the request cost.

{
  "error": "Insufficient credits. Please purchase more credits to continue.",
  "remainingCredits": 0
}

On the Extract endpoint the message is "Insufficient credits". Extract checks your balance against the maximum cost of the request (every URL charged) before it runs, and then charges only the successful URLs.

The remainingCredits field shows your current balance. Top up credits from the billing page.

403 Forbidden

Returned by the Extract endpoint when a request sets "stealth": true and your plan does not include stealth mode. Nothing is charged and nothing is fetched.

{
  "error": "Stealth mode is not included in your plan. Contact support@serpex.dev to add it."
}

410 Gone

Returned by the Extract endpoint when a request sets "stealth": true on or after 1 November 2026 (00:00 UTC). Nothing is charged and nothing is fetched. Send the request without stealth.

{
  "error": "Stealth mode is no longer available (ended 1 November 2026). Send the request without stealth.",
  "retryable": false
}

429 Rate Limited

Returned when you exceed your plan's request-per-second limit.

{
  "error": "Rate limit exceeded",
  "limit": 50,
  "retryAfterMs": 800
}

Response headers include:

  • X-RateLimit-Limit — your plan's per-second ceiling
  • X-RateLimit-Remaining — requests remaining in the current window
  • Retry-After — seconds to wait before retrying

Retry guidance: Wait for retryAfterMs milliseconds, then retry the request. Use exponential backoff if you are consistently hitting the limit.

Plan tierRate limit
Starter (largest purchase under $50)5 req/sec
Standard ($50–$499)25 req/sec
Scale ($500+)50 req/sec
Enterprise (contact sales)Custom

500 Internal Server Error

Returned by Search and Extract when something unexpected fails on our side. The message is always the same and never includes internal details. The request is not charged.

{
  "error": "Internal server error",
  "request_id": "3f6c1a52-8d0e-4b7a-9c41-0e2d5a7b9f13"
}

Quote the request_id when you contact support@serpex.dev so we can find the exact request.

502 Bad Gateway

Returned by the Extract endpoint when the extraction service fails. Nothing is charged.

{
  "error": "Extraction service error. Not charged. Please retry.",
  "retryable": true,
  "request_id": "3f6c1a52-8d0e-4b7a-9c41-0e2d5a7b9f13"
}

Retry guidance: Retry the request. If it keeps failing, contact support with the request_id.

Request ID

Error responses from Search and Extract that point to a problem on our side (500, 502, and the Extract 400 below) include a request_id field. Quote it to support.

If an Extract request is rejected because urls is not a list of 1 to 10 valid absolute URLs, the body is:

{
  "error": "Invalid request: send 1 to 10 valid absolute URLs in `urls`.",
  "retryable": false,
  "request_id": "3f6c1a52-8d0e-4b7a-9c41-0e2d5a7b9f13"
}

503 Service Unavailable

Returned when the request cannot be completed right now. It is never charged and is safe to retry.

Search returns this when the search could not be completed after automatic retries:

{
  "status": "error",
  "error": "Search temporarily unavailable, please retry.",
  "retryable": true,
  "metadata": {
    "status": "error",
    "response_time": 30412,
    "timestamp": "2025-06-21T10:30:00.000Z"
  }
}

Extract with "stealth": true returns this when stealth capacity is busy:

{
  "error": "Stealth capacity is busy, please retry shortly.",
  "retryable": true
}

Retry guidance: Wait at least 1 second, then retry. Use exponential backoff with a maximum of 3 retries. If the issue persists beyond a few minutes, check the status page.

504 Gateway Timeout

Returned by the Extract endpoint when extraction does not finish in time. Nothing is charged.

{
  "error": "Extraction timed out upstream and was not charged. Retry, or split the request into fewer URLs.",
  "retryable": true
}

Retry guidance: Retry the request, or send fewer URLs per request.

Error Handling Example

import { SerpexClient, SerpApiException } from "serpex";

const client = new SerpexClient("sk_your_api_key");

try {
  const results = await client.search({ q: "test query" });
} catch (error) {
  if (error instanceof SerpApiException) {
    switch (error.statusCode) {
      case 429:
        console.log(`Rate limited. Retry after ${error.details?.retryAfterMs}ms`);
        break;
      case 402:
        console.log(`Out of credits. Balance: ${error.details?.remainingCredits}`);
        break;
      default:
        console.log(`API error ${error.statusCode}: ${error.message}`);
    }
  }
}
from serpex import SerpexClient, SerpApiException

client = SerpexClient("sk_your_api_key")

try:
    results = client.search({"q": "test query"})
except SerpApiException as e:
    if e.status_code == 429:
        print(f"Rate limited. Retry after {e.details.get('retryAfterMs')}ms")
    elif e.status_code == 402:
        print(f"Out of credits. Balance: {e.details.get('remainingCredits')}")
    else:
        print(f"API error {e.status_code}: {e}")

On this page