# marklipi API reference

marklipi converts text-layer PDFs to clean Markdown. It is built for agents: stateless, zero-config, no API key for basic use, structured JSON responses. No vision model — fast and cheap for documents that have a text layer (bank statements, ownership records, contracts, tables).

- **Base URL:** `https://api.marklipi.com`
- **OpenAPI spec:** [https://api.marklipi.com/openapi.json](https://api.marklipi.com/openapi.json)
- **Auth:** none required
- **Formats:** request `multipart/form-data`, response `application/json`
- **Status:** public beta — free, rate-limited (see [Rate limits](#rate-limits)).

## Quickstart

Convert a PDF with one request — upload the file, get Markdown back:

```bash
curl -s https://api.marklipi.com/convert \
  -F "file=@statement.pdf"
```

```json
{
  "markdown": "# Account Statement\n\n| Date | Description | Amount |\n| --- | --- | --- |\n...",
  "filename": "statement.pdf",
  "characters": 18342
}
```

## POST /convert

Convert a PDF to Markdown. Stateless: the file is processed in memory and discarded — nothing is stored.

### Request

`multipart/form-data` with a single field:

| Field  | Type   | Required | Description                          |
| ------ | ------ | -------- | ------------------------------------ |
| `file` | binary | yes      | The PDF file to convert. Max 25 MB. |

The API accepts file uploads only — there is no URL parameter. If the PDF lives at a URL, download it yourself and upload the bytes.

### Response — 200 OK

| Field        | Type    | Description                                  |
| ------------ | ------- | -------------------------------------------- |
| `markdown`   | string  | The converted Markdown.                      |
| `filename`   | string  | Echo of the uploaded filename.               |
| `characters` | integer | Length of the Markdown output in characters. |

### Errors

All errors return JSON: `{"detail": "<human-readable message>"}`.

| Status | Meaning                                                                                          |
| ------ | ------------------------------------------------------------------------------------------------ |
| `413`  | File exceeds the 25 MB upload limit.                                                             |
| `422`  | Conversion produced empty output — usually a scanned/image-only PDF with no text layer.          |
| `429`  | Rate limit exceeded. Honor the `Retry-After` response header (seconds) before retrying.          |
| `502`  | PDF conversion failed — corrupt or unsupported file.                                             |

### Examples

Python (httpx):

```python
import httpx

with open("statement.pdf", "rb") as f:
    response = httpx.post(
        "https://api.marklipi.com/convert",
        files={"file": ("statement.pdf", f, "application/pdf")},
        timeout=60,
    )
response.raise_for_status()
print(response.json()["markdown"])
```

JavaScript (fetch):

```js
const form = new FormData();
form.append("file", pdfBlob, "statement.pdf");

const res = await fetch("https://api.marklipi.com/convert", {
  method: "POST",
  body: form,
});
if (!res.ok) throw new Error((await res.json()).detail);
const { markdown } = await res.json();
```

## GET /health

Liveness check. Returns the running API version.

```bash
curl -s https://api.marklipi.com/health
```

```json
{ "status": "ok", "version": "0.1.0" }
```

## Rate limits

Per client IP, on `/convert`:

| Limit        | Window     |
| ------------ | ---------- |
| 10 requests  | per minute |
| 100 requests | per day    |

On `429`, the `Retry-After` header tells you how many seconds to wait. Back off for that long — retrying sooner only re-triggers the limit. Need more? See [Pricing](#pricing).

## Pricing

The free tier stays free — no key, no signup. Paid tiers lift the daily limit on `/convert`:

| Tier               | Price       | Limits                                                |
| ------------------ | ----------- | ----------------------------------------------------- |
| Free               | $0          | 10/min, 100/day per IP. No key.                       |
| Founding Supporter | $5 one-time | 1,000 conversions/day for life. First 20 buyers only. |
| Pro                | $19/month   | 25,000 conversions/day, priority support.             |

To buy: email [hello@dovey.com.au](mailto:hello@dovey.com.au?subject=Founding%20Supporter) with the tier name. Paid keys are issued by email within 24 hours of purchase, along with usage instructions.

## What it's good at (and not)

marklipi extracts the existing text layer. It does **not** run OCR or a vision model.

- **Great:** digital-native PDFs — bank statements, invoices, contracts, government records, reports, tables.
- **Returns 422:** scanned documents, photos of documents, image-only PDFs. Use an OCR or vision pipeline for those.

Rule of thumb: if you can select text in the PDF, marklipi can convert it.

## Privacy

Stateless by design: no sessions, no persistence. Uploaded files are processed in memory and discarded — nothing is stored.

## Machine-readable resources

- [llms.txt](https://marklipi.com/llms.txt) — index of agent-readable resources
- [llms-full.txt](https://marklipi.com/llms-full.txt) — this entire documentation in one file
- [docs.md](https://marklipi.com/docs.md) — this page as raw Markdown
- [openapi.json](https://api.marklipi.com/openapi.json) — OpenAPI 3.1 spec
