> ## Documentation Index
> Fetch the complete documentation index at: https://apidocs.overtenai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Converting documents

> Convert files between formats — PDF from DOCX/XLSX/PPTX, CSVs from spreadsheets, images from slides.

We expose two conversion endpoints:

* **`POST /v1/runs/{run_id}/export`** — re-export a document that our
  API produced (via `/word/generate`, `/excel/generate`,
  `/slides/generate`, `/projects/{id}/reports`, etc.) in a different
  format.
* **`POST /v1/files/{file_id}/convert`** — convert a file you uploaded
  via `POST /v1/files`. Works on any supported source format.

Both go through the same conversion pipeline, so output quality is
identical. Results are cached by `(run_id, format)` and
`(file_id, format)` respectively — repeat calls for the same conversion
return a fresh signed URL instantly without re-running the converter.

## Supported conversions

| From   | To                           |
| ------ | ---------------------------- |
| `xlsx` | `pdf`, `csv`, `png`, `html`  |
| `xls`  | `pdf`, `csv`, `xlsx`, `html` |
| `docx` | `pdf`, `html`, `txt`, `odt`  |
| `doc`  | `pdf`, `docx`, `html`, `txt` |
| `pptx` | `pdf`, `png`, `odp`          |
| `ppt`  | `pdf`, `pptx`, `png`         |

An unsupported pair returns `400 invalid_request` with the set of valid
targets for that source in the message.

## Convert a file you uploaded

Useful when your users already have a `.docx` and you want a PDF to
email or render in your product.

```python theme={null}
import requests

API = "https://backend.overtenai.com/api/v1"
KEY = "sk_live_..."
H = {"X-API-Key": KEY}

# 1. Upload the source
with open("contract.docx", "rb") as f:
    upload = requests.post(
        f"{API}/files",
        headers=H,
        files={"file": f},
        data={"purpose": "reference"},
    ).json()

file_id = upload["file_id"]

# 2. Convert to PDF
convert = requests.post(
    f"{API}/files/{file_id}/convert",
    headers=H,
    data={"format": "pdf"},
).json()
print(convert["download_url"])
```

Response shape:

```json theme={null}
{
  "file_id": "file_...",
  "source_format": "docx",
  "format": "pdf",
  "download_url": "https://storage.googleapis.com/...?...signed...",
  "expires_at": "2026-04-20T12:00:00+00:00"
}
```

`download_url` is signed for 1 hour. The converted artifact itself is
cached permanently — re-calling the endpoint re-signs the existing URL
instead of re-running the conversion.

### Request format

`POST /v1/files/{file_id}/convert` accepts a multipart form with a
single field:

| Field    | Required | Description                                 |
| -------- | -------- | ------------------------------------------- |
| `format` | yes      | Target extension, e.g. `pdf`, `html`, `txt` |

Authentication is a standard `sk_live_*` API key via the `X-API-Key`
header (or the legacy `Authorization: Bearer` header). Per-file scope
gating is applied — you can only convert files you can see under your
current key's scope (personal or workspace).

## Convert a run's output

Every `/*/generate` call persists its primary artifact. To export that
artifact in a different format, call `/runs/{run_id}/export`:

```python theme={null}
report = requests.post(
    f"{API}/projects/{project_id}/reports",
    headers=H,
    json={"title": "Findings"},
).json()
run_id = report["run_id"]  # .docx produced

# Now fetch a PDF rendition
pdf = requests.post(
    f"{API}/runs/{run_id}/export",
    headers=H,
    json={"format": "pdf"},
).json()
print(pdf["download_url"])
```

Response shape:

```json theme={null}
{
  "format": "pdf",
  "download_url": "https://...",
  "expires_at": "2026-04-20T12:00:00+00:00"
}
```

Unlike `/files/{id}/convert` which takes multipart form-data, this
endpoint takes JSON (it matches the existing `/runs/*` family).

## Errors

| Status | Error             | Meaning                                                       |
| ------ | ----------------- | ------------------------------------------------------------- |
| 400    | `invalid_request` | Unsupported source→target pair. Message lists valid targets.  |
| 404    | `not_found`       | The file/run doesn't exist or isn't visible to this key.      |
| 409    | `conflict`        | (Runs only) the run isn't complete yet — no output to export. |
| 502    | `upstream_error`  | Conversion failed mid-run. Retry usually resolves.            |

## Performance notes

* First conversion of a large `.pptx → .pdf` can take 5–20 seconds.
  Subsequent calls for the same `(file_id, format)` are \~100ms thanks
  to the cache.
* `png` outputs for slide decks render only the **first slide**. Use
  `pdf` if you need every slide.
* `csv` from multi-sheet workbooks exports only the active sheet.
  We're considering a `?sheet=<n>` parameter in a future release;
  please let us know if you need it.
