Anything to PDF API#
The POST /v1/convert/anything-to-pdf endpoint converts almost any uploaded file — Word, Excel, PowerPoint, OpenDocument, Apple Pages and Numbers, HTML, Markdown, plain text, EPUB, images, and SVG — into a PDF. It auto-detects the format from the file you send, dispatches to the right rendering engine, and returns a single PDF. One endpoint replaces the whole per-format PDF stack: you upload a file, you get a PDF back, whatever the source type.
It is the single-call superset of the format-specific PDF endpoints (html-to-pdf, doc-to-pdf, excel-to-pdf, and the rest) — reach for those when you already know the input type and want fine-grained page control, and reach for this one when the input could be anything. This endpoint is file-based only; to render a live web page to PDF, use url-to-pdf. For the Markdown counterpart that turns any file into clean Markdown, see anything-to-markdown.
Endpoint#
POST /v1/convert/anything-to-pdf
Content-Type: multipart/form-data
Output format: PDF (.pdf, application/pdf). The input type is auto-detected from the uploaded filename's extension and its magic bytes — you do not specify an input format.
Supported input formats#
The input type is detected from the file extension (validated against the file's magic bytes). These are every format the endpoint accepts:
| Category | Formats | Extensions | Notes |
|---|---|---|---|
| Word | DOCX, DOC | .docx, .doc |
Rendered through LibreOffice, preserving styles, tables, and layout. |
| Excel | XLSX, XLS | .xlsx, .xls |
Spreadsheets rendered to paginated PDF via LibreOffice. |
| PowerPoint | PPTX, PPT | .pptx, .ppt |
One PDF page per slide, via LibreOffice. |
| OpenDocument | ODT, ODS, ODP, OTS | .odt, .ods, .odp, .ots |
Text, spreadsheet, presentation, and spreadsheet-template documents, via LibreOffice. |
| Apple iWork | Pages, Numbers | .pages, .numbers |
Apple Pages and Numbers documents, via LibreOffice. |
| Rich text / data | RTF, CSV | .rtf, .csv |
RTF documents and CSV tables rendered via LibreOffice. |
| Web / markup | HTML, XHTML | .html, .htm, .xhtml |
Rendered with WeasyPrint, honouring the document's own CSS. |
| Markdown | Markdown | .md, .markdown, .mdown, .mkd |
Rendered to a styled PDF with headings, tables, and fenced code. |
| Plain text | Text | .txt, .text |
Rendered in a monospace layout that preserves whitespace. |
| E-books | EPUB | .epub |
Chapters converted in reading (spine) order to a text PDF. |
| Images | PNG, JPEG, GIF, BMP, TIFF, WebP, HEIC | .png, .jpg, .jpeg, .gif, .bmp, .tiff, .tif, .webp, .heic, .heif |
Each image becomes a single-page PDF; transparency is flattened onto white. |
| Vector | SVG | .svg |
Rendered as vector (not rasterised) with CairoSVG. |
.pdf |
Accepted and returned as-is — useful for grayscale normalisation (see pdf_options). |
grayscale is honoured on this endpoint. For full page control, send HTML or Markdown to html-to-pdf or markdown-to-pdf instead. To convert a live URL to PDF, use url-to-pdf.
Authentication#
This endpoint supports both private and public key authentication.
Private Key#
Include your secret key in the X-API-Key header. Use this for server-to-server calls where the key is never exposed to the client.
X-API-Key: sk_live_your_private_key
Public Key with JWT#
For client-side usage, first generate a JWT token with your public key, then pass it as a Bearer token.
Step 1 -- Get a token:
POST /v1/auth/token
X-API-Key: pk_live_your_public_key
Step 2 -- Use the token:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
The full flow, including domain locking and token refresh, is in the authentication guide. Each API key carries an allowed-endpoints allowlist — if /v1/convert/anything-to-pdf is not on the key's list, the request is rejected with 403.
Request Parameters#
Send the file as multipart/form-data. The document goes in the file field; the rest are optional form fields.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file |
file | Yes | -- | The document, image, or markup file to convert. Its extension must be one of the supported input formats above. |
output_filename |
string |
No | Input name | Custom name for the output file. The .pdf extension is added automatically. |
direct_download |
boolean |
No | true |
Accepted for request-shape parity with the other conversion endpoints. |
job_id |
string |
No | -- | Client-provided job ID for timeout recovery. When a sync conversion exceeds reverse-proxy timeout limits, poll GET /v1/convert/status/{job_id} to retrieve the result. |
pdf_options |
string |
No | null |
JSON string of PDF options. Only grayscale is honoured on this endpoint — see below. |
PDF Options#
Pass as a JSON string in the pdf_options form field. Because the input format is auto-detected and each format is rendered by a different engine, only grayscale is applied uniformly here.
| Parameter | Type | Default | Description |
|---|---|---|---|
grayscale |
boolean |
false |
Convert the output PDF to grayscale via Ghostscript post-processing. Applies to every input type, including an already-PDF upload. |
For a custom page size, margins, orientation, headers, or footers, convert HTML or Markdown through the format-specific html-to-pdf or markdown-to-pdf endpoints, which accept the full pdf_options schema.
Response#
The conversion runs in-process and the resulting .pdf file is stored, then the endpoint returns a JSON body with a pre-signed download URL:
{
"presigned_url": "https://spaces.example.com/...signed...",
"object_key": "env/files/{project_id}/anything-to-pdf/report_20260714_101530123.pdf",
"filename": "report_20260714_101530123.pdf",
"file_size": 51240,
"conversion_time_seconds": 2.1,
"job_id": null
}
The same values are echoed in response headers (X-Object-Key, X-File-Size, X-Conversion-Time, X-Filename) so you can read them without parsing the body. Download the PDF from presigned_url — the link is short-lived.
How each format is converted#
Every format is normalised into a PDF, so you get one consistent output regardless of the source type.
- Word / Excel / PowerPoint — Rendered with LibreOffice in headless mode, preserving styles, tables, and layout; presentations produce one page per slide. Legacy binary formats (
.doc,.xls,.ppt) are handled by the same engine. - OpenDocument, Apple Pages / Numbers, RTF, CSV — Also rendered through LibreOffice, so ODF documents, iWork exports, rich text, and CSV tables all paginate cleanly.
- HTML / XHTML — Rendered with WeasyPrint, which honours the document's own CSS. External resources referenced by URL may not resolve — inline your CSS and base64-encode images for best results.
- Markdown — Converted to HTML (headings, GitHub-Flavored tables, fenced code) and rendered with WeasyPrint into a clean, styled PDF.
- Plain text — Rendered in a monospace layout that preserves whitespace and wraps long lines, so logs and code stay readable.
- EPUB — Content documents are read in spine (reading) order and rendered chapter by chapter into a text PDF; the navigation document is skipped.
- Images (PNG, JPEG, GIF, BMP, TIFF, WebP, HEIC) — Each image becomes a single-page PDF via Pillow. Transparency is flattened onto a white background, and only the first frame of a multi-frame image (animated GIF, multi-page TIFF) is used.
- SVG — Rendered as true vector graphics with CairoSVG, so the result stays crisp at any zoom.
- PDF — An uploaded PDF is validated and returned unchanged, which makes this endpoint a convenient way to grayscale-normalise an existing PDF.
Output format#
The result is a standard PDF (application/pdf):
- Documents keep their pagination, headings, tables, and styling from the source rendering engine.
- Images produce a single page sized to the image; SVG stays vector.
- Grayscale — when
pdf_options.grayscaleistrue, the finished PDF is desaturated via a Ghostscript post-processing pass.
If you need clean Markdown instead of a PDF — for example to feed an LLM or RAG pipeline — send the same file to anything-to-markdown or the ingest endpoint instead.
Supported formats by endpoint#
The file-upload endpoints share the same format auto-detection but target different outputs. This endpoint (anything-to-pdf) accepts the widest set — all 36 formats below. anything-to-markdown and /v2/ingest accept the same 22 document formats as each other (images, SVG, and the Apple/OTS formats are PDF-only), and /v2/ingest additionally accepts web sources — a URL list, a sitemap, or a crawl — not just files.
| Category | Extensions | anything-to-pdf | anything-to-markdown | /v2/ingest |
|---|---|---|---|---|
.pdf |
✓ | ✓ | ✓ | |
| Word | .docx, .doc |
✓ | ✓ | ✓ |
| Excel | .xlsx, .xls |
✓ | ✓ | ✓ |
| PowerPoint | .pptx, .ppt |
✓ | ✓ | ✓ |
| CSV | .csv |
✓ | ✓ | ✓ |
| Rich text | .rtf |
✓ | ✓ | ✓ |
| OpenDocument | .odt, .ods, .odp |
✓ | ✓ | ✓ |
| ODF template | .ots |
✓ | — | — |
| Apple iWork | .pages, .numbers |
✓ | — | — |
| Web / markup | .html, .htm, .xhtml |
✓ | ✓ | ✓ |
| Markdown / text | .md, .markdown, .mdown, .mkd, .txt, .text |
✓ | ✓ | ✓ |
| E-books | .epub |
✓ | ✓ | ✓ |
| Images | .png, .jpg, .jpeg, .gif, .bmp, .tiff, .tif, .webp, .heic, .heif |
✓ | — | — |
| Vector | .svg |
✓ | — | — |
A ✓ means the endpoint accepts that format as a file upload; a — means it does not. Images and SVG convert to PDF here but are rejected by the Markdown-output endpoints (image OCR is a separate pipeline). Per-file size limits are plan-dependent (Free: 5 MB) across all three endpoints.
Code Examples#
curl (Private Key)#
curl -X POST https://api.enconvert.com/v1/convert/anything-to-pdf \
-H "X-API-Key: sk_live_your_private_key" \
-F "[email protected]"
Python (Private Key)#
import requests
with open("quarterly-report.docx", "rb") as f:
response = requests.post(
"https://api.enconvert.com/v1/convert/anything-to-pdf",
headers={"X-API-Key": "sk_live_your_private_key"},
files={"file": ("quarterly-report.docx", f)},
)
response.raise_for_status()
result = response.json()
# Download the PDF from the pre-signed URL.
pdf = requests.get(result["presigned_url"]).content
with open("quarterly-report.pdf", "wb") as out:
out.write(pdf)
Node.js (Private Key)#
import { readFile, writeFile } from "node:fs/promises";
const form = new FormData();
form.append(
"file",
new Blob([await readFile("quarterly-report.docx")]),
"quarterly-report.docx"
);
const response = await fetch(
"https://api.enconvert.com/v1/convert/anything-to-pdf",
{ method: "POST", headers: { "X-API-Key": "sk_live_your_private_key" }, body: form }
);
const result = await response.json();
const pdf = await fetch(result.presigned_url).then((r) => r.arrayBuffer());
await writeFile("quarterly-report.pdf", Buffer.from(pdf));
PHP (Private Key)#
$ch = curl_init("https://api.enconvert.com/v1/convert/anything-to-pdf");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["X-API-Key: sk_live_your_private_key"],
CURLOPT_POSTFIELDS => [
"file" => new CURLFile("quarterly-report.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "quarterly-report.docx"),
],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data["presigned_url"];
Error Responses#
| Status | Condition |
|---|---|
400 Bad Request |
Unsupported file type, an empty file, or a corrupt/unreadable document (e.g. an invalid image or a malformed EPUB). |
400 Bad Request |
The file's bytes do not match its declared extension (magic-byte mismatch). |
400 Bad Request |
Invalid pdf_options JSON. |
401 Unauthorized |
Missing or invalid API key / JWT token. |
402 Payment Required |
Monthly conversion limit or storage limit reached. |
403 Forbidden |
/v1/convert/anything-to-pdf is not in the API key's allowed endpoints. |
413 Payload Too Large |
The upload exceeds your plan's per-file size limit. |
500 Internal Server Error |
Conversion failed unexpectedly. |
The full status-code reference is in the error-codes guide.
Limits#
| Limit | Value |
|---|---|
| Maximum upload size | Plan-dependent (Free: 5 MB) |
| Monthly conversions | Plan-dependent (Free: 100) |
| File retention | Plan-dependent (Free: 1 hour) |
| Page geometry options | Not applied on this endpoint (only grayscale) |
| Supported input formats | See the supported input formats table |
Frequently asked questions#
How do I convert any file to PDF with an API?#
Send a POST request to /v1/convert/anything-to-pdf as multipart/form-data with your file in the file field and your key in the X-API-Key header. The endpoint auto-detects the format, renders it to PDF, and returns JSON with a presigned_url to the finished .pdf. You do not need to tell it the input type — the extension and magic bytes decide.
Which file formats can I convert to PDF?#
Word (.docx, .doc), Excel (.xlsx, .xls), PowerPoint (.pptx, .ppt), OpenDocument (.odt, .ods, .odp, .ots), Apple Pages and Numbers, RTF, CSV, HTML/XHTML, Markdown, plain text, EPUB, images (.png, .jpg, .jpeg, .gif, .bmp, .tiff, .webp, .heic), and SVG. An existing PDF is accepted and returned as-is. The full list with per-format notes is in the supported input formats table.
Can I convert Word, Excel, or PowerPoint to PDF via the API?#
Yes. Office documents — modern (.docx, .xlsx, .pptx) and legacy (.doc, .xls, .ppt) — are rendered with LibreOffice, preserving styles, tables, and layout, with one page per slide for presentations. Upload the file and you get the PDF back.
How do I convert an image such as PNG, JPEG, or HEIC to PDF?#
Upload it to the same endpoint. Each image becomes a single-page PDF, with transparency flattened onto a white background; iPhone .heic/.heif photos and .svg vectors are supported too. For a multi-frame image (animated GIF or multi-page TIFF), the first frame is used.
Can I set a custom page size, margins, or headers on the PDF?#
Not on this endpoint — only grayscale is honoured, because the input format is auto-detected and each type uses a different rendering engine. For full page control (page size, margins, orientation, headers, footers), send HTML or Markdown to the html-to-pdf or markdown-to-pdf endpoints, which accept the complete pdf_options schema.
How is this different from the doc-to-pdf or html-to-pdf endpoints?#
The format-specific endpoints each accept one input type and expose full page-geometry options; anything-to-pdf accepts them all behind a single call and auto-detects the format, which is ideal when the input could be anything. Use a specific endpoint when you know the type and want page control; use this one when you want a single upload path for many formats.