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

    Submit

    POST the document (or Markdown text, or a GitHub link) and add ?wait=50 to wait for the result.

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

RequestWhat it does
POST /api/v1/jobs?wait=50Submit 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=50The 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/infoAvailable styles, the limits and the current queue.

Fields to submit (multipart/form-data)

FieldWhat it does
fileA file to convert; repeat it for the document and the images, .bib files and so on it uses. A .zip works too.
pathsOptional: the relative paths of the files, in the same order (JSON list), to keep folders — e.g. ["report.md", "images/a.png"].
markdownMarkdown text instead of a file.
urlA Markdown file in a public GitHub repository instead of a file; its images are fetched too.
templateOptional: a .docx template — the result follows its page setup, fonts, styles, headers and footers.
optionsConversion options (a JSON object), below.

Conversion options (options)

OptionWhat it does
formats["pdf", "docx"] (default), ["pdf"] or ["docx"]; for Word, LaTeX and PDF input also ["markdown"] for editable Markdown only.
themeStyle name, default business; the choices are in /api/v1/info.
toctrue: add a table of contents.
number_sectionstrue / false: number the headings.
docx_fontswindows (default) or mac: the CJK font names used in Word.
mainWith several documents uploaded, the one to convert (relative path).
filenameFile name for submitted markdown text.
track_changesWord input: accept (default) or reject tracked changes.
keep_source_formatWord and LaTeX input: false uses the chosen style's formatting instead.
pdf_ocrPDF 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

codeWhat it does
bad_request / no_document400: wrong parameters, or no document to convert was found.
file_too_big / total_too_big / too_many_files413: over the size or file-count limit.
too_many_active / rate_hour / rate_limited429: too many at once or over the hourly allowance; retry later (when there is a Retry-After header, wait that many seconds).
busy / storage_full503: the server is busy; try again in a few minutes.
not_found404: the job does not exist or has expired.
pdf_scannedJob failed: a scanned PDF; set pdf_ocr: true to recognise it.
timeout / conversion_failedJob 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.

Writing syntax

Open as a page

Loading…

Send feedback

Tell us what went wrong or what would make this better. We read every message.

Prefer another way? Email · GitHub