# Save API — URL to Markdown

> Turn any URL into clean, LLM-ready Markdown with one HTTP call. Built for AI agents, RAG pipelines, and scrapers. The same engine behind the Save extension, as a developer API.

This page is the agent-readable spec. Human docs: https://www.savemarkdown.co/api

## Endpoint

```
POST https://api.savemarkdown.co/v1/convert
Authorization: Bearer sk_live_...
Content-Type: application/json
```

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | string | yes | The page to convert. http(s) only. |
| `template` | string | no | Omit for raw Markdown (no LLM). Pass an AI template (`clean`, `summary`, `outline`, …) to reshape the content with an LLM (token-metered). |
| `render` | `"auto"` \| `"never"` \| `"always"` | no | JavaScript rendering. Default `"auto"` escalates to a headless render only when a page is a JS shell. |
| `fresh` | boolean | no | Bypass the 24h cache and refetch. |

## Response

```json
{
  "markdown": "📄 Title: Example Article\n🔗 Source: ...\n\n---\n\n## Heading\n\nClean body...",
  "meta": { "tier": 1, "cached": false, "domain": "example.com", "template": "markdown" },
  "usage": { "credits": 1 }
}
```

`meta.tier` is `1` (fetch + extract, no LLM), `2` (headless render), or `"adapter"` (platform channel, e.g. YouTube). It tells you which rate applied.

## Examples

### curl

```bash
curl -X POST https://api.savemarkdown.co/v1/convert \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/article"}'
```

### JavaScript

```js
const res = await fetch("https://api.savemarkdown.co/v1/convert", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SAVE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ url: "https://example.com/article" }),
});
const { markdown } = await res.json();
```

### Python

```python
import os, requests
res = requests.post(
    "https://api.savemarkdown.co/v1/convert",
    headers={"Authorization": f"Bearer {os.environ['SAVE_API_KEY']}"},
    json={"url": "https://example.com/article"},
)
print(res.json()["markdown"])
```

## Errors

| Status | Meaning |
| --- | --- |
| 400 | Bad request (missing/invalid `url`, blocked address) |
| 401 | Missing or invalid API key |
| 403 | API not yet enabled for live keys |
| 422 | Could not extract readable content |
| 429 | Rate limit exceeded (`Retry-After` header) |

## How it works

1. **Fetch** — server-side request with a real browser fingerprint and an SSRF guard. Static/SSR pages stop here (cheapest).
2. **Render** — if a page is a JavaScript shell, escalate to a headless render, then extract.
3. **Extract** — strip nav, ads, cookie banners and boilerplate; keep headings, lists, links, images, code.

## Pricing

| Tier | Price |
| --- | --- |
| Markdown (fetch + extract, no LLM) | $2 / 1,000 pages |
| Rendered (JavaScript pages) | $8 / 1,000 pages |
| AI-formatted (templates) | $3 / $25 per 1M input / output tokens |

Free trial: 100 pages. Pay as you go, no seats.

## Walled gardens

YouTube routes through its official transcript channel. X / Instagram / TikTok are best-effort. We never use ghost accounts or scrape behind logins.

## Access — get a free key instantly (no human, no card)

```bash
curl -X POST https://api.savemarkdown.co/v1/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com"}'
```

Returns `{ "key": "sk_test_…", "monthlyLimit": 100 }`. The key is shown once. Free tier: 100 conversions/month. Then use it as `Authorization: Bearer <key>` on `/v1/convert`. Higher limits / paid plan: hello@savemarkdown.co

## Discovery

- Agent skills: https://www.savemarkdown.co/.well-known/agent-skills/index.json (`save.api.url-to-markdown`)
- API catalog: https://www.savemarkdown.co/.well-known/api-catalog.json
- llms.txt: https://www.savemarkdown.co/llms.txt
