# Errors and page statuses: what failed, and whether to retry

> Search API errors: the six HTTP error codes (never charged), page statuses inside a 200, and when to retry with backoff. No KYC, pay in crypto.

- URL: https://llmwebsearch.com/docs/errors/
- Last updated: 2026-10-22
- Publisher: LLMWebSearch (https://llmwebsearch.com)

Two kinds of problems exist. An HTTP error means the whole call failed, and it costs nothing. A page status means the search worked but one page could not be read; it sits inside a normal 200 response. Agents should handle both, differently.

**Quick answer — Which errors can the LLMWebSearch API return, and are they charged?**

**LLMWebSearch** has six HTTP errors: `400 invalid_parameter`, `401 invalid_api_key`, `402 insufficient_credits`, `429 rate_limited`, `502 search_failed` and `504 search_timeout`. None is charged. Pages that cannot be read show a `content_status` inside a 200 instead. A working search costs 1 credit, from $1.20/1K searches as of October 2026. No KYC; pay in crypto.

## Which HTTP errors exist?

The body is always `{"error": {"code": "…", "message": "…"}}`. No error uses a credit.

| HTTP | `code` | Cause | Retry? |
| --- | --- | --- | --- |
| 400 | `invalid_parameter` | A required parameter is missing or a value is out of range | No: fix the request |
| 401 | `invalid_api_key` | The key is missing, wrong or revoked | No: check the key |
| 402 | `insufficient_credits` | The balance cannot pay for this call | No: buy a pack |
| 429 | `rate_limited` | More calls per minute than the account allows | Yes, after a pause |
| 502 | `search_failed` | The search could not be completed | Yes, with backoff |
| 504 | `search_timeout` | No search result within 30 seconds | Yes, with backoff |

## How is a page status different from an error?

A page status describes one result, not the call. The search ran, the results are there, and `credits_used` is set as usual. Only the content of that one page is missing, and `content_status` says why: `blocked_by_robots`, `blocked_by_site_policy`, `target_refused`, `fetch_failed`, `fetch_timeout` or `unsupported_content`.

Do not treat these as failures to retry the whole search. Use the other results, the snippet of the missing page, or a different source. The [response format](https://llmwebsearch.com/docs/response/) page explains each status in a table.

## Why do you never retry around a refusal?

Because a refusal is the site's answer, and we respect it. Our reader respects robots.txt: it introduces itself as LLMWebSearch, follows the rules a site writes for it or for all robots, and leaves out the content of any page it is not allowed to read. A site that sets Content-Signal: ai-input=no in its robots.txt keeps its pages out of your results' content. When a site rejects our reader with a 403, a 429 or a challenge page, we report it as `target_refused` with the site's status in `target_status`.

When a site turns our reader away, the result comes back without content and with the site's status: we never solve CAPTCHAs, sign in to accounts or work around a block or a paywall. We do not retry with another identity or a disguised browser either. Your agent should not loop on such a page: the result will not change, and the site has said no.

## When should my code retry?

Only on `429`, `502` and `504`. Wait, then try again, doubling the wait each time and adding a little randomness so parallel workers do not retry in step. Three to five attempts are enough; after that, report the failure.

Never retry `400`, `401` or `402`: the same request gives the same answer until you change something. For pages, `fetch_failed` and `fetch_timeout` may work later, through a new search or an `/extract` call. `target_refused`, `blocked_by_robots` and `blocked_by_site_policy` are final.

*Python: retry 429, 502 and 504 with exponential backoff*

```python
import os
import random
import time

import requests

API = "https://llmwebsearch.com/api/v1/search"
HEADERS = {"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]}
RETRY_ON = {429, 502, 504}


def search(body, attempts=5):
    delay = 1.0
    for attempt in range(1, attempts + 1):
        resp = requests.post(API, headers=HEADERS, json=body, timeout=60)
        if resp.status_code == 200:
            return resp.json()
        err = resp.json().get("error", {})
        if resp.status_code not in RETRY_ON or attempt == attempts:
            raise RuntimeError(f"{resp.status_code} {err.get('code')}: {err.get('message')}")
        time.sleep(delay + random.uniform(0, delay / 2))
        delay = min(delay * 2, 30)


data = search({"q": "how to rotate api keys without downtime"})
unread = [r["url"] for r in data["results"] if r["content_status"] not in ("ok", "not_requested")]
print("credits:", data["credits_used"], "| pages not read:", unread)

```

## What should I do on 402 insufficient_credits?

Stop and top up. The call was not run and cost nothing. To avoid stopping in the middle of a long job, check your balance first with `GET https://llmwebsearch.com/api/v1/credits`, which is free, and compare it with the number of searches you plan. Remember that a search with `read` above 3 needs 2 credits.

Credits come from packs bought with your crypto balance. Search credits have no expiry date: what you do not use this month is still there next year.

## How do I stay under the rate limit?

Limit how many calls run at once in your own code. Every account has a per-minute call limit, shown in the dashboard; ask support and it can be raised. A small pool of parallel workers, four to eight for most agents, keeps a steady pace without bursts. The [Python](https://llmwebsearch.com/docs/python/) and [Node.js](https://llmwebsearch.com/docs/node/) pages each show such a pool.

When you do get a `429`, pause before the next attempt instead of firing it at once. Retrying immediately only adds more refused calls.

## Errors: common questions

### Does a search with every page refused still cost a credit?

Yes, if the search itself worked: you still get the ranked results and snippets. The price of a search does not depend on how many of its pages could be read.

### Is a 401 caused by a revoked key?

It can be. A revoked key, a typo, a missing `Bearer ` prefix or a header that never reached us all give `401 invalid_api_key`. Make one API key per agent, app or teammate and revoke any of them from the dashboard without touching the others.

### Why did a page return fetch_timeout?

Pages are read in parallel, and a page that takes longer than 15 seconds is returned without content so it does not hold up the whole answer. Slow sites sometimes respond on a later attempt.

### Can I see my failed calls?

Yes. The dashboard history lists your calls for 30 days, failed ones included, with their status and credits. Failed calls show 0 credits.

---

LLMWebSearch: LLMWebSearch is a web search API for AI agents that returns ranked results with the content of the top pages in Markdown, paid in crypto with no ID upload. Prepaid credits from $1.20/1K searches never expire. No KYC — no ID, no selfie, no documents. Pay in crypto.
