HTTP API
Use the converter from scripts, automations or your own software: upload a file, wait for the result, download the PDF and Word. No sign-up and no key.
How it works
- 1
Submit
POST the document (or Markdown text, or a GitHub link) and add ?wait=50 to wait for the result.
- 2
Wait
Most documents finish in seconds. If it takes longer than 50 seconds you get the job id first; keep waiting with GET.
- 3
Download
files in the result lists a download link for each file, valid for 2 hours.
No key
Call it directly; the same free allowance as the web page.
Same quality as the page
Styles, tables, equations, references and Word templates all work.
Many inputs
Markdown (with an image folder or a .zip), Word, LaTeX, PDF, GitHub links.
Deleted automatically
Results are deleted after 2 hours, or immediately with DELETE.
Quick start
Convert report.md into PDF and Word. When it is finished you get 200 and the download links in files:
curl -F "file=@report.md" -F 'options={"formats":["pdf","docx"]}' \
"https://mdpdfword.com/api/v1/jobs?wait=50"If you get 202 (still queued or converting), keep waiting with the job id:
curl "https://mdpdfword.com/api/v1/jobs/JOB_ID?wait=50"Endpoints
| Request | What it does |
|---|---|
POST /api/v1/jobs?wait=50 | Submit a conversion and wait up to wait seconds (at most 50). 200 when finished, otherwise 202 with the job id. |
GET /api/v1/jobs/{job_id}?wait=50 | The job's state; with wait, waits until it has finished or the time is up. |
DELETE /api/v1/jobs/{job_id} | Delete this job's result files now. |
GET /api/v1/info | Available styles, the limits and the current queue. |
Fields to submit (multipart/form-data)
| Field | What it does |
|---|---|
file | A file to convert; repeat it for the document and the images, .bib files and so on it uses. A .zip works too. |
paths | Optional: the relative paths of the files, in the same order (JSON list), to keep folders — e.g. ["report.md", "images/a.png"]. |
markdown | Markdown text instead of a file. |
url | A Markdown file in a public GitHub repository instead of a file; its images are fetched too. |
template | Optional: a .docx template — the result follows its page setup, fonts, styles, headers and footers. |
options | Conversion options (a JSON object), below. |
Conversion options (options)
| Option | What it does |
|---|---|
formats | ["pdf", "docx"] (default), ["pdf"] or ["docx"]; for Word, LaTeX and PDF input also ["markdown"] for editable Markdown only. |
theme | Style name, default business; the choices are in /api/v1/info. |
toc | true: add a table of contents. |
number_sections | true / false: number the headings. |
docx_fonts | windows (default) or mac: the CJK font names used in Word. |
main | With several documents uploaded, the one to convert (relative path). |
filename | File name for submitted markdown text. |
track_changes | Word input: accept (default) or reject tracked changes. |
keep_source_format | Word and LaTeX input: false uses the chosen style's formatting instead. |
pdf_ocr | PDF input: true means you agree that the PDF is sent to SoMark for enhanced recognition (see Privacy below). Without it nothing is sent. |
The result
status is queued, running, done, or error (then error and code say why). warnings lists things to check, such as missing pictures.
{
"ok": true,
"job_id": "Vq3…",
"status": "done",
"version": 3,
"main": "report.md",
"elapsed": 4.2,
"files": [
{
"format": "pdf",
"name": "report.pdf",
"size": 182340,
"url": "https://mdpdfword.com/files/results/…/report.pdf",
"file_id": "…"
},
{
"format": "docx",
"name": "report.docx",
"size": 48211,
"url": "https://mdpdfword.com/files/results/…/report.docx",
"file_id": "…"
}
],
"warnings": [],
"pdf_pages": 3,
"expires_in_minutes": 120
}Python example
import json
import requests
API = "https://mdpdfword.com/api/v1/jobs"
with open("report.md", "rb") as f:
job = requests.post(API, params={"wait": 50}, files={"file": f},
data={"options": json.dumps({"formats": ["pdf", "docx"]})},
timeout=70).json()
while job.get("status") in ("queued", "running"):
job = requests.get(f"{API}/{job['job_id']}", params={"wait": 50}, timeout=70).json()
if not job.get("ok"):
raise SystemExit(f"{job.get('code')}: {job.get('error')}")
for out in job["files"]:
with open(out["name"], "wb") as f:
f.write(requests.get(out["url"], timeout=120).content)Error codes
| code | What it does |
|---|---|
bad_request / no_document | 400: wrong parameters, or no document to convert was found. |
file_too_big / total_too_big / too_many_files | 413: over the size or file-count limit. |
too_many_active / rate_hour / rate_limited | 429: too many at once or over the hourly allowance; retry later (when there is a Retry-After header, wait that many seconds). |
busy / storage_full | 503: the server is busy; try again in a few minutes. |
not_found | 404: the job does not exist or has expired. |
pdf_scanned | Job failed: a scanned PDF; set pdf_ocr: true to recognise it. |
timeout / conversion_failed | Job failed: the document is too complex or has an error; error explains it. |
Limits
The same as on the web page: per IP address at most 2 at once and 30 per hour; 20 MB per file, 60 MB and 300 files in total; up to 5 minutes per conversion; results kept for 2 hours.
The service runs on one machine. So that people on the web page never wait behind scripts, API requests share part of the conversion slots, and the queue can be longer when it is busy. Please submit one at a time rather than in parallel batches.
Privacy
Uploaded files are used for this conversion only, and results are deleted after 2 hours. PDFs are read on this site's server only; only when the request says "pdf_ocr": true is the PDF sent to the third-party SoMark for enhanced recognition — do not set it for sensitive files. See the privacy policy. Privacy policy
Questions and answers
Do I need to sign up or get an API key?
No. Call it directly; it shares the web page's free allowance.
Can I call it from a web page (browser JavaScript)?
No. So that other sites cannot route their visitors' files here, the API does not allow cross-site calls. Call it from a server or a script.
How is this different from MCP?
MCP is for AI assistants such as Claude Code and Codex; the HTTP API is for scripts and programs. Quality and allowance are the same.
Will the API change?
/api/v1 is stable: fields may be added, but existing ones keep their meaning. /api/jobs, used inside the web page, is not guaranteed — please do not depend on it.