PDF to Markdown API

The MarkdFlow conversion API takes a document — as a base64 payload, a public URL, or an already-uploaded file URL — and returns structured Markdown plus per-block confidence scores. One credit is charged per processed page, and failed conversions cost nothing.

Updated

Endpoint

POST https://markdflow.org/api/convert
Content-Type: application/json
Authorization: Bearer mf_live_YOUR_KEY

{
  "fileName":   "quarterly-report.pdf",
  "mimeType":   "application/pdf",
  "sourceType": "pdf",
  "fileData":   "data:application/pdf;base64,JVBERi0xLjQK...",
  "pageCount":  12
}

At least one source field must be provided: fileData (inline base64 data URL), rawText (plain text), documentUrl (public HTTPS URL) or fileUrl (a file already uploaded to our storage).

Authentication

Every request needs one of two credentials:

  • API key (recommended for scripts) — send Authorization: Bearer mf_live_.... Create keys in your profile under API Keys: name them, copy the key once, revoke any time. Up to 5 active keys per account; email verification required.
  • Session cookie — works for browser extensions and tools that already run inside your signed-in session.

Keys are shown once: The full key is displayed only at creation time and we store only its SHA-256 hash, so a database leak can never reveal it. If you lose the key, revoke it and create a new one.

Request fields

FieldTypeDescription
fileNamestringOriginal file name. Used to infer the source type from the extension.
fileSizenumberSize in bytes.
mimeTypestringMIME type of the source.
sourceTypestringOne of image | pdf | text | document. Inferred from fileName when omitted.
fileDatastringInline base64 data URL of the document.
rawTextstringPlain text content for text and source files.
documentUrlstringPublic HTTPS URL to fetch. Subject to SSRF checks.
fileUrlstringURL of a file already uploaded through the upload endpoint.
pageCountnumberKnown page count, used for the pre-flight credit check.

Examples

curl -X POST https://markdflow.org/api/convert \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer mf_live_YOUR_KEY" \
  -d '{
    "fileName": "invoice.pdf",
    "mimeType": "application/pdf",
    "fileData": "data:application/pdf;base64,'"$(base64 -i invoice.pdf)"'"
  }'
import base64, requests

API_KEY = "mf_live_YOUR_KEY"

def to_markdown(path: str) -> dict:
    with open(path, "rb") as fh:
        data_url = "data:application/pdf;base64," + base64.b64encode(fh.read()).decode()

    res = requests.post(
        "https://markdflow.org/api/convert",
        headers={
            "Content-Type": "application/json",
            "Authorization": f"Bearer {API_KEY}",
        },
        json={"fileName": path.split("/")[-1], "mimeType": "application/pdf", "fileData": data_url},
        timeout=120,
    )
    res.raise_for_status()
    return res.json()

result = to_markdown("quarterly-report.pdf")
print(result["markdownText"])
print("blocks:", result["blocksCount"], "confidence:", result["confidence"])
import fs from "node:fs/promises";

const API_KEY = "mf_live_YOUR_KEY";
const buf = await fs.readFile("paper.pdf");

const res = await fetch("https://markdflow.org/api/convert", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${API_KEY}`,
  },
  body: JSON.stringify({
    fileName: "paper.pdf",
    mimeType: "application/pdf",
    fileData: "data:application/pdf;base64," + buf.toString("base64"),
  }),
});

if (!res.ok) {
  const { error } = await res.json();
  throw new Error(error);
}

const { markdownText, blocks, confidence } = await res.json();

Response

On success you get the Markdown plus structural metadata:

FieldDescription
markdownTextThe converted Markdown
blocksPer-block array: type, readingOrder, confidence, content
blocksCountCounts by type: headers, paragraphs, tables, equations, lists
confidenceOverall confidence for the document
detectedLanguageDetected language code
wordCount / charCountSize of the output
pagesProcessedPages actually processed — this is what you are charged for

Error codes

StatusCodeMeaning
400invalid_json | unsupported_source_type | document_requiredMalformed body or no usable source
401unauthorizedNo valid session
402points_insufficientNot enough credits for the estimated pages
413url_too_largeRemote document exceeds 50 MB
415unsupported_url_formatURL points at an unsupported type
422invalid_url | url_blocked | url_unreachableURL failed validation or could not be fetched
429rate_limitedToo many requests (30/hour per IP, 60/hour per user)
503mistral_not_configured | conversion_failedUpstream OCR failure — no credits charged

Billing on failure: Credits are pre-checked but only deducted after a successful conversion, based on the pages actually processed. Failed, mock and unconfigured conversions cost nothing.

Limits and pricing

  • 1 credit = 1 processed page.
  • Max file size: 10 MB free tier, 20 MB trial, 50 MB Pro and Annual.
  • Rate limits: 30 requests per hour per IP, 60 per hour per user (session and API-key requests share the user limit).
  • Up to 5 active API keys per account; keys are revocable at any time.
  • Remote URLs are fetched with SSRF protection; private and metadata addresses are blocked.

Frequently asked questions

How much does an API conversion cost?

One credit per processed page. Failed conversions are not charged.

Can I send a URL instead of a file?

Yes — documentUrl accepts a public HTTPS URL up to 50 MB. Private, localhost and cloud metadata addresses are blocked.

Do you return table structure?

Yes. Tables are returned as Markdown tables inside markdownText, and are counted in blocksCount.tables so you can assert on them.

Are there long-lived API keys?

Yes. Create keys in your profile under API Keys (email verification required, up to 5 active keys). The key is shown once and only its hash is stored, and you can revoke it any time.

What are the rate limits?

30 requests per hour per IP and 60 per hour per user. Exceeding them returns 429 rate_limited.

Related guides

Wire document conversion into your pipeline

One endpoint, per-page pricing, per-block confidence. Start with 30 free credits.