Web Fetch
Give the model the full text of a page you already have the URL for. Add one tool entry and Synthorai fetches the page, cleans it, and puts the readable body into the conversation — on any model, through any channel.
Minimal request
Add synthorai:web_fetch to tools on /v1/messages. Nothing else changes:
curl https://synthorai.io/v1/messages \
-H "x-api-key: $YOUR_KEY" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"tools": [{"type": "synthorai:web_fetch"}],
"messages": [
{"role": "user", "content": "Summarise https://docs.anthropic.com/en/docs/build-with-claude/tool-use"}
]
}' A page is only fetched when the model decides it needs one and you included synthorai:web_fetch. Requests without the tool are ordinary requests — zero impact on behavior or cost.
Options
Every field on the synthorai:web_fetch entry is optional:
| Parameter | Description |
|---|---|
max_uses | Maximum pages to fetch in one request. Defaults to 3, capped at 10. This is a spend limit, so it is enforced across retries — a request declaring max_uses: 1 is billed for at most one fetch even if it is retried across channels. |
{
"type": "synthorai:web_fetch",
"max_uses": 2
} Using it with Web Search
Search finds pages; fetch reads them. Declaring both lets the model search, pick a promising result, and pull the whole page in — which is usually what you want for research-style questions:
"tools": [
{"type": "synthorai:web_search"},
{"type": "synthorai:web_fetch"}
] Response shape
Each fetch appears in the assistant turn as a pair of blocks, followed by the model's answer:
{
"type": "server_tool_use",
"id": "srvtoolu_synth_...",
"name": "web_fetch",
"input": { "url": "https://example.com/page" }
},
{
"type": "web_fetch_tool_result",
"tool_use_id": "srvtoolu_synth_...",
"content": {
"type": "web_fetch_result",
"url": "https://example.com/page",
"title": "Example page",
"content": { "type": "text", "text": "…page body…" }
}
} The number of fetches is reported in usage, so you can reconcile the charge yourself:
"usage": {
"input_tokens": 9241,
"output_tokens": 412,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0,
"server_tool_use": { "web_fetch_requests": 1 }
} Billing
| Item | Price |
|---|---|
| Each page fetched | $0.01 / fetch |
| Tokens (prompt + completion) | Standard input price for the model in use |
The per-fetch fee is not the whole cost. A fetched page enters the conversation as input tokens, and a long article can be several thousand of them — on most models that token cost exceeds the $0.01 fee. Budget for both.
Three ways to keep it predictable:
- Set
max_usesto the smallest number your task needs — it caps the fee for the whole request, retries included. - Fetch specific pages rather than letting the model explore. A URL the user pasted is one fetch; "read around the topic" can be three.
- Watch
usage.server_tool_use.web_fetch_requestsandusage.input_tokenstogether — the second is where the money usually goes.
Limits and safety
- Only
httpandhttpsURLs are fetched. URLs with embedded credentials are rejected. - Private, loopback, link-local and cloud-metadata addresses are refused — web_fetch reaches public pages only.
- Page bodies are truncated to a configured character limit before entering the conversation, so a single huge page cannot inflate one request without bound.
- A page that cannot be fetched comes back as an error block rather than failing the whole request, and the model can react to it or answer without the page.
- While you declare
synthorai:web_fetch, the bare nameweb_fetchis reserved — declaring a tool of your own by that name returns a400naming it. Rename yours, or drop thesynthorai:parameter. - A fetch we refuse before it leaves our network — rejected URL, blocked domain, backend not configured — is not charged. A fetch that reached the provider and failed there is charged, because the provider charged us. Both still count against
max_uses.
Your responsibility for what you fetch
web_fetch retrieves a page on your instruction. You decide which URL to fetch, so you are responsible for that retrieval and for what you do with what comes back.
- You must have the right to access the content. That includes the target site's terms of service, its
robots.txt, any paywall or login boundary, and applicable copyright and database rights. Fetching through us does not grant you access you would not otherwise have. - Personal data stays your obligation. If a fetched page contains personal information, you remain the controller of it under GDPR, PIPL and equivalent regimes — including lawful basis, retention and any request to erase.
- Claims arising from your fetches are yours. If a rights holder or a site operator brings a claim over content you retrieved, that claim is directed at you and you bear the cost of it. This mirrors the terms of the upstream retrieval providers we route through.
- Model output is not cleared for reuse. A model answer built on fetched material may reproduce parts of it. Whether you may republish that output is a question about the source's licence, and we make no representation about it.
What is on us: we run the retrieval infrastructure, block internal and private-network addresses, honour the domain blocklist your administrator configures, and do not retain fetched page content beyond serving your request. We do not review the legality of individual URLs, and we cannot — a URL alone does not carry its own licence.
We will suspend web_fetch on an API key that draws credible abuse reports or that a retrieval provider flags, because a suspended provider account takes the feature down for every customer.
FAQ
Can the model fetch a page I did not mention?
It can follow a URL it found through synthorai:web_search in the same conversation, which is the point of combining the two. It is instructed not to invent URLs; if it needs to find a page it should search first.
What happens if the page is behind a login or blocks crawlers?
You get an error block for that fetch and the model continues without the page. The fetch still counts toward max_uses because the request was really made on your behalf.
Does declaring the tool change anything when no page is fetched?
No. Billing and behavior are identical to a plain request until the model actually fetches something.