API reference
Web search and web fetch tools
Add the provider's own web tool to a request and the model can search the web and read pages while it answers. Vani runs each search and page read, gives the model the results, and returns the answer with the tool calls, results and citations in the provider's own format: Anthropic's web_search and web_fetch server tools on /messages, the web_search tool on /responses, and web_search_options on /chat/completions.
- Price
- USD 0.01 per search (USD 10 per 1,000), plus tokens
- Page reads
- Tokens only
- Per request
- Up to 8 uses of each tool
- Endpoints
- POST /messages · /responses · /chat/completions
On this pageHow it works
How it works
The model decides when to search or read a page. Each call runs on Vani while the request is open, the result goes back to the model, and the model goes on with its answer. It works with every chat model in GET /models except the Derisked models (GLM 5.3 Derisked and its Flash version), whose requests are sent exactly as written: a request that asks one of them for web tools is refused with 400 hosted_web_tools_unsupported_model before anything is billed.
- Results are input tokens of the model's next step, like any tool result.
usageis the sum of every step of the request. - Search results and pages are untrusted web content: the model is told to use them as reference only and never to follow instructions found in them.
- Web tools and your own function tools work in the same request. A step that calls both runs the web tools first; your tool calls come back to you as usual.
Messages: web_search and web_fetch
Add {"type": "web_search_20250305", "name": "web_search"} and, to read pages, {"type": "web_fetch_20250910", "name": "web_fetch"} to tools. The later dated versions work the same way: web_search_20260209 and web_search_20260318, web_fetch_20260209, web_fetch_20260309 and web_fetch_20260318 (as the Vercel AI SDK sends them). The anthropic-beta headers web-fetch-2025-09-10 and code-execution-web-tools-2026-02-09 are accepted but not needed.
web_searchtakesmax_uses,allowed_domainsorblocked_domains(not both;example.comcovers its subdomains,example.com/docsthe pages under that path) anduser_location({"type": "approximate", "city", "region", "country", "timezone"}, given to the model, which adds a place to a query when it matters).web_fetchtakesmax_uses,allowed_domains/blocked_domains,citations: {"enabled": true}andmax_content_tokens. It reads only URLs that you send (in your messages, tool results or system prompt) and URLs that earlier search and page results brought, never an address the model wrote in an earlier answer, so a model cannot be led to send data to an address of its own choosing. Pages are read from public HTTPS addresses whose robots.txt allows Vani's research fetcher; HTML, plain text and PDF come back as text.- The later versions' options: Vani runs no code execution, so there is no dynamic filtering.
allowed_callersandresponse_inclusionare accepted and change nothing: every call is the model's own, and every result comes back in full. Theserver_tool_useblocks of the 2026 versions say"caller": {"type": "direct"}.use_cache: false(web_fetch 20260309 and later) reads the page live from its site, never from a stored copy.url_sources(web_fetch, every version) narrows where a URL may come from:user_input(your messages and system prompt;allornone),client_tool_resultsandserver_tool_results(all,none, oronly/exceptwith{"type": "tool_reference", "name"}entries naming tools of the request). tool_choice: {"type": "tool", "name": "web_search"}(orweb_fetch) makes the first step call that tool.- The answer holds a
server_tool_useblock (srvtoolu_…id,inputwith the query or URL), itsweb_search_tool_result(each result withtype: web_search_result,url,title,page_ageand an opaqueencrypted_content) orweb_fetch_tool_result(adocumentwith the page text andretrieved_at), then the text. A text block that links to a search result carries aweb_search_result_locationcitation with a shortcited_text. - A failed or refused call is a result block, never an HTTP error, and is not charged:
web_search_tool_result_errorwithmax_uses_exceeded,too_many_requests,invalid_input,query_too_longorunavailable;web_fetch_tool_result_errorwithurl_not_allowed,url_not_accessible,unsupported_content_type,url_too_long,invalid_input,max_uses_exceeded,too_many_requestsorunavailable. usage.server_tool_usecountsweb_search_requests(the charged searches) andweb_fetch_requests. A stream sends the blocks in order: theserver_tool_useinput as aninput_json_delta, citations ascitations_delta, and the counts inmessage_delta.- Send an answer back in the history as it came. Its server tool blocks are read as text (what was searched or read, the results' titles and URLs, the page text);
encrypted_contentandencrypted_indexare opaque and carry nothing, andpage_ageisnullwhere a page's date is not known.
A Messages request with web search
curl "https://api.vani.ai/v1/messages" \
-H "x-api-key: $VANI_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-5.5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "What changed in the latest Rust release?"}],
"tools": [{"type": "web_search_20250305", "name": "web_search", "max_uses": 3}]
}'The answer (shortened)
{
"content": [
{"type": "server_tool_use", "id": "srvtoolu_01…", "name": "web_search", "input": {"query": "Rust latest release notes"}},
{"type": "web_search_tool_result", "tool_use_id": "srvtoolu_01…", "content": [
{"type": "web_search_result", "url": "https://blog.rust-lang.org/…", "title": "Announcing Rust …", "encrypted_content": "vws1.…", "page_age": null}
]},
{"type": "text", "text": "The latest release … ([Rust blog](https://blog.rust-lang.org/…)).",
"citations": [{"type": "web_search_result_location", "url": "https://blog.rust-lang.org/…", "title": "Announcing Rust …", "cited_text": "…", "encrypted_index": "vwi1.…"}]}
],
"stop_reason": "end_turn",
"usage": {"input_tokens": 2810, "output_tokens": 164, "server_tool_use": {"web_search_requests": 1, "web_fetch_requests": 0}}
}Responses: the web_search tool
Add {"type": "web_search"} (or web_search_preview, and their dated names) to tools.
- Options:
search_context_size(low,mediumby default, orhigh: how many results the model reads and how much of each),user_location({"type": "approximate", city, region, country, timezone}) andfilters.allowed_domains.tool_choice: {"type": "web_search"}makes the first step search. - Each search is a
web_search_calloutput item withstatusandaction: {"type": "search", "query"}; withinclude: ["web_search_call.action.sources"]the action also lists the result URLs insources. The message'soutput_textcarriesurl_citationannotations (start_index,end_index,url,title) for its links to results. - A stream sends
response.output_item.added,response.web_search_call.in_progress,response.web_search_call.searching,response.web_search_call.completedandresponse.output_item.donefor each search, andresponse.output_text.annotation.addedbeforeresponse.output_text.done. - Earlier
web_search_callitems and annotated messages ininputare accepted.
A Responses request with web search
curl "https://api.vani.ai/v1/responses" \
-H "Authorization: Bearer $VANI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"openai/gpt-6-sol","input":"What changed in the latest Rust release?","tools":[{"type":"web_search","search_context_size":"medium"}],"store":false}'Chat Completions: web_search_options
Add web_search_options (search_context_size; user_location: {"type": "approximate", "approximate": {city, region, country, timezone}}). The model searches when the question needs it and answers with links; message.annotations lists url_citation entries (start_index, end_index, url, title). A stream sends them in one annotations delta just before the finish chunk.
A Chat Completions request with web search
curl "https://api.vani.ai/v1/chat/completions" \
-H "Authorization: Bearer $VANI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"google/gemini-3.8-flash","messages":[{"role":"user","content":"What changed in the latest Rust release?"}],"web_search_options":{"search_context_size":"low"}}'Price and billing
- USD 0.01 per search that ran (USD 10 per 1,000), on top of the request's tokens. A search that ran but found nothing still counts; a search that failed or was refused (an error result) is never charged.
- Page reads (
web_fetch) cost tokens only: the page text the model reads is input tokens. - Prepaid keys pay from the prepaid balance; keys created in Vani Chat pay from the plan allowance, at the same amount.
- When a request starts, Vani reserves the cost of every search its
max_usesallows (8 when not set) on top of its tokens; what the searches did not use is released when the request ends. The balance or allowance must cover that reservation. - The request log keeps
server_tool_usewith the number of searches, page reads and the search fee. A request that fails before delivering anything is not charged, its searches included. A request you cancel, or whose stream you leave, after its searches ran is charged for those searches and the tokens it used.
Limits and privacy
- Up to 8 uses of each tool per request; a larger
max_usesis lowered to 8. A request runs at most 8 model steps and 16 tool calls. - Search queries up to 500 bytes (
query_too_longabove); URLs up to 2,000 characters; up to 60 web tool calls a minute per account (too_many_requestsabove). max_content_tokenstakes up to 25,000 tokens of page text (about 100,000 characters); longer pages are shortened.- A query that looks like personal data (an e-mail address, a phone number or another long number) is searched with extra privacy, and the pages it finds, like the URLs you send, are read by Vani's own fetcher only.
- Vani does not keep search results or pages after the request; nothing is shared between accounts.
Clients
- Claude Code: its WebSearch tool works with no extra setting (tested with Claude Code 2.1.299). Each WebSearch call is one search; Claude Code's WebFetch reads pages on your machine (no search fee; the page text it gives the model costs tokens as usual).
- Codex: with
web_searchset tocached,indexedorlive(cachedis Codex's default), Codex sends its web search tool with the models it knows to support it, and Vani runs each search, always as a live search. Codex 0.159.2 does so withgpt-5.5andgpt-5.4, for example, but sends no web search tool withgpt-6-solor a model id it does not know. Keep itdisabledif you do not want search fees. - The Anthropic and OpenAI SDKs read these blocks, items and annotations with their own types.
Claude Code and other client guidesAnthropic-compatible APIOpenAI-compatible API
More reference: OpenAI-compatible API · Anthropic-compatible API · Model ids, limits, headers and usage · MCP tools on the API · Media API: images and videos · Artifacts API · Responses API: scope and limits · API overview · Docs and quickstart