# HTML to PDF

Use `/htmlToPdf` to render HTML as a PDF. It is the primary endpoint for custom templates, invoices, reports, and other HTML-based documents.

## Endpoint

```
POST /htmlToPdf
```

## Authentication

Send a valid API key or OAuth token in the `Authorization` header:

```
Authorization: Bearer YOUR_API_KEY
```

See [Authentication](https://pdf-mcp.io/docs/authentication) for details.

---

## Request body

This endpoint accepts both JSON and multipart form data.

### JSON body

**Content-Type:** `application/json`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `html` | string | Yes | HTML content to convert to PDF |
| `css` | string | No | Additional CSS styles to apply |
| `filename` | string | No | Output filename (default: `document.pdf`) |
| `base_url` | string | No | Base URL for resolving relative URLs in the HTML |
| `storage` | object | No | Storage options for the generated PDF (see below) |
| `return_binary` | boolean | No | Return PDF binary even when using storage (default: `false`) |

### Multipart form data

**Content-Type:** `multipart/form-data`

Upload large HTML documents as files when they may exceed the JSON body limit:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `file` | file | Yes | HTML file to convert to PDF |
| `css_file` | file | No | CSS file with styles to apply |
| `html` | string | No | HTML string (alternative to file upload) |
| `css` | string | No | CSS string (alternative to css_file upload) |
| `filename` | string | No | Output filename (default: `document.pdf`) |
| `base_url` | string | No | Base URL for resolving relative URLs |

When uploading files, the `file` field takes priority over the `html` form field, and `css_file` takes priority over the `css` form field.

### Field details

**html** (required)

The renderer supports full HTML5, including:
- Semantic elements (`<header>`, `<section>`, `<article>`, etc.)
- Tables for data presentation
- Images (inline base64 or absolute URLs)
- Custom fonts via `@font-face` or CDN links
- CSS Grid and Flexbox layouts

**css** (optional)

Additional CSS to apply to the document. If not provided, a default stylesheet is applied that includes page break handling for common elements like tables and rows.

Default CSS includes:
```css
/* Prevent page breaks inside elements */
.no-break {
    page-break-inside: avoid;
    break-inside: avoid;
}

/* Force page break after element */
.page-break {
    page-break-after: always;
    break-after: page;
}

/* Table rows don't split across pages */
tr {
    page-break-inside: avoid;
    break-inside: avoid;
}
```

**filename** (optional)

The filename for the downloaded PDF. If not provided, defaults to `document.pdf`. The `.pdf` extension is automatically appended if not present.

**base_url** (optional)

Base URL for resolving relative URLs in your HTML (images, stylesheets, etc.). Useful when your HTML references assets with relative paths.

### Storage options

Control how the generated PDF is stored and returned.

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `storage.mode` | string | No | `memory` | Storage mode: `memory`, `default`, or `byob` |
| `storage.filename` | string | No | endpoint default | Custom filename (auto-suffixed with timestamp if duplicate) |
| `storage.expires_in` | integer | No | 3600 | Signed URL expiry in seconds (60-604800) |
| `storage.retention_days` | integer | No | 14 | Auto-delete document after N days (1-365) |

**Storage modes:**

- **memory**: Return PDF bytes directly in response (no persistence). This is the default for REST API calls.
- **default**: Store in pdf-mcp S3 bucket, return JSON with document metadata and signed URL.
- **byob**: Store in your own S3 bucket (requires [BYOB configuration](https://pdf-mcp.io/docs/storage-modes)).

See [Storage Modes](https://pdf-mcp.io/docs/storage-modes) for a detailed guide on storage behavior, channel defaults, and the `return_binary` parameter.

---

## Request examples

### Basic HTML conversion

```bash
curl -X POST https://api.pdf-mcp.io/htmlToPdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Hello, World!</h1><p>This is a PDF document.</p>"
  }' \
  --output document.pdf
```

### Invoice with custom CSS

```bash
curl -X POST https://api.pdf-mcp.io/htmlToPdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<!DOCTYPE html><html><head><title>Invoice</title></head><body><h1>Invoice #12345</h1><table><tr><th>Item</th><th>Amount</th></tr><tr><td>Service Fee</td><td>$99.00</td></tr></table><p>Total: $99.00</p></body></html>",
    "css": "@page { size: A4; margin: 2cm; } body { font-family: Arial, sans-serif; } table { width: 100%; border-collapse: collapse; } th, td { border: 1px solid #ddd; padding: 8px; }",
    "filename": "invoice-12345.pdf"
  }' \
  --output invoice-12345.pdf
```

### HTML with external assets

```bash
curl -X POST https://api.pdf-mcp.io/htmlToPdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<html><body><img src=\"/logo.png\"><h1>Report</h1></body></html>",
    "base_url": "https://example.com/assets"
  }' \
  --output report.pdf
```

### Persistent storage

```bash
curl -X POST https://api.pdf-mcp.io/htmlToPdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Invoice #12345</h1><p>Amount Due: $99.00</p>",
    "storage": {
      "mode": "default",
      "filename": "invoice-12345.pdf",
      "expires_in": 86400,
      "retention_days": 30
    }
  }'
```

### Multipart file upload

```bash
curl -X POST https://api.pdf-mcp.io/htmlToPdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@report.html" \
  -F "css_file=@styles.css" \
  -F "filename=report.pdf" \
  --output report.pdf
```

### Store and return the binary

```bash
curl -X POST https://api.pdf-mcp.io/htmlToPdf \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Report</h1>",
    "storage": { "mode": "default" },
    "return_binary": true
  }' \
  --output report.pdf
```

The API stores the file in S3 but returns the binary PDF instead of JSON. Custom response headers contain the storage metadata (`X-Document-Id`, `X-Storage-Mode`, `X-Storage-Url`).

---

## Response

### Success (memory mode)

When `storage.mode` is `memory` or not provided, returns the PDF as a binary file download.

**Headers:**
```
Content-Type: application/pdf
Content-Disposition: attachment; filename="document.pdf"
```

### Success (with storage)

When `storage.mode` is `default` or `byob`, returns JSON with document metadata and a signed download URL:

```json
{
  "success": true,
  "document_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://s3.eu-central-1.amazonaws.com/...",
  "filename": "invoice-12345.pdf",
  "file_size_bytes": 45678,
  "page_count": 3,
  "storage_mode": "default",
  "expires_at": "2024-02-15T10:30:00Z",
  "signed_url_expires_at": "2024-01-15T12:00:00Z"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` on success |
| `document_id` | string | UUID of the stored document |
| `url` | string | Presigned URL for downloading the PDF |
| `filename` | string | Document filename |
| `file_size_bytes` | integer | Size of the PDF in bytes |
| `page_count` | integer | Number of pages in the PDF |
| `storage_mode` | string | Storage mode used (`default` or `byob`) |
| `expires_at` | string | Auto-deletion timestamp (ISO 8601), if retention is set |
| `signed_url_expires_at` | string | Expiration time of the signed URL (ISO 8601) |

### Error

```json
{
  "error": "Internal server error",
  "message": "Error description"
}
```

**Status codes:**

| Code | Description |
|------|-------------|
| 200 | Success - PDF returned or stored |
| 400 | Bad Request - Invalid input or BYOB not configured |
| 401 | Unauthorized - Missing or invalid Authorization header |
| 402 | Payment Required - Insufficient credits |
| 403 | Forbidden - Invalid API key or OAuth token |
| 500 | Internal Server Error - PDF generation failed |
| 502 | Bad Gateway - Storage operation failed (S3 upload or URL generation) |

---

## Page formatting

### Page size

Control page dimensions using the `@page` CSS rule:

```css
@page {
  size: A4;          /* A4, Letter, Legal, etc. */
  margin: 2cm;       /* Page margins */
}

/* Or explicit dimensions */
@page {
  size: 8.5in 11in;  /* Width x Height */
}
```

### Page breaks

Control pagination with CSS:

```html
<!-- Force page break before an element -->
<div style="page-break-before: always;">New page content</div>

<!-- Force page break after an element -->
<div style="page-break-after: always;">End of section</div>

<!-- Prevent page break inside an element -->
<div style="page-break-inside: avoid;">Keep together</div>
```

### Headers and footers

Use CSS `@page` rules for running headers/footers:

```css
@page {
  @top-center {
    content: "Company Name";
  }
  @bottom-right {
    content: "Page " counter(page) " of " counter(pages);
  }
}
```

---

## Implementation notes

### Performance
- Inline critical CSS to avoid external requests
- Use base64-encoded images for small graphics
- Keep HTML structure simple and semantic

### Compatibility
- Use absolute URLs or set `base_url` for external resources
- Test with different page sizes for international documents
- Use web-safe fonts or embed fonts via `@font-face`

### Print styling
- Add `@media print` styles for PDF-specific formatting
- Use `page-break-inside: avoid` for elements that should stay together
- Test with multi-page content to verify pagination

---

## Related endpoints

- [Text to PDF](https://pdf-mcp.io/docs/api-text-to-pdf): convert plain text to PDF
- [Image to PDF](https://pdf-mcp.io/docs/api-image-to-pdf): convert images to PDF
- [Merge PDFs](https://pdf-mcp.io/docs/api-merge-pdfs): combine multiple PDFs

## Credit usage

The first page costs **1 credit**. Each additional page costs **0.01 credits**.
