Skip to main content
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

FromTo
xlsxpdf, csv, png, html
xlspdf, csv, xlsx, html
docxpdf, html, txt, odt
docpdf, docx, html, txt
pptxpdf, png, odp
pptpdf, 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.
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:
{
  "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:
FieldRequiredDescription
formatyesTarget 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:
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:
{
  "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

StatusErrorMeaning
400invalid_requestUnsupported source→target pair. Message lists valid targets.
404not_foundThe file/run doesn’t exist or isn’t visible to this key.
409conflict(Runs only) the run isn’t complete yet — no output to export.
502upstream_errorConversion 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.