Fetch any URL and receive its summary as text, not JSON. Choose length (short, medium, long) or an exact max_words target, the format (plain text or markdown) and the language (defaults to the page’s own). Add free-text instructions to steer the summary: what to focus on, the audience or tone, a question to answer from the page. The response also includes key_points (the bullet form of the summary), the page title and the detected language.
HTTP Request
Send the parameters as a JSON body. The same parameters are also accepted as query-string parameters on a GET request. Same handler, same billing, same errors.
| |
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | — | Absolute http(s) URL to fetch. URL-encode it on GET if it has its own query string |
length | string | No | medium | How long: short is about 1-2 sentences (about 60 words), medium is about one paragraph (about 150 words), long is 3-5 short paragraphs (about 400 words). A target the model aims for, not a hard limit. Ignored when max_words is set |
max_words | integer | No | — | Word target (20-1000) that overrides length. Plain text lands within about 10% of the target; markdown and non-English output can run about 30% over. The text is never cut, treat it as a target, not a hard limit |
format | string | No | text | Shape of summary: text (plain prose) or markdown (prose with light markdown, short headings and emphasis). The bullet form is always available in key_points |
language | string | No | page’s language | Language to write the summary in, as a lowercase ISO-639-1 code with optional region (en, es, pt-BR). Omit to use the page’s own language |
instructions | string | No | — | Extra instructions, max 1000 characters: what to focus on (pricing and delivery), audience or tone (for a 10-year-old), a question to answer from the page (what does it say about refunds?), things to leave out. The summary never invents facts that are not on the page: if the page does not cover what you ask, it says so |
render_js | string | No | auto | false = plain HTTP fetch; true = headless browser rendering; auto = HTTP first, browser only if blocked |
proxy_type | string | No | datacenter | datacenter or isp (static-residential exits, higher trust with strict targets, higher credit cost) |
session_id | string | No | — | Sticky handle (1-64 chars A-Za-z0-9_-): the same value always routes through the same outbound IP. Omit to get a fresh one; the id used is returned in data.session_id |
cookies | object / string / array | No | — | Cookies to send: object, a=1; b=2 string, or a list of {name, value} objects. Only used on the HTTP path. GET form: the cookie string |
user_agent | string | No | — | User-Agent to send. Drives the TLS and header fingerprint automatically. Only used on the HTTP path |
headers | object | No | — | Extra request headers. Reserved names (Host, Cookie, User-Agent, Content-Length, sec-, x-forwarded-, cf-*, Authorization) are rejected. GET form: a JSON object string |
method | string | No | GET | HTTP method used against the target: GET or POST |
body | string | No | — | Request body sent to the target when method is POST. Requires a Content-Type in headers |
wait_for | string | No | — | Browser path only: after the page loads, wait for this CSS selector to appear before capturing (lazy-loaded content). Waits at most 15 s and never past timeout |
timeout | integer | No | 25 | Total budget in seconds for the whole request, fetch and rendering included (max 27) |
fields | string | No | — | Comma-separated allow-list of data keys to return, e.g. summary,key_points. Unknown names return a 400 listing the valid ones |
Response
The response returns a JSON object with the summary plus fetch details.
| |
Response Fields
| Field | Type | Description |
|---|---|---|
status | boolean | true when the summary was produced; false when data.ai_error is set |
request_id | string | Unique identifier for the request |
data.url | string | Final URL after redirects |
data.http_status | integer | HTTP status the site returned for the final document, never masked |
data.summary | string | null | The summary, in the requested format and language. Null when no summary was produced (see ai_error) |
data.key_points[] | array | 3-7 short takeaways from the page, in page order (the bullet form of the summary). Empty when summary is null |
data.language | string | null | Language the summary is written in, as an ISO-639-1 code; null when unknown |
data.title | string | null | The page <title>; null when the page has none |
data.truncated | boolean | True when the page was longer than the model budget and only its first part was summarized. Never about the summary’s own length |
data.ai_error | string | null | Set when summary is null although a page was fetched: blocked, empty_page, llm_timeout, llm_error or invalid_output. See Error Responses below |
data.blocked | boolean | True when the site served an anti-bot challenge or rejection instead of content |
data.block_reason | string | null | Why it was considered blocked, a stable slug (cloudflare_challenge, captcha, rate_limited, forbidden, …); null when not blocked |
data.detected_protection | string | null | Anti-bot vendor detected on the page (cloudflare, akamai, datadome, perimeterx, incapsula). Informational: it does not mean the request was blocked |
data.render_used | string | Which path fetched the page: plain http or headless browser rendering |
data.credits | integer | Requests billed for this call. 0 when the target blocked the request |
data.elapsed_ms | integer | Total time the request took, fetch and summary included, in milliseconds |
data.session_id | string | Sticky-session handle used for this request. Reuse it to keep the same outbound IP |
data.proxy_type | string | Proxy pool this request went out of |
Error Responses
Errors use a consistent envelope: {"status": false, "error": "description", "request_id": "..."}.
| Code | When |
|---|---|
400 | Invalid request (bad URL, reserved header, out-of-range timeout, unknown fields name, invalid language code, body without a Content-Type), or the URL points at a non-public address |
415 | The URL returned a non-textual document (for example image/png) |
502 | The target could not be fetched. The body reads could not fetch target: <reason> where <reason> is a fixed slug (DNS failure, connection refused, TLS error, timeout), never raw library text |
503 | Service temporarily unavailable (our infrastructure, not the target) |
Thin pages: a page with no readable text, common for script-rendered pages fetched over plain HTTP, returns HTTP 200 with summary: null and ai_error: "empty_page". Retry with render_js=true.
Code Examples
| |
| |
| |
Related
- AI Article Extractor & Summarizer API Documentation — index, authentication and billing