No KYC — no ID, no selfie, no documents. Pay in crypto: BTC, USDT, USDC, ETH, SOL, LTC
Language: English
Get an API key

Docs · Errors · API v1

SERP API errors: codes, causes, fixes and retries

Six error codes, one rule: an error never uses a credit. This page says what triggers each code, whether to retry, and gives retry code with exponential backoff in Python and Node.js.

Last updated: · 5 min read

Quick answer

Which SERP API errors should I retry, and are failed searches charged?

SerpCrypto never charges an error: only a successful search uses 1 credit. Retry 429 concurrency_limit, 502 search_failed and 504 search_timeout with exponential backoff. Do not retry 400, 401 or 402: fix the parameter, the key or the balance first. Credits cost from $0.30/1K searches and never expire; payment is in crypto, with no KYC.

What does each error code mean?

No row of this table uses a credit. 1 credit = 1 successful search request, which returns one page of results on any supported engine. A request that fails is not charged.

HTTPcodeCauseWhat to doRetry?
400invalid_parameterq is missing, or a value is outside the allowed listFix the request; the message names the parameterNo
401invalid_api_keyNo key, a mistyped key or a revoked keyCheck the header or api_key; create a new key if neededNo
402insufficient_creditsThe account has 0 creditsBuy a pack from your balanceAfter buying
429concurrency_limitMore searches at once than your account allowsWait, lower parallelism, or ask support for a higher limitYes, with backoff
502search_failedThe engine or the collection failed for this requestRetry the same requestYes, with backoff
504search_timeoutNo answer in timeRetry the same requestYes, with backoff

What does an error answer look like?

Every error has the same small JSON body with a stable code and a human-readable message. Branch on code in your program and log message for people. The HTTP status matches the table above.

Body of a 402 answer
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your account has no search credits left."
  }
}

Why do I get 400 invalid_parameter?

A required value is missing or one value is outside the list the API accepts. The usual causes are an empty q, an engine name with a typo such as google-news instead of google_news, a page above 10, or a device other than desktop or mobile.

The message names the parameter at fault. Compare your request with the API reference; nothing is charged, so you can correct and resend at once.

Why do I get 401 invalid_api_key?

The key did not reach the API, or it is not valid. Check that the header is exactly Authorization: Bearer YOUR_KEY, with a space after Bearer. Check also that your environment variable is set in the shell or service that runs the code, not only in your terminal. A revoked key keeps failing: create a new one in the dashboard.

What should I do about 402 insufficient_credits?

Buy a credit pack from your balance, then resend. If the balance is too low, top up in crypto first; the minimum top-up is $25. Read credits_remaining from GET https://serpcrypto.com/api/v1/credits before a large job to avoid stopping halfway: that call is free.

How do I handle 429 concurrency_limit?

Slow down rather than stop. The limit counts searches running at the same time, not searches per day. Each account can run a set number of searches at the same time; the limit is shown in your dashboard and raised on request. Read concurrency_limit from the credits endpoint and size your worker pool to it; the Python and Node.js pages show a pool that never exceeds it.

When are 502 and 504 returned?

502 search_failed means the search could not be completed for this request; 504 search_timeout means it did not complete in time. Both are free and both are worth retrying. Wait a little longer before each new attempt, as the code below does, and give up after five attempts so a stuck job does not loop for ever.

Python: retry 429, 502 and 504 with exponential backoff
import os
import random
import time

import requests

API_URL = "https://serpcrypto.com/api/v1/search"
RETRYABLE = {429, 502, 504}


def search(params, max_attempts=5):
    headers = {"Authorization": "Bearer " + os.environ["SERPCRYPTO_API_KEY"]}
    for attempt in range(1, max_attempts + 1):
        r = requests.get(API_URL, params=params, headers=headers, timeout=90)
        if r.status_code == 200:
            return r.json()
        error = r.json().get("error", {})
        if r.status_code not in RETRYABLE or attempt == max_attempts:
            raise RuntimeError(f"{r.status_code} {error.get('code')}: {error.get('message')}")
        # exponential backoff with jitter: about 1 s, 2 s, 4 s, 8 s
        time.sleep(2 ** (attempt - 1) + random.random())
    raise RuntimeError("unreachable")


print(search({"q": "solar panel installers", "gl": "au", "hl": "en"})["search_metadata"])
Node.js: the same logic with fetch
// retry.mjs — Node.js 18+
const API_URL = "https://serpcrypto.com/api/v1/search";
const RETRYABLE = new Set([429, 502, 504]);
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

export async function search(params, maxAttempts = 5) {
  const url = `${API_URL}?${new URLSearchParams(params)}`;
  const headers = { Authorization: `Bearer ${process.env.SERPCRYPTO_API_KEY}` };
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fetch(url, { headers });
    if (res.ok) return res.json();
    const body = await res.json().catch(() => ({}));
    const code = body.error?.code ?? "unknown";
    if (!RETRYABLE.has(res.status) || attempt === maxAttempts) {
      throw new Error(`${res.status} ${code}: ${body.error?.message ?? ""}`);
    }
    // exponential backoff with jitter: about 1 s, 2 s, 4 s, 8 s
    await sleep(1000 * 2 ** (attempt - 1) + Math.random() * 1000);
  }
  throw new Error("unreachable");
}

console.log((await search({ q: "solar panel installers", gl: "au", hl: "en" })).search_metadata);

Should my HTTP timeout be short or long?

Long enough for a search to finish: a search runs live, so set your client timeout to 60 to 90 seconds rather than a few seconds. A client that gives up too early sends a second request while the first is still running, which wastes a concurrency slot and, if both succeed, two credits.

Error questions

Is a search charged if my program crashes before reading the answer?

Yes, if the API completed the search and returned 200: the credit is used when the search succeeds, not when you read it. That is another reason to set a long client timeout.

Do retries cost extra?

Only the attempt that succeeds uses a credit. Failed attempts with 429, 502 or 504 are free, so a request that succeeds on its third try costs 1 credit in total.

Where do I report an error that keeps coming back?

Write to [email protected] with the search_metadata.id of a successful search or the time, engine and parameters of the failing one. Email replies within 12 hours, 7 days a week, including help with API integration.

From $0.30/1K searches · no KYC

Get an API key