Blog

How to convert a PDF to Markdown with Python, Node.js, or curl

Published July 7, 2026 · Read as Markdown

The fastest way to convert a PDF to Markdown programmatically is a single HTTP request: POST the file to https://api.marklipi.com/convert and you get JSON back with the Markdown inside. No API key, no signup, no library to install — the free tier allows 10 conversions a minute and 100 a day per IP.

This works for text-layer PDFs: bank statements, contracts, invoices, reports, papers — anything where you can select the text in a PDF viewer. Scanned or image-only PDFs need OCR instead (here’s how to tell the difference).

Convert a PDF to Markdown with curl

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

Response:

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

That’s the whole integration. Save just the Markdown with jq:

curl -s https://api.marklipi.com/convert -F "file=@statement.pdf" | jq -r .markdown > statement.md

Convert a PDF to Markdown in Python

No SDK needed — the standard requests library does it:

import requests

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

with open("statement.md", "w") as out:
    out.write(markdown)

Feeding the result to an LLM afterwards? Markdown typically costs 60–90% fewer tokens than pushing the raw PDF at a vision model — the token math is here.

Convert a PDF to Markdown in Node.js

Modern Node (18+) has fetch and FormData built in:

import { readFile } from "node:fs/promises";

const bytes = await readFile("statement.pdf");
const form = new FormData();
form.append("file", new Blob([bytes], { type: "application/pdf" }), "statement.pdf");

const resp = await fetch("https://api.marklipi.com/convert", {
  method: "POST",
  body: form,
});
if (!resp.ok) throw new Error(`convert failed: ${resp.status}`);

const { markdown } = await resp.json();
console.log(markdown);

Handling errors

The API returns errors as JSON with a detail field:

StatusMeaningWhat to do
413File over 25 MBSplit the PDF or compress it
422No text layer (scanned/image PDF)Route to an OCR pipeline instead
429Rate limit hit (10/min or 100/day per IP)Back off and retry, or get a key with higher limits

The 422 behavior is deliberate: marklipi extracts the existing text layer and never runs OCR, so a scan returns a clear error instead of hallucinated text.

Why not just use a Python PDF library?

Libraries like pdfplumber, PyMuPDF, or Marker work well if you want local processing and are happy managing the dependency (and for Marker, a GPU). The trade-off is setup and maintenance versus one stateless HTTP call. Files sent to marklipi are processed in memory and discarded — nothing is stored. For a comparison of the options, see the best PDF-to-Markdown tools compared.

FAQ

Do I need an API key?

No. Basic use is keyless — the free tier is 10 conversions/minute and 100/day per IP.

What’s the maximum file size?

25 MB per PDF.

Does it keep tables?

Yes — tables in the text layer come out as Markdown tables, which is most of the point for statements and financial documents.

Can I run this from a browser instead?

Yes — the free in-browser converter uses the same API with a drag-and-drop UI.

Try it on a real PDF.

Free in-browser converter, no signup — or one curl to the API.