---
title: "Export Canvas"
method: POST
path: "/canvases/{canvas_id}/export"
tags: ["canvases"]
---

# Export Canvas

`POST /canvases/{canvas_id}/export`

Export a canvas as PNG, JPEG, PDF, or PPTX. Returns a signed URL or a polling handle.

Exports run the headless browser against the authenticated canvas URL,
so they require DB-level team access regardless of share-link status.
Share-link-only callers can read the canvas via ``GET /canvases/{id}``
with a ``share_token`` query param but cannot export.

Large multi-page exports may exceed the synchronous wait budget; in that
case the response carries ``status='in_progress'`` with a ``task_id`` —
call ``GET /canvases/{id}/export-status?task_id=...`` to retrieve the
signed URL once the background export finishes.

## Path parameters

- `canvas_id` string, required — Prefixed ``cvs_`` wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, **a bare UUID string is also accepted** in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working). Both are permanent, supported inputs.

## Query parameters

- `format` string — Export format: png, jpeg, pdf, or pptx
- `page_number` integer, nullable — 1-indexed page number to export. Omit to export all pages — PDF/PPTX bundle every page natively, while multi-page PNG/JPEG are returned as a ``.zip`` of per-page files (``page-1.png``, ``page-2.png``, …) since a single image container can't hold multiple pages. ``format`` in the response reflects what was actually delivered (``zip`` in the bundled case).
- `pixel_ratio` integer, nullable — Render scale multiplier (1-4). Higher values produce sharper exports at larger file sizes. Supported for PNG, JPEG, and PDF exports. PPTX ignores this parameter.
- `flatten` boolean — PDF only: produce a raster-only PDF with no searchable text, vector elements, or hyperlinks.
- `wait` boolean — When True (default), block up to ~20s for the export to finish before returning an in-progress handle. When False, return ``status='in_progress'`` with a ``task_id`` immediately — poll ``/canvases/{id}/export-status`` until terminal.
- `force_refresh` boolean — When False (default), reuse a cached export if the canvas is unchanged since it was rendered — fast, no browser render. Set True to force a fresh render.

## Headers

- `Moda-Version` '2026-04-12' | '2026-05-01'

## Response `200`

Successful Response

- ExportCanvasResponse — Response for ``POST /canvases/{id}/export``. Carries one of two shapes depending on ``status``: - ``completed`` — ``url`` is the signed download URL. - ``in_progress`` — ``task_id`` lets the caller poll ``GET /canvases/{id}/export-status?task_id=...`` until terminal.
  - `status` string — ``completed`` when ``url`` is set, or ``in_progress`` when polling is required.
  - `canvas_id` string, required — Prefixed canvas identifier for the canvas that was exported.
  - `canvas_url` string, required — Full URL to open the source canvas in the Moda editor.
  - `url` string, nullable — Signed download URL for the exported file (set when ``status='completed'``). Expires in 7 days.
  - `format` string, required — Delivered format — ``png``, ``jpeg``, ``pdf``, ``pptx``, or ``zip``. A multi-page PNG/JPEG export (``page_number`` omitted, canvas has >1 page) is bundled into a ``.zip`` of per-page files, so ``format`` is ``zip`` even though the request asked for an image format.
  - `task_id` string, nullable — Export task ID set when ``status='in_progress'``; poll the export-status endpoint with it.
  - `retry_after_seconds` integer, nullable — Suggested poll interval when ``status='in_progress'``.
  - `total_pages` integer, nullable — Total page count for the source canvas (echoed for client convenience).
  - `source` string, nullable — How the export was served: ``cache`` (existing artifact reused), ``slice`` (page extracted from a cached document, no render), or ``render`` (freshly rendered). ``null`` while ``status='in_progress'``.

## Other responses

- `401` — Authentication required.
- `403` — Permission denied for this scope.
- `404` — Resource not found.
- `409` — Conflict (idempotency / resource state).
- `422` — Request validation failed.
- `429` — Rate limit exceeded.
- `500` — Internal error.

---

[API](https://skmtc.net/moda/apis/moda-public-api.md) · [All operations](https://skmtc.net/moda/apis/moda-public-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/moda/moda-public-api/versions/b34cb4cca59e/schema)
