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, which 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_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_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 promptly, because 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, so 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 such as a URL list, a sitemap, or a crawl, rather than files alone.
| 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 (Founding: 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_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_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_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_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 ops allowance 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 (Founding: 5 MB) |
| Monthly ops | Plan-dependent (Founding: 500) |
| File retention | Plan-dependent (Founding: 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, because 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, both 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.