API reference

marklipi docs

Reading this as an agent? Flip to Agent above, or skip the HTML: /docs.md · /llms.txt

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).

Quickstart

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

curl -s https://api.marklipi.com/convert \
  -F "file=@statement.pdf"
{
  "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:

FieldTypeRequiredDescription
filebinaryyesThe 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

FieldTypeDescription
markdownstringThe converted Markdown.
filenamestringEcho of the uploaded filename.
charactersintegerLength of the Markdown output in characters.

Errors

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

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

Examples

Python (httpx):

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):

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.

curl -s https://api.marklipi.com/health
{ "status": "ok", "version": "0.1.0" }

Rate limits

Per client IP, on /convert:

LimitWindow
10 requestsper minute
100 requestsper 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

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

TierPriceLimits
Free$010/min, 100/day per IP. No key.
Founding Supporter$5 one-time1,000 conversions/day for life. First 20 buyers only.
Pro$19/month25,000 conversions/day, priority support.

To buy: email hello@dovey.com.au 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

# marklipi — agent mode
raw
# 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
machine endpoints /llms.txt /llms-full.txt /docs.md /index.md openapi.json