Features
Hosted tools
Use web search, fetching, code execution and other tools that run on the provider's side, with per-tool configuration and per-call billing.
Hosted tools run at the provider instead of in your code. You declare them in tools next to any function tools; the provider runs them while generating, and you receive the outcome: the final text, citations and inline files. Queries, generated code, call traces, resource identifiers and credentials are never returned.
Hosted tools are a fixed, versioned set. A request routes only to endpoints that support every tool it asks for, and each tool call is billed at the endpoint's published per-call rate.
Request a hosted tool
Add the tool to tools. The simplest form names a common tool type:
curl -X POST "https://api.numes.ai/api/v1/chat/completions" \ -H "Authorization: Bearer $NUMES_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-6-luna", "messages": [ { "role": "user", "content": "What changed in the latest stable release of SQLite? Cite your sources." } ], "tools": [ { "type": "web_search" } ], "max_tool_calls": 3 }'There are two forms:
| Form | Example | Routes to |
|---|---|---|
| Common type | {"type": "web_search"} | Any endpoint that supports one of the tool IDs behind that type |
| Namespaced ID | {"type": "hosted", "id": "openrouter.web_search@1"} | Only endpoints that support that exact tool ID |
Use a common type when any implementation will do. Use a namespaced ID when you need a specific implementation or its configuration keys: common types accept a smaller set of configuration keys, and several accept none.
Hosted tool
typestringRequiredA common tool type from the table below, or
hostedfor the namespaced form.idstringRequired when
typeishosted: one of the namespaced IDs. Not allowed on common types.configurationobjectTool-specific settings. Only the keys listed for that tool are accepted. At most 16 properties and 32 KiB. See Configuration reference.
resource_aliasesstring[]Up to 32 unique names of provider-configured resources. See Resource aliases.
Each tool may appear once per request. Hosted tools cannot take function, parameters or strict.
Common tool types
A common type resolves to whichever of its namespaced IDs the selected endpoint supports.
| Common type | Resolves to | Configuration keys |
|---|---|---|
web_search | openrouter.web_search@1, openai.web_search@1, anthropic.web_search@1, google.search@1 | None |
web_fetch | openrouter.web_fetch@1, anthropic.web_fetch@1 | None |
datetime | openrouter.datetime@1 | timezone |
image_generation | openrouter.image_generation@1, openai.image_generation@1 | Image generation keys |
code_execution | openai.code_interpreter@1, anthropic.code_execution@1, google.code_execution@1 | None |
file_search | openai.file_search@1, google.file_search@1 | None |
shell | openai.shell@1 | None |
mcp | openai.mcp@1, anthropic.mcp@1 | None |
tool_search | openai.tool_search@1, anthropic.tool_search@1 | None |
skills | openai.skills@1 | None |
maps | google.maps@1 | None |
url_context | google.url_context@1 | None |
advisor | openrouter.advisor@1, anthropic.advisor@1 | model, max_uses, caching |
apply_patch | openrouter.apply_patch@1 | None |
fusion | openrouter.fusion@1 | models |
subagent | openrouter.subagent@1 | model, max_turns |
"None" means the tool accepts an omitted, null or empty configuration only. To configure web search, for example, use a namespaced ID such as openrouter.web_search@1.
Namespaced IDs
The namespaced form is {"type": "hosted", "id": "<id>"}. New tools arrive only with a new versioned ID.
| ID | Configuration keys |
|---|---|
openrouter.web_search@1 | max_results, search_prompt, engine |
openrouter.web_fetch@1 | max_uses, max_content_tokens, allowed_domains, blocked_domains, citations |
openrouter.datetime@1 | timezone |
openrouter.image_generation@1 | Image generation keys |
openrouter.apply_patch@1 | None |
openrouter.fusion@1 | models |
openrouter.advisor@1 | model, max_uses, caching |
openrouter.subagent@1 | model, max_turns |
openai.web_search@1 | external_web_access, filters, search_context_size, user_location |
openai.file_search@1 | max_num_results, top_k, metadata_filter |
openai.code_interpreter@1 | None |
openai.image_generation@1 | Image generation keys |
openai.shell@1 | None |
openai.mcp@1 | server_label, server_description, allowed_tools |
openai.connectors@1 | server_label, server_description, allowed_tools |
openai.tool_search@1 | execution, description |
openai.skills@1 | None |
anthropic.web_search@1 | max_uses, allowed_domains, blocked_domains, user_location |
anthropic.web_fetch@1 | max_uses, max_content_tokens, allowed_domains, blocked_domains, citations |
anthropic.code_execution@1 | None |
anthropic.advisor@1 | model, max_uses, caching |
anthropic.tool_search@1 | None |
anthropic.mcp@1 | server_label, server_description, allowed_tools |
google.search@1 | search_types, time_range_filter |
google.maps@1 | None |
google.url_context@1 | None |
google.file_search@1 | max_num_results, top_k, metadata_filter |
google.code_execution@1 | None |
openai.connectors@1 has no common type; request it by ID. An accepted ID doesn't mean any endpoint offers the tool: check discovery first.
Configure a tool
This request restricts a fetch tool to one domain and asks for citations:
curl -X POST "https://api.numes.ai/api/v1/chat/completions" \ -H "Authorization: Bearer $NUMES_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-6-luna", "messages": [ { "role": "user", "content": "Summarize the changelog at https://docs.example.com/changes" } ], "tools": [ { "type": "hosted", "id": "anthropic.web_fetch@1", "configuration": { "max_uses": 2, "allowed_domains": [ "docs.example.com" ], "citations": { "enabled": true } } } ] }'A key the tool doesn't accept, a value outside its range or an unknown key inside a nested object fails with 400 invalid_request; configuration is never silently dropped. Configuration never carries credentials or upstream resource identifiers; use resource aliases for resources.
Configuration reference
Each key is accepted only by the tools listed for it in the tables above.
Search and fetch
max_resultsinteger1–20. Results per search (
openrouter.web_search@1).search_promptstring1–4096 bytes. Guidance for the search step (
openrouter.web_search@1).enginestringauto,nativeorexa(openrouter.web_search@1).max_usesinteger1–20. Maximum uses of the tool in one response.
max_content_tokensinteger1–1,000,000. Limit on fetched content.
allowed_domainsstring[]Up to 100 unique domains, each 1–253 bytes.
blocked_domainsstring[]Up to 100 unique domains, each 1–253 bytes.
citationsobject{"enabled": boolean}.external_web_accessbooleanAllow live web access (
openai.web_search@1).filtersobject{"allowed_domains": string[]}with the same limits as above (openai.web_search@1).search_context_sizestringlow,mediumorhigh(openai.web_search@1).user_locationobjectApproximate location to localize results.
Show child attributesHide child attributes
typestringapproximate.countrystringTwo-letter country code.
citystring1–128 bytes.
regionstring1–128 bytes.
timezonestring1–128 bytes.
search_typesobject{"web_search": {}, "image_search": {}}; include the types to enable (google.search@1).time_range_filterobjectstart_timeandend_timestrings, 1–128 bytes each (google.search@1).
Files and connected services
max_num_resultsinteger1–100.
top_kinteger1–100.
metadata_filterstring1–4096 bytes.
server_labelstring1–128 bytes.
server_descriptionstring1–4096 bytes.
allowed_toolsstring[]Up to 256 unique names, each 1–128 bytes.
executionstringserver(openai.tool_search@1).descriptionstring1–4096 bytes (
openai.tool_search@1).
Models and agents
modelstring1–256 bytes. The model the tool uses (
advisor,subagentand their IDs).max_usesinteger1–20 (
advisorand its IDs).cachingobjecttypeephemeralandttl5mor1h(advisorand its IDs).max_turnsinteger1–64 (
subagent,openrouter.subagent@1).modelsstring[]Up to 16 unique model names, each 1–256 bytes (
fusion,openrouter.fusion@1).timezonestring1–128 bytes (
datetime,openrouter.datetime@1).
Image generation
Accepted by image_generation, openrouter.image_generation@1 and openai.image_generation@1.
backgroundstringauto,opaqueortransparent.input_fidelitystringloworhigh.modelstring1–256 bytes.
moderationstringauto.output_compressioninteger0–100.
output_formatstringpng,jpegorwebp.partial_imagesinteger0–3.
qualitystringauto,low,mediumorhigh.sizestringauto,1024x1024,1024x1536or1536x1024.
Resource aliases
Some tools work on resources that belong to the provider: file and vector stores for file_search, MCP servers for mcp, and connectors for openai.connectors@1. You refer to such a resource by an alias, a short name the provider gave you for it:
{ "type": "hosted", "id": "openai.file_search@1", "configuration": { "max_num_results": 8 }, "resource_aliases": ["product-manuals"]}Each alias matches
^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$; up to 32 unique aliases per tool.The resource ID and any credential stay with the provider and never appear in your request, the response or usage.
Aliases belong to one provider. Use them with an endpoint whose provider gave you the alias, and pin that endpoint with
provider.only.
Discover support
Models and endpoints list the namespaced IDs they support in supported_hosted_tools; the field is omitted when there are none. A model row describes one representative offer, so check the endpoints of the model for the full picture:
curl "https://api.numes.ai/api/v1/models/openai/gpt-6-luna/endpoints" \ -H "Authorization: Bearer $NUMES_API_KEY"{ "name": "Example Provider: primary", "tag": "example-provider/primary", "supported_parameters": ["max_tokens", "reasoning", "tools", "tool_choice"], "supported_hosted_tools": ["openrouter.web_search@1", "openrouter.web_fetch@1", "openrouter.datetime@1"]}An endpoint that supports openrouter.web_search@1 also serves requests for the common web_search type. The catalogue can filter models by hosted tool and shows each endpoint's per-call rates.
Routing requirements
A request with hosted tools routes only to endpoints that support tool calling and every requested hosted tool; if none qualifies, it fails with 503 provider_unavailable. A tool is never dropped to find an endpoint.
tool_choice: "none"removes all tools from the request, hosted ones included, and removes the requirement.A named
tool_choicesends only that function tool, so hosted tools are unavailable in that request.tool_choice: "required"is satisfied only by a function call returned to you. Hosted tool executions are not returned as calls and do not count.Function tools can be combined with hosted tools. Only function calls come back in
tool_calls; see Tool calling.
Results
Hosted tool output arrives in the assistant message:
{ "choices": [ { "index": 0, "finish_reason": "stop", "message": { "role": "assistant", "content": "The latest release adds new JSON functions and improves query planning [1].", "annotations": [ { "type": "url_citation", "url": "https://docs.example.com/changes", "title": "Release History", "start_index": 71, "end_index": 74 } ] } } ], "usage": { "prompt_tokens": 1240, "completion_tokens": 96, "total_tokens": 1336, "hosted_tool_usage": { "openrouter.web_search@1": 1 }, "cost": 0.004375, "cost_details": { "upstream_inference_cost": 0.004375 } }}Message fields
contentstring | nullThe answer, informed by the tool results.
annotationsobject[]Citations. Up to 256 per response.
Show child attributesHide child attributes
typestringurl_citationorfile_citation.urlstringCited URL, for
url_citation.titlestringTitle of the cited source.
filenamestringCited file, for
file_citation.start_indexintegerStart of the cited span in
content.end_indexintegerEnd of the cited span in
content.
artifactsobject[]Files produced by a tool, such as a generated image or a file from code execution. At most
max_tool_callsper response.Show child attributesHide child attributes
typestringimage,audioorfile, derived from the media type.filenamestringFile name.
media_typestringMIME type.
datastringBase64 content.
In a stream, annotations and artifacts arrive as delta.annotations and delta.artifacts. See Streaming. Hosted tool executions never appear in tool_calls.
Usage and billing
Each hosted tool is billed per call, as a SKU named by its namespaced ID. The reported quantity appears in usage.hosted_tool_usage (only when non-zero) and on GET /generation:
"hosted_tool_usage": { "openrouter.web_search@1": 2, "openrouter.web_fetch@1": 1 }The charge is the quantity times the endpoint's per-call rate for that SKU, plus the platform fee, in your key's billing currency. An endpoint serves a hosted tool only if it publishes a per-call rate for it.
Hosted-tool charges are based on the usage the platform accepts from the provider's response. Quantities are whole calls, bounded by
max_tool_calls.While the request runs, funds are held for up to
max_tool_callscalls of each requested tool (128 when you omit it). You're charged only for actual usage, but a lowermax_tool_callsreduces the hold and the chance of a402. See Credits.
Errors
| Status | error_type | Cause |
|---|---|---|
400 | invalid_request | Unknown type or ID, id on a common type, duplicate tool, disallowed or out-of-range configuration key, invalid or duplicate resource alias. |
402 | insufficient_credits | The balance or key budget can't cover the hold, including max_tool_calls hosted calls. |
503 | provider_unavailable | No eligible endpoint supports tool calling and every requested hosted tool. |
502 | provider_unavailable | The endpoint couldn't run the request, for example because it doesn't have the resource alias. |
Best practices
Start with a common type and switch to a namespaced ID only when you need its configuration or a specific implementation.
Set
max_tool_callsto the number of calls a request needs. It bounds cost and the hold on your balance.Ask for citations in the prompt and render
annotationsnext to the answer so readers can verify sources.Check discovery before relying on a tool. An accepted ID doesn't mean any endpoint serves it.
Pin endpoints when you use resource aliases, since aliases exist only on the provider that configured them.