# Dynamic Document API: Renders

> Create and manage renders (PDFs, images, HTML).

> Part of the Dynamic Document API documentation. Index of all pages for agents: [llms.txt](https://dynamicdocumentapi.com/llms.txt), every page in one file: [llms-full.txt](https://dynamicdocumentapi.com/llms-full.txt).

15 endpoints of the [API reference](https://dynamicdocumentapi.com/docs/api-reference/index.md), version 1.0.0. Interactive reference: https://dynamicdocumentapi.com/docs/api-reference#tag/renders. Machine-readable OpenAPI document: https://dynamicdocumentapi.com/openapi/openapi-public.json

## Servers

- https://api-eu.dynamicdocumentapi.com — EU (Germany)

## Endpoints

- `GET /v1/f/{token}` — Open a short file link
- `POST /v1/images/from-html` — Screenshot of HTML
- `POST /v1/images/from-template` — Image from a template
- `POST /v1/images/from-url` — Screenshot of a URL
- `POST /v1/pdf/from-html` — PDF from HTML
- `POST /v1/pdf/from-markdown` — PDF from Markdown
- `POST /v1/pdf/from-template` — PDF from a template
- `POST /v1/pdf/from-url` — PDF from a URL
- `GET /v1/renders` — List renders
- `POST /v1/renders` — Create a render
- `GET /v1/renders/{render_id}` — Retrieve a render
- `POST /v1/renders/{render_id}/cancel` — Cancel a render
- `DELETE /v1/renders/{render_id}/files` — Purge stored files
- `GET /v1/renders/{render_id}/files/{file_id}` — Download a render file
- `GET /v1/renders/{render_id}/logs` — Request/response log

## GET /v1/f/{token}

**Open a short file link**

The `short_url` of a render file, opened without an API key: the link's signature is the credential. Redirects to a fresh signed URL of the file, valid for 5 minutes. Query parameters other than `download` are ignored, so a link still works after a chat app or mail client has added its own. A link stops working at its file's `url_expires_at`; `GET /v1/renders/{id}` returns new links.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `download` | query | boolean | Attachment disposition. |
| `token` (required) | path | string | The last path segment of `short_url`. |

Responses:

- `302` Redirect to a signed URL.
- `404` Unknown or altered link, or the file is gone. Every file of a zero-retention render answers 404.
- `410` `file_expired`: the link expired, or the file expired or was deleted.

## POST /v1/images/from-html

**Screenshot of HTML**

Convenience wrapper over `POST /v1/renders` with flat, no-code friendly fields.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): object

| Field | Type | Description |
|---|---|---|
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or "url" \| "binary" \| "base64" \| "none" |  |
| `engine` | string or null |  |
| `expires_in` | integer |  |
| `filename` | string | Jinja-enabled filename. |
| `format` | "png" \| "jpeg" \| "webp" |  |
| `head` | string or null |  |
| `hosted` | boolean or null | Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one. |
| `html` (required) | string |  |
| `image` | ImageOptions or null |  |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `retention_days` | integer or null |  |
| `templating` | boolean or null |  |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `webhook` | WebhookSpec or null |  |
| `webhook_url` | string |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## POST /v1/images/from-template

**Image from a template**

Convenience wrapper over `POST /v1/renders` with flat, no-code friendly fields.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): object

| Field | Type | Description |
|---|---|---|
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or "url" \| "binary" \| "base64" \| "none" |  |
| `engine` | string or null |  |
| `expires_in` | integer |  |
| `filename` | string | Jinja-enabled filename. |
| `format` | "png" \| "jpeg" \| "webp" |  |
| `hosted` | boolean or null | Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one. |
| `image` | ImageOptions or null |  |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `overrides` | array of object or null |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `retention_days` | integer or null |  |
| `template_id` (required) | string |  |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `version` | "live" \| "draft" or integer |  |
| `webhook` | WebhookSpec or null |  |
| `webhook_url` | string |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## POST /v1/images/from-url

**Screenshot of a URL**

Convenience wrapper over `POST /v1/renders` with flat, no-code friendly fields.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): object

| Field | Type | Description |
|---|---|---|
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or "url" \| "binary" \| "base64" \| "none" |  |
| `engine` | string or null |  |
| `expires_in` | integer |  |
| `filename` | string | Jinja-enabled filename. |
| `format` | "png" \| "jpeg" \| "webp" |  |
| `hosted` | boolean or null | Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one. |
| `http` | HttpOptions or null |  |
| `image` | ImageOptions or null |  |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `retention_days` | integer or null |  |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `url` (required) | string |  |
| `webhook` | WebhookSpec or null |  |
| `webhook_url` | string |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## POST /v1/pdf/from-html

**PDF from HTML**

Convenience wrapper over `POST /v1/renders` with flat, no-code friendly fields.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): object

| Field | Type | Description |
|---|---|---|
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or "url" \| "binary" \| "base64" \| "none" |  |
| `einvoice` | EInvoiceSpec or null |  |
| `engine` | string or null |  |
| `expires_in` | integer |  |
| `filename` | string | Jinja-enabled filename. |
| `head` | string or null |  |
| `hosted` | boolean or null | Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one. |
| `html` (required) | string |  |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `pdf` | PdfOptions or null |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `retention_days` | integer or null |  |
| `templating` | boolean or null |  |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `webhook` | WebhookSpec or null |  |
| `webhook_url` | string |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## POST /v1/pdf/from-markdown

**PDF from Markdown**

Convenience wrapper over `POST /v1/renders` with flat, no-code friendly fields.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): object

| Field | Type | Description |
|---|---|---|
| `allow_raw_html` | boolean or null |  |
| `css` | string or null |  |
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or "url" \| "binary" \| "base64" \| "none" |  |
| `einvoice` | EInvoiceSpec or null |  |
| `engine` | string or null |  |
| `expires_in` | integer |  |
| `filename` | string | Jinja-enabled filename. |
| `hosted` | boolean or null | Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one. |
| `markdown` (required) | string |  |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `pdf` | PdfOptions or null |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `retention_days` | integer or null |  |
| `templating` | boolean or null |  |
| `test` | boolean or null |  |
| `theme` | "default" \| "github" \| "academic" \| "minimal" \| "none" |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `webhook` | WebhookSpec or null |  |
| `webhook_url` | string |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## POST /v1/pdf/from-template

**PDF from a template**

Convenience wrapper over `POST /v1/renders` with flat, no-code friendly fields.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): object

| Field | Type | Description |
|---|---|---|
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or "url" \| "binary" \| "base64" \| "none" |  |
| `einvoice` | EInvoiceSpec or null |  |
| `engine` | string or null |  |
| `expires_in` | integer |  |
| `filename` | string | Jinja-enabled filename. |
| `hosted` | boolean or null | Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one. |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `overrides` | array of object or null |  |
| `pdf` | PdfOptions or null |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `retention_days` | integer or null |  |
| `template_id` (required) | string |  |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `version` | "live" \| "draft" or integer |  |
| `webhook` | WebhookSpec or null |  |
| `webhook_url` | string |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## POST /v1/pdf/from-url

**PDF from a URL**

Convenience wrapper over `POST /v1/renders` with flat, no-code friendly fields.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): object

| Field | Type | Description |
|---|---|---|
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or "url" \| "binary" \| "base64" \| "none" |  |
| `einvoice` | EInvoiceSpec or null |  |
| `engine` | string or null |  |
| `expires_in` | integer |  |
| `filename` | string | Jinja-enabled filename. |
| `hosted` | boolean or null | Keep the hosted copy; `false` deletes it once the storage uploads and email sends have succeeded. Absent or `null`: `false` when every storage destination of the render has `keep_hosted_copy: false`, else `true`. Zero-retention renders never keep one. |
| `http` | HttpOptions or null |  |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `pdf` | PdfOptions or null |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `retention_days` | integer or null |  |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `url` (required) | string |  |
| `webhook` | WebhookSpec or null |  |
| `webhook_url` | string |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## GET /v1/renders

**List renders**

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `batch_id` | query | string |  |
| `created[gte]` | query | string |  |
| `created[lte]` | query | string |  |
| `cursor` | query | string |  |
| `input_type` | query | "einvoice" \| "html" \| "markdown" \| "pdf_tool" \| "template" \| "url" |  |
| `limit` | query | integer | 1 to 100 (default 50). |
| `metadata[key]` | query | string | Filter by a metadata key/value. |
| `output_format` | query | "html" \| "jpeg" \| "pdf" \| "png" \| "webp" \| "xml" \| "zip" |  |
| `reference` | query | string |  |
| `source` | query | string |  |
| `status` | query | "queued" \| "processing" \| "succeeded" \| "failed" \| "canceled" \| "expired" or array of "queued" \| "processing" \| "succeeded" \| "failed" \| "canceled" \| "expired" | Repeat it (or comma-separate the values) to match any of several statuses. |
| `template_id` | query | string |  |
| `test` | query | boolean |  |

Responses:

- `200` 
- `401` Missing, invalid, expired or revoked credentials.
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified.
- `429` Rate limited (`Retry-After`).

## POST /v1/renders

**Create a render**

Unified endpoint for template, HTML, URL and Markdown inputs → PDF, images or HTML. `output.pdf.pdfa` makes the PDF PDF/A-2b or -3b; `output.pdf.pdfua` makes it PDF/UA-1 (accessible, Growth plan and up); `output.einvoice` embeds a Factur-X / ZUGFeRD / XRechnung invoice (a hybrid PDF/A-3b, no extra billed render). All are validated (veraPDF, KoSIT); the report is the render's `result`.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |

Request body (`application/json`): RenderRequest

| Field | Type | Description |
|---|---|---|
| `data` | object or null |  |
| `data_url` | string or null |  |
| `delivery` | DeliverySpec or null |  |
| `engine` | string or null |  |
| `input` (required) | TemplateInputSpec or HtmlInputSpec or UrlInputSpec or MarkdownInputSpec |  |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `output` | OutputSpec or null |  |
| `overrides` | array of object or null |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `webhook` | WebhookSpec or null |  |

Responses:

- `200` Sync render finished (`status=succeeded`). With `delivery.type=binary` the body is the file.
- `202` Async render accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. an unknown, switched-off or another template's rule at `/delivery/email/<i>/rule_id`.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`) or feature not on plan (`plan_feature_unavailable`, e.g. a `delivery.email` list below the Growth plan).
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified; or `region_not_enabled`: the workspace's enabled regions leave out this region.
- `404` Template or version not found.
- `408` Sync timeout exceeded and the render was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` Template deleted.
- `413` Payload or output too large.
- `422` Render failed (`render_id`, `render_error`; `render_failed` when the worker reports no more specific code), schema mismatch, URL not allowed or idempotency key reused. `einvoice_invalid`, `einvoice_validation_failed`, `pdfa_conversion_failed` and `pdfua_validation_failed` also carry the conformance report as `result`. `email_needs_hosted_file`: `delivery.email` lists rules, but a zero-retention render keeps no file to email. `render_canceled`: the sync render was canceled, or its job expired, before it finished. `scene_invalid`, `data_invalid`: a canvas template's scene can't be rendered (e.g. an output over 16,384 px per side), or its `data` isn't an object or lacks a required dynamic property.
- `429` Rate limited (`Retry-After`).
- `503` Region degraded (`Retry-After`).

## GET /v1/renders/{render_id}

**Retrieve a render**

Fresh signed file URLs are issued on every retrieve while files are hosted.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `render_id` (required) | path | string |  |

Responses:

- `200` 
- `401` Missing, invalid, expired or revoked credentials.
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified.
- `404` Render not found.
- `429` Rate limited (`Retry-After`).

## POST /v1/renders/{render_id}/cancel

**Cancel a render**

Best effort: queued renders are canceled immediately; processing renders finish.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `Idempotency-Key` | header | string | Replays the stored response for 24 h; a different body with the same key → 422. |
| `render_id` (required) | path | string |  |

Responses:

- `200` 
- `401` Missing, invalid, expired or revoked credentials.
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified.
- `404` Render not found.
- `409` `conflict`: the render already finished.
- `429` Rate limited (`Retry-After`).

## DELETE /v1/renders/{render_id}/files

**Purge stored files**

Deletes hosted copies now; the render becomes `expired`. BYOS copies are untouched. For a zero-retention render it deletes the transient copies its storage uploads read (uploads still pending then fail), and the status stays.

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `render_id` (required) | path | string |  |

Responses:

- `200` 
- `401` Missing, invalid, expired or revoked credentials.
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified.
- `404` Render not found.
- `409` `conflict`: the render is still running; cancel it first.
- `429` Rate limited (`Retry-After`).

## GET /v1/renders/{render_id}/files/{file_id}

**Download a render file**

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `download` | query | boolean | Attachment disposition. |
| `file_id` (required) | path | string |  |
| `inline` | query | boolean | Stream through the API instead of 302. |
| `render_id` (required) | path | string |  |

Responses:

- `200` File (`?inline=true`).
- `302` Redirect to a signed URL.
- `401` Missing, invalid, expired or revoked credentials.
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified.
- `404` Render or file not found. Every file of a zero-retention render answers 404: its copies for storage destinations can't be opened.
- `410` File expired or deleted.
- `429` Rate limited (`Retry-After`).

## GET /v1/renders/{render_id}/logs

**Request/response log**

Parameters:

| Name | In | Type | Description |
|---|---|---|---|
| `render_id` (required) | path | string |  |

Responses:

- `200` 
- `401` Missing, invalid, expired or revoked credentials.
- `403` Insufficient scope, IP not allowed, workspace suspended or scheduled for deletion, or email not verified.
- `404` Logging disabled or log expired.
- `429` Rate limited (`Retry-After`).
