> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://openrouter.ai/docs/guides/features/server-tools/llms.txt. > For full documentation content, see https://openrouter.ai/docs/guides/features/server-tools/llms-full.txt. # Server Tools # Server Tools Server tools are currently in beta. The API and behavior may change. Server tools are specialized tools operated by OpenRouter that any model can call during a request. When a model decides to use a server tool, OpenRouter executes it server-side and returns the result to the model — no client-side implementation needed. ## Server Tools vs Plugins vs User-Defined Tools | | Server Tools | Plugins | User-Defined Tools | | ------------------------- | ------------------------ | ---------------- | ------------------------ | | **Who decides to use it** | The model | Always runs | The model | | **Who executes it** | OpenRouter | OpenRouter | Your application | | **Call frequency** | 0 to N times per request | Once per request | 0 to N times per request | | **Specified via** | `tools` array | `plugins` array | `tools` array | | **Type prefix** | `openrouter:*` | N/A | `function` | **Server tools** are tools the model can invoke zero or more times during a request. OpenRouter handles execution transparently. **Plugins** inject or mutate a request or response to add functionality (e.g. response healing, PDF parsing). They always run once when enabled. **User-defined tools** are standard function-calling tools where the model suggests a call and *your* application executes it. ## Available Server Tools | Tool | Type | Description | | --------------------------------------------------------------------------- | ----------------------------- | -------------------------------------- | | [**Web Search**](/docs/guides/features/server-tools/web-search) | `openrouter:web_search` | Search the web for current information | | [**Datetime**](/docs/guides/features/server-tools/datetime) | `openrouter:datetime` | Get the current date and time | | [**Image Generation**](/docs/guides/features/server-tools/image-generation) | `openrouter:image_generation` | Generate images from text prompts | | [**Web Fetch**](/docs/guides/features/server-tools/web-fetch) | `openrouter:web_fetch` | Fetch and extract content from URLs | ## How Server Tools Work 1. You include one or more server tools in the `tools` array of your API request. 2. The model decides whether and when to call each server tool based on the user's prompt. 3. OpenRouter intercepts the tool call, executes it server-side, and returns the result to the model. 4. The model uses the result to formulate its response. It may call the tool again if needed. Server tools work alongside your own user-defined tools — you can include both in the same request. ## Quick Start Add server tools to the `tools` array using the `openrouter:` type prefix: ## Combining with User-Defined Tools Server tools and user-defined tools can be used in the same request: ```json { "model": "openai/gpt-5.2", "messages": [...], "tools": [ { "type": "openrouter:web_search", "parameters": { "max_results": 3 } }, { "type": "openrouter:datetime" }, { "type": "function", "function": { "name": "get_stock_price", "description": "Get the current stock price for a ticker symbol", "parameters": { "type": "object", "properties": { "ticker": { "type": "string" } }, "required": ["ticker"] } } } ] } ``` The model can call any combination of server tools and user-defined tools. OpenRouter executes the server tools automatically, while your application handles the user-defined tool calls as usual. ## Usage Tracking Server tool usage is tracked in the response `usage` object: ```json { "usage": { "input_tokens": 105, "output_tokens": 250, "server_tool_use": { "web_search_requests": 2 } } } ``` ## Next Steps * [Web Search](/docs/guides/features/server-tools/web-search) — Search the web for real-time information * [Datetime](/docs/guides/features/server-tools/datetime) — Get the current date and time * [Image Generation](/docs/guides/features/server-tools/image-generation) — Generate images from text prompts * [Web Fetch](/docs/guides/features/server-tools/web-fetch) — Fetch and extract content from URLs * [Tool Calling](/docs/guides/features/tool-calling) — Learn about user-defined tool calling # Web Search Server tools are currently in beta. The API and behavior may change. The `openrouter:web_search` server tool gives any model on OpenRouter access to real-time web information. When the model determines it needs current information, it calls the tool with a search query. OpenRouter executes the search and returns results that the model uses to formulate a grounded, cited response. ## How It Works 1. You include `{ "type": "openrouter:web_search" }` in your `tools` array. 2. Based on the user's prompt, the model decides whether a web search is needed and generates a search query. 3. OpenRouter executes the search using the configured engine (defaults to `auto`, which uses native provider search when available or falls back to [Exa](https://exa.ai)). 4. The search results (URLs, titles, and content snippets) are returned to the model. 5. The model synthesizes the results into its response. It may search multiple times in a single request if needed. ## Quick Start ## Configuration The web search tool accepts optional `parameters` to customize search behavior: ```json { "type": "openrouter:web_search", "parameters": { "engine": "exa", "max_results": 5, "max_total_results": 20, "search_context_size": "medium", "allowed_domains": ["example.com"], "excluded_domains": ["reddit.com"] } } ``` | Parameter | Type | Default | Description | | --------------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `engine` | string | `auto` | Search engine to use: `auto`, `native`, `exa`, `firecrawl`, or `parallel` | | `max_results` | integer | 5 | Maximum results per search call (1–25). Applies to Exa, Firecrawl, and Parallel engines; ignored with native provider search | | `max_total_results` | integer | — | Maximum total results across all search calls in a single request. Useful for controlling cost and context size in agentic loops | | `search_context_size` | string | `medium` | How much context to retrieve: `low`, `medium`, or `high`. For Exa, controls characters per result; for Parallel, controls total characters across all results. Ignored with native provider search and Firecrawl | | `user_location` | object | — | Approximate user location for location-biased results. Currently only supported by native provider search; ignored with Exa, Firecrawl, and Parallel (see below) | | `allowed_domains` | string\[] | — | Limit results to these domains. Supported by Exa, Firecrawl, Parallel, and most native providers (see [domain filtering](#domain-filtering)) | | `excluded_domains` | string\[] | — | Exclude results from these domains. Supported by Exa, Firecrawl, Parallel, and some native providers (see [domain filtering](#domain-filtering)) | ### User Location Pass an approximate user location to bias search results geographically: ```json { "type": "openrouter:web_search", "parameters": { "user_location": { "type": "approximate", "city": "San Francisco", "region": "California", "country": "US", "timezone": "America/Los_Angeles" } } } ``` All fields within `user_location` are optional. ## Engine Selection The web search server tool supports multiple search engines: * **`auto`** (default): Uses native search if the provider supports it, otherwise falls back to Exa * **`native`**: Forces the provider's built-in web search (falls back to Exa with a warning if the provider doesn't support it) * **`exa`**: Uses [Exa](https://exa.ai)'s search API, which combines keyword and embeddings-based search * **`firecrawl`**: Uses [Firecrawl](https://firecrawl.dev)'s search API (BYOK — bring your own key) * **`parallel`**: Uses [Parallel](https://parallel.ai)'s search API ### Engine Capabilities | Feature | Exa | Firecrawl | Parallel | Native | | ------------------------ | ----------- | --------------- | ----------- | ------------------ | | **Domain filtering** | Yes | Yes | Yes | Varies by provider | | **Context size control** | Yes\* | No | Yes\*\* | No | | **API key** | Server-side | BYOK (your key) | Server-side | Provider-handled | *\* Exa: limit applies **per result*** *\*\* Parallel: limit applies as a **total across all results*** ### Firecrawl (BYOK) Firecrawl uses your own API key. To set it up: 1. Go to your [OpenRouter plugin settings](https://openrouter.ai/settings/plugins) and select Firecrawl as the web search engine 2. Accept the [Firecrawl Terms of Service](https://www.firecrawl.dev/terms-of-service) — this creates a Firecrawl account linked to your email 3. Your account starts with **10,000 free credits** (credits expire after 3 months) Firecrawl searches use your Firecrawl credits directly — no additional charge from OpenRouter. Firecrawl supports domain filtering (`allowed_domains` / `excluded_domains`), but they are mutually exclusive — you cannot use both in the same request. ### Parallel [Parallel](https://parallel.ai) supports domain filtering and context size control (`search_context_size`), and uses OpenRouter credits at \$0.005 per request. Includes up to 10 results in a request, then \$0.001 per additional result. ## Domain Filtering Restrict which domains appear in search results using `allowed_domains` and `excluded_domains`: ```json { "type": "openrouter:web_search", "parameters": { "allowed_domains": ["arxiv.org", "nature.com"], "excluded_domains": ["reddit.com"] } } ``` | Engine | `allowed_domains` | `excluded_domains` | Notes | | ----------------------- | :---------------: | :----------------: | ----------------------------------- | | **Exa** | Yes | Yes | Both can be used simultaneously | | **Parallel** | Yes | Yes | Mutually exclusive | | **Firecrawl** | Yes | Yes | Mutually exclusive | | **Native (Anthropic)** | Yes | Yes | Mutually exclusive | | **Native (OpenAI)** | Yes | No | `excluded_domains` silently ignored | | **Native (xAI)** | Yes | Yes | Mutually exclusive | | **Native (Perplexity)** | No | No | Not supported via server tool path | ## Controlling Total Results When the model searches multiple times in a single request, use `max_total_results` to cap the cumulative number of results: ```json { "type": "openrouter:web_search", "parameters": { "max_results": 5, "max_total_results": 15 } } ``` Once the limit is reached, subsequent search calls return a message telling the model the limit was hit instead of performing another search. This is useful for controlling cost and context window usage in agentic loops. ## Works with the Responses API The web search server tool also works with the Responses API: ## Usage Tracking Web search usage is reported in the response `usage` object: ```json { "usage": { "input_tokens": 105, "output_tokens": 250, "server_tool_use": { "web_search_requests": 2 } } } ``` The `web_search_requests` field counts the total number of search queries the model made during the request. ## Pricing | Engine | Pricing | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Exa** | \$4 per 1,000 results using OpenRouter credits (default 5 results = max \$0.02 per search) | | **Parallel** | \$0.005 per request using OpenRouter credits. Includes up to 10 results in a request, then \$0.001 per additional result | | **Firecrawl** | Uses your Firecrawl credits directly — no OpenRouter charge | | **Native** | Passed through from the provider ([OpenAI](https://platform.openai.com/docs/pricing#built-in-tools), [Anthropic](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool#usage-and-pricing), [Perplexity](https://docs.perplexity.ai/getting-started/pricing), [xAI](https://docs.x.ai/docs/models#tool-invocation-costs)) | All pricing is in addition to standard LLM token costs for processing the search result content. ## Migrating from the Web Search Plugin The [web search plugin](/docs/guides/features/plugins/web-search) (`plugins: [{ id: "web" }]`) and the [`:online` variant](/docs/guides/routing/model-variants/online) are deprecated. Use the `openrouter:web_search` server tool instead. The key differences: | | Web Search Plugin (deprecated) | Web Search Server Tool | | ------------------------- | -------------------------------- | -------------------------------------------- | | **How to enable** | `plugins: [{ id: "web" }]` | `tools: [{ type: "openrouter:web_search" }]` | | **Who decides to search** | Always searches once | Model decides when/whether to search | | **Call frequency** | Once per request | 0 to N times per request | | **Engine options** | Native, Exa, Firecrawl, Parallel | Auto, Native, Exa, Firecrawl, Parallel | | **Domain filtering** | Yes (Exa, Parallel, some native) | Yes (Exa, Parallel, most native) | | **Context size control** | Via `web_search_options` | Via `search_context_size` parameter | | **Total results cap** | No | Yes (`max_total_results`) | | **Pricing** | Varies by engine | Varies by engine (same rates) | ### Migration example ```json // Before (deprecated) { "model": "openai/gpt-5.2", "messages": [...], "plugins": [{ "id": "web", "max_results": 3 }] } // After { "model": "openai/gpt-5.2", "messages": [...], "tools": [ { "type": "openrouter:web_search", "parameters": { "max_results": 3 } } ] } ``` ```json // Before (deprecated) — engine and domain filtering { "model": "openai/gpt-5.2", "messages": [...], "plugins": [{ "id": "web", "engine": "exa", "max_results": 5, "include_domains": ["arxiv.org"] }] } // After { "model": "openai/gpt-5.2", "messages": [...], "tools": [{ "type": "openrouter:web_search", "parameters": { "engine": "exa", "max_results": 5, "allowed_domains": ["arxiv.org"] } }] } ``` ```json // Before (deprecated) — :online variant { "model": "openai/gpt-5.2:online" } // After { "model": "openai/gpt-5.2", "tools": [{ "type": "openrouter:web_search" }] } ``` ## Next Steps * [Server Tools Overview](/docs/guides/features/server-tools) — Learn about server tools * [Datetime](/docs/guides/features/server-tools/datetime) — Get the current date and time * [Tool Calling](/docs/guides/features/tool-calling) — Learn about user-defined tool calling # Web Fetch Server tools are currently in beta. The API and behavior may change. The `openrouter:web_fetch` server tool gives any model the ability to fetch content from a specific URL. When the model needs to read a web page or PDF document, it calls the tool with the URL. OpenRouter fetches and extracts the content, returning text that the model can use in its response. ## How It Works 1. You include `{ "type": "openrouter:web_fetch" }` in your `tools` array. 2. Based on the user's prompt, the model decides whether it needs to fetch a URL and generates the request. 3. OpenRouter fetches the URL using the configured engine (defaults to `auto`, which uses native provider fetch when available or falls back to [Exa](https://exa.ai)). 4. The page content (text, title, and URL) is returned to the model. 5. The model incorporates the fetched content into its response. It may fetch multiple URLs in a single request if needed. ## Quick Start ## Configuration The web fetch tool accepts optional `parameters` to customize behavior: ```json { "type": "openrouter:web_fetch", "parameters": { "engine": "exa", "max_uses": 10, "max_content_tokens": 100000, "allowed_domains": ["docs.example.com"], "blocked_domains": ["private.example.com"] } } ``` | Parameter | Type | Default | Description | | -------------------- | --------- | ------- | --------------------------------------------------------------------------------- | | `engine` | string | `auto` | Fetch engine to use: `auto`, `native`, `exa`, `openrouter`, or `firecrawl` | | `max_uses` | integer | — | Maximum fetches per request. Once exceeded, the tool returns an error | | `max_content_tokens` | integer | — | Maximum content length in approximate tokens. Content exceeding this is truncated | | `allowed_domains` | string\[] | — | Only fetch from these domains | | `blocked_domains` | string\[] | — | Never fetch from these domains | ## Engine Selection The web fetch server tool supports multiple fetch engines: * **`auto`** (default): Uses native fetch if the provider supports it, otherwise falls back to Exa * **`native`**: Forces the provider's built-in web fetch * **`exa`**: Uses [Exa](https://exa.ai)'s Contents API to extract page content (supports BYOK) * **`openrouter`**: Uses direct HTTP fetch with content extraction * **`firecrawl`**: Uses [Firecrawl](https://firecrawl.dev)'s scrape API (BYOK — bring your own key) ### Engine Capabilities | Feature | Exa | Firecrawl | OpenRouter | Native | | -------------------- | ------------------- | --------------- | ----------- | ---------------- | | **Domain filtering** | Yes | Yes | Yes | Varies | | **Token truncation** | Yes | Yes | Yes | No | | **API key** | Server-side or BYOK | BYOK (your key) | Server-side | Provider-handled | | **Hard limit** | None | None | 50/request | 50/request | ### Firecrawl (BYOK) Firecrawl uses your own API key. To set it up: 1. Go to your [OpenRouter plugin settings](https://openrouter.ai/settings/plugins) and configure your Firecrawl API key 2. Your Firecrawl account is billed separately from OpenRouter ### Hard Limits To prevent runaway costs: * **Exa engine**: No hard limit (billed via API credits) * **Firecrawl engine**: No hard limit (uses your Firecrawl credits) * **OpenRouter/native engines**: Hard limit of 50 fetches per request ## Domain Filtering Restrict which domains can be fetched using `allowed_domains` and `blocked_domains`: ```json { "type": "openrouter:web_fetch", "parameters": { "allowed_domains": ["docs.example.com", "api.example.com"], "blocked_domains": ["internal.example.com"] } } ``` When `allowed_domains` is set, only URLs from those domains will be fetched. When `blocked_domains` is set, URLs from those domains will be rejected. ## Content Truncation Use `max_content_tokens` to limit the amount of content returned: ```json { "type": "openrouter:web_fetch", "parameters": { "max_content_tokens": 50000 } } ``` Content exceeding this limit is truncated. This is useful for controlling context window usage when fetching large pages. ## Works with the Responses API The web fetch server tool also works with the Responses API: ## Response Format When the model calls the web fetch tool, it receives a response like: ```json { "url": "https://example.com/article", "title": "Article Title", "content": "The full text content of the page...", "status": "completed", "retrieved_at": "2025-07-15T14:30:00.000Z" } ``` If the fetch fails, the response includes an error: ```json { "url": "https://example.com/404", "status": "failed", "error": "HTTP 404: Page not found" } ``` ## Pricing | Engine | Pricing | | -------------- | ----------------------------------------------------------- | | **Exa** | \$1 per 1,000 fetches (free with BYOK) | | **Firecrawl** | Uses your Firecrawl credits directly — no OpenRouter charge | | **OpenRouter** | Free | | **Native** | Passed through from the provider | All pricing is in addition to standard LLM token costs for processing the fetched content. ### Exa BYOK If you configure your own Exa API key in your [provider settings](https://openrouter.ai/settings/plugins), web fetches using the Exa engine are free through OpenRouter — you pay Exa directly. ## Next Steps * [Server Tools Overview](/docs/guides/features/server-tools) — Learn about server tools * [Web Search](/docs/guides/features/server-tools/web-search) — Search the web for real-time information * [Datetime](/docs/guides/features/server-tools/datetime) — Get the current date and time * [Tool Calling](/docs/guides/features/tool-calling) — Learn about user-defined tool calling # Datetime Server tools are currently in beta. The API and behavior may change. The `openrouter:datetime` server tool gives any model access to the current date and time. This is useful for prompts that require temporal awareness — scheduling, time-sensitive questions, or any task where the model needs to know "right now." ## Quick Start ## Configuration The datetime tool accepts an optional `timezone` parameter: ```json { "type": "openrouter:datetime", "parameters": { "timezone": "America/New_York" } } ``` | Parameter | Type | Default | Description | | ---------- | ------ | ------- | --------------------------------------------------------------------------------- | | `timezone` | string | `UTC` | IANA timezone name (e.g. `"America/New_York"`, `"Europe/London"`, `"Asia/Tokyo"`) | ## Response When the model calls the datetime tool, it receives a response like: ```json { "datetime": "2025-07-15T14:30:00.000-04:00", "timezone": "America/New_York" } ``` ## Pricing The datetime tool has no additional cost beyond standard token usage. ## Next Steps * [Server Tools Overview](/docs/guides/features/server-tools) — Learn about server tools * [Web Search](/docs/guides/features/server-tools/web-search) — Search the web for real-time information * [Tool Calling](/docs/guides/features/tool-calling) — Learn about user-defined tool calling # Image Generation Server tools are currently in beta. The API and behavior may change. The `openrouter:image_generation` server tool enables any model to generate images from text prompts. When the model determines it needs to create an image, it calls the tool with a description. OpenRouter executes the image generation and returns the result to the model. ## How It Works 1. You include `{ "type": "openrouter:image_generation" }` in your `tools` array. 2. Based on the user's request, the model decides whether image generation is needed and crafts a prompt. 3. OpenRouter generates the image using the configured model (defaults to `openai/gpt-image-1`). 4. The generated image URL is returned to the model. 5. The model incorporates the image into its response. It may generate multiple images in a single request if needed. ## Quick Start ## Configuration The image generation tool accepts optional `parameters` to customize the output: ```json { "type": "openrouter:image_generation", "parameters": { "model": "openai/gpt-image-1", "quality": "high", "aspect_ratio": "16:9", "size": "1024x1024", "background": "transparent", "output_format": "png" } } ``` | Parameter | Type | Default | Description | | -------------------- | ------ | -------------------- | ------------------------------------------------------------------------- | | `model` | string | `openai/gpt-image-1` | Which image generation model to use | | `quality` | string | — | Image quality level (model-dependent, e.g. `"low"`, `"medium"`, `"high"`) | | `size` | string | — | Image dimensions (e.g. `"1024x1024"`, `"512x512"`) | | `aspect_ratio` | string | — | Aspect ratio (e.g. `"16:9"`, `"1:1"`, `"4:3"`) | | `background` | string | — | Background style (e.g. `"transparent"`, `"opaque"`) | | `output_format` | string | — | Output format (e.g. `"png"`, `"jpeg"`, `"webp"`) | | `output_compression` | number | — | Compression level (0-100) for lossy formats | | `moderation` | string | — | Content moderation level (e.g. `"auto"`, `"low"`) | All parameters except `model` are passed directly to the underlying image generation API. Available options depend on the specific model being used. ## Response When the model calls the image generation tool, it receives a response like: ```json { "status": "ok", "imageUrl": "https://..." } ``` If generation fails, the response includes an error: ```json { "status": "error", "error": "Generation failed due to content policy" } ``` ## Works with the Responses API The image generation server tool also works with the Responses API: ## Pricing Image generation pricing depends on the underlying model used: * **openai/gpt-image-1**: See [OpenAI pricing](https://openai.com/api/pricing/) * Other models: See the model's pricing page on OpenRouter The cost is in addition to standard LLM token costs for processing the request and response. ## Next Steps * [Server Tools Overview](/docs/guides/features/server-tools) — Learn about server tools * [Web Search](/docs/guides/features/server-tools/web-search) — Search the web for real-time information * [Datetime](/docs/guides/features/server-tools/datetime) — Get the current date and time * [Tool Calling](/docs/guides/features/tool-calling) — Learn about user-defined tool calling