API v1 · Production ready

Markdown to PDF API

Turn Markdown into a clean, print-ready PDF or PNG. Tables, task lists and syntax highlighted code all render correctly — with thirteen typefaces, a full colour palette, and complete control over page size, orientation and margins.

Get started free Documentation POST https://api.corenexis.com/markdown-to-pdf/v1
13 TypefacesSans, serif, mono, Devanagari
1,000+ PagesLong documents supported
PDF + PNGPage images for long documents
InstantSynchronous response
Features

Built for every Markdown workflow

Export AI answers, turn a README into a handout, build a resume or ship a status report — all from plain Markdown, with output that looks designed rather than generated.

Real Markdown

CommonMark with the GitHub extensions: tables, task lists, strikethrough and autolinks.

Highlighted Code

Fenced code blocks are coloured on the server for more than thirty languages.

Your Colours and Type

Thirteen typefaces, a light and dark theme, and every document colour under your control.

Print-Ready Layout

Code blocks and tables never split across pages, and table headers repeat on every page.

Every Writing System

Devanagari, Chinese, Japanese, Korean, Arabic, Hebrew, Thai, Cyrillic and Greek render with no configuration.

PDF or PNG

Take a paginated PDF, or one tall image of the whole document at up to 300 DPI.

Pricing

Simple, transparent pricing

Start free and scale as you grow. No hidden fees.

Free
Free
  • 50 documents/month
  • 5 requests/minute
  • Up to 1 MB input (~300 pages)
  • PDF as a hosted link, valid 2 hours
  • Page size, orientation, margins
  • Syntax highlighted code
Start Free
Most popular
Starter
$4.99 /mo
  • 1,000 documents/month
  • 15 requests/minute
  • Up to 2 MB input (~640 pages)
  • PNG output, long documents as an image sequence
  • Hosted link valid 7 days
  • 13 fonts and custom colours
  • Headers, footers, page numbers
Get Started
Pro
$12.99 /mo
  • 5,000 documents/month
  • 30 requests/minute
  • Up to 3 MB input (~960 pages)
  • PNG output, long documents as an image sequence
  • Hosted link valid 7 days
  • 13 fonts and custom colours
  • Headers, footers, page numbers
Choose Pro
Max
$24.99 /mo
  • 15,000 documents/month
  • 60 requests/minute
  • Up to 4 MB input (~1,300 pages)
  • PNG output, long documents as an image sequence
  • Hosted link valid 7 days
  • 13 fonts and custom colours
  • Priority processing
Choose Max
Agency
Custom
  • Unlimited documents
  • Custom rate limit
  • Custom input size
  • All features included
  • Dedicated support
Contact Sales
Documentation

API reference

Everything you need to integrate the Markdown to PDF API.

Authentication

Every request needs your API key in the x-api-key header. Keys are created in the dashboard and belong to your account rather than to a single API.

Header
x-api-key: your_api_key

Keep the key server side. Anyone holding it can spend your quota. Call this API from your backend, never from a browser.

API endpoint

POSThttps://api.corenexis.com/markdown-to-pdf/v1

One synchronous endpoint. Send the Markdown and the finished document comes back in the same response — there is no job to poll.

Input modes

The Markdown can arrive in any of these forms. Use whichever suits your environment.

cURL
curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"markdown": "# Invoice\n\nThank you for your business.", "page_size": "a4"}'

2. Form field

cURL
curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: your_api_key" \
  -F "markdown=# Hello" \
  -F "page_size=letter"

3. File upload

cURL
curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: your_api_key" \
  -F "markdown=@report.md"

4. Raw request body

cURL
curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: your_api_key" \
  -H "Content-Type: text/markdown" \
  --data-binary @report.md

Parameters

Parameter Type Description
x-api-key Required String Your API key. Send in the request header.
markdown Required String The Markdown to render. May also be sent as an uploaded file or as the raw request body.
format String pdf or png. PNG requires a paid plan.
Default: pdf
output String Only url. Every result is delivered as a hosted link, on every plan, so this can be omitted. base64 and binary were withdrawn and now return a clear error.
Default: url
page_size String a3, a4, a5, letter, legal or tabloid.
Default: a4
orientation String portrait or landscape.
Default: portrait
margin_top Number Top margin in millimetres, 0 to 100.
Default: 20
margin_right Number Right margin in millimetres, 0 to 100.
Default: 15
margin_bottom Number Bottom margin in millimetres, 0 to 100.
Default: 20
margin_left Number Left margin in millimetres, 0 to 100.
Default: 15
font String Body typeface, from the list below. Paid plans only.
Default: roboto
mono_font String Typeface for code. Paid plans only.
Default: jetbrainsmono
font_size Number Base size in points, 7 to 18. Paid plans only.
Default: 11
theme String light or dark. Paid plans only.
Default: light
colors Object Colour overrides as hex values. Paid plans only.
header_text String Running header text. Paid plans only.
footer_text String Running footer. Use {PAGENO} and {nb} for page numbers. Paid plans only.
png_mode String stack returns the whole document as an ordered sequence of images, first takes page one, page takes a chosen page.
Default: stack
png_page Number Which page to capture when png_mode is page. Any page the document has.
Default: 1
png_dpi Number Resolution for PNG output, 72 to 300.
Default: 144
filename String Name for the produced file, without extension.
Default: document

Everything except the Markdown is optional. Send nothing else and you get a sensible A4 portrait document. Anything you do send is applied.

Fonts, colours & Markdown

Fonts

Pass a key from this list as font for body text, or as mono_font for code. Font selection is a paid feature; the free plan renders in the defaults.

Group Available keys
Sans roboto (default), opensans, lato, montserrat, nunito, ibmplexsans
Serif ibmplexserif, liberationserif
Monospace jetbrainsmono (default), ibmplexmono, firacode
Devanagari lohitdevanagari

Other writing systems work automatically. Devanagari, Chinese, Japanese, Korean, Arabic, Hebrew, Thai, Cyrillic and Greek all render without choosing a font. Whatever the selected typeface cannot draw is filled in from a fallback.

Colours and theme

Send a colors object to restyle the document. Every value must be a hex colour such as #2563eb; anything else is rejected. Available on paid plans.

JSON
{
  "markdown": "# Report",
  "theme": "light",
  "colors": {
    "text": "#1f2937",
    "heading": "#111827",
    "link": "#2563eb",
    "accent": "#2563eb",
    "code_text": "#111827",
    "code_bg": "#f3f4f6",
    "border": "#e5e7eb",
    "quote": "#4b5563",
    "background": "#ffffff",
    "table_header_bg": "#f9fafb"
  }
}

Set theme to dark for a dark document, then override individual colours on top if you want.

Supported Markdown

CommonMark plus the GitHub extensions: tables, task lists, strikethrough and autolinks. Fenced code blocks are syntax highlighted on the server for more than thirty languages, so the colours survive into the PDF.

Raw HTML is escaped, not rendered. HTML written inside your Markdown appears as visible text. Use the HTML to PDF API when you need HTML and CSS.

Delivery & output

How the result is delivered

Every result is stored and handed back as a hosted link under data.url, on every plan including the free one. There is nothing to decode and nothing to stream.

Plan Link valid for Why
Free 2 hours Long enough to fetch and use the file in the workflow that produced it.
Any paid plan 7 days Long enough to email, queue or hand on to another service.

Fetch the file, do not hotlink it. The link expires. Download it once and store the bytes yourself rather than pointing your users at it.

What changed

Inline delivery was withdrawn. A caller still sending the old value gets an error that says so rather than a silent change of behaviour.

output Status Notes
base64 Withdrawn The file inside the JSON response. It inflated every result by a third and had to be held in memory twice.
binary Withdrawn The raw file as the response body. It could not carry a document that had become several images.
url The only mode A hosted link under data.url. This is now the default, so the parameter can be omitted.

PDF and page images

Set format to png to receive page images instead of a PDF. PNG output is a paid feature.

A document is usually taller than one image can be: the compositor refuses any dimension above 32,000 pixels, which at the default resolution is seventeen A4 pages. So png_mode=stack returns an ordered sequence of images in data.images, each covering a page range, and data.image.truncated tells you whether the sequence covers the whole document.

png_mode What you get When to use it
stack The whole document as an ordered sequence of images. Default. Reading or displaying every page.
first One image of page one. Thumbnails and previews.
page One image of the page named by png_page. Pulling a single page out of a long document.

How many pages per image. It depends on resolution, because the height limit is fixed: seventeen A4 pages at the default 144 dpi, thirty-five at 72, eight at 300. The response reports it as image.pages_per_image.

Code examples

Python

Python
import requests

resp = requests.post(
    "https://api.corenexis.com/markdown-to-pdf/v1",
    headers={"x-api-key": "your_api_key"},
    json={
        "markdown": open("report.md").read(),
        "page_size": "a4",
        "font": "montserrat",
        "colors": {"accent": "#2563eb"},
        "footer_text": "Page {PAGENO} of {nb}",
    },
    timeout=120,
)
data = resp.json()
if not data["success"]:
    raise SystemExit(data["message"])

# The result is a hosted link. Fetch it once and keep the file; the link expires.
pdf = requests.get(data["data"]["url"], timeout=120)
with open("report.pdf", "wb") as fh:
    fh.write(pdf.content)

Node.js

JavaScript
const fs = require("fs");

const res = await fetch("https://api.corenexis.com/markdown-to-pdf/v1", {
  method: "POST",
  headers: { "x-api-key": "your_api_key", "Content-Type": "application/json" },
  body: JSON.stringify({
    markdown: fs.readFileSync("report.md", "utf8"),
    format: "pdf",
    output: "url",
  }),
});

const data = await res.json();
if (!data.success) throw new Error(data.message);
console.log(data.data.url, "expires", data.data.expires_at);

PHP

PHP
<?php
$ch = curl_init('https://api.corenexis.com/markdown-to-pdf/v1');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'x-api-key: your_api_key',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'markdown'  => file_get_contents('report.md'),
        'page_size' => 'a4',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

if (empty($response['success'])) {
    exit($response['message'] ?? 'request failed');
}

// The result is a hosted link. Fetch it once and keep the file; the link expires.
file_put_contents('report.pdf', file_get_contents($response['data']['url']));

Set a User-Agent. Python’s built-in urllib sends a default agent string our edge network refuses. The requests library, Node, Go, Java and cURL all work unchanged.

Response

JSON
{
  "success": true,
  "plan": "pro",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0, "skipped": 0, "bytes": 0, "budget_reached": false
    },
    "render_time_ms": 324,
    "url": "https://cdn.corenexis.com/f/35at4d5YCjQ.pdf",
    "filename": "document.pdf",
    "size_bytes": 21168,
    "expires_at": "2026-08-16T06:10:13+00:00"
  },
  "usage": { "remaining": 4998, "rate_limit": 30, "monthly_limit": 5000 }
}

Always check the success field rather than the status code alone. On failure the body carries a code and a message naming what to change.

Every option, worked

Every option below was sent to the live API and the response shown is what came back, including the request that produced it. Copy a command, put your own key in it, and you get the same shape of answer.

Minimal request

Only the document is required. Everything else has a default: A4 portrait, 11 pt Roboto, light theme.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 631,
    "url": "https://cdn.corenexis.com/f/oxeBmDm6eJL.pdf",
    "filename": "document.pdf",
    "size_bytes": 50395,
    "expires_at": "2026-08-09T06:57:05+00:00"
  },
  "usage": {
    "remaining": 4977,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Page size

One of a3, a4, a5, letter, legal or tabloid. The response echoes it back, and the produced file really is that size.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "page_size": "a5"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a5",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 194,
    "url": "https://cdn.corenexis.com/f/YjzZHeTWCQU.pdf",
    "filename": "document.pdf",
    "size_bytes": 50393,
    "expires_at": "2026-08-09T06:57:06+00:00"
  },
  "usage": {
    "remaining": 4976,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Landscape orientation

Swaps the page width and height. Combines with any page size.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "orientation": "landscape"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "landscape",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 164,
    "url": "https://cdn.corenexis.com/f/sdCMl1hlrdl.pdf",
    "filename": "document.pdf",
    "size_bytes": 50394,
    "expires_at": "2026-08-09T06:57:06+00:00"
  },
  "usage": {
    "remaining": 4975,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

All four margins

Millimetres, 0 to 100 each. Set them independently; a value outside the range is refused before the document is rendered.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "margin_top": 30,
    "margin_right": 25,
    "margin_bottom": 30,
    "margin_left": 25
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 139,
    "url": "https://cdn.corenexis.com/f/if0faXFgh7A.pdf",
    "filename": "document.pdf",
    "size_bytes": 50394,
    "expires_at": "2026-08-09T06:57:06+00:00"
  },
  "usage": {
    "remaining": 4974,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Font size

Points, 7 to 18. Headings scale with it, so the document stays proportioned rather than merely larger.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "font_size": 13
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 128,
    "url": "https://cdn.corenexis.com/f/dLV7w0Belpx.pdf",
    "filename": "document.pdf",
    "size_bytes": 50396,
    "expires_at": "2026-08-09T06:57:06+00:00"
  },
  "usage": {
    "remaining": 4973,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Body and code font

Any pair from the font tables above. Requesting a font is a paid feature.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "font": "opensans",
    "mono_font": "firacode"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "opensans",
    "mono_font": "firacode",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 923,
    "url": "https://cdn.corenexis.com/f/uEMhTrGlhmI.pdf",
    "filename": "document.pdf",
    "size_bytes": 63127,
    "expires_at": "2026-08-09T06:57:07+00:00"
  },
  "usage": {
    "remaining": 4972,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Dark theme

Repaints the page background as well as the text, so the margins are dark too rather than leaving a white border.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "theme": "dark"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "dark",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 136,
    "url": "https://cdn.corenexis.com/f/qHKtneUhaVI.pdf",
    "filename": "document.pdf",
    "size_bytes": 50402,
    "expires_at": "2026-08-09T06:57:07+00:00"
  },
  "usage": {
    "remaining": 4971,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Custom colour palette

Any subset of the palette keys. Only #rgb and #rrggbb are accepted; an unknown key or a malformed colour is reported rather than ignored.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "colors": {
      "accent": "#7c3aed",
      "link": "#7c3aed",
      "heading": "#111827",
      "code_bg": "#f5f3ff"
    }
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 169,
    "url": "https://cdn.corenexis.com/f/Zpdm4jN9OOU.pdf",
    "filename": "document.pdf",
    "size_bytes": 50389,
    "expires_at": "2026-08-09T06:57:08+00:00"
  },
  "usage": {
    "remaining": 4970,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

{PAGENO} and {nb} are substituted per page. Verified across chunk boundaries on documents of several hundred pages.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "...long document...",
    "header_text": "Quarterly Report — Confidential",
    "footer_text": "Page {PAGENO} of {nb}"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 37,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 1055,
    "url": "https://cdn.corenexis.com/f/RyZN0BtksWp.pdf",
    "filename": "document.pdf",
    "size_bytes": 86316,
    "expires_at": "2026-08-09T06:57:09+00:00"
  },
  "usage": {
    "remaining": 4969,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Filename

Sets the stored filename. Letters, digits, dot, dash and underscore, up to 80 characters; the extension is added.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "filename": "invoice-2026-0184"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "pdf",
    "mime": "application/pdf",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 308,
    "url": "https://cdn.corenexis.com/f/cJYU2qcqOAN.pdf",
    "filename": "invoice-2026-0184.pdf",
    "size_bytes": 50413,
    "expires_at": "2026-08-09T06:57:09+00:00"
  },
  "usage": {
    "remaining": 4968,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

PNG, whole document

A document too tall for one image comes back as an ordered sequence. Each image holds as many pages as the compositor allows, and truncated tells you whether the set is complete.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "...long document...",
    "format": "png"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "png",
    "mime": "image/png",
    "pages": 37,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 22574,
    "url": "https://cdn.corenexis.com/f/ljTe16hzNpA.png",
    "filename": "document-p1-17.png",
    "size_bytes": 1368378,
    "expires_at": "2026-08-09T06:57:32+00:00",
    "image": {
      "dpi": 144,
      "pages_total": 37,
      "pages_rendered": 37,
      "pages_per_image": 17,
      "truncated": false
    },
    "image_count": 3,
    "total_bytes": 2945732,
    "images": [
      {
        "url": "https://cdn.corenexis.com/f/ljTe16hzNpA.png",
        "filename": "document-p1-17.png",
        "size_bytes": 1368378,
        "expires_at": "2026-08-09T06:57:32+00:00",
        "page_from": 1,
        "page_to": 17,
        "width": 1191,
        "height": 28628
      },
      {
        "url": "https://cdn.corenexis.com/f/5FtJndj9BX7.png",
        "filename": "document-p18-34.png",
        "size_bytes": 1387052,
        "expires_at": "2026-08-09T06:57:32+00:00",
        "page_from": 18,
        "page_to": 34,
        "width": 1191,
        "height": 28628
      },
      "... 1 more, one per page range, in order"
    ]
  },
  "usage": {
    "remaining": 4967,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

PNG, first page only

One image of page one. Useful for a thumbnail.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "...long document...",
    "format": "png",
    "png_mode": "first"
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "png",
    "mime": "image/png",
    "pages": 37,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 2665,
    "url": "https://cdn.corenexis.com/f/dBsZESv6l3a.png",
    "filename": "document.png",
    "size_bytes": 148265,
    "expires_at": "2026-08-09T06:57:35+00:00",
    "image": {
      "dpi": 144,
      "pages_total": 37,
      "pages_rendered": 1,
      "pages_per_image": 17,
      "truncated": false
    },
    "image_count": 1,
    "total_bytes": 148265,
    "images": [
      {
        "url": "https://cdn.corenexis.com/f/dBsZESv6l3a.png",
        "filename": "document.png",
        "size_bytes": 148265,
        "expires_at": "2026-08-09T06:57:35+00:00",
        "page_from": 1,
        "page_to": 1,
        "width": 1191,
        "height": 1684
      }
    ]
  },
  "usage": {
    "remaining": 4966,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

PNG, one chosen page

Any page the document has. Asking beyond the end reports the real count.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "...long document...",
    "format": "png",
    "png_mode": "page",
    "png_page": 12
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "png",
    "mime": "image/png",
    "pages": 37,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 1109,
    "url": "https://cdn.corenexis.com/f/7qc2gnVdmPw.png",
    "filename": "document.png",
    "size_bytes": 151355,
    "expires_at": "2026-08-09T06:57:36+00:00",
    "image": {
      "dpi": 144,
      "pages_total": 37,
      "pages_rendered": 1,
      "pages_per_image": 17,
      "truncated": false
    },
    "image_count": 1,
    "total_bytes": 151355,
    "images": [
      {
        "url": "https://cdn.corenexis.com/f/7qc2gnVdmPw.png",
        "filename": "document.png",
        "size_bytes": 151355,
        "expires_at": "2026-08-09T06:57:36+00:00",
        "page_from": 12,
        "page_to": 12,
        "width": 1191,
        "height": 1684
      }
    ]
  },
  "usage": {
    "remaining": 4965,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

PNG resolution

72 to 300 dpi. Higher resolution means fewer pages fit in one image, because the compositor’s height limit is fixed.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "format": "png",
    "png_dpi": 300
  }'
{
  "success": true,
  "plan": "basic",
  "data": {
    "status": "completed",
    "format": "png",
    "mime": "image/png",
    "pages": 1,
    "page_size": "a4",
    "orientation": "portrait",
    "font": "roboto",
    "mono_font": "jetbrainsmono",
    "theme": "light",
    "source_images": {
      "embedded": 0,
      "skipped": 0,
      "bytes": 0,
      "budget_reached": false
    },
    "render_time_ms": 744,
    "url": "https://cdn.corenexis.com/f/tU78MX1UDiV.png",
    "filename": "document.png",
    "size_bytes": 84565,
    "expires_at": "2026-08-09T06:57:37+00:00",
    "image": {
      "dpi": 300,
      "pages_total": 1,
      "pages_rendered": 1,
      "pages_per_image": 8,
      "truncated": false
    },
    "image_count": 1,
    "total_bytes": 84565,
    "images": [
      {
        "url": "https://cdn.corenexis.com/f/tU78MX1UDiV.png",
        "filename": "document.png",
        "size_bytes": 84565,
        "expires_at": "2026-08-09T06:57:37+00:00",
        "page_from": 1,
        "page_to": 1,
        "width": 2480,
        "height": 3508
      }
    ]
  },
  "usage": {
    "remaining": 4964,
    "rate_limit": 120,
    "monthly_limit": 5000
  }
}

Refused: one unbroken block

Laying out a single run of text costs time in proportion to its length squared, so this one shape is refused by name. The same words split into paragraphs render in under three seconds.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "...40,000 words with no paragraph breaks..."
  }'
{
  "success": false,
  "code": "INVALID_INPUT",
  "message": "This document contains a single unbroken block of text of 559,999 characters, which is too long to lay out. Break it into paragraphs separated by blank lines. Document length itself is not the problem.",
  "longest_text_block": 559999
}

Refused: too many table cells

Collapsed borders are resolved across the whole table before any of it is drawn, which is what makes a long table the most memory-hungry shape.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "...a 7,000-row table..."
  }'
{
  "success": false,
  "code": "INVALID_INPUT",
  "message": "This document contains 28,005 table cells, which is more than can be laid out in one request. Split the tables across several documents and combine the results.",
  "table_cells": 28005
}

Refused: retired output mode

Inline delivery was withdrawn. Every result is a hosted link.

curl -X POST "https://api.corenexis.com/markdown-to-pdf/v1" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Quarterly Report\n\nRevenue held steady while costs fell.\n\n| Region | Revenue | Change |\n|---|---|---|\n| North | 48,200 | +4% |\n| South | 31,700 | -2% |\n\n- [x] Figures verified\n- [ ] Board review\n\n```python\ndef margin(revenue, cost):\n    return (revenue - cost) / revenue\n```\n",
    "output": "base64"
  }'
{
  "success": false,
  "code": "INVALID_INPUT",
  "message": "'output' no longer accepts 'base64'. Every result is delivered as a hosted link, so omit the parameter or send output=url. The response carries the link in data.url."
}

Errors

Errors arrive as JSON with a stable code.

Code HTTP Meaning
MISSING_KEY 401 The x-api-key header was not sent.
INVALID_KEY 401 The key does not exist or has been revoked.
KEY_DISABLED 403 The key exists but has been switched off.
ACCOUNT_SUSPENDED 403 The account is suspended.
NO_SUBSCRIPTION 402 The account has no subscription to this API.
SUBSCRIPTION_EXPIRED 402 The subscription lapsed and the grace period has passed.
RATE_LIMIT_EXCEEDED 429 Too many requests this minute. Retry shortly.
QUOTA_EXCEEDED 429 The monthly allowance is used up.
PARAM_LIMIT_EXCEEDED 400 A requested feature or value is above what the plan allows. The response names the parameter.
INVALID_INPUT 400 Something in the request is malformed. The message names the field.
RENDER_TIMEOUT 408 The document took too long. Simplify it and retry.
PROCESSING_FAILED 422 The document could not be rendered.
RENDERER_BUSY 503 Every worker is busy. Retry in a moment.

Quota-safe failures. If rendering fails after your request was accepted, your monthly quota is not charged. Only successful documents count.

Rate limiting. Free 5/min · Starter 15/min · Pro 30/min · Max 60/min.

Limits

Limit Value
Maximum input size 1 MB free, up to 4 MB on Max
Pages that means in practice About 300 pages free, about 1,300 on Max, for ordinary prose
Page limit There is no page limit. Documents of a thousand pages and more render normally
What is actually refused A single unbroken block of text, or more table cells than fit in memory. Both are named in the error
Maximum delivered file 15 MB. Text contributes about 1.7 KB per page, so this is only reachable with embedded images
Embedded images 6 MB per image, 40 per document, 12 MB in total
Hosted link lifetime 2 hours on the free plan, 7 days on any paid plan

Length is not what gets refused. Nothing is rejected for being long. What costs is a single run of text with no break in it, because laying one out takes time in proportion to its length squared. The same words split into paragraphs render in seconds. The error names which property is the problem so you know what to change.

Sample output

The samples/ directory in the project repository holds real output across page sizes, orientations, fonts, themes, palettes and both formats, so you can see what each option produces before calling the API.

Ready to ship better documents?

Create your free account and turn your first Markdown file into a PDF in seconds. No credit card required.

Stay in the loop

New APIs, features and offers, straight to your inbox. No spam.

Already subscribed? Manage preferences