Add {"type": "web_search"} to tools. The model searches when it needs to and answers from the results. The search runs server-side, so your client runs no tool.
json
{
"model": "everyais/gemini-3-8-flash",
"messages": [{"role": "user", "content": "What's the weather in Seoul today?"}],
"tools": [{"type": "web_search"}]
}Supported models
Use models with capabilities.web_search: true in GET /v1/models. Support varies even within the Gemini family.
bash
curl https://api.everyais.com/v1/models \
-H "Authorization: Bearer $EVERYAIS_API_KEY" \
| jq '.data[] | select(.capabilities.web_search) | .id'Other models return 400 web_search_unsupported_model and are not charged.
- Only one
web_searchentry is allowed. Two or more return 400. - You can combine it with function tools.
tool_choice: "none"turns off both. With only the search tool,requiredor a named function returns 400. - Only
/v1/chat/completionssupports web search.
Billing
Search is billed on top of tokens: billed_queries × the model's search price.
| Model family | How searches are counted |
|---|---|
| Gemini | Each query run. Two searches count as 2; no search counts as 0 |
- Search is billed even when tokens are free.
pricing.is_freecovers only input, output and cache tokens. - A stream you cut off still pays for the searches Google ran. Google reports the count at the end of the answer, so the gateway waits up to 10 seconds after the cut for it; if it doesn't arrive, the 10 searches reserved with the request are charged.
- Pages fetched by Google search are not billed as input tokens.
x_everyais.web_search.billed_querieshas the billed count. Thex-everyais-cost-usdheader on non-streaming responses includes search.- You can't cap the number of searches. Use the key's monthly or daily spend limit instead.
Citations
json
{
"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 citations. start_index and end_index are character positions in content |
x_everyais.web_search.queries | Queries the model ran |
x_everyais.web_search.billed_queries | Searches billed |
x_everyais.web_search.search_entry_point_html | Google search suggestions as HTML |
If you show search results, Google requires you to display search_entry_point_html. Render this third-party HTML isolated, for example in <iframe sandbox srcdoc="...">.
Streaming
With stream: true, events arrive in this order:
delta.contentchunks- One
delta.annotationschunk - The
finish_reasonchunk - The usage chunk (
choices: []) withx_everyais.web_search
Read the stream to the end if you track citations or cost.