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 /htmlToPdfAuthentication
Send a valid API key or OAuth token in the Authorization header:
Authorization: Bearer YOUR_API_KEYSee 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-faceor 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:
/* 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).
See Storage Modes for a detailed guide on storage behavior, channel defaults, and the return_binary parameter.
Request examples
Basic HTML conversion
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.pdfInvoice with custom CSS
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.pdfHTML with external assets
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.pdfPersistent storage
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
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.pdfStore and return the binary
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.pdfThe 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:
{
"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
{
"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:
@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:
<!-- 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:
@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_urlfor external resources - Test with different page sizes for international documents
- Use web-safe fonts or embed fonts via
@font-face
Print styling
- Add
@media printstyles for PDF-specific formatting - Use
page-break-inside: avoidfor elements that should stay together - Test with multi-page content to verify pagination
Related endpoints
- Text to PDF: convert plain text to PDF
- Image to PDF: convert images to PDF
- Merge PDFs: combine multiple PDFs
Credit usage
The first page costs 1 credit. Each additional page costs 0.01 credits.