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.
Support varies by model within both Gemini and Z.AI families. Check the current catalog.
Check this field for the example model too, and replace the ID if the supported models change.
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_choice: "none"disables both functions and search. Requiring a tool or naming a function when only search is present returns 400. - It is
/v1/chat/completionsonly —/v1/messagesand/v1/responsesdo not support it yet.
Search billing by provider
Google Gemini bills per executed search query. Two queries within one request are billed as two searches. If the model does not search, search billing is zero.
Z.AI bills one search for each successful request with web search enabled, even when there
are no results or the model does not search: billed_queries = 1. This search charge also applies
to models whose tokens are free.
- Search cost =
billed_queries × search price, and it is summed separately from token billing. pricing.is_freecovers only input, output, and cache tokens; it does not waive search charges.- Content fetched by Google search is not billed as input tokens.
- 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 | Search billing units: executed queries for Google; 1 per successful search-enabled Z.AI request |
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.