# PDF to Markdown & RAG Chunks: Word, Excel, PowerPoint (`quarrywise/pdf-to-markdown-rag`) Actor

PDF to Markdown converter for RAG and LLMs: turn PDF, Word (DOCX), PowerPoint (PPTX), Excel (XLSX) and HTML files into clean Markdown, JSON blocks or page-cited RAG chunks. Tables kept, headers and footers removed, scans flagged for OCR. No GPU, no setup.

- **URL**: https://apify.com/quarrywise/pdf-to-markdown-rag.md
- **Developed by:** [Quarrywise](https://apify.com/quarrywise) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 page converteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## PDF to Markdown & RAG Chunks: Word, Excel, PowerPoint

**Turn PDF, Word, PowerPoint and Excel files into clean Markdown, JSON blocks or page-cited RAG
chunks in one call, with a per-page quality report that tells you what to trust. No GPU, no setup,
no AI guessing.**

Feed your retrieval pipeline, LLM app, AI agent or knowledge base with documents that keep their
structure: real heading levels, tables as tables, page numbers for citations, and running headers
and footers removed. Scanned pages are never returned as silent empty text: they are flagged as
"needs OCR" and not charged. You pay per document and per page converted, at the prices shown
below.

### PDF to Markdown converter for RAG and LLMs

- **Developers and AI teams building RAG** who need chunks with source, page range and heading
  path, ready to embed.
- **Agent and automation builders** (API, MCP, n8n, Make, Zapier) who want one predictable call
  that turns a file link into Markdown or JSON.
- **Knowledge-base and search teams** importing manuals, reports, policies, slide decks and
  spreadsheets.
- **Analysts** who want tables from born-digital PDFs and Office files as Markdown tables.

What sets it apart:

- **Scans are flagged, never silently empty.** Pages without a text layer are listed in
  `pages_needing_ocr`, explained, and free.
- **A quality report per page:** text found or not, characters, words, a garble score for
  unreadable fonts, tables, images, removed header and footer lines (with their text), and
  plain-language warnings.
- **Tables joined across pages:** a ruled table that continues on the next page comes out as one
  table, header once.
- **Headers and footers removed, values kept:** running headers, footers and page numbers go;
  lines with amounts, account numbers or changing values stay.
- **Page-cited heading paths** on every block and chunk.

### PDF text extractor that keeps tables and headings

- **Structure that survives:** heading levels from PDF bookmarks, "3.1"-style numbering, font size
  and weight, and Word heading styles; bullet and numbered lists; bold, italic and links from Word.
- **Tables as tables:** ruled PDF tables, simple aligned tables without lines, and native Word,
  PowerPoint, Excel, HTML and CSV tables. Tables with merged cells are written as HTML so no cell
  lands in the wrong column.
- **Clean text for chunking:** two-column PDF pages are read column by column; Word headers and
  footers are left out.
- **Clear failures:** password-protected PDFs, damaged files, unsupported formats, blocked
  downloads and scans each get their own status and message. Failed inputs are free.
- **Deterministic:** the same file gives the same output every time. No language model is involved.

### Word, PowerPoint and Excel to Markdown

| Format | What is extracted | Pages (for billing) |
|---|---|---|
| PDF (born-digital, with a text layer) | Headings, paragraphs, lists, ruled and simple aligned tables, reading order in two-column pages | Each PDF page with text |
| Word (.docx) | Heading styles, lists, tables (merged cells as HTML), bold, italic, links | Every 3,000 characters of output |
| PowerPoint (.pptx) | Slide titles as headings, text and bullet levels, tables, speaker notes | Each slide |
| Excel (.xlsx, .xls) | Each visible sheet as tables; blank cells stay empty; dates as ISO dates | Every 3,000 characters of output |
| HTML | Main content only (navigation, header, footer, scripts removed), tables, lists, code | Every 3,000 characters of output |
| Markdown, plain text, CSV | Headings, lists, tables | Every 3,000 characters of output |

Docx to Markdown, pptx to Markdown, xlsx to Markdown, HTML to Markdown and PDF to JSON all run
through the same call; choose the output below.

Not supported in this version: scanned PDFs and images (they are flagged as needing OCR), legacy
.doc and .ppt (save them as .docx or .pptx), OpenDocument, EPUB and RTF. Each of these gets a clear
error row, free of charge.

### How to use it

1. Paste links to your documents in **Document links**, or upload files with **Upload files**.
2. Choose **Output**: Markdown, JSON blocks, or RAG chunks (set the chunk size and overlap).
3. Optionally limit pages (for example `1-5, 8`) and set a maximum charge for the run.
4. Start the run. Results appear in the dataset; the run summary is in the `OUTPUT` record and a
   per-document report in the `DOCUMENTS` record.

From code, call the Actor through the Apify API or client and read the dataset items. For API
users there are two more ways to send files: records in a key-value store (`keyValueStoreId` and
`fileKeys`) and small files as base64 (`base64Files`).

### Use it from n8n, Make, Zapier or an AI agent

- **n8n:** add Apify's verified n8n node (`@apify/n8n-nodes-apify`; on n8n Cloud the instance owner
  first enables verified community nodes). Use the operation "Run an Actor and Get Dataset" and
  select this Actor By URL (enter exactly
  `https://console.apify.com/actors/lnxVsBgOB9lHLTIYG/input`) or by ID (`lnxVsBgOB9lHLTIYG`); the
  From list picker may not show it while the Actor is hidden from Store search. The Actor's Store
  page URL does not work in the By URL field. Then send `documentUrls` with `outputFormat` `chunks`.
  Keep the rows whose `row_type` is `chunk` and send them to your vector store node; each chunk
  carries `page_start`, `page_end` and `heading_path` for citations.
- **Make:** Apify's app: the "Run an Actor" module, then "Get Dataset Items" (the "Watch Actor
  Runs" trigger fires when a run finishes).
- **Zapier:** Apify's app: the "Run Actor" action, then "Fetch dataset items" (the "Finished
  Actor run" trigger fires when a run finishes).
- **AI agents (MCP clients):** add this Actor as a tool through Apify's MCP server:
  `https://mcp.apify.com?tools=quarrywise/pdf-to-markdown-rag`
  The MCP server needs an Apify sign-in or API token.
- **API:** `POST https://api.apify.com/v2/acts/quarrywise~pdf-to-markdown-rag/run-sync-get-dataset-items`
  with your Apify token in the `Authorization: Bearer` header and the input JSON as the body.
  Large documents can take longer than the 300 seconds this call waits (HTTP 408 after that);
  start the Actor asynchronously for those and read the dataset when it finishes.

### Input

| Field | What it does | Default |
|---|---|---|
| `documentUrls` | Links to documents, one per line (public or signed links) | none |
| `uploadedFiles` | Files uploaded in the form | none |
| `outputFormat` | `markdown`, `blocks` or `chunks` | `markdown` |
| `chunkSize` | Target chunk size in tokens (64 to 8,000) | `500` |
| `chunkOverlap` | Overlap between chunks of one section, in tokens | `50` |
| `chunkHeadingContext` | Start each chunk with its heading path | `true` |
| `pageRange` | Pages or slides to convert, for example `1-5, 8, 10-` | all |
| `maxPages` | Maximum pages or slides per document | `300` |
| `removeHeadersFooters` | Remove running headers, footers and page numbers from PDFs | `true` |
| `pageMarkers` | Add `<!-- page N -->` comments to the Markdown | `false` |
| `includeSpeakerNotes` | Add PowerPoint speaker notes | `true` |
| `includeHiddenSheets` | Include hidden Excel sheets | `false` |
| `maxRowsPerSheet` | Row cap per sheet or CSV file | `5000` |
| `saveMarkdownFiles` | Also save each document as a `.md` file in the key-value store | `false` |
| `keyValueStoreId`, `fileKeys` | Read documents from key-value store records | none |
| `base64Files` | Small files inside the input: `[{"fileName": "a.pdf", "contentBase64": "..."}]` | none |
| `maxFileSizeMb` | Skip larger files (hard limit 100 MB) | `50` |
| `maxDocuments` | Maximum documents per run (up to 1,000) | `100` |

Example: chunks for a RAG pipeline.

```json
{
    "documentUrls": ["https://quarrywise.com/samples/quarterly-report.pdf"],
    "outputFormat": "chunks",
    "chunkSize": 500,
    "chunkOverlap": 50
}
```

### Output

Markdown mode gives one row per document:

```json
{
    "row_type": "document",
    "input_index": 1,
    "source": "https://quarrywise.com/samples/quarterly-report.pdf",
    "file_name": "quarterly-report.pdf",
    "document_id": "9abfce51c8d261d9c32c",
    "status": "ok",
    "format": "pdf",
    "title": "Example Orchard Cooperative: Quarterly Report",
    "pages_total": 3,
    "pages_converted": 3,
    "pages_needing_ocr": [],
    "billable_pages": 3,
    "markdown": "# Example Orchard Cooperative: Quarterly Report\n\n...\n\n## 2 Harvest by variety\n\n| Variety | Hectares | Tonnes | Change |\n|---|---|---|---|\n| Elstar apple | 42 | 1,260 | +8% |\n...",
    "quality": {
        "pages": [{ "page": 1, "status": "ok", "chars": 912, "words": 167, "garble_score": 0.003, "tables": 1, "images": 0, "furniture_removed": 2, "warnings": [] }],
        "stats": { "furniture_lines_removed": 6, "headings": 10, "tables": 1 },
        "furniture_removed_text": ["Example Orchard Cooperative | Quarterly report Q3 (sample)", "Page 1 of 3", "Page 2 of 3", "Page 3 of 3"]
    },
    "warnings": []
}
```

### RAG chunking with page citations

Chunks mode gives one row per chunk:

```json
{
    "row_type": "chunk",
    "chunk_id": "9abfce51c8d261d9c32c-0001",
    "chunk_index": 1,
    "chunk_count": 4,
    "file_name": "quarterly-report.pdf",
    "heading_path": ["Example Orchard Cooperative: Quarterly Report", "2 Harvest by variety"],
    "page_start": 1,
    "page_end": 2,
    "token_estimate": 179,
    "char_count": 713,
    "text": "# Example Orchard Cooperative: Quarterly Report\n\n## 2 Harvest by variety\n\nThe table lists the harvested area ...\n\n| Variety | Hectares | Tonnes | Change |\n|---|---|---|---|\n| Elstar apple | 42 | 1,260 | +8% |\n..."
}
```

Chunks follow headings and stay within your chunk size (the heading path at the top, and a heading
kept together with its first text, can add a little): long paragraphs are split at sentence ends,
long lists by item, code blocks by lines, and tables by rows with the header row repeated in each
part. `chunk_id` is the document ID plus the chunk
number, so the same file always gives the same IDs (handy for upserts into a vector store).

**In RAG chunks mode, keep rows with `row_type` "chunk".** The same dataset also holds one
`notice` row per document that has warnings (or a saved Markdown file), and `error` rows for
inputs that failed; their `text` is empty and they are free.

JSON blocks mode gives one row per document with `blocks`: a list of headings, paragraphs, list
items and tables, each with `type`, `text`, `level`, `page`, `page_end` and `heading_path` (tables
also have `rows`).

A scan returns a row like this, and is not charged:

```json
{ "row_type": "document", "file_name": "scanned-notice.pdf", "status": "needs_ocr", "pages_needing_ocr": [1], "billable_pages": 0,
  "error_message": "No text layer found: this looks like a scanned or image-only document. It needs OCR, which this Actor does not do. Nothing was charged." }
```

The dataset has three views: **Documents**, **RAG chunks** and **Quality and problems**.

### Output fields

| Field | Meaning |
|---|---|
| `row_type` | `document` (one converted document), `chunk` (one RAG chunk), `notice` (warnings for a document in chunks mode, free) or `error` (an input that failed, free) |
| `input_index` | Position of the document in the input (1 = first) |
| `source` | Where the document came from, without query string (signed-link tokens are never stored) |
| `file_name` | File name from the link, the download or the upload |
| `document_id` | First 20 hex characters of the file's SHA-256: the same file always gets the same ID |
| `status` | See the list below |
| `format` | `pdf`, `docx`, `pptx`, `xlsx`, `xls`, `html`, `markdown`, `text` or `csv` |
| `title` | Document title from its metadata, else its first heading |
| `pages_total` | Pages, slides or sheets in the file |
| `pages_converted` | PDF pages or slides converted with text |
| `pages_needing_ocr` | Pages without a usable text layer (not charged) |
| `billable_pages` | Pages charged for this document |
| `truncated` | True when a page or row limit, the time limit or your maximum charge cut the document short |
| `markdown` | The document as Markdown (Markdown and JSON blocks modes) |
| `markdown_file_url` | Link to the `.md` file in the run's key-value store, when you asked for files or the Markdown is too large for one row |
| `blocks` | JSON blocks (JSON blocks mode) |
| `blocks_file_url` | Link to the JSON blocks file, when the blocks are too large for one row |
| `chunk_id`, `chunk_index`, `chunk_count` | The chunk's ID, its position (from 0) and the number of chunks in its document |
| `text` | The chunk text (Markdown) |
| `heading_path` | The headings the chunk sits under, outermost first |
| `page_start`, `page_end` | First and last page or slide the chunk comes from |
| `token_estimate`, `char_count` | Size of the chunk (about 4 characters per token) |
| `quality` | Per-page report, counters and, for PDFs, the removed header and footer texts |
| `warnings` | Plain-language warnings for the document |
| `error_reason`, `error_message` | Why an input failed, as a short code and as a sentence |

`status` values: `ok`; `partial` (some pages need OCR); `needs_ocr` (no text layer at all);
`empty` (no text); `encrypted` (password-protected PDF); `unsupported` (a format this Actor does
not read); `download_failed` (the link could not be read); `error` (a damaged file, a file
whose pages could not be read, or one too large or too complex to convert); `invalid_input` (the run input itself was not valid). Only `ok`
and `partial` documents are charged.

### Pricing

Pay per event: you pay for documents and pages actually converted and saved, plus Apify's
standard Actor start event, a fraction of a cent per run.

| Event | Price |
|---|---|
| Document converted | $0.003 per document |
| Page converted | $0.0004 per page (a PDF page or slide with text, or 3,000 characters of output for other formats) |

Free: documents that fail, pages that need OCR, empty pages and documents, notice and error rows.

| Example | Cost |
|---|---|
| One 10-page PDF | $0.007 |
| One 100-page PDF | $0.043 |
| 1,000 PDFs of 10 pages each | $7.00 |
| A 40-slide deck | $0.019 |
| The prefilled example (4 sample files, 9 pages) | about $0.016 |
| A 30-page scan (needs OCR) | $0 (plus the start event) |

The examples leave out the start event. Set a **maximum charge per run** in the run options to cap
spending. The Actor checks the budget before saving each document, converts as many pages as the
budget allows, says so in the document's warnings, and then stops cleanly with status
`limit-reached` in the run summary.

### Limits

- Files up to 50 MB by default (`maxFileSizeMb`, at most 100 MB), up to 1,000 documents per run.
- Up to 300 pages per document by default (`maxPages`, at most 5,000).
- Each document gets up to 10 minutes and the run's memory. A document that needs more (a very
  long or very dense file, a very large HTML page, or a decompression bomb) gets a free error row
  with reason `too-complex`, and the run goes on with the next document. Long documents and large
  HTML pages are best run with 2 to 4 GB of memory.
- Spreadsheets: up to 512 filled columns per sheet and 2,000,000 cells per file. Formulas whose
  result was never saved in the file come out blank, with a warning.
- Scanned or image-only pages are detected and reported, not converted (no OCR in this Actor).
- Tables without ruling lines are recognised only when their columns line up cleanly; complex
  layouts (merged cells without lines, tables inside text columns, more than two columns of text)
  may come out as paragraphs. The quality report helps you find those pages.
- Password-protected PDFs are not opened. Remove the password and run again.
- Links behind a login, and social media or video sites, are not supported. When a server refuses
  access (401, 403 or a bot check), or a link returns a login page instead of the file, the
  document gets an error row; the Actor never tries to get around it. Use a public or signed link,
  or upload the file.
- Charts and images are not described; their count is in the quality report.

### Privacy and data handling

- Your documents are processed only to produce your results. We act as a processor for the files
  you send.
- Documents are processed in memory during the run and stored only in the run's own default
  dataset and key-value store, which you control and can delete. Nothing is kept elsewhere and
  nothing is used for training.
- Document content is never written to the run log; the log shows only input numbers, formats,
  page counts and error codes.
- `markdown_file_url` and `blocks_file_url` are shareable links: anyone who has one can read that
  file without an Apify token. They appear only on the document (or notice) row, never on chunk
  rows, so they do not travel into your vector store with every chunk.
- Treat the output as untrusted text, like the documents it comes from: sanitise it before you
  render it as HTML. Tag-like text from documents is escaped (`<` becomes `&lt;`) and link targets
  are encoded, but Markdown renderers differ.
- Query strings of links (for example signed-link tokens) are removed before the source is stored
  in your results.
- The Actor runs with limited permissions: it reads your input, your uploaded files and the
  key-value store you name, and writes only to the run's own storages. Links you paste are
  downloaded without your Apify token, even when they point to Apify storage.
- Downloads identify themselves as `QuarrywiseBot/1.0 (+https://quarrywise.com/bot)` and refuse
  private and internal network addresses.

### FAQ

**What does "needs OCR" mean?** The page has no usable text layer: it is a scan, a photo, or uses
fonts whose text cannot be read. Such pages are listed in `pages_needing_ocr`, explained in the
warnings, and not charged. Run them through an OCR tool first.

**How are tokens counted?** `token_estimate` uses about 4 characters per token, a common rule of
thumb for English text. It is an estimate, not a count from a specific tokenizer.

**Why does a Word or Excel file count as several pages?** These formats have no fixed pages, so
every 3,000 characters of output count as one page. A short memo is one page. In tables only filled
cells count, so empty cells in a sparse sheet cost nothing.

**Can I convert files from cloud storage?** Yes: use a signed link, or put the files in an Apify
key-value store and pass `keyValueStoreId` and `fileKeys`.

**Is the output the same every time?** Yes. The same file with the same settings gives the same
Markdown, blocks and chunks, and the same `document_id`.

**Which header and footer lines were removed?** `quality.furniture_removed_text` lists each removed
text once, so you can check that nothing of value went.

**Why is a table split into paragraphs?** The table probably has no ruling lines and uneven
columns. Check the page in the quality report; complex tables are planned for a slower layout-model
option.

**Does this use Docling or MarkItDown?** No. It runs its own layout code on pdfplumber, with no
GPU and no models, and flags scans for OCR instead of returning empty text.

**Do you keep my files?** No. See Privacy and data handling above.

### Changelog

See the Changelog tab. Version 0.1 (2026-10-26): first release.

### Provider

Provided by Quarrywise, a trade name of Picazzo Research & Development, Zinkstraat 24, Box C4687, 4823 AD Breda, the Netherlands. KvK 42060545, VAT NL005464235B85. Contact: hello@quarrywise.com or the Issues tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/quarrywise/pdf-to-markdown-rag/changelog.md

# Actor input Schema

## `documentUrls` (type: `array`):

Links to PDF, Word (.docx), PowerPoint (.pptx), Excel (.xlsx, .xls), HTML, Markdown, plain text or CSV files, one per line. Public links and signed links (for example from cloud storage) work. Links behind a login, and links to social media or video sites, are not supported. If a server refuses access, the document gets an error row; the Actor never tries to get around it.

## `uploadedFiles` (type: `array`):

Upload documents from your computer instead of giving links. Uploaded files are read from your Apify storage and processed only for this run.

## `outputFormat` (type: `string`):

Markdown: one row per document with the full Markdown. JSON blocks: one row per document with a list of headings, paragraphs, list items and tables, each with its page number and heading path. RAG chunks: one row per chunk, ready for embedding, with source, page range, heading path and a token estimate.

## `chunkSize` (type: `integer`):

Target size of each chunk in tokens (estimated at about 4 characters per token). Chunks follow headings: a section is only split when it is longer than this. Used when Output is RAG chunks.

## `chunkOverlap` (type: `integer`):

How much text from the end of a chunk is repeated at the start of the next chunk of the same section, in whole sentences. At most half the chunk size.

## `chunkHeadingContext` (type: `boolean`):

When on, each chunk starts with the headings it belongs to (for example '# Annual report' and '## 3 Costs'), so a chunk still makes sense on its own after retrieval.

## `pageRange` (type: `string`):

Convert only these pages or slides, for example '1-5, 8, 10-'. Leave empty for all pages. Applies to PDF files and slide decks.

## `maxPages` (type: `integer`):

Stop each PDF or slide deck after this many pages (within the page range). Protects your budget from unexpectedly long files.

## `removeHeadersFooters` (type: `boolean`):

Removes lines that repeat at the top or bottom of PDF pages (running headers, footers, page numbers) so they do not end up inside your text and chunks. Word headers and footers are always left out.

## `pageMarkers` (type: `boolean`):

Adds an HTML comment such as '' where each PDF page or slide starts.

## `includeSpeakerNotes` (type: `boolean`):

Adds each slide's speaker notes after the slide content.

## `includeHiddenSheets` (type: `boolean`):

Hidden sheets are skipped by default because they often hold drafts or lookups.

## `maxRowsPerSheet` (type: `integer`):

Rows after this are left out (a warning says so).

## `saveMarkdownFiles` (type: `boolean`):

Saves each document's Markdown in the run's key-value store and adds its link (markdown_file_url) to the results. Very large documents are always saved this way.

## `keyValueStoreId` (type: `string`):

Optional. A key-value store that holds documents as records. With record keys below, only those records are converted; without keys, every record is converted (up to the maximum number of documents). The Actor only reads this store.

## `fileKeys` (type: `array`):

Keys of records that hold documents: in the store chosen above, or in this run's own default key-value store when no store is chosen.

## `base64Files` (type: `array`):

Small files sent inside the input, as a list of objects: \[{"fileName": "notes.pdf", "contentBase64": "JVBERi0..."}]. The run input has a size limit, so use links or uploads for large files.

## `maxFileSizeMb` (type: `integer`):

Larger files are skipped with an error row. The hard limit is 100 MB.

## `maxDocuments` (type: `integer`):

Only the first documents up to this number are converted.

## Actor input object example

```json
{
  "documentUrls": [
    "https://quarrywise.com/samples/quarterly-report.pdf",
    "https://quarrywise.com/samples/volunteer-handbook.docx",
    "https://quarrywise.com/samples/volunteer-day-slides.pptx",
    "https://quarrywise.com/samples/budget.xlsx"
  ],
  "outputFormat": "markdown",
  "chunkSize": 500,
  "chunkOverlap": 50,
  "chunkHeadingContext": true,
  "maxPages": 300,
  "removeHeadersFooters": true,
  "pageMarkers": false,
  "includeSpeakerNotes": true,
  "includeHiddenSheets": false,
  "maxRowsPerSheet": 5000,
  "saveMarkdownFiles": false,
  "maxFileSizeMb": 50,
  "maxDocuments": 100
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `documents` (type: `string`):

No description

# 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 = {
    "documentUrls": [
        "https://quarrywise.com/samples/quarterly-report.pdf",
        "https://quarrywise.com/samples/volunteer-handbook.docx",
        "https://quarrywise.com/samples/volunteer-day-slides.pptx",
        "https://quarrywise.com/samples/budget.xlsx"
    ],
    "outputFormat": "markdown"
};

// Run the Actor and wait for it to finish
const run = await client.actor("quarrywise/pdf-to-markdown-rag").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 = {
    "documentUrls": [
        "https://quarrywise.com/samples/quarterly-report.pdf",
        "https://quarrywise.com/samples/volunteer-handbook.docx",
        "https://quarrywise.com/samples/volunteer-day-slides.pptx",
        "https://quarrywise.com/samples/budget.xlsx",
    ],
    "outputFormat": "markdown",
}

# Run the Actor and wait for it to finish
run = client.actor("quarrywise/pdf-to-markdown-rag").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 '{
  "documentUrls": [
    "https://quarrywise.com/samples/quarterly-report.pdf",
    "https://quarrywise.com/samples/volunteer-handbook.docx",
    "https://quarrywise.com/samples/volunteer-day-slides.pptx",
    "https://quarrywise.com/samples/budget.xlsx"
  ],
  "outputFormat": "markdown"
}' |
apify call quarrywise/pdf-to-markdown-rag --silent --output-dataset

```

## MCP server setup

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

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/lnxVsBgOB9lHLTIYG/builds/g7qfZjqY5MAtu3UOv/openapi.json
