Web fetch
The built-in syntic_web_fetch tool lets the model read the full content of a web page or online PDF during a request. Syntic downloads the page, turns it into clean text and hands it to the model. Pair it with web search (search finds pages, fetch reads them in full) or use it alone when the user gives an address.
When to use it
- “Summarise this article” or “What does this page say about returns?” with a link.
- Reading documentation pages, release notes or public PDFs.
- Following up on search results that need more than a snippet.
Endpoint and auth
POST https://app.syntic.ai/v1/chat/completions (and Messages), Authorization: Bearer sk_live_....
Tool definition
| Field | Type | Required | Details |
|---|---|---|---|
type | string | Yes | "syntic_web_fetch" |
max_uses | integer | No | Fetches allowed in this request, 1 to 20. Default 5. |
allowed_domains / blocked_domains | array of strings | No | As on web search. |
max_content_tokens | integer | No | Truncate each page to this many tokens. Default 20,000, maximum 100,000. |
citations | object | No | {"enabled": true} to cite passages from fetched pages. |
Which addresses can be fetched
To stop the tool being used to leak data, the model may fetch only addresses that already appear in the conversation (in a user message, a tool result or an earlier search result). It cannot invent new addresses or build them from private data.
| Allowed | Not allowed |
|---|---|
Public http and https pages and PDFs | Private, internal or loopback addresses |
| Redirects up to 5 hops (each hop checked again) | Non-standard ports other than 80, 443, 8080, 8443 |
| Pages up to 10 MB | Pages that need a login, cookies or JavaScript to show content |
Response
Like web search: the answer text, annotations when citations are on, and a record of the fetches:
{
"message": {
"role": "assistant",
"content": "The returns window is 30 days and plants must be unopened.",
"server_tool_calls": [
{ "id": "srv_02", "type": "syntic_web_fetch", "url": "https://shop.example.com/returns", "status": "ok", "content_tokens": 1830, "truncated": false }
]
},
"usage": { "prompt_tokens": 2410, "completion_tokens": 19, "total_tokens": 2429, "server_tool_use": { "web_fetch_requests": 1 } }
}status | Meaning |
|---|---|
ok | Content read. |
not_allowed | Address not in the conversation, blocked by domain rules or not public. |
failed | Timeout, HTTP error or unsupported content. |
too_large | Over 10 MB. |
Failed fetches are reported to the model, which explains the problem or tries another source.
Examples
curl https://app.syntic.ai/v1/chat/completions \
-H "Authorization: Bearer $SYNTIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "Amara S1.2",
"stream": false,
"tools": [{ "type": "syntic_web_fetch", "max_uses": 2, "citations": { "enabled": true } }],
"messages": [{ "role": "user", "content": "Summarise https://shop.example.com/returns in three bullet points." }]
}'Errors
Unified envelope. Individual fetch failures do not fail the request.
| Status | code | Cause |
|---|---|---|
| 400 | server_tool_not_supported | The model cannot use web fetch. |
| 400 | invalid_domain_filter | Both lists sent or malformed domains. |
| 400 | invalid_max_content_tokens | Above 100,000. |
| 403 | tool_disabled | Turned off for your organisation. |
Pricing and limits
| Fetch fee | None. You pay only for the fetched content as input tokens. |
| Fetches per request | 20 |
| Timeout | 15 seconds per fetch |
| Cache | Pages are cached for up to 15 minutes per organisation. |
Build notes for the platform team
- Same server-side loop as web search; ship right after it.
- Every fetch and every redirect hop goes through the shared outbound URL checks with DNS pinning.
- Enforce the “address already in the conversation” rule in the server, not in the prompt.