# Read endpoint reference: GET and POST /read

> Read endpoint reference: every parameter of GET and POST /read, from format and render to country and max_chars, with examples. From $0.07/1K pages, no KYC.

- URL: https://webreaderapi.com/docs/read/
- Last updated: 2026-10-22
- Publisher: WebReaderAPI (https://webreaderapi.com)

`/read` fetches one public page, extracts its main content and returns it as Markdown, plain text or cleaned HTML. This page lists every parameter, its default and what it costs.

**Quick answer — What parameters does the WebReaderAPI read endpoint take?**

**WebReaderAPI**'s `/read` endpoint needs one parameter, `url`. Optional ones choose the output (`format`), how much of the page to keep (`main_content`), whether a browser runs (`render`), links and images, the reading country, a character cap and a timeout. A plain page costs 1 credit, 2 with a browser, from $0.07/1K pages as of October 2026. No KYC; pay in crypto.

## /read at a glance

| Attribute | Value |
| --- | --- |
| Methods | `GET` with query parameters, or `POST` with a JSON body using the same names |
| URL | `https://webreaderapi.com/api/v1/read` |
| Required | `url`: an http or https address, up to 2,048 characters |
| Default output | Markdown of the main content |
| Billing | 1 credit = 1 page read without a browser; 2 credits when the page needs a browser to render JavaScript. A request that fails, or that a site's robots.txt refuses, is not charged |
| Country | Choosing the country a page is read from adds 10 credits, because the page is then read through a residential connection in that country |
| PDF | PDF files up to 20 MB and 100 pages are converted to Markdown, at 1 credit per started block of 10 pages |
| Crawler identity | `WebReaderAPI/1.0 (+https://webreaderapi.com/bot/)` |

## Read one page (GET)

`GET /api/v1/read`

Fetches one public page and returns its main content as Markdown, with the page's metadata. Parameters go in the query string, URL-encoded. The example reads a blog post; IDs, dates and values are illustrative.

Authentication: API key in the `Authorization: Bearer API_KEY` header.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `url` | query | string | Yes | The page to read: http or https, at most 2,048 characters. Private, local and cloud metadata addresses are refused. |
| `format` | query | string | No | `markdown` (default), `text` (plain text, no markup) or `html` (cleaned HTML of the content). |
| `main_content` | query | boolean | No | `true` (default) keeps the article or main content only; `false` converts the whole page, menus and footer included. |
| `render` | query | string | No | `auto` (default) starts a browser only when the raw HTML holds too little text; `true` always; `false` never. A rendered page costs 2 credits. |
| `include_links` | query | boolean | No | `true` adds a `links` list of `{url, text}`. Default `false`. |
| `include_images` | query | boolean | No | `true` keeps images as `![alt](src)` in the Markdown. Default `false`. |
| `country` | query | string | No | Two-letter country code (ISO 3166-1 alpha-2). The page is read from an address in that country, for 10 extra credits (residential connection). |
| `max_chars` | query | integer | No | Cuts the output at this many characters, from 1,000 to 500,000. Useful to fit a model's context. |
| `timeout` | query | integer | No | Seconds to wait for the site, from 5 to 60. Default 30. |
| `api_key` | query | string | No | Your key, if you do not send the `Authorization` header. |

**Response** `200`

```json
{
  "url": "https://example.com/blog/first-post",
  "final_url": "https://example.com/blog/first-post",
  "status_code": 200,
  "fetched_at": "2026-10-22T09:41:12Z",
  "rendered": false,
  "credits_used": 1,
  "title": "Our first post",
  "description": "Why we started this blog and what comes next.",
  "language": "en",
  "author": "Jane Doe",
  "published_at": "2026-10-01",
  "site_name": "Example Blog",
  "markdown": "# Our first post\n\nWe started this blog to share what we learn...\n\n## What comes next\n\n- A post every month\n- Notes from our team",
  "word_count": 612
}
```

*curl*

```bash
curl -sG "https://webreaderapi.com/api/v1/read" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  --data-urlencode "url=https://example.com/blog/first-post" \
  -d format=markdown -d max_chars=20000
```

*Python*

```python
import os
import requests

resp = requests.get(
    "https://webreaderapi.com/api/v1/read",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    params={"url": "https://example.com/blog/first-post", "max_chars": 20000},
    timeout=70,
)
resp.raise_for_status()
print(resp.json()["markdown"][:300])
```

*Node.js*

```javascript
const params = new URLSearchParams({ url: 'https://example.com/blog/first-post', max_chars: '20000' });
const res = await fetch(`https://webreaderapi.com/api/v1/read?${params}`, {
  headers: { Authorization: `Bearer ${process.env.WEBREADER_API_KEY}` },
});
const page = await res.json();
console.log(page.markdown.slice(0, 300));
```

## Read one page (POST)

`POST /api/v1/read`

Same endpoint, same parameters, sent as a JSON body. Prefer POST when the URL is very long or when your HTTP client builds JSON more easily than query strings. The response is identical to the GET form.

Authentication: API key in the `Authorization: Bearer API_KEY` header.

**Request body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | string | Yes | The page to read. |
| `format`, `main_content`, `render`, `include_links`, `include_images`, `country`, `max_chars`, `timeout` | mixed | No | As in the GET table above, with JSON types: booleans as `true`/`false`, numbers unquoted. |

*Example: a JavaScript-heavy page, read from Germany, with its links*

```json
{
  "url": "https://example.com/app/pricing",
  "render": "true",
  "country": "de",
  "include_links": true,
  "max_chars": 30000
}
```

**Response** `200`

```json
{
  "url": "https://example.com/app/pricing",
  "final_url": "https://example.com/de/app/pricing",
  "status_code": 200,
  "fetched_at": "2026-10-22T09:44:03Z",
  "rendered": true,
  "credits_used": 3,
  "title": "Pricing",
  "language": "de",
  "markdown": "# Pricing\n\n| Plan | Price |\n|---|---|\n| Basic | ... |",
  "word_count": 214,
  "links": [
    {
      "url": "https://example.com/de/contact",
      "text": "Contact"
    }
  ]
}
```

*curl*

```bash
curl -s "https://webreaderapi.com/api/v1/read" \
  -H "Authorization: Bearer $WEBREADER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/app/pricing", "render": "true", "country": "de", "include_links": true}'
```

*Python*

```python
import os
import requests

resp = requests.post(
    "https://webreaderapi.com/api/v1/read",
    headers={"Authorization": "Bearer " + os.environ["WEBREADER_API_KEY"]},
    json={"url": "https://example.com/app/pricing", "render": "true", "country": "de", "include_links": True},
    timeout=70,
)
print(resp.json()["credits_used"], "credits")
```

*Node.js*

```javascript
const res = await fetch('https://webreaderapi.com/api/v1/read', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.WEBREADER_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ url: 'https://example.com/app/pricing', render: 'true', country: 'de', include_links: true }),
});
console.log((await res.json()).credits_used);
```

## Which output format should I choose?

Choose `markdown` for language models and RAG: headings, lists, tables and links survive, and the text stays compact. Choose `text` when you only count words, classify or search, and markup would be noise. Choose `html` when your own pipeline already parses HTML and you only want the clutter gone.

The metadata fields are the same in all three formats. Only the name of the content field changes: `markdown`, `text` or `html`.

## When should I set main_content to false?

Set it to `false` when the parts around the article are what you need. Examples are a site's navigation to map its sections, a footer with legal or contact details, or a product page whose specifications sit in a sidebar.

With the default `true`, the extractor keeps the main content block and drops navigation, cookie banners, ads, share buttons and footers. That is what most agents and RAG pipelines want, and it often cuts a page to a fraction of its HTML size.

## How does render=auto decide to use a browser?

It first fetches the raw HTML, which is fast and costs 1 credit. If that HTML holds too little readable text, typically an app that builds the page with JavaScript, it loads the page again in a headless browser and the call costs 2 credits. The response tells you which path ran: `rendered` is `true` or `false`.

Set `render=false` when you know the site serves full HTML and want a fixed cost. Set `render=true` for single-page apps, to skip the first attempt.

## What do country and max_chars change?

`country` reads the page from an address in the country you name, with the same User-Agent. Use it for pages whose prices, language or availability change by country. It adds 10 credits, because the page is then read through a residential connection, and it cannot be used with the countries the service does not operate in.

`max_chars` cuts the output after that many characters. It does not change the price, but it protects an agent's context window: 20,000 characters is a sensible default for a single page passed to a model.

## Can /read handle PDF files?

Yes. When the URL returns a PDF, the text comes back as Markdown in the same `markdown` field. PDF files up to 20 MB and 100 pages are converted to Markdown, at 1 credit per started block of 10 pages. Scanned PDFs without a text layer return little or no text, because there is no character recognition step.

## Read endpoint: common questions

### Does /read follow redirects?

Yes, up to 5. The response gives the address you asked for in `url` and the address actually read in `final_url`. A redirect to a private or local address is refused.

### Can I read a page that needs a login?

No. If a site refuses our request, we return its answer: we never solve CAPTCHAs, log in to accounts, or try to get around a block or a paywall. Pages behind a login or a paywall return the site's refusal, and the call is free.

### Is the robots.txt check done on every call?

Yes, against a copy of the site's robots.txt that is at most 24 hours old. A disallowed URL returns `403 blocked_by_robots` and uses no credit.

### How many pages can I read at the same time?

Every account has a limit on how many pages it reads at once; your dashboard shows it, and support can raise it. For many URLs, a [batch job](https://webreaderapi.com/docs/crawl/) is simpler than running many parallel calls.

---

WebReaderAPI: WebReaderAPI is a web reader API for AI agents that turns any public web page into clean Markdown, paid in crypto with no ID upload. Prepaid credits from $0.07/1K pages never expire, and robots.txt is respected. No KYC — no ID, no selfie, no documents. Pay in crypto.
