Quick answer
What does the LLMWebSearch API return for a search?
LLMWebSearch returns JSON with the query, created_at, credits_used and a ranked results array. Each result has its position, title, URL, host and snippet, and a content_status; when it is ok, the page's main content is in content with a word_count. One search with up to 3 pages read costs 1 credit, from $1.20/1K searches as of October 2026. No KYC; pay in crypto.
Which fields describe the call?
Top level of a /search response.
| Field | Type | Meaning |
|---|---|---|
query | string | The query as we ran it, after trimming spaces |
created_at | string | When the search ran, ISO 8601 in UTC |
credits_used | integer | What the call cost: 1, or 2 when read was 4 to 10 |
results | array | Ranked results, best first, at most max_results items |
Which fields does each result carry?
A field the page or the search result does not provide is left out rather than sent empty.
| Field | Type | When present | Meaning |
|---|---|---|---|
position | integer | Always | Rank in the search, starting at 1 |
title | string | Always | Title of the result |
url | string | Always | Address of the page |
host | string | Always | Host name of the page, handy for grouping or citing |
snippet | string | Always | Short extract shown by the search |
published_at | string | When a date is known | Publication date from the page or the search result |
content_status | string | Always | Whether the page was read, and if not, why |
content | string | When content_status is ok | Main content as Markdown or plain text, cut at max_chars |
word_count | integer | When content_status is ok | Words in the whole extracted text, counted before the cut |
target_status | integer | With target_refused | The HTTP status the site answered, such as 403 or 429 |
What does each content_status mean?
None of these changes the price of the search. They describe one page, never the whole call.
content_status | Meaning | What an agent should do |
|---|---|---|
ok | The page was read; content holds its main text | Use it and cite the url |
not_requested | The result is beyond the read count | Raise read, or read it through /extract if needed |
blocked_by_robots | The site's robots.txt does not allow our reader on this page | Rely on the snippet or another source |
blocked_by_site_policy | The site declares Content-Signal: ai-input=no | Rely on the snippet or another source |
target_refused | The site refused the request; see target_status | Do not retry the page; use another source |
fetch_failed | DNS, TLS or connection error, or the page is gone | Try another result; a later retry may work |
fetch_timeout | The page did not answer within 15 seconds | Try another result; a later retry may work |
unsupported_content | The link is a file we cannot turn into text | Use the snippet or another result |
What does a full response look like?
The example below asked for 5 results with the first 4 read, so it cost 2 credits. Results 1 and 3 were read. Result 2 belongs to a site whose robots.txt keeps our reader out, result 4 refused the request, and result 5 lies beyond read. Titles, URLs and values are illustrative.
{
"query": "how to rotate api keys without downtime",
"created_at": "2026-10-22T10:15:04Z",
"credits_used": 2,
"results": [
{
"position": 1,
"title": "Rotating API keys",
"url": "https://docs.example.com/security/key-rotation",
"host": "docs.example.com",
"snippet": "Create a second key, deploy it everywhere, then revoke the first one.",
"published_at": "2026-09-30",
"content_status": "ok",
"content": "# Rotating API keys\n\n## Zero-downtime rotation\n\n1. Create a second key.\n2. Deploy it to every service.\n3. Revoke the old key.",
"word_count": 948
},
{
"position": 2,
"title": "Key rotation checklist",
"url": "https://blog.example.org/key-rotation-checklist",
"host": "blog.example.org",
"snippet": "Keep two keys active during the switch and alert on the old one.",
"content_status": "blocked_by_robots"
},
{
"position": 3,
"title": "Secrets management basics",
"url": "https://security.example.net/secrets-basics",
"host": "security.example.net",
"snippet": "Never commit keys to a repository.",
"content_status": "ok",
"content": "# Secrets management basics\n\n**Never** commit keys to a repository.",
"word_count": 1310
},
{
"position": 4,
"title": "Key management service guide",
"url": "https://cloud.example.com/kms-guide",
"host": "cloud.example.com",
"snippet": "Store keys in a managed vault and rotate them on a schedule.",
"content_status": "target_refused",
"target_status": 403
},
{
"position": 5,
"title": "API key best practices",
"url": "https://dev.example.com/api-key-best-practices",
"host": "dev.example.com",
"snippet": "Scope each key to one service and one environment.",
"content_status": "not_requested"
}
]
}Which results get a page status other than not_requested?
Only the first read results, and every item of an /extract call. Those are the pages our reader actually tried. Everything after the read count stays not_requested, whatever the site would have answered.
The order never changes: the reader works on positions 1, 2, 3 and so on, never on a later result instead of an earlier one that failed. If an agent needs a replacement for a refused page, it can read the next result through /extract.
What does an extract response look like?
/extract returns credits_used and a results array in the order of the URLs you sent. Each item has the url and a content_status; with ok it adds title, content and word_count, and with target_refused it adds target_status. There is no position, host or snippet, because no search ran.
The extract reference shows a complete example and explains how its credits are counted.
How do I turn results into context for a model?
Number the sources, keep the URL next to each, and pass only what the model needs. A compact layout works well: [1] title — url, then the content of that page, then the next source. Ask the model to cite with the same numbers.
When a result has no content, give the model its snippet instead and say it is only a snippet. That avoids answers built on a page the model never saw. The Python page has a short loop that does all of this within a token budget.
Response format: common questions
Is content always Markdown?
Markdown by default. Send format: "text" to get plain text without markup, for example when you only count words or classify pages. The field name stays content.
Why is published_at missing on some results?
Many pages state no date, and some search results show none either. The field is left out in that case, so check for its presence before using it.
Can new fields appear later?
Yes. In version 1, fields may be added but are never renamed or removed. Write your parser to ignore fields it does not know.
Is the content stored on your side?
No. We do not train any model on your queries or on what the API returns, and we add no rule of our own against storing results; the rights of the sites whose pages you read still apply. Our request log keeps only a short trace of each call, described on the privacy page.