Drop your .md file, paste your text, or call the REST API from any app.
Export pixel-perfect PDF, DOCX, or HTML — Mermaid diagrams, LaTeX math, YAML frontmatter, and zero overflow.
Editor, file upload, or URL — pick your workflow.
Your preview will appear here
Type directly in the editor, drag-and-drop a .md file, or paste a raw URL from GitHub, GitLab, or any public source.
Toggle a Table of Contents, enable automatic page breaks at every chapter, or set a custom document title shown in the footer.
Choose PDF, DOCX, or HTML. Pixel-perfect output with no layout hacks, no overflow — ready to share or publish.
Auto-generated title page with title, author, and date. Document title in the header, page X / Y in the footer — cover page gets blank headers automatically.
Clickable TOC with correct nesting. Optional 1.1.1 heading numbering for formal documents. In DOCX, a native Word TOC field.
190+ languages with GitHub-light theme. Code blocks with gray backgrounds, borders, and monospace fonts — never overflows the page.
Pipe, grid, and multiline tables. Header shading, alternating row colors, borders — auto-scaled to page width so nothing overflows.
Flowcharts, sequence diagrams, git graphs, Gantt charts, ER diagrams, pie charts, mindmaps — rendered as crisp SVGs in both PDF and DOCX.
LaTeX math via KaTeX, numbered footnotes, task lists, definition lists, and full GitHub Flavoured Markdown — strikethrough, autolinks, and more.
Local images base64-inlined so they always render. Alt text becomes figure captions in DOCX. Constrained to page width automatically.
Manual <!-- pagebreak --> or auto-break before every H1. TOC gets its own page. Full control over document flow.
Self-contained HTML with all images base64-inlined. Includes TOC, syntax highlighting, and full styling — ready to open in any browser.
Add a YAML block at the top of any .md file to set title, author, page size, watermark, theme, and more. Use {{title}} and {{author}} placeholders anywhere in the document.
Add a diagonal watermark (DRAFT, CONFIDENTIAL, etc.) to every page. Choose from A4, Letter, A3, A5, or Legal — portrait or landscape.
Enqueue large conversions via POST /api/v1/jobs, poll with GET /api/v1/jobs/:id, and get notified via webhook when done. Prometheus metrics at /api/v1/metrics.
Call the conversion API from any language. Build pipelines, automate doc generation, or embed into your own platform.
http://localhost:3000/api/v1
INKDOWN_API_KEYS env var to require an API key.
Pass it as X-API-Key: <key> or Authorization: Bearer <key>.
| Parameter | Type | Required | Description |
|---|---|---|---|
markdown |
string | required* | Raw Markdown content to convert |
url |
string | required* | Public URL of a raw .md file to fetch and convert |
file |
file | required* | Multipart file upload of a .md file |
format |
string | optional | "pdf" (default), "docx", or "html" |
title |
string | optional | Document title shown in the PDF footer. Defaults to filename. |
author |
string | optional | Author name shown on cover / metadata. |
toc |
boolean | optional | Generate a Table of Contents from headings. Default: false |
autoBreak |
boolean | optional | Insert a page break before every H1 heading. Default: false |
pageSize |
string | optional | "A4" (default), "Letter", "A3", "A5", or "Legal" |
landscape |
boolean | optional | Landscape orientation (PDF only). Default: false |
watermark |
string | optional | Diagonal watermark text on every page, e.g. "DRAFT" or "CONFIDENTIAL" |
* Exactly one of markdown, url, or a multipart file is required.
curl -X POST http://localhost:3000/api/v1/convert \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-d '{
"markdown": "# Hello World\n\nThis is my document.",
"format": "pdf",
"title": "My Document",
"author": "Jane Smith",
"pageSize": "Letter",
"toc": true,
"watermark": "DRAFT"
}' \
--output document.pdf
const response = await fetch('http://localhost:3000/api/v1/convert', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your_api_key',
},
body: JSON.stringify({
markdown: '# Hello World\n\nThis is my document.',
format: 'pdf', // 'pdf' | 'docx' | 'html'
title: 'My Document',
author: 'Jane Smith',
pageSize: 'Letter',
toc: true,
watermark: 'DRAFT',
}),
});
if (!response.ok) {
const err = await response.json();
throw new Error(err.error);
}
// Save as file (browser)
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.pdf';
a.click();
import requests
response = requests.post(
'http://localhost:3000/api/v1/convert',
headers={'X-API-Key': 'your_api_key'},
json={
'markdown': '# Hello World\n\nThis is my document.',
'format': 'html', # 'pdf' | 'docx' | 'html'
'title': 'My Document',
'author': 'Jane Smith',
'toc': True,
},
)
response.raise_for_status()
with open('document.html', 'wb') as f:
f.write(response.content)
print('Saved document.html')
<?php
$ch = curl_init('http://localhost:3000/api/v1/convert');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-API-Key: your_api_key',
],
CURLOPT_POSTFIELDS => json_encode([
'markdown' => "# Hello World\n\nThis is my document.",
'format' => 'pdf',
'title' => 'My Document',
'toc' => true,
]),
]);
$pdf = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 200) {
file_put_contents('document.pdf', $pdf);
echo "Saved document.pdf\n";
}
import fs from 'fs';
import FormData from 'form-data';
import fetch from 'node-fetch';
// Option A — send markdown as JSON
const res = await fetch('http://localhost:3000/api/v1/convert', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your_api_key',
},
body: JSON.stringify({
markdown: fs.readFileSync('README.md', 'utf-8'),
format: 'pdf',
title: 'README',
}),
});
// Option B — send as file upload
const form = new FormData();
form.append('file', fs.createReadStream('README.md'));
form.append('format', 'pdf');
const res2 = await fetch('http://localhost:3000/api/v1/convert', {
method: 'POST',
headers: { 'X-API-Key': 'your_api_key', ...form.getHeaders() },
body: form,
});
fs.writeFileSync('output.pdf', Buffer.from(await res.arrayBuffer()));
Content-Disposition: attachment; filename="..."
{ "error": "...", "code": "BAD_REQUEST" } — missing input or invalid URL
{ "error": "...", "code": "UNAUTHORIZED" } — invalid or missing API key
{ "error": "...", "code": "CONVERSION_ERROR" } — conversion failed
{
"status": "ok",
"version": "1.0.0",
"timestamp": "2026-06-06T10:00:00.000Z",
"formats": ["pdf", "docx", "html", "epub", "slides"]
}
Pre-built image on Docker Hub. No Node.js, no Chrome, no Pandoc install — everything is bundled. Works on Linux, macOS, and Windows.
docker run -p 3000:3000 aryansin1234/inkdown:latest
/api/v1/convertcurl -O https://raw.githubusercontent.com/Aryansin1234/InkDown/docker-version/docker-compose.yml docker compose up
docker run -p 3000:3000 \ -e INKDOWN_API_KEYS=my-secret-key \ aryansin1234/inkdown:latest
X-API-Key: ...Authorization: Bearer ...| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP port the server listens on inside the container |
INKDOWN_API_KEYS |
unset · open | Comma-separated API keys. When set, /api/v1/convert requires a valid key. |
INKDOWN_CORS_ORIGINS |
* |
Restrict CORS. E.g. https://myapp.com,https://staging.myapp.com |
PUPPETEER_EXECUTABLE_PATH |
/usr/bin/chromium |
Chromium binary path — pre-configured in the image, no need to change |
git clone https://github.com/Aryansin1234/InkDown.git && cd InkDown docker build -t aryansin1234/inkdown . docker run -p 3000:3000 aryansin1234/inkdown