# EPUB to PDF Converter - Ebook to PDF Online (`marcel-rbro/epub-to-pdf`) Actor

Convert EPUB to PDF online in seconds. Upload an ebook or paste a URL and get a PDF back, with page size, margins and fonts under your control. Also converts AZW3, MOBI, FB2 and CBZ. Up to 100 books per run, returned as a single ZIP archive.

- **URL**: https://apify.com/marcel-rbro/epub-to-pdf.md
- **Developed by:** [Marcel Rebro](https://apify.com/marcel-rbro) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Convert **EPUB to PDF** online, along with AZW3, MOBI, FB2, CBZ, LIT and PDB files. Upload one ebook or a whole folder of them, choose a page size, and get typeset PDFs back. Powered by calibre, with no install, no account on some ebook forum and no desktop software.

An EPUB is reflowable: the text has no pages until a reader gives it a screen. A PDF is fixed: every line break is decided once, at conversion time, and never moves again. So this is not a lossless transform, it is a typesetting job, and the settings below are the ones that decide how the result reads. You need a PDF when something downstream demands one - a printer, a university submission portal, an e-reader that refuses EPUB, a colleague with Acrobat and nothing else.

- 📄 **A real typesetting pass, not a screenshot** - selectable text, working links, a PDF outline and an embedded cover
- 📐 **Nine page sizes** - A4 and US Letter for printing, A5 and A6 for something that reads like a paperback rather than an office memo
- 🔠 **Font, size and margins are yours** - serif or sans body text, a base font size in points, and all four margins
- 📚 **Reads more than EPUB** - `.azw3`, `.mobi`, `.fb2`, `.cbz`, `.lit` and `.pdb`, as long as they are DRM-free
- 🔢 **Page numbers, headers and footers** - optional running heads with the title, author, section and page number
- 📦 **Converts a whole folder in one run** - up to 100 ebooks, results zipped, and a DRM-protected book in the middle does not stop the rest
- 🔌 **Runs from the API, a schedule or an integration** - it is an Apify Actor, so Zapier, Make, n8n and MCP clients can call it

### How to convert EPUB to PDF

1. Click **Try for free** and sign in to Apify.
2. Upload your `.epub` file in the **Ebooks** field, or paste a direct URL to it. You can add as many as you like.
3. Choose a **Page size**. A4 is the default; pick A5 if the PDF is for reading on screen rather than printing.
4. Click **Start**.
5. Download the PDF from the **Storage** tab, or from the download URL in the run's dataset record.

The remaining settings all change how the page looks rather than whether it works, so the defaults are a reasonable book. The two worth touching first are **Page size** and **Base font size**.

#### How to convert AZW3 to PDF

Identical steps with an `.azw3` file. AZW3 (also called KF8) is Amazon's newer format and it carries real CSS, so it typesets better than old MOBI does. `.azw` and `.prc` go through the same path. DRM-protected Kindle purchases do not - see [Limitations](#limitations).

#### How to convert MOBI to PDF

Upload a `.mobi` file instead. MOBI is built on a cut-down HTML 3.2, so there is less structure in the source for the conversion to work with: expect simpler tables and looser layout than the same book in EPUB or AZW3. Nothing extra to configure - the Actor reads the file's own header to work out what it has.

#### How to convert FB2 to PDF

Upload an `.fb2` file. FB2 is a single XML document rather than an archive, and it is common in Russian-language libraries. It carries clean semantic markup, so it converts tidily.

#### How to convert CBZ to PDF

Upload a `.cbz` comic archive - a zip full of page images - and each image becomes a PDF page. Turn **Preserve cover aspect ratio** on, which is the default, unless you want the artwork stretched to the paper. For comics, consider setting all four margins to 1 point and picking a page size close to the artwork's own proportions; A4 will otherwise letterbox a US comic page.

#### How to convert LIT and PDB to PDF

`.lit` (Microsoft Reader) and `.pdb` (PalmDOC) both work, as long as they are DRM-free. Both are dead formats, which is usually why someone is converting them.

#### What about PDF to EPUB?

That is the other direction, and this Actor does not do it. Converting a fixed-layout PDF back into reflowable text is a genuinely different and much harder problem - it means recovering reading order and structure that the PDF threw away. It will be its own Actor.

#### How to batch convert a folder of ebooks to PDF

Put every file in the **Ebooks** field - up to 100 per run - and each one is converted on its own with the same settings. This is the cheap way to do it: starting the container is most of the cost of a short run, so a hundred books in one run costs far less than a hundred runs of one book.

Each PDF is stored under its own filename, and the run also produces a ZIP of all of them, which is what you get from the **Storage** tab or the API response. Two books with the same filename do not overwrite each other - the second becomes `book-2.pdf`.

A batch does not stop on a bad file. A DRM-protected book, a dead URL or something that is not an ebook at all is recorded against that file with a reason, and the rest of the batch carries on; the run fails only if nothing at all converted. That matters for Kindle formats in particular, because most `.azw` and `.mobi` files bought from Amazon are protected, so a real folder converts partially by nature. The run's log ends with how many converted, how many failed, and how many failed specifically on DRM, and the dataset has one row per input file with an `ok` flag and the reason.

Batches take longer than the 300-second `run-sync` window, so drive them with the asynchronous [Run Actor](https://docs.apify.com/api/v2/act-runs-post) endpoint rather than `run-sync`.

### Input

Upload your files in the **Ebooks** field, or pass direct URLs to them.

| Field | Description |
|---|---|
| `files` | The ebooks to convert, as an array. A multi-file upload or a list of URLs. Up to 100. |
| `file` | A single ebook as a URL. Hidden in the Console; kept for API callers. Ignored when `files` is set. |
| `paperSize` | `a4` (default), `letter`, `legal`, `a3`, `a5`, `a6`, `b4`, `b5` or `b6`. |
| `baseFontSize` | Body text size in points. `0` (default) lets calibre choose to suit the page. |
| `marginTop`, `marginBottom`, `marginLeft`, `marginRight` | In points, 72 pt to the inch. Default 72. |
| `pdfPageNumbers` | Print a page number at the bottom of every page. |
| `standardFont` | `serif` (default), `sans` or `mono` for the body text. |
| `serifFamily`, `sansFamily` | Font family names. Must be installed in the container - see [Which fonts can I use?](#which-fonts-can-i-use) |
| `preserveCoverAspectRatio` | On by default. Keeps the cover's proportions instead of stretching it to the page. |
| `smartenPunctuation` | Convert quotes, dashes and ellipses to typographic equivalents. |
| `pdfHeaderTemplate`, `pdfFooterTemplate` | HTML running heads. `_PAGENUM_`, `_TITLE_`, `_AUTHOR_` and `_SECTION_` are substituted. |
| `outputFilename` | Defaults to the input filename with a `.pdf` extension. Ignored for a batch, where every PDF keeps its own name. |
| `bookTitle`, `bookAuthors` | Override the PDF metadata. Separate authors with `&`. |
| `fileBase64`, `filename` | A single file as base64, for API callers who prefer JSON to a URL. |
| `verboseLog` | Include the full calibre log in the Actor log. |

One quirk worth knowing, because it is calibre's and not this Actor's: a page margin of `0` means "fall back to the general margin setting", not "no margin". Use `1` if you want an edge-to-edge page. The input schema enforces a floor of 1 for that reason.

### Output

Every converted PDF is written to the run's key-value store under its own filename, so it is downloadable from the **Storage** tab.

`OUTPUT` is the record the API hands back, and it holds whichever of these you actually want:

- **One ebook in** - `OUTPUT` is the PDF itself, so `run-sync` returns a PDF in the response body.
- **Several ebooks in** - `OUTPUT` is a ZIP of every PDF.
- **A batch whose PDFs total more than 200 MB** - the ZIP is skipped, because it has to be held in memory to be uploaded. `OUTPUT` is then a JSON manifest listing every PDF's key, size and URL. The PDFs themselves are stored exactly as before.

The dataset gets **one record per input ebook**, pushed as it is produced, carrying an `ok` flag, the source format, the source EPUB version, the page size, the page count, file sizes, the title and authors, the seconds it took, and - when `ok` is false - a plain-language `error` and a machine-readable `errorKind` (`drm`, `unsupported`, `download`, `timeout`, `caps`, `budget` or `conversion`).

### How much does it cost to convert EPUB to PDF?

| Job | Run time | Cost |
|---|---|---|
| One 10-chapter novel | 13.5 s | **$0.0017** |
| 10 novels in one run | 62.1 s | **$0.0054**, or $0.0005 each |

Measured 2026-08-26 on the Free plan at the default 2048 MB, read back from the run API.

**A book costs a fraction of a cent**, and Apify's [free plan](https://apify.com/pricing) includes $5
of usage a month, so a personal library converts for nothing.

**Convert a library as one run.** Ten books took 62 s against 13.5 s for one, and as ten separate runs
they would have cost about $0.017 rather than $0.0054 - roughly three times more. Container startup is
paid once per run rather than once per book; past that, each book still costs its own few seconds of
calibre time, so the saving is real but not unlimited.

Compute is most of the bill here, with storage writes and data transfer making up the rest.

Illustrated books and omnibus collections are the exception to all of the above - they are far slower
than a text novel, and a very large one is better given a run of its own than dropped in the middle of
a library.

### How to convert EPUB to PDF with the API

`run-sync` returns the PDF in the response body:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/marcel-rbro~epub-to-pdf/run-sync?token=<TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"file": "https://example.com/book.epub", "paperSize": "a4"}' \
  --output book.pdf
```

With the typesetting settings spelled out - A5 pages, 11 pt body text, half-inch margins and page numbers:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/marcel-rbro~epub-to-pdf/run-sync?token=<TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{
        "file": "https://example.com/book.epub",
        "paperSize": "a5",
        "baseFontSize": 11,
        "marginTop": 36, "marginBottom": 36, "marginLeft": 36, "marginRight": 36,
        "pdfPageNumbers": true
      }' \
  --output book.pdf
```

A batch takes a list. It will outlast the `run-sync` window, so start it asynchronously and collect the results afterwards:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/marcel-rbro~epub-to-pdf/runs?token=<TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{
        "files": [
          "https://example.com/one.epub",
          "https://example.com/two.azw3",
          "https://example.com/three.fb2"
        ],
        "paperSize": "a5"
      }'
```

If you hold the bytes rather than a URL, pass them as base64 in `fileBase64`. That path takes one ebook at a time:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/marcel-rbro~epub-to-pdf/run-sync?token=<TOKEN>" \
  -H 'Content-Type: application/json' \
  -d "{\"fileBase64\": \"$(base64 < book.epub)\", \"filename\": \"book.epub\"}" \
  --output book.pdf
```

Base64 adds about a third to the payload, so prefer a URL for large files. A URL and base64 are the two input paths: the Apify API requires Actor input to be `application/json` and rejects anything else with HTTP 400 before the run starts, so there is no way to post the ebook as a raw request body.

`run-sync` waits up to 300 seconds. Use the asynchronous [Run Actor](https://docs.apify.com/api/v2/act-runs-post) endpoint for anything larger. There are [client libraries for JavaScript and Python](https://docs.apify.com/api/client), and the same run can be triggered on a schedule or from Zapier, Make, n8n, Slack or an MCP client.

### Limitations

- **Reflowable in, fixed-layout out.** This is the one thing worth understanding before you start. An EPUB has no pages: the reader decides where lines and pages break, at whatever size and font the reader was set to. A PDF has nothing but pages, fixed at conversion time. So the conversion has to *invent* a page - a size, a font, a measure, a set of breaks - and the settings in the input are how you choose which one it invents. The text and images survive; the specific typography of the EPUB as you saw it in your reader does not, because it never existed as a fixed thing in the first place.
- **Going back is much harder than coming here.** A PDF made this way is a dead end for reflowing. Keep the EPUB.
- **DRM-protected files fail.** The Actor reads the container before converting: `META-INF/rights.xml` or `META-INF/encryption.xml` for EPUB, the encryption flag in the header for Kindle formats. The run stops with an explanation rather than producing a broken file. Most books bought from Amazon, Kobo or Google are protected. Removing that DRM is out of scope. Font obfuscation, which uses the same `encryption.xml` file and is not DRM, is correctly ignored.
- **Complex layout comes through simplified.** Multi-column pages, sidebars, drop caps and footnote placement are the usual casualties. Fixed-layout EPUBs - children's books, cookbooks, textbooks - convert least faithfully of all, because the source already had a page design and the conversion imposes a different one.
- **Only fonts installed in the container are available.** `serifFamily` and `sansFamily` name a system font, not a file you can upload. See the FAQ for the list.
- **Up to 100 ebooks per run**, within a 500 MB total input, a 200 MB ceiling on any single file, and a 55-minute whole-run conversion budget. Books the budget does not reach are recorded as failed with that reason rather than silently cut off, so raise the memory or split the batch if you hit it.
- **`outputFilename` does not apply to a batch.** Naming every output the same thing is not useful, so each PDF keeps its own filename and the option is ignored with a warning.

### Other file converters

| Actor | Converts |
|---|---|
| **EPUB to PDF converter** (this one) | EPUB, AZW3, MOBI, FB2, CBZ, LIT, PDB → PDF |
| [MOBI to EPUB converter](https://apify.com/marcel-rbro/mobi-to-epub) | MOBI, PRC, AZW, AZW3 → EPUB |
| [Word to PDF converter](https://apify.com/marcel-rbro/word-to-pdf) | DOC, DOCX, ODT, RTF → PDF |
| [JPG to PDF converter](https://apify.com/marcel-rbro/jpg-to-pdf) | JPEG, PNG → PDF |
| [PDF to JPG converter](https://apify.com/marcel-rbro/pdf-to-jpg) | PDF → JPEG, PNG |
| [HEIC to JPG converter](https://apify.com/marcel-rbro/heic-to-jpg) | HEIC, HEIF, AVIF → JPEG, PNG, WebP, AVIF, TIFF |
| [PNG to JPG converter](https://apify.com/marcel-rbro/png-to-jpg) | PNG → JPEG, WebP |

### FAQ

#### Is this EPUB to PDF converter free?

Apify's free plan includes $5 of platform usage per month and needs no card, which covers a personal library many times over. See [How much does it cost](#how-much-does-it-cost-to-convert-epub-to-pdf) for what a book actually costs.

#### Will the formatting survive the conversion to PDF?

The text, images, cover, links and chapter structure survive. The *page* does not, because the EPUB never had one - a reflowable book is re-typeset from scratch to whatever page size you pick. So the honest answer is that the result will look like a competently set book, but not like your e-reader with the settings you had it on. Fixed-layout EPUBs are the exception in the other direction: those did have a page design, and imposing a different one on them goes worse than it does for a novel.

#### Can I convert an EPUB I bought from Kobo, Google Play Books or Amazon?

Only if it is DRM-free, which most retail purchases are not. The Actor inspects the container and stops with an explanation rather than producing a broken file: for EPUB it looks for the Adobe ADEPT and Apple FairPlay markers and for encrypted content in `META-INF/encryption.xml`, and for Kindle formats it reads the encryption flag in the header. Stripping that DRM is out of scope. Project Gutenberg, Standard Ebooks, most Humble Bundles and anything from a publisher's own DRM-free store all convert fine.

#### My EPUB has an encryption.xml but is not DRM-protected. Does it still work?

Yes. The IDPF and Adobe font-obfuscation schemes use the same `META-INF/encryption.xml` file to mangle embedded fonts, and that is not DRM - calibre de-obfuscates it in passing. The Actor checks which algorithm the file names and only fails when something other than a font is actually encrypted.

#### Which page size should I choose?

A4 if you are going to print it outside the US, US Letter inside it. A5 or A6 if the PDF is for reading on a screen or a small e-reader - an A4 page of body text is a very wide measure to read, which is exactly why real books are not A4. A5 with a base font size around 11 pt is the closest this Actor gets to a trade paperback.

#### Which fonts can I use?

`serifFamily` and `sansFamily` take the name of a font installed in the container, not an upload. The container has **DejaVu Serif**, **DejaVu Sans**, **DejaVu Sans Mono**, **Liberation Serif**, **Liberation Sans** and **Liberation Mono**. Liberation Serif is metrically compatible with Times New Roman and Liberation Sans with Arial, so those are the ones to name if you are matching a house style. Leave both empty and calibre picks a sensible default. Fonts embedded in the EPUB itself are used for the text that asks for them, regardless of this setting.

#### How do I add page numbers, or a running header with the chapter title?

Turn on `pdfPageNumbers` for a plain number at the foot of each page. For anything more, use `pdfHeaderTemplate` and `pdfFooterTemplate`, which take HTML and substitute `_PAGENUM_`, `_TITLE_`, `_AUTHOR_` and `_SECTION_`. A conventional running head is:

```
<div style="text-align:center; font-size:9pt">_SECTION_</div>
```

A footer template overrides `pdfPageNumbers`, so put `_PAGENUM_` in the template if you use both.

#### Does the PDF keep the table of contents and links?

Yes. The chapter structure becomes the PDF outline - the bookmarks panel in your PDF reader - and internal and external links stay clickable. If you also want a printed contents page with page numbers in it, that is a different thing, and this Actor does not add one.

#### Can I convert a whole folder of ebooks at once?

Yes, that is the normal way to use it - up to 100 per run. See [How to batch convert a folder of ebooks to PDF](#how-to-batch-convert-a-folder-of-ebooks-to-pdf). It is also much cheaper than one run per book, because container startup is most of what a short run costs.

#### One book in my batch is DRM-protected. Does the whole run fail?

No. Each book is converted on its own and a failure is recorded against that book, with the reason, while the rest of the batch carries on. The run fails only if nothing converted. This is deliberate: most Kindle purchases are DRM-protected, so a folder of `.azw3` files converting partially is the expected outcome rather than an error. Check the `ok` column in the dataset to see which ones came through.

#### Can an AI agent call this converter?

Yes. Every Apify Actor is exposed through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp), so Claude, Cursor and other MCP clients can run this conversion as a tool.

#### The conversion failed or the PDF looks wrong. What now?

Turn on `verboseLog` and re-run: the Actor log will carry calibre's own output. The common causes, roughly in order:

- A DRM-protected file. The run stops before calibre is involved and says so.
- A URL that returns an HTML page rather than the ebook - a download page or a login wall instead of the file itself.
- A truncated upload. A partly downloaded EPUB is a valid-looking zip with no central directory, and the Actor reports it as an unreadable zip rather than handing calibre a broken file.
- An omnibus or heavily illustrated book large enough to hit the 15 minute conversion timeout at low memory. Raise the memory.
- Text running off the page, which is nearly always margins set too narrow for the page size you chose.

### Development

```bash
npm install
npm test      # inspector, batch bookkeeping and ZIP writer; no calibre needed
apify run     # needs calibre on your PATH
```

`src/source.js` is the inspector, `src/batch.js` is the batch bookkeeping - key collisions, size and
time budgets, the ZIP ceiling - and `src/zip.js` is a small stored-entry ZIP writer shared with
`marcel-rbro/pdf-to-jpg`. All three are pure and are what the tests cover; everything else needs the
container.

The inspector reads the OCF container - the zip central directory, the `mimetype` entry, `META-INF/container.xml` and the package document - to identify the file, read its EPUB version and tell DRM apart from font obfuscation, all before calibre is involved. It also reads the PalmDB header for Kindle input.

Conversion runs calibre's `ebook-convert` in a Debian container. PDF output drives QtWebEngine, so the image asserts at build time that a real EPUB to PDF conversion succeeds - a Debian package that quietly loses one of its Qt libraries fails the build once rather than every run.

This Actor's code is MIT licensed; calibre is GPL-3 and runs as a separate process - see [THIRD\_PARTY\_NOTICES.md](THIRD_PARTY_NOTICES.md).

# Actor input Schema

## `files` (type: `array`):

The ebooks to convert. Upload files or paste direct URLs. Each one is converted separately and the results come back as a ZIP. Accepts .epub, .azw3, .mobi, .fb2, .cbz, .lit and .pdb. A DRM-protected or unreadable file is skipped with an explanation and does not stop the rest of the batch.

## `file` (type: `string`):

One ebook as a URL, kept for API callers and saved input configurations that predate the Ebooks field. Ignored when Ebooks is filled in.

## `paperSize` (type: `string`):

A4 for printing outside the US, Letter inside it. A5 and A6 give a paperback or e-reader page instead of an office one, which is usually more comfortable to read on screen.

## `baseFontSize` (type: `integer`):

Base body text size in points. Every other size in the book is rescaled around it. Leave at 0 to let calibre choose a size that suits the page.

## `marginTop` (type: `integer`):

In points. 72 pt is one inch. calibre treats a page margin of 0 as "unset" rather than "no margin", so use 1 for a near-edge-to-edge page.

## `marginBottom` (type: `integer`):

In points. Leave room here if you turn page numbers on.

## `marginLeft` (type: `integer`):

In points.

## `marginRight` (type: `integer`):

In points.

## `pdfPageNumbers` (type: `boolean`):

Prints a page number at the bottom of every page. A footer template, if you set one, takes precedence over this.

## `standardFont` (type: `string`):

Which of the three font slots the body text uses. Serif is the conventional choice for a book.

## `serifFamily` (type: `string`):

Font family to use for serif text. Must be installed in the container: DejaVu Serif or Liberation Serif. Leave empty for calibre's default.

## `sansFamily` (type: `string`):

Font family to use for sans-serif text. Must be installed in the container: DejaVu Sans or Liberation Sans. Leave empty for calibre's default.

## `preserveCoverAspectRatio` (type: `boolean`):

Keeps the cover's proportions instead of stretching it to fill the first page. On by default, because a stretched cover is rarely what anyone wants.

## `smartenPunctuation` (type: `boolean`):

Converts plain quotes, dashes and ellipses into their typographic equivalents.

## `pdfHeaderTemplate` (type: `string`):

HTML printed at the top of every page. The strings *PAGENUM*, *TITLE*, *AUTHOR* and *SECTION* are replaced with their current values, for example: <div style="text-align:center">*SECTION*</div>

## `pdfFooterTemplate` (type: `string`):

HTML printed at the bottom of every page, using the same replaceable strings. Overrides the page numbers switch.

## `outputFilename` (type: `string`):

Name of the resulting PDF. Defaults to the input filename with a .pdf extension. Ignored for a batch, where every PDF keeps its own filename and the ZIP is always converted-ebooks.zip.

## `bookTitle` (type: `string`):

Sets the title metadata of the PDF. Leave empty to keep the title stored in the source file.

## `bookAuthors` (type: `string`):

Sets the author metadata of the PDF. Separate multiple authors with an ampersand, for example "Ursula K. Le Guin & Someone Else".

## `fileBase64` (type: `string`):

Alternative to the file field for API callers: a single source ebook encoded as base64. Adds about 33% to the payload size.

## `filename` (type: `string`):

Original filename to use when the file is passed as base64.

## `verboseLog` (type: `boolean`):

Includes the full calibre conversion log in the Actor log. Useful when a conversion produces odd output.

## Actor input object example

```json
{
  "paperSize": "a4",
  "baseFontSize": 0,
  "marginTop": 72,
  "marginBottom": 72,
  "marginLeft": 72,
  "marginRight": 72,
  "pdfPageNumbers": false,
  "standardFont": "serif",
  "preserveCoverAspectRatio": true,
  "smartenPunctuation": false,
  "verboseLog": false
}
```

# Actor output Schema

## `output` (type: `string`):

The converted PDF when one ebook was converted, or a ZIP of every PDF when several were. This is the same record that the run-sync API endpoint returns in its HTTP response body.

## `allFiles` (type: `string`):

Every record in the run's key-value store: each converted PDF under its own filename, and the ZIP if there was a batch.

## `conversionDetails` (type: `string`):

One record per input ebook: source format, EPUB version, page size, page count, file sizes, metadata, whether it converted, and why not if it did not.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("marcel-rbro/epub-to-pdf").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("marcel-rbro/epub-to-pdf").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 '{}' |
apify call marcel-rbro/epub-to-pdf --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,marcel-rbro/epub-to-pdf"
        }
    }
}

```

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/DMU8a7vPqUeyuP0EE/builds/Wi2tHf6aNS9eeqObt/openapi.json
