# Markdown & HTML to PDF / DOCX Generator (Reports, Invoices) (`steady_kahikatea/markdown-html-to-pdf-docx`) Actor

Turn Markdown or HTML into PDF and Word (DOCX) files with themes, page numbers, a table of contents, code highlighting, tables, images and JSON templating (built-in invoice). No JavaScript is executed; files stay in the run's storage under normal Apify retention.

- **URL**: https://apify.com/steady_kahikatea/markdown-html-to-pdf-docx.md
- **Developed by:** [Nick Hellmich](https://apify.com/steady_kahikatea) (community)
- **Categories:** Developer tools, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 96.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Markdown & HTML to PDF / DOCX Generator (Reports, Invoices)

Turn **Markdown or HTML** into polished **PDF** and **Word (DOCX)** files, plus HTML if you want it. It's built for AI agents and automations that need to deliver real documents: reports with a table of contents, invoices from JSON data, briefs and documentation. It's the companion to **Document to Markdown & RAG Chunks**.

### Quick start

1. Click **Start**. The prefill renders a short status report (a table and code) to PDF and DOCX for **$0.005**.
2. Paste your Markdown or HTML, upload `.md` / `.html` files, or paste links. GitHub file pages, Google Docs and Dropbox share links are converted automatically.
3. Open the **Output** tab and click **PDF** or **DOCX** to download.

### Features

- **3 themes**: clean, classic and modern. Page size (A4, Letter, Legal, A5), landscape orientation and margins.
- **Headers and footers** with `{page}`, `{pages}`, `{title}` and `{date}`. A **table of contents** with page numbers.
- **Code highlighting**, GitHub-style tables, footnotes, task lists and images (URLs or data URIs).
- **Non-Latin text**: CJK, Arabic, Hebrew, Devanagari, Cyrillic, Greek and emoji.
- **Templating**: `{{ placeholders }}` and loops filled from JSON `data`, plus a built-in **invoice** template that computes the totals.
- **Custom CSS** for the PDF and HTML outputs.

### Examples

```json
{ "markdown": "# Q3 Report\n\n## Summary\n...", "tableOfContents": true, "headerText": "{title}", "formats": ["pdf", "docx"] }
```

```json
{ "template": "invoice", "formats": ["pdf"], "data": { "invoiceNumber": "INV-0042", "date": "2026-10-10", "currency": "USD", "taxRate": 8.25,
  "seller": { "name": "Acme LLC", "address": "100 Main St\nAustin, TX" }, "client": { "name": "Globex Corp" },
  "items": [ { "description": "Consulting", "quantity": 10, "unitPrice": 120 } ] } }
```

### Output

There's one row per document with **pdfUrl**, **docxUrl** and **htmlUrl** download links, plus `pages`, `charged`, `warnings` (for example, a blocked image) and `error`:

```json
{ "index": 0, "title": "Weekly status report", "ok": true, "pages": 1, "charged": true,
  "pdfUrl": "https://api.apify.com/v2/key-value-stores/.../records/ab12cd-Weekly-status-report.pdf",
  "docxUrl": "https://api.apify.com/v2/key-value-stores/.../records/ab12cd-Weekly-status-report.docx" }
```

### Pricing (pay per event)

| Event | Price |
|---|---|
| Document generated, in all requested formats, including its first 10 pages | $0.005 |
| Extra page beyond 10 | $0.0005 |

Examples: an invoice costs **$0.005**; a 14-page report costs **$0.007**; a 100-page report costs **$0.05**. **Failed documents are never charged.** Bronze, Silver and Gold plans get **10/20/30% off**.

### Fidelity notes

- **PDF** is rendered by WeasyPrint, a print-CSS engine. It handles running headers, page counters and TOC page numbers very well. **JavaScript is never run**, so charts drawn by scripts won't appear; use images or SVG instead.
- **DOCX** is produced by pandoc. Headings, lists, tables, code, images, footnotes, headers and footers with page numbers, page size and margins all carry over. Custom CSS and complex layouts (flex or grid) are simplified. Word fills in TOC page numbers when it updates fields on open.

### Limits and safety

- **Limits:** 20 documents per run, 5 MB of text per source, 300 pages per document and 180 s of rendering per document. Remote images, styles and fonts share a 60 s, 50 MB budget per document.
- **Remote resources** are fetched through an SSRF-safe fetcher that blocks private and metadata addresses and re-checks every redirect. Links in your document are never fetched.
- **Privacy:** inputs are deleted after each document and content is never logged. Generated files stay in the run's key-value store under Apify's normal retention, and anyone with a link can download them.

### FAQ

**Can I use my own fonts or styles?** Use `customCss` (for PDF and HTML). Remote `@font-face` URLs are fetched safely.
**Why is an image missing?** Check `warnings`. The URL may be private, too large or blocked.
**GitHub README?** Paste the github.com file link; it's converted to the raw file. Relative image paths in it won't resolve.
**Can an AI agent use it?** Yes, through the Apify API or MCP, and it supports x402 payments.

### Integrations: no-code and AI

#### Zapier: new Airtable/Sheets row → invoice PDF emailed to the client

1. **Trigger:** Google Sheets → *New Spreadsheet Row* (invoice number, client, line items).
2. **Action:** Apify → *Run Actor* → `Markdown & HTML to PDF / DOCX Generator`, run synchronously (it renders in a few seconds; if it times out, use the *Finished Actor run* trigger instead). Input: `{"template": "invoice", "formats": ["pdf"], "data": {"invoiceNumber": "{{Invoice}}", "client": {"name": "{{Client}}"}, "items": [{"description": "{{Item}}", "quantity": {{Qty}}, "unitPrice": {{Price}}}]}}`.
3. **Search:** *Fetch dataset items* → Gmail *Send Email* with the `pdfUrl` link (or attach the file after downloading it with *Webhooks GET*).

#### Make: ChatGPT report → branded DOCX in Google Drive

*OpenAI Create a Completion* (ask for Markdown) → *Apify Run an Actor* (`{"markdown": "{{choices[].message.content}}", "formats": ["docx", "pdf"], "theme": "modern", "tableOfContents": true}`) → *Get Dataset Items* → *HTTP Get a file* (`docxUrl`) → *Google Drive Upload a File*.

#### n8n: AI agent that "hands over" real documents

In an **AI Agent** node, add the *Apify Tool* → *Run an Actor and get dataset* with this Actor, and click the sparkle icon so the model fills `markdown`. The agent writes the report, calls the tool and replies with `pdfUrl`.

#### LangChain: give your agent a "make PDF" tool

```python
from langchain_apify import ApifyActorsTool
make_pdf = ApifyActorsTool("steady_kahikatea/markdown-html-to-pdf-docx")
make_pdf.invoke({"run_input": {"markdown": "# Weekly summary\n\n- Revenue up 8%", "formats": ["pdf"]}})
```

(LlamaIndex: the reader classes load data *into* an index; to produce documents, call this Actor through `apify-client`, or wrap it as a FunctionTool.)

**Sample input → output:** `{"markdown": "# Q3 Report\n...", "formats": ["pdf", "docx"], "tableOfContents": true}` → `{"ok": true, "pages": 4, "pdfUrl": "https://api.apify.com/.../Q3-Report.pdf", "docxUrl": "https://api.apify.com/.../Q3-Report.docx", "charged": true}`. Cost: $0.005.

> **Tip:** Zapier's synchronous *Run Actor* times out after 30 seconds. For anything longer, run it asynchronously and start a second Zap from the **Finished Actor run** trigger. Make's synchronous timeout depends on your plan; use **Watch Actor Runs** for long jobs.

**Also works with:** the Apify API ("API" tab), the Apify MCP server for Claude/Cursor-style agents, and x402 payments.

**Docs used:** [Zapier](https://docs.apify.com/platform/integrations/zapier) · [Make](https://docs.apify.com/platform/integrations/make) · [n8n](https://docs.apify.com/platform/integrations/n8n) · [LangChain](https://docs.apify.com/platform/integrations/langchain) · [LlamaIndex](https://docs.apify.com/platform/integrations/llama-index)

### For AI agents

```
Actor: steady_kahikatea/markdown-html-to-pdf-docx
Input: {"markdown": "# Title\n...", "formats": ["pdf"]}  or  {"template": "invoice", "data": {...}}
Output: rows with pdfUrl, docxUrl, htmlUrl, pages, charged, error
```

### Licenses

WeasyPrint (BSD-3), markdown-it-py (MIT), Pygments (BSD-2), Jinja2 (BSD-3), python-docx (MIT) and Noto fonts (OFL). pandoc (GPL-2) runs as a separate, unmodified program.

Questions? Use the Issues tab. If it's useful, a rating helps others find it.

# Actor input Schema

## `markdown` (type: `string`):

Markdown text (GitHub-style tables, code fences, footnotes, task lists). Can contain Jinja-style {{ placeholders }} filled from `data`.

## `html` (type: `string`):

HTML text. Scripts are removed and never executed.

## `fileUrls` (type: `array`):

Upload .md/.html files or paste direct links. Max 5 MB each.

## `template` (type: `string`):

Render a built-in template with `data`. Currently: invoice.

## `data` (type: `object`):

Values for {{ placeholders }} in your Markdown/HTML or for the built-in template (sandboxed Jinja2).

## `documents` (type: `array`):

Advanced: up to 20 documents, each {markdown|html|fileUrl|template, data, title, filename}.

## `formats` (type: `array`):

Any of pdf, docx, html.

## `theme` (type: `string`):

clean (sans, blue), classic (serif), modern (sans, violet).

## `pageSize` (type: `string`):

Page size.

## `landscape` (type: `boolean`):

Landscape orientation.

## `marginMm` (type: `integer`):

All four margins, 5–50 mm.

## `headerText` (type: `string`):

Placeholders: {page}, {pages}, {title}, {date}.

## `footerText` (type: `string`):

Placeholders: {page}, {pages}, {title}, {date}. Empty for none.

## `tableOfContents` (type: `boolean`):

Adds a contents page with page numbers (PDF) / a Word TOC field (DOCX).

## `tocDepth` (type: `integer`):

Heading levels to include (1–4).

## `title` (type: `string`):

Defaults to the first heading.

## `highlightCode` (type: `boolean`):

Syntax colours for fenced code blocks.

## `customCss` (type: `string`):

Extra CSS applied after the theme. Remote url() resources go through the same SSRF protection.

## `maxPages` (type: `integer`):

Safety limit (max 300).

## Actor input object example

````json
{
  "markdown": "# Weekly status report\n\n## Highlights\n\n- Shipped the **new onboarding flow**\n- Resolved 12 support tickets\n\n## Metrics\n\n| Metric | This week | Last week |\n|---|---:|---:|\n| Signups | 128 | 97 |\n| Churn | 1.8% | 2.1% |\n\n```python\nprint(\"Hello, PDF!\")\n```\n",
  "formats": [
    "pdf",
    "docx"
  ],
  "theme": "clean",
  "pageSize": "A4",
  "landscape": false,
  "marginMm": 18,
  "footerText": "Page {page} of {pages}",
  "tableOfContents": false,
  "tocDepth": 3,
  "highlightCode": true,
  "maxPages": 300
}
````

# Actor output Schema

## `results` (type: `string`):

No description

## `files` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

`````javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "markdown": `# Weekly status report

## Highlights

- Shipped the **new onboarding flow**
- Resolved 12 support tickets

## Metrics

| Metric | This week | Last week |
|---|---:|---:|
| Signups | 128 | 97 |
| Churn | 1.8% | 2.1% |

```python
print("Hello, PDF!")
````,
    "formats": [
        "pdf",
        "docx"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steady_kahikatea/markdown-html-to-pdf-docx").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

`````

## Python example

````python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "markdown": """# Weekly status report

## Highlights

- Shipped the **new onboarding flow**
- Resolved 12 support tickets

## Metrics

| Metric | This week | Last week |
|---|---:|---:|
| Signups | 128 | 97 |
| Churn | 1.8% | 2.1% |

```python
print(\"Hello, PDF!\")
````

""",
"formats": \[
"pdf",
"docx",
],
}

# Run the Actor and wait for it to finish

run = client.actor("steady_kahikatea/markdown-html-to-pdf-docx").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)

print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

````

## CLI example

```bash
echo '{
  "markdown": "# Weekly status report\\n\\n## Highlights\\n\\n- Shipped the **new onboarding flow**\\n- Resolved 12 support tickets\\n\\n## Metrics\\n\\n| Metric | This week | Last week |\\n|---|---:|---:|\\n| Signups | 128 | 97 |\\n| Churn | 1.8% | 2.1% |\\n\\n```python\\nprint(\\"Hello, PDF!\\")\\n```\\n",
  "formats": [
    "pdf",
    "docx"
  ]
}' |
apify call steady_kahikatea/markdown-html-to-pdf-docx --silent --output-dataset

````

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steady_kahikatea/markdown-html-to-pdf-docx"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Di8Cyxa8mDZ0ZBRhf/builds/2pckYTPfQA8oiHXsg/openapi.json
