# Markdown to PDF Converter

Open, no-auth API that turns Markdown into a formatted PDF (FastAPI + ReportLab). POST Markdown, get a clean paginated PDF: headings, lists, tables, code, blockquotes and rules.

## Endpoints

Base URL `https://mdtopdf.tigzig.com`

- `POST /v1/convert/text` - JSON body, returns the PDF file directly. Canonical; the MCP tool wraps this one.
- `POST /v1/convert` - upload a `.md`, `.markdown` or `.txt` file as `multipart/form-data`, returns the PDF file directly.
- `POST /v1/convert/text/hosted` - JSON body, returns `{"pdf_url": "..."}` instead of the binary, for clients that would rather have a link.

```bash
curl -X POST https://mdtopdf.tigzig.com/v1/convert/text \
  -H 'Content-Type: application/json' \
  -d '{"content": "# Title\n\nHello **world**", "filename": "out.pdf"}' \
  --output out.pdf
```

```bash
curl -X POST https://mdtopdf.tigzig.com/v1/convert \
  -F 'file=@notes.md' \
  --output out.pdf
```

## Limits

Every one of these is enforced, so none of them should be a surprise you meet by being refused.

- **10 requests per minute** and **200 per day**, per IP.
- **1 MB** per document, which is roughly 400 pages of ordinary prose.
- **50,000 characters** in a single unbroken paragraph. Laying out one very long paragraph costs far more than the same text split up, so a document with no blank lines in it is refused with `PARAGRAPH_TOO_LONG` rather than run slowly.
- **15 seconds** per conversion. Almost everything finishes in a few seconds; a document that exceeds this is stopped and returns `CONVERSION_TIMEOUT`.

Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`, and a `429` carries `Retry-After` with a real number of seconds. Concurrent requests are QUEUED rather than refused, so a burst waits a moment instead of failing and you do not need to serialise your calls.

## Request encoding

The request body must be UTF-8; JSON requires it (RFC 8259). Send the body UTF-8 encoded rather than GBK or Latin-1.

## Markdown supported

- Headings `h1` to `h6`
- Bold, italic, strikethrough, inline code
- Links, clickable in the PDF
- Bullet and numbered lists with real nesting (two-space indentation works)
- Task lists
- Tables, any column count; wide tables shrink to fit rather than failing
- Fenced code blocks
- Blockquotes and horizontal rules
- Emoji, mapped to matching symbols rather than a blank box
- Currency and maths symbols

## Page breaks

Markdown has no page break, so this API adds one. Put any of `:::pagebreak:::`, `\pagebreak`, `\newpage` or `<!-- pagebreak -->` on a line by itself and the content after it starts on a new page. Markers inside fenced code blocks are left alone.

## Plain text files

Upload a `.txt` file to `POST /v1/convert` and its single line breaks are kept, so a letter stays laid out the way it was written. A `.md` file follows standard Markdown rules, where a single newline is just a space.

## Symbols

Greek letters (alpha, beta, sigma, Delta, Omega), maths and logic operators (`<=`, `>=`, `!=`, `~=`, sqrt, sum, product, integral, partial, infinity, element-of, subset, union) and arrows both single and double all render correctly, as do typographic punctuation, dashes, curly quotes and the dollar, pound, euro, yen and cent signs.

The rupee, won, rouble, naira, lira and bitcoin signs are drawn by none of the bundled fonts, so they are written out instead: `₹1,950` converts to `Rs.1,950`. The amount is preserved, the sign is not.

## Not supported

Listed so you can plan around it. None of these fail the conversion.

- Images are skipped; the surrounding text is unaffected.
- Non-Latin scripts (Devanagari, Arabic, CJK, Cyrillic) render as filled boxes, because the bundled fonts have no glyphs for them.
- Uncommon emoji with no equivalent symbol fall back to a small dot.
- Raw HTML tags are ignored, though their text is kept.

## Errors

Every `4xx` and `5xx` returns the same envelope:

```json
{"error": {"code": "...", "message": "...", "path": "...", "example": "..."}, "help": {}}
```

`code` is a stable slug, `message` says what to change, and `example` is a curl line that works. Malformed JSON is a `400`; well-formed JSON that fails the schema is a `422`.

The slugs: `INVALID_JSON_BODY`, `INVALID_REQUEST_BODY`, `FILE_NOT_TEXT`, `DOCUMENT_TOO_LARGE`, `PARAGRAPH_TOO_LONG`, `CONVERSION_TIMEOUT`, `SERVICE_BUSY`, `STORAGE_BUDGET_EXCEEDED`, `NOT_FOUND`, `ENDPOINT_NOT_FOUND` on a convert-like path, `METHOD_NOT_ALLOWED`, `RATE_LIMITED`.

## MCP server

`https://mdtopdf.tigzig.com/mcp` over Streamable HTTP, tool `convert_markdown_to_pdf`, which returns a hosted PDF URL rather than the binary. Add it as a custom connector in Claude, ChatGPT, Cursor, LM Studio or n8n.

## More Tigzig tools

Free, no auth: market and fund data, macro and credit indicators, portfolio and risk analytics, India corporate filings, SQL databases. Catalog at `https://api.tigzig.com/.well-known/api-catalog`, guide at `https://www.tigzig.com/llms.txt`.

## Upload a Markdown or text file, get the PDF file back

`POST /v1/convert`

Upload a Markdown or plain-text file and get the PDF back in the response body.

Send the file as multipart/form-data under the field name `file`. Accepts .md, .markdown
and .txt; a .txt is treated as plain text so its single line breaks are preserved, while
.md follows standard Markdown rules. The response is application/pdf, not JSON, and the
download name is taken from the uploaded filename. A file that is not UTF-8 text (a .pdf
or .docx, say) returns 400 FILE_NOT_TEXT rather than failing mid-conversion.

Supports headings, bold, italic, strikethrough, inline and fenced code, links, nested and
numbered lists, task lists, tables with column alignment, blockquotes, rules, Greek and
maths symbols, and the page-break markers described in the API description.

## Send Markdown as JSON, get the PDF file back (canonical)

`POST /v1/convert/text`

Send Markdown as JSON and get the PDF back in the response body.

Body: {"content": "# your **markdown**", "filename": "out.pdf"} - `content` is required,
`filename` is optional and only names the download. The body must be UTF-8 (RFC 8259).
The response is application/pdf, not JSON; if your HTTP client is awkward with binary
bodies, POST /v1/convert/text/hosted instead and get a URL to the PDF.

Supports headings, bold, italic, strikethrough, inline and fenced code, links, nested and
numbered lists, task lists, tables with column alignment, blockquotes, rules, Greek and
maths symbols, and the page-break markers described in the API description.

## Send Markdown as JSON, get a hosted PDF link back (the MCP tool)

`POST /v1/convert/text/hosted`

Convert Markdown text into a formatted PDF and return a hosted URL to it.

Give it Markdown (including AI-generated Markdown) and get back a URL to a cleanly
formatted PDF: headings, lists, tables, code, blockquotes, rules. Send a JSON body
{"content": "# your **markdown**", "filename": "out.pdf"} - the text must be UTF-8.
Returns {"pdf_url": "..."}. Generated files are served from /static/pdfs and cleaned
up after 24h. (This is the hosted variant of POST /v1/convert/text - a URL instead of
the binary - because an MCP tool result is text and cannot carry a PDF payload.)
