Serpex

Rate Limits

Per-plan request-per-second limits and retry guidance.

Serpex enforces per-organization rate limits based on your highest completed purchase. Limits are exact — there is no burst allowance.

Limits by tier

Prop

Type

The tier is set by your largest single completed purchase, not your current balance or the sum of purchases.

A search with page content uses more of the limit: it counts as 1, plus 1 for every 5 pages of content you ask for (content_results). Content for 5 results counts as 2 requests toward your per-second limit; content for 10 results counts as 3. Usage calls (/api/usage) count as 1.

HTTP response codes

CodeMeaningAction
200Success—
401Invalid or missing API keyFix the key; don't retry
402Insufficient creditsTop up at app.serpex.dev
429Rate limit exceededBack off and retry (see below)
500 / 503Transient server errorRetry with exponential backoff

The 429 response includes Retry-After and X-RateLimit-Limit headers:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 0
Retry-After: 1

Retry strategy

Implement exponential backoff for 429 and 5xx responses:

async function searchWithRetry(client: SerpexClient, query: string, maxRetries = 4) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await client.search({ q: query });
    } catch (err: any) {
      const status = err?.status ?? err?.response?.status;
      if (status === 429 || status === 503) {
        const waitMs = Math.min(1000 * 2 ** attempt, 16000);
        await new Promise((r) => setTimeout(r, waitMs));
        continue;
      }
      throw err; // non-retryable (401, 402, 400, …)
    }
  }
  throw new Error("Max retries exceeded");
}
import time

def search_with_retry(client, query: str, max_retries: int = 4):
    for attempt in range(max_retries):
        try:
            return client.search({"q": query})
        except Exception as e:
            status = getattr(e, "status_code", None)
            if status in (429, 503):
                wait = min(1 * (2 ** attempt), 16)
                time.sleep(wait)
                continue
            raise  # non-retryable
    raise RuntimeError("Max retries exceeded")

Do not retry 401 (bad key) or 402 (no credits). Those errors won't resolve on their own.

High-volume usage

If your workload requires sustained throughput above the Scale tier, contact us to discuss an Enterprise plan with a custom limit.

On this page