When the model decides it needs to, it runs a web search itself and answers from the results.
Your client does not have to execute any tool — just add a single web_search entry to tools.
{
"model": "everyais/gemini-3-6-flash",
"messages": [{"role": "user", "content": "What's the weather in Seoul today?"}],
"tools": [{"type": "web_search"}]
}resp = client.chat.completions.create(
model="everyais/gemini-3-6-flash",
messages=[{"role": "user", "content": "What's the weather in Seoul today?"}],
tools=[{"type": "web_search"}],
)Supported models
Check capabilities.web_search in GET /v1/models — that list is the only source of truth.
Not every Gemini model supports it, and support differs from model to model even within the same generation.
As of this writing (2026-08) there is exactly one: everyais/gemini-3-6-flash.
curl https://api.everyais.com/v1/models \ -H "Authorization: Bearer $EVERYAIS_API_KEY" \ | jq '.data[] | select(.capabilities.web_search) | .id'
If you send web_search to a model that does not support it, you get 400
web_search_unsupported_model before the provider is called (no billing).
- You can put at most 1
web_searchentry in thetoolsarray (2 or more returns 400). - You can use it alongside function tools.
tool_choiceapplies only to function tools. - It is
/v1/chat/completionsonly —/v1/messagesand/v1/responsesdo not support it yet.
⚠️ Billing is per search query, not per request
The model can run several searches within one request. For a single question like "Compare A and B", if the model runs two queries — one for A and one for B — you are billed for 2. One request is not one search.
- Search cost =
number of search queries executed × per-query price, and it is summed separately from token billing. - The content fetched by the search is not billed as input tokens.
- If the model decides no search is needed, the query count is 0 and the search billing is 0.
- Check the number of queries actually billed in
x_everyais.web_search.billed_queriesin the response. On non-streaming responses, thex-everyais-cost-usdheader carries the total including search cost.
There is no parameter that forcibly caps the query count (the provider does not offer one). To control spend, use the monthly/daily spend limit on the API key.
Reading citations from the response
{
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Seoul is clear today with a high of 28 degrees.",
"annotations": [
{
"type": "url_citation",
"url_citation": {
"url": "https://...",
"title": "Seoul weather",
"start_index": 0,
"end_index": 47
}
}
]
},
"finish_reason": "stop"
}],
"x_everyais": {
"web_search": {
"queries": ["Seoul weather today"],
"search_entry_point_html": "<div>...</div>",
"billed_queries": 1
}
}
}| Field | Description |
|---|---|
message.annotations[] | OpenAI url_citation-compatible citations. start_index/end_index are character indexes into content, so slicing with them directly gives you the cited span |
x_everyais.web_search.queries | The search terms the model actually ran |
x_everyais.web_search.billed_queries | Number of queries billed |
x_everyais.web_search.search_entry_point_html | Search suggestion HTML provided by Google |
⚠️
search_entry_point_htmlis HTML that Google requires you to display. If your service shows search results on screen, render it as-is. It is untrusted external HTML, so isolate it — for example with<iframe sandbox srcdoc="...">.
Streaming
With stream: true, the citations and search info follow after the body.
- The body
delta.contentchunks - One
delta.annotationschunk (just before finish) - The
finish_reasonchunk - The usage chunk (
choices: []) — this is wherex_everyais.web_searchrides
Citation indexes can only be fixed once the whole body has arrived, so they come exactly once, at the end. The search query count is also only in the final usage chunk, so read the stream to the end to reconcile cost.