New User Offer Get $5 free credit instantly — no credit card required. Use code WELCOME Claim $5 Free
API V1 — Production Ready

Markdown to PDF & PNG 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.

13 Typefaces
Sans, serif, mono, Devanagari
1,000+ Pages
Long documents supported
PDF + PNG
Page images for long documents
Instant
Synchronous response

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.

Simple, Transparent Pricing

Start free and move up when you need more. Every plan renders with the same engine — higher tiers unlock larger documents, more output formats and full styling control.

Free
Free
  • 50 documents/month
  • 5 requests/minute
  • Up to 1 MB input (~300 pages)
  • Hosted link valid 2 hours
  • Page size, orientation, margins
  • Syntax highlighted code
  • Tables, task lists and images
Start Free
Starter
$4.99/month
  • 1,000 documents/month
  • 15 requests/minute
  • Up to 2 MB input (~640 pages)
  • PNG page images
  • Hosted link valid 7 days
  • 13 fonts and full colour control
  • Headers, footers, page numbers
Get Started
Pro
$12.99/month
  • 5,000 documents/month
  • 30 requests/minute
  • Up to 3 MB input (~960 pages)
  • PNG page images
  • Hosted link valid 7 days
  • 13 fonts and full colour control
  • Headers, footers, page numbers
Choose Pro
Max
$24.99/month
  • 15,000 documents/month
  • 60 requests/minute
  • Up to 4 MB input (~1,300 pages)
  • PNG page images
  • Hosted link valid 7 days
  • 13 fonts and full colour control
  • Priority processing
Choose Max
Enterprise

Enterprise & Agency Plan

High-volume document generation, custom limits, dedicated capacity and SLAs. We build the plan around your workload.

Unlimited documents
Custom input size
Custom rate limit
Dedicated capacity
24/7 Support

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

1. JSON body — recommended

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 "[email protected]"

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

ParameterTypeDescription
x-api-keyRequiredStringYour API key. Send in the request header.
markdownRequiredStringThe Markdown to render. May also be sent as an uploaded file or as the raw request body.
formatOptionalStringpdf or png. PNG requires a paid plan.
Default: pdf
outputOptionalStringOnly 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_sizeOptionalStringa3, a4, a5, letter, legal or tabloid.
Default: a4
orientationOptionalStringportrait or landscape.
Default: portrait
margin_topOptionalNumberTop margin in millimetres, 0 to 100.
Default: 20
margin_rightOptionalNumberRight margin in millimetres, 0 to 100.
Default: 15
margin_bottomOptionalNumberBottom margin in millimetres, 0 to 100.
Default: 20
margin_leftOptionalNumberLeft margin in millimetres, 0 to 100.
Default: 15
fontOptionalStringBody typeface, from the list below. Paid plans only.
Default: roboto
mono_fontOptionalStringTypeface for code. Paid plans only.
Default: jetbrainsmono
font_sizeOptionalNumberBase size in points, 7 to 18. Paid plans only.
Default: 11
themeOptionalStringlight or dark. Paid plans only.
Default: light
colorsOptionalObjectColour overrides as hex values. Paid plans only.
header_textOptionalStringRunning header text. Paid plans only.
footer_textOptionalStringRunning footer. Use {PAGENO} and {nb} for page numbers. Paid plans only.
png_modeOptionalStringstack returns the whole document as an ordered sequence of images, first takes page one, page takes a chosen page.
Default: stack
png_pageOptionalNumberWhich page to capture when png_mode is page. Any page the document has.
Default: 1
png_dpiOptionalNumberResolution for PNG output, 72 to 300.
Default: 144
filenameOptionalStringName for the produced file, without extension.
Default: document
Everything except the Markdown is optionalSend nothing else and you get a sensible A4 portrait document. Anything you do send is applied.

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.

GroupAvailable keys
Sansroboto (default), opensans, lato, montserrat, nunito, ibmplexsans
Serifibmplexserif, liberationserif
Monospacejetbrainsmono (default), ibmplexmono, firacode
Devanagarilohitdevanagari
Other writing systems work automaticallyDevanagari, 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 renderedHTML written inside your Markdown appears as visible text. Use the HTML to PDF API when you need HTML and CSS.

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.

PlanLink valid forWhy
Free2 hoursLong enough to fetch and use the file in the workflow that produced it.
Any paid plan7 daysLong enough to email, queue or hand on to another service.
Fetch the file, do not hotlink itThe 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.

outputStatusNotes
base64WithdrawnThe file inside the JSON response. It inflated every result by a third and had to be held in memory twice.
binaryWithdrawnThe raw file as the response body. It could not carry a document that had become several images.
urlThe only modeA 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_modeWhat you getWhen to use it
stackThe whole document as an ordered sequence of images.Default. Reading or displaying every page.
firstOne image of page one.Thumbnails and previews.
pageOne image of the page named by png_page.Pulling a single page out of a long document.
How many pages per imageIt 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-AgentPython'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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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
  }'
Response — HTTP 200
{
  "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.

Request
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
  }'
Response — HTTP 200
{
  "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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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"
    }
  }'
Response — HTTP 200
{
  "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
  }
}

Header and footer with page numbers

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

Request
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}"
  }'
Response — HTTP 200
{
  "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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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"
  }'
Response — HTTP 200
{
  "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.

Request
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
  }'
Response — HTTP 200
{
  "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.

Request
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
  }'
Response — HTTP 200
{
  "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.

Request
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..."
  }'
Response — HTTP 413
{
  "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.

Request
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..."
  }'
Response — HTTP 413
{
  "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.

Request
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"
  }'
Response — HTTP 400
{
  "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.

CodeHTTPMeaning
MISSING_KEY401The x-api-key header was not sent.
INVALID_KEY401The key does not exist or has been revoked.
KEY_DISABLED403The key exists but has been switched off.
ACCOUNT_SUSPENDED403The account is suspended.
NO_SUBSCRIPTION402The account has no subscription to this API.
SUBSCRIPTION_EXPIRED402The subscription lapsed and the grace period has passed.
RATE_LIMIT_EXCEEDED429Too many requests this minute. Retry shortly.
QUOTA_EXCEEDED429The monthly allowance is used up.
PARAM_LIMIT_EXCEEDED400A requested feature or value is above what the plan allows. The response names the parameter.
INVALID_INPUT400Something in the request is malformed. The message names the field.
RENDER_TIMEOUT408The document took too long. Simplify it and retry.
PROCESSING_FAILED422The document could not be rendered.
RENDERER_BUSY503Every worker is busy. Retry in a moment.
Quota-safe failuresIf rendering fails after your request was accepted, your monthly quota is not charged. Only successful documents count.
Rate limitingFree 5/min · Starter 15/min · Pro 30/min · Max 60/min.

Limits

LimitValue
Maximum input size1 MB free, up to 4 MB on Max
Pages that means in practiceAbout 300 pages free, about 1,300 on Max, for ordinary prose
Page limitThere is no page limit. Documents of a thousand pages and more render normally
What is actually refusedA single unbroken block of text, or more table cells than fit in memory. Both are named in the error
Maximum delivered file15 MB. Text contributes about 1.7 KB per page, so this is only reachable with embedded images
Embedded images6 MB per image, 40 per document, 12 MB in total
Hosted link lifetime2 hours on the free plan, 7 days on any paid plan
Length is not what gets refusedNothing 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

Get the latest updates delivered straight to your inbox