Errors
The error envelope and every error code, with its HTTP status and what to do about it.
Error envelope
Every error response has the same JSON shape:
{
"error": {
"code": "insufficient_balance",
"message": "insufficient balance, please top up"
}
}
codeis stable — branch on it in your code.messageis human-readable and may change; log it, don't parse it.
Any call that returns an error is not charged.
Error codes
| HTTP | Code | Meaning | What to do |
|---|---|---|---|
| 400 | validation_error | A parameter is missing or invalid, the engine/type combination is not supported, or the fetch URL is not publicly reachable. The message names the field, e.g. num: Input should be less than or equal to 100. | Fix the request. Don't retry unchanged. |
| 401 | invalid_api_key | The key is missing, unknown or disabled, the account is suspended, or the request IP is not on the key's allowlist. | Check the header and key at /dashboard/keys. See Authentication. |
| 402 | insufficient_balance | Your balance can't cover the maximum cost of this call. | Top up at /dashboard/wallet, or lower include_content. |
| 404 | not_found | The resource doesn't exist — e.g. an unknown search ID, one from another account, or one older than 30 days. Also returned for unknown paths. | Check the ID and path. |
| 429 | rate_limited | Too many requests per minute for this key, or the key's daily credit limit is reached (daily credit limit for this API key reached). | Wait for the number of seconds in Retry-After, then retry. For the daily limit, raise it at /dashboard/keys or wait until the next UTC day. |
| 502 | all_upstreams_failed | We tried every available path for this request and none succeeded. Not charged. | Retry after a short delay with exponential backoff. If it persists, check /v1/engines or try another engine. |
| 503 | engine_unavailable | The engine has not launched (baidu) or is temporarily unavailable for this type. | Use another engine, or engine=auto. Check /v1/engines. |
A request with the wrong HTTP method (for example GET /v1/search) returns 405 with code validation_error.
Retrying
| Status | Retry? |
|---|---|
| 400, 401, 402, 404 | No — fix the request, key or balance first. |
| 429 | Yes, after Retry-After seconds. |
| 502, 503 | Yes, with backoff (for example 1 s, 2 s, 4 s, max 3–5 attempts). |
| Other 5xx | Yes, with backoff. If it repeats, contact support. |
Retrying is safe: failed calls cost nothing, and a successful retry is charged once.
import time, httpx
def search(payload, key, attempts=4):
for i in range(attempts):
r = httpx.post("https://api.serphubapi.com/v1/search",
headers={"X-API-Key": key}, json=payload, timeout=30)
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After", "1")))
continue
if r.status_code >= 500 and i < attempts - 1:
time.sleep(2 ** i)
continue
r.raise_for_status()
return r.json()
r.raise_for_status()
Getting help
Email support@serphubapi.com with the call ID (meta.id or X-Search-Id) if you have one, the time of the request and the error code. You can find recent calls, including failed ones, at /dashboard/logs.