Web search
BetaWe just launched Apps: hosted models, actions and pages, on the same bill as your inference.Read the Apps docs
Gateway/Models and routing/Web search

Web search

Models search the web with their provider's own search, and results and citations come back in the provider's format. Each search is billed on top of tokens.

Which models search

GET /v1/models reports it per model in capabilities:

FieldMeaning
webSearch: "tool"Searches when you pass a web_search tool: Anthropic's to POST /v1/messages (Claude models), or OpenAI's to POST /v1/responses (OpenAI models).
webSearch: "built_in"Searches on every request to POST /v1/chat/completions. Perplexity Sonar.
webSearchToolsThe web_search tools the model accepts here: Messages versions such as web_search_20250305 and web_search_20260209, or web_search for the Responses tool.

Claude: the web_search tool

Pass Anthropic's server tool with max_uses. max_uses is required here because it caps how many searches one request can run, which is what lets the request's cost be reserved up front.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({ baseURL: "https://api.inferencebureau.com", apiKey: process.env.IB_API_KEY });

const msg = await client.messages.create({
  model: "anthropic/claude-sonnet-5",
  max_tokens: 1024,
  tools: [{ type: "web_search_20250305", name: "web_search", max_uses: 3 }],
  messages: [{ role: "user", content: "What changed in the latest Next.js release?" }],
});

// The model decides whether to search; check that it did.
const searched = msg.usage.server_tool_use?.web_search_requests ?? 0;

The response is Anthropic's, unchanged. web_search_tool_result blocks list each result's url and title, text blocks carry citations, and usage.server_tool_use.web_search_requests counts the searches that ran. allowed_domains, blocked_domains, and user_location pass through. A pause_turn stop reason passes through as well: send the response content back as an assistant turn to continue, as with the Anthropic API. Each continuation is its own request with its own hold.

VersionNotes
web_search_20250305Every Claude model that searches. Results go straight into the model's context.
web_search_20260209Newer Sonnet and Opus models. The provider filters results with code execution before the model reads them (not billed separately). allowed_callers is not forwarded, so filtering is always on, and Haiku can't use this version. Slower: allow minutes, not seconds.

The model decides whether to search, so a request can succeed with web_search_requests: 0, just as it can on the Anthropic API. If an answer must be grounded in a search, check that count.

OpenAI: the Responses web_search tool

Pass OpenAI's hosted web_search tool to POST /v1/responses with max_tool_calls. The tool has no max_uses, so max_tool_calls is required: it is what bounds the searches one request can run.

import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.inferencebureau.com/v1", apiKey: process.env.IB_API_KEY });

const res = await client.responses.create({
  model: "openai/gpt-5.4-mini",
  tools: [{ type: "web_search" }],
  max_tool_calls: 3,
  input: "What changed in the latest Next.js release?",
});

// The model decides whether to search; web_search_call items show what ran.
const searched = res.output.filter((o) => o.type === "web_search_call").length;

The response is OpenAI's, unchanged: web_search_call output items show each search (and each page the model opened), and output_text annotations carry url_citations. filters, user_location and search_context_size pass through. web_search_preview is not supported; use web_search.

Each web_search_call is billed as a search, including the ones that open a page or search within it. OpenAI can run one more than max_tool_calls when the model browses, so the hold reserves max_tool_calls + 1 searches, and you're charged for the ones that ran.

Routing and verification

Search is verified per provider and per tool version with a real billed search. A request that includes the web_search tool is sent only to providers that passed that version, and it never runs without the tool. Amazon Bedrock, for example, rejects Claude's search tool, so search requests are never routed to Bedrock. If none of the providers your key may use supports the version you sent, the request fails with policy_denied (reason no_web_search) and nothing is charged.

Time limits

Requests with the web_search tool may run for up to 10 minutes, compared with 4 minutes for other requests. Non-streamed search requests wait for the whole response. A stream is still ended if nothing arrives for 30 seconds. Providers send progress events during a search, so this only triggers when a provider stalls. For long searches, especially with web_search_20260209, prefer stream: true.

How long a search takes is up to the provider. Measured against the provider directly with a five-search research prompt: Opus 4.8 took 33 seconds with web_search_20250305 and almost 9 minutes with web_search_20260209, and Sonnet 4.6 took 2 minutes with web_search_20260209. Set your own client timeouts with that range in mind.

Billing and the hold

  • Per search. Each search the provider runs is billed at web_search_per_call from GET /v1/pricing, plus the platform fee, like tokens.
  • Result tokens. Search results are added to the model's input. After each search, the model reads the prompt and every earlier result again, so input tokens grow faster than the number of searches.
  • The hold. Before dispatch, the request's cost is reserved from your balance: max_uses searches (Claude) or max_tool_calls + 1 (OpenAI), each with another read of your prompt plus about 40,000 tokens of results and re-reading (web_search_20250305), 50,000 (web_search_20260209) or 20,000 (OpenAI's web_search). After the request, you're charged what actually ran, never more than the hold, and the rest is released, usually within seconds.

The hold grows in line with max_uses. Holds per request, platform fee included, for a short prompt and max_tokens: 4096:

ModelPer 1,000 searches20250305 ×120250305 ×320250305 ×520260209 ×120260209 ×320260209 ×5
anthropic/claude-sonnet-5.5$10$0.14$0.34$0.53$0.16$0.40$0.64
anthropic/claude-sonnet-5$10$0.14$0.34$0.53$0.16$0.40$0.64
anthropic/claude-sonnet-4.6$10$0.21$0.49$0.77$0.24$0.59$0.93
anthropic/claude-sonnet-4.5$10$0.21$0.49$0.77$0.24$0.59$0.93
anthropic/claude-opus-5.5-fast$10$0.54$1.25$1.97$0.62$1.51$2.40
anthropic/claude-opus-5.5$10$0.27$0.64$1.01$0.32$0.77$1.23
anthropic/claude-opus-5-fast$10$0.67$1.56$2.45$0.78$1.88$2.99
anthropic/claude-opus-5$10$0.34$0.80$1.25———
anthropic/claude-opus-4.8-fast$10$0.67$1.56$2.45$0.78$1.88$2.99
anthropic/claude-opus-4.8$10$0.34$0.80$1.25$0.39$0.96$1.52
anthropic/claude-opus-4.7$10$0.34$0.80$1.25$0.39$0.96$1.52
anthropic/claude-opus-4.6$10$0.34$0.80$1.25$0.39$0.96$1.52
anthropic/claude-opus-4.5$10$0.34$0.80$1.25$0.39$0.96$1.52
anthropic/claude-haiku-4.5$10$0.08$0.18$0.29———

OpenAI models on /v1/responses, for a short prompt and max_output_tokens: 4096:

ModelPer 1,000 searchesmax_tool_calls 1max_tool_calls 3max_tool_calls 5
openai/gpt-6.1-sol$10$0.15$0.26$0.37
openai/gpt-6-sol$10$0.15$0.26$0.37
openai/gpt-6-luna$10$0.03$0.05$0.08
openai/gpt-5.5$10$0.37$0.61$0.85
openai/gpt-5.4-mini$10$0.07$0.13$0.18
openai/gpt-5.4$10$0.20$0.33$0.46
openai/gpt-5-mini$10$0.04$0.07$0.11
openai/gpt-5$10$0.12$0.20$0.27
openai/gpt-4.1-mini$10$0.05$0.09$0.12
openai/gpt-4.1$10$0.14$0.25$0.36

Actual charges are usually far lower. On Opus 4.8 with web_search_20260209 and max_uses: 5, a five-search research prompt billed about $0.82 against a hold of about $1.50. With 10 requests in flight, keep at least ten holds' worth of balance available, or requests are refused with insufficient_balance. GET /v1/balance shows reserved and available, and auto reload tops up before you run out.

Perplexity Sonar

perplexity/sonar searches before every answer, with no tool to pass, and is reserved as one search per request:

curl https://api.inferencebureau.com/v1/chat/completions \
  -H "Authorization: Bearer $IB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "perplexity/sonar", "messages": [{ "role": "user", "content": "What changed in the latest Next.js release?" }] }'

Sonar responses carry the answer text but not the list of source URLs: the upstream gateway doesn't return them today, streamed or not. If you need citations, use a Claude or OpenAI model with its web_search tool.

Not supported yet

These requests are refused with unsupported_parameter instead of running searches that can't be priced in advance:

  • web_search_options and OpenRouter's plugins on chat completions.
  • OpenAI's other hosted tools on the Responses API: web_search_preview, file_search, code_interpreter, computer use, image_generation, remote mcp and hosted shell.
  • Gemini's Google Search grounding.
  • Other Anthropic server tools: web fetch, code execution as a standalone tool, and MCP connectors (mcp_servers). Client tools such as custom tools, bash, and text_editor work as usual.