# Web Page to Markdown API

> Clean article text from any page as Markdown, ready for LLM ingestion.

Fetches a page, extracts the main article with a Readability algorithm, converts it to Markdown with headings, lists, code blocks, tables, absolute links and images, and returns it with the title, byline, excerpt and word count. Send `mode=full` for the whole body instead of the article, or POST raw `html` to convert your own markup.

- **Endpoint:** `GET https://api.zactonz.com/markdown/`
- **Category:** Web
- **Version:** 1
- **Status:** stable
- **Authentication:** `Authorization: Bearer YOUR_API_KEY`
- **Reference page:** https://developers.zactonz.com/apis/markdown/

## Parameters

Send parameters in the query string.

| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| `url` | string | no |  | The page to convert. Omit it and POST `html` to convert markup you already have. |
| `mode` | enum | no | `article` | `article` (default) keeps the main content. `full` converts the whole body. Allowed values: `article`, `full`. |
| `render` | boolean | no | `false` | `1` loads the page in a headless browser first. |
| `images` | boolean | no | `true` | `0` drops images from the output. |
| `links` | boolean | no | `true` | `0` replaces links with their text. |
| `max_chars` | integer | no | `100000` | Maximum Markdown length, 1000 to 500000. |
| `format` | enum | no | `json` | `json` (default) or `text` to receive the Markdown body alone as `text/markdown`. Allowed values: `json`, `text`. |
| `fresh` | boolean | no | `false` | `1` bypasses the cache. |

## Example request

```bash
curl "https://api.zactonz.com/markdown/?url=https%3A%2F%2Fdevelopers.zactonz.com%2Fapis%2Fauthentication%2F&mode=article&render=&images=1&links=1&max_chars=100000&format=json&fresh=" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## Response

OK

| Field | Type | Description |
|---|---|---|
| `status` | integer | `200` on success. |
| `data` | object | The result. |
| `data.url` | string | Final URL. |
| `data.title` | string | Article title. |
| `data.byline` | string | Author when declared. |
| `data.excerpt` | string | Short summary. |
| `data.site_name` | string | Site name. |
| `data.language` | string | Page language. |
| `data.image` | string | Lead image URL. |
| `data.published_time` | string | Publication date as declared. |
| `data.mode` | string | `article` or `full`; falls back to `full` when no article could be isolated. |
| `data.word_count` | integer | Words in the Markdown. |
| `data.length` | integer | Characters in the Markdown. |
| `data.truncated` | boolean | Whether `max_chars` cut the output. |
| `data.markdown` | string | The Markdown. |
| `data.rendered` | boolean | Whether a browser was used. |
| `data.from_cache` | boolean | Whether the answer came from the cache. |

```json
{
    "status": 200,
    "data": {
        "url": "https://developers.zactonz.com/apis/authentication/",
        "title": "Authentication",
        "byline": null,
        "excerpt": "Every request needs an API key, sent as a Bearer token in the Authorization header.",
        "site_name": null,
        "language": "en",
        "image": null,
        "published_time": null,
        "mode": "article",
        "word_count": 72,
        "length": 2688,
        "truncated": false,
        "markdown": "Every endpoint on `api.zactonz.com` requires an API key. Send it on each request in the `Authorization` header using the Bearer scheme:\n\n```\nAuthorization: Bearer YOUR_API_KEY\n```\n\n## Example\n\n…",
        "rendered": false,
        "from_cache": false
    }
}
```

## Status codes

The outcome is reported in the JSON `status` field. General rules: https://developers.zactonz.com/apis/errors.md

| status | Meaning | Description |
|---|---|---|
| `400` | Bad request | Neither `url` nor `html` was provided, or the URL is not reachable from here. |
| `413` | Too large | The page or the posted HTML exceeds the size limit. |
| `415` | Not HTML | The URL does not serve HTML or plain text. |
| `422` | Unreachable | The page could not be fetched. |
| `401` | Unauthorized | The Authorization header is missing or the key is not recognised. |
| `403` | Forbidden | The key is not licensed for this product. |
| `429` | Too many requests | The per-minute rate or the plan quota is exhausted. Retry after the seconds given in `Retry-After`. |

## Notes

Scripts, styles, forms, iframes and hidden elements are removed. Output is capped by `max_chars` and flagged `truncated` when cut. Pages that only render with JavaScript need `render=1`, which costs 5 units instead of 2. Results are cached for an hour per URL and option set.
