# Document to Markdown – DOCX, PPTX, XLSX (`sfoln/document-to-markdown`) Actor

Convert DOCX, PPTX, XLSX, XLS, ODS, CSV, EPUB, RTF, ODT, HTML, TXT and PDF files to clean Markdown with GFM tables, slides with speaker notes, sheets as tables or JSON rows. $3 per 1,000 documents (up to 20 pages or 10,000 rows each).

- **URL**: https://apify.com/sfoln/document-to-markdown.md
- **Developed by:** [SFOLN LLC](https://apify.com/sfoln) (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 $2.70 / 1,000 converted documents

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

**Document to Markdown** converts office documents, spreadsheets, e-books and PDFs into **clean Markdown for LLMs, RAG and search**: Word headings, lists and tables become GFM, PowerPoint decks become one section per slide with speaker notes, Excel and OpenDocument sheets become Markdown tables (and, if you want, typed JSON rows), EPUBs become chapters. Give it document URLs, an uploaded file, `data:` URIs or Apify key-value store records; each document becomes one dataset record. The format is detected from the file itself, so wrong extensions do not matter.

- **Formats:** DOCX, PPTX, XLSX (and XLSB), XLS, ODS, CSV/TSV, EPUB, RTF, ODT, HTML, TXT (JSON and XML as code blocks) and PDF (text layer).
- **What you get:** `markdown`, `title`, `metadata` (author, dates, language…), `sections[]` per page, slide, sheet or chapter, `tables[]` with optional JSON `rows`, word and page counts.
- **Price:** $0.003 per document (`document`, up to 20 pages or 10,000 rows), $0.0007 per further 20 pages or 10,000 rows (`document-overage`). No start fee; failed files are not charged.
- **Safe on untrusted files:** zip bombs, XML entity tricks, macros and embedded objects are refused or ignored.
- **Works everywhere:** API, MCP for AI agents, Make, Zapier, n8n, schedules and webhooks.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `documentUrls` | string\[] | – | Documents, one per line: http(s) URLs, `data:` URIs (base64) or key-value store records (`kvs://<storeId>/<key>` or the record's API URL, read with the run's token). Max 25 MB per office file, 50 MB per PDF. |
| `documentFile` | string | – | Upload a document from your computer (Apify Console) or give its URL; converted with the URLs above. |
| `includeSections` | boolean | `true` | Return `sections[]`: one entry per PDF page, slide, sheet or chapter. |
| `includeRows` | boolean | `false` | Spreadsheets: also return each sheet's rows as JSON objects keyed by the header row (`tables[].rows`). |
| `includePlainText` | boolean | `false` | Also return `text` (no Markdown syntax). |
| `password` | string (secret) | – | Password for encrypted PDFs (never written to the output). |
| `maxPages` | integer | 1000 | Pages per document (PDF pages, slides, or 3,000-character pages of text), 1–5000. |
| `maxRows` | integer | 100000 | Non-empty spreadsheet rows per document, all sheets together (1–200,000; give the run 2 GB of memory above about 100,000 rows). |
| `maxSheets` | integer | 50 | Sheets per workbook (1–200). |
| `maxItems` | integer | 1000 | Safety cap on documents per run; extra ones are ignored and counted as `inputItemsDropped` in `OUTPUT`. |
| `concurrency` | integer | 2 | Documents converted in parallel (1–5). |

```json
{
  "documentUrls": [
    "https://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx",
    "https://example.com/files/q1-sales.xlsx"
  ],
  "includeRows": true
}
```

### Output

One dataset record per document:

```json
{
  "input": "https://example.com/files/q1-sales.xlsx",
  "status": "ok",
  "charged": true,
  "chargedEvent": "document",
  "source": "document-converter",
  "fetchedAt": "2026-10-14T10:00:00.000Z",
  "url": "https://example.com/files/q1-sales.xlsx",
  "fileName": "q1-sales.xlsx",
  "fileSizeBytes": 8317,
  "sha256": "8b1a9953c4611296a827abf8c47804d7e6c49c6b6b0f6d9a8f5f1f4e2d3c4b5a",
  "format": "xlsx",
  "title": "Sales Workbook",
  "metadata": { "title": "Sales Workbook", "author": "Example Author", "subject": null, "description": null, "keywords": [], "language": null, "publisher": null, "createdAt": "2026-04-01T09:00:00.000Z", "modifiedAt": "2026-04-01T09:00:00.000Z" },
  "language": null,
  "pageCount": 0,
  "rowCount": 4,
  "wordCount": 29,
  "charCount": 140,
  "markdown": "## Sales\n\n| Region | Q1 | Q2 | Total | Updated |\n| --- | --- | --- | --- | --- |\n| North | 1240 | 1310 | 2550 | 2026-04-02 |\n| South | 980 | 1002 | 1982 | 2026-04-03 |\n| West | 1105 | 1190 | 2295 | 2026-04-04 |",
  "markdownUrl": null,
  "sections": [
    { "type": "sheet", "index": 1, "title": "Sales", "markdown": "## Sales\n\n| Region | Q1 | Q2 | Total | Updated |\n…", "hidden": false, "rowCount": 4, "columnCount": 5 }
  ],
  "tables": [
    { "sheet": "Sales", "index": 1, "rowCount": 4, "columnCount": 5, "columns": ["Region", "Q1", "Q2", "Total", "Updated"], "headerRow": true, "hidden": false, "rows": [{ "Region": "North", "Q1": 1240, "Q2": 1310, "Total": 2550, "Updated": "2026-04-02" }] }
  ],
  "tablesUrl": null,
  "truncated": false,
  "truncation": [],
  "billedBlocks": 1,
  "overageCharged": 0
}
```

| Field | Description |
| --- | --- |
| `format` | Detected format: `docx`, `pptx`, `xlsx`, `xls`, `ods`, `csv`, `epub`, `rtf`, `odt`, `html`, `txt` or `pdf`. |
| `markdown` | The whole document. Word: headings, bold/italic, lists, links, GFM tables (first row as header). Slides: `## Slide N: Title`, bullets with their levels, tables, `> **Notes:**`. Sheets: `## Sheet name` + one table (dates as ISO, numbers as displayed). EPUB: chapters in reading order. PDF: pages separated by `<!-- page N -->`. Images become `[Image: alt text]` when they have alt text. |
| `sections[]` | One entry per PDF page, slide (`notes`, `hidden`), sheet (`rowCount`, `columnCount`, `hidden`) or chapter, each with its Markdown. Word, ODT, RTF, HTML and text files have none. |
| `tables[]` | Spreadsheets: per sheet `columns` (the header row, or column letters when the first row is data; always unique: a blank header becomes its column letter, a repeated one gets a `_2`, `_3`, … suffix), counts and, with `includeRows`, `rows` as typed JSON objects. |
| `metadata` | Title, author, subject, description, keywords, declared language, publisher (EPUB), creation and modification dates. |
| `pageCount`, `rowCount` | What was billed: PDF pages, slides or 3,000-character text pages; non-empty spreadsheet rows (counted from the converted document, also when `truncation` lists content missing from the record). |
| `truncated`, `truncation` | Something was left out by a limit (pages, rows, sheets, columns, free plan or budget) and what; on a `storage_failed` error, also the content the key-value store did not save (how much of it the record holds). |
| `scannedPages` | PDFs: pages without a text layer (use [PDF OCR to Markdown](https://apify.com/sfoln/pdf-ocr-markdown) for those). |
| `markdownUrl`, `textUrl`, `tablesUrl` | Only for very large documents (a record above ~6 MB): the full content is saved in the run's key-value store and the record keeps the beginning. A file the store does not save (after retries) keeps a null URL and makes the record a `storage_failed` error. |
| `billedBlocks`, `overageCharged` | Blocks of 20 pages / 10,000 rows billed, and the `document-overage` events among them. |

**`status`**: `ok` – converted (charged). `not_found` – the URL returned 404/410 (not charged). `error` – download failed, or the file is unsupported (`unsupported_document`, e.g. a legacy .doc or an image), password-protected (`encrypted_document`, `wrong_password`), corrupt (`corrupt_document`) or a zip bomb (`zip_bomb`); not charged. `error` with `storage_failed` – converted, but the key-value store did not save the full content of a very large document (after retries): the record keeps the beginning and the URLs of the files that were saved, `truncation` lists what is missing, and the `document` event is not charged (`document-overage` events already charged before the save are shown in `overageCharged`). `skipped_invalid` – not a URL, `data:` URI or key-value record, or too large; not charged. `skipped_budget` / `skipped_free_plan` – not processed because of your cost cap or the free-plan limit. The key-value store record `OUTPUT` holds the run totals.

### Pricing

Store discounts: the FREE and BRONZE tiers use the list prices below. The `document` event receives 5% off on SILVER and 10% off on GOLD, PLATINUM and DIAMOND. The `document-overage` event stays at $0.0007 on every tier, and the platform start fee is unchanged. Check the Actor's Store pricing table for the prices currently in effect.

| Event | Price | When charged |
| --- | --- | --- |
| `document` | **$0.003** per document ($3 / 1,000) | once per document with `status: "ok"`; covers up to 20 pages or 10,000 rows |
| `document-overage` | **$0.0007** per block ($0.70 / 1,000) | per further block of 20 pages or 10,000 rows of a converted document |

A 10-page Word file or a 30-slide deck costs $0.003 / $0.0037; a 45,000-row workbook $0.0058. Before each document the Actor checks that your **Maximum cost per run** still covers the `document` event, and it converts only as many further blocks as the remaining budget pays for (the record is then marked `truncated`, with a warning). Accounts on the Apify free plan can process up to 10 documents per run, the first 20 pages or 10,000 rows of each; upgrade to any paid plan for complete documents and batches.

### Use with AI agents (MCP)

Use this Actor from Claude, ChatGPT, Cursor, VS Code or any other MCP client through the [Apify MCP server](https://mcp.apify.com). Add this server URL to your client and sign in with your Apify account when asked:

```text
https://mcp.apify.com?tools=sfoln/document-to-markdown
```

To run the MCP server locally instead, start `npx -y @apify/actors-mcp-server --tools sfoln/document-to-markdown` with your `APIFY_TOKEN` in the environment.

Example prompt:

> Convert https://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx to Markdown with document-to-markdown and show me the table it contains.

Runs started by an agent are billed like any other run (see Pricing). Agents can cap what a run may spend with `maxTotalChargeUsd`.

### API usage

Run the Actor and get its dataset items in one call (the call waits up to 5 minutes for the run to finish):

```bash
curl -X POST "https://api.apify.com/v2/acts/sfoln~document-to-markdown/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"documentUrls": ["https://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx"]}'
```

For large inputs, start the run asynchronously and download the dataset when it has finished:

```bash
## 1. Start a run: the response holds the run ID (data.id) and its dataset ID (data.defaultDatasetId)
curl -X POST "https://api.apify.com/v2/acts/sfoln~document-to-markdown/runs" \
  -H "Authorization: Bearer <APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"documentUrls": ["https://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx"]}'
## 2. Repeat until data.status is SUCCEEDED (each call waits up to 60 s)
curl "https://api.apify.com/v2/actor-runs/<runId>?waitForFinish=60" -H "Authorization: Bearer <APIFY_TOKEN>"
## 3. Download the results (format=json, csv or xlsx)
curl "https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json" -H "Authorization: Bearer <APIFY_TOKEN>"
```

Python ([apify-client](https://pypi.org/project/apify-client/)):

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("sfoln/document-to-markdown").call(run_input={"documentUrls": ["https://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

Instead of polling, you can attach a webhook to the run (see Integrations). The API tab of this page shows the same calls for JavaScript and the Apify CLI.

### Integrations

- **Make, Zapier and n8n:** run `sfoln/document-to-markdown` with the Apify app (in n8n, the Apify node) and pass the dataset items to the next step of your workflow.
- **Google Sheets:** add the items to a sheet with the Google Sheets step of Make, Zapier or n8n, or download them as CSV or Excel from the run's Storage tab or the API (`format=csv` or `format=xlsx`).
- **Webhooks:** get a POST request when a run succeeds or fails: add a webhook in the Actor's Integrations tab, or pass `webhooks` when you start a run through the API.
- **Schedules:** run it hourly, daily or weekly with the same input from Apify Schedules; every run keeps its results in its own dataset.
- **More:** Slack, Google Drive, GitHub, LangChain, LlamaIndex and other [Apify integrations](https://docs.apify.com/platform/integrations).

### Related Actors

- [PDF Text Extractor – PDF to Text & Markdown](https://apify.com/sfoln/pdf-text-extractor)
- [PDF OCR to Markdown Converter](https://apify.com/sfoln/pdf-ocr-markdown)
- [Document Parser – AI PDF & Image to JSON](https://apify.com/sfoln/document-to-json)
- [URL to Markdown & Article Extractor](https://apify.com/sfoln/url-to-markdown-summary)

See [all our Actors](https://apify.com/sfoln) on Apify Store.

### FAQ

#### How much does it cost, and am I charged for failed items?

You pay per event at the prices under Pricing above, plus a run start fee of $0.00005 per GB of memory, with no subscription; platform usage is included. Errors and skipped items (`skipped_…` statuses) are never charged; a lookup that finds nothing is charged only where Pricing says so, and every record's `charged` field shows whether it was billed. Set **Maximum cost per run** to cap what a single run can spend.

#### How fresh is the data?

Each run queries its source while it runs, so you get what the source returns at that moment. Source-specific details, such as how often a provider refreshes its own database, are under Limits & notes.

#### What are the limits?

Per-run caps (for example the maximum number of items) are listed under Input, source limits under Limits & notes, and the free-plan limit under Pricing. For big batches, start the run asynchronously (see API usage) and read the dataset when it has finished.

#### Can I schedule runs or get results by webhook?

Yes. Create a schedule in Apify Console to run it hourly, daily or weekly with the same input, and add a webhook to get a POST request when a run finishes (see Integrations).

#### What does this Actor record about my runs?

This Actor records operational metrics about each run (item counts, duration, charges, error codes and a pseudonymous hash of your Apify user ID) to monitor reliability and costs. It never stores your input or results.

#### Which formats are supported?

DOCX, PPTX, XLSX, XLSB, XLS, ODS, CSV/TSV, EPUB, RTF, ODT, HTML, plain text (JSON and XML are returned as code blocks) and PDF (its text layer). The format is detected from the file's bytes, so a wrong extension does not matter. Legacy .doc and .ppt files are not supported: save them as DOCX or PPTX.

#### How are pages counted for pricing?

PDF pages and slides count as pages; for text documents a page is 3,000 characters of output (about 500 words); spreadsheets count non-empty rows. One document event covers 20 pages or 10,000 rows, each further block of 20 pages or 10,000 rows is one document-overage event ($0.0007).

#### Can I get spreadsheet data as JSON?

Yes: set includeRows and every sheet's rows come back in tables\[].rows as JSON objects keyed by the header row, with numbers, booleans and ISO dates typed.

#### Is it safe to convert untrusted files?

Archives are checked before they are unpacked (entry count and uncompressed size, so zip bombs are refused), XML entity declarations are refused and nothing in a document is executed. Images, macros and embedded objects are ignored.

#### How do I get help?

Open an issue in the Actor's Issues tab and include the link to the run, so we can reproduce the problem. Feature requests are welcome there too.

### Limits & notes

- Text is converted, not rendered: images, charts, SmartArt, macros and embedded objects are left out (images keep their alt text). Formulas return their last computed values. Merged cells keep their value in the first cell.
- PDF pages are read from the text layer; scanned pages have none (see `scannedPages`). A damaged page that cannot be decoded is left empty with a warning and is not counted in `pageCount` or billed.
- Limits per document: 25 MB office files, 50 MB PDFs, 10,000 archive entries, 200 columns and 1,000 characters per spreadsheet cell, `maxPages`, `maxRows` and `maxSheets`. Uncompressed content: 64 MB for Word, PowerPoint, OpenDocument text and EPUB files (32 MB per part), 150 MB for spreadsheets (100 MB per part). Archives over these caps, and parts that unpack past their declared size, are refused as `zip_bomb`.
- Very large inputs are cut, not refused (the record is then `truncated`, with the reason in `truncation`): HTML files and EPUB chapters after 3,000,000 characters of HTML; Word files after the document XML the run's memory can convert (about 2.5 MB of it on 1 GB of memory, a few hundred pages of text; give the run more memory for longer documents), Word footnotes, endnotes and comments above 2 MB of XML are left out; spreadsheet repeats of OpenDocument files after 1,000,000 repeated cells; spreadsheet sheets after their first `maxRows` rows and a tenth more (at least 1,000 more): blank rows are skipped and not counted in `maxRows`, but only that many of them are read.
- Legacy binary Word (.doc) and PowerPoint (.ppt) files and password-protected Office files are not supported.
- Downloads follow at most 5 redirects and only reach public hosts (no private or local addresses).

# Actor input Schema

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

Documents to convert, one per line: public http(s) URLs, data: URIs (base64) or Apify key-value store records (kvs://<storeId>/<key>, or the record's API URL, read with the run's token). Formats: DOCX, PPTX, XLSX, XLS, ODS, CSV, EPUB, RTF, ODT, HTML, TXT and PDF, detected from the bytes (not the file name). Max 25 MB per office file, 50 MB per PDF. Accounts on the Apify free plan can process up to 10 documents per run (the first 20 pages or 10,000 rows of each).

## `documentFile` (type: `string`):

A document from your computer (or its URL). It is converted together with the document URLs above.

## `includeSections` (type: `boolean`):

Return sections\[]: one entry per PDF page, slide (with speaker notes), sheet or e-book chapter, each with its own Markdown.

## `includeRows` (type: `boolean`):

For XLSX, XLS, ODS and CSV, also return every sheet's rows as JSON objects keyed by the header row (typed numbers, booleans and ISO dates) in tables\[].rows.

## `includePlainText` (type: `boolean`):

Also return the content as plain text (text), without Markdown syntax.

## `password` (type: `string`):

Password for encrypted PDFs (used for every PDF of this run). It is never written to the output.

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

Convert at most this many pages per document: PDF pages, slides, or pages of 3,000 characters for text documents. Every 20 pages beyond the first 20 are one document-overage event.

## `maxRows` (type: `integer`):

Convert at most this many non-empty rows per spreadsheet (all sheets together). Every 10,000 rows beyond the first 10,000 are one document-overage event. About 100,000 rows of 10 columns fit in the default 1 GB of memory; give the run 2 GB or more for bigger workbooks.

## `maxSheets` (type: `integer`):

Convert at most this many sheets of a workbook (in workbook order).

## `maxItems` (type: `integer`):

Safety cap on how many documents are processed in this run; further ones are ignored and counted as inputItemsDropped in the OUTPUT record.

## `concurrency` (type: `integer`):

Documents converted in parallel (1–5).

## Actor input object example

```json
{
  "documentUrls": [
    "https://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx"
  ],
  "includeSections": true,
  "includeRows": false,
  "includePlainText": false,
  "maxPages": 1000,
  "maxRows": 100000,
  "maxSheets": 50,
  "maxItems": 1000,
  "concurrency": 2
}
```

# Actor output Schema

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

No description

## `summary` (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://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sfoln/document-to-markdown").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://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx"] }

# Run the Actor and wait for it to finish
run = client.actor("sfoln/document-to-markdown").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://raw.githubusercontent.com/mwilliamson/mammoth.js/791a189230977143cde64dbf9f1d24dce96ac8a1/test/test-data/tables.docx"
  ]
}' |
apify call sfoln/document-to-markdown --silent --output-dataset

```

## MCP server setup

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

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/p4fYUiVNWEt0hlkY0/builds/3D9gl52Qa7JOqcwFd/openapi.json
