# Dynamic Document API: E-invoices

> XRechnung, Factur-X / ZUGFeRD and EN 16931 invoices: standalone CII or UBL XML here; hybrid PDF/A-3b invoices through `output.einvoice` on any PDF render. Validated with KoSIT. `POST /v1/einvoices/validate` checks e-invoices you receive.

> 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).

2 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/e-invoices. Machine-readable OpenAPI document: https://dynamicdocumentapi.com/openapi/openapi-public.json

## Servers

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

## Endpoints

- `POST /v1/einvoices` — Create an e-invoice XML
- `POST /v1/einvoices/validate` — Validate an e-invoice

## POST /v1/einvoices

**Create an e-invoice XML**

Generates a standalone e-invoice from the invoice model: UN/CEFACT CII (every profile) or UBL 2.1 (`EN16931`, `XRECHNUNG`), e.g. an XRechnung for German public buyers. The XML is validated with the KoSIT validator (report in `result.conformance.einvoice`) and delivered as one `application/xml` file; a model that breaks a profile rule fails with `einvoice_invalid` and the list of issues. Answers a Render object with `input_type: "einvoice"` and `kind: "einvoice_xml"`; `delivery`, `mode`, `webhook`, `reference`, `metadata` and `test` behave as on `POST /v1/renders`. 1 billed render. Test renders are free, and their XML has a TEST note as its first invoice note (BT-22; every profile but `MINIMUM`, which has no notes; `EXTENDED` also sets `TestIndicator`). To embed the invoice in a PDF instead, use `output.einvoice` on a render.

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`): EInvoiceRequest

| Field | Type | Description |
|---|---|---|
| `delivery` | DeliverySpec or null |  |
| `filename` | string or null | Output filename (`.xml` is enforced). Default: the invoice number, sanitised, + `.xml`. |
| `invoice` (required) | object | The invoice model (EN 16931 business terms). |
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `priority` | "normal" \| "low" |  |
| `profile` (required) | "MINIMUM" \| "BASIC_WL" \| "BASIC" \| "EN16931" \| "EXTENDED" \| "XRECHNUNG" | EN 16931 profile of the XML: `XRECHNUNG` (German public sector), `EN16931`, or a Factur-X / ZUGFeRD profile (`MINIMUM`, `BASIC_WL`, `BASIC`, `EXTENDED`; CII only). |
| `reference` | string or null |  |
| `syntax` | "cii" \| "ubl" | `cii` (UN/CEFACT Cross Industry Invoice D16B) or `ubl` (UBL 2.1 Invoice / CreditNote; `EN16931` and `XRECHNUNG` only). |
| `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`).

## POST /v1/einvoices/validate

**Validate an e-invoice**

Checks an e-invoice you received, from any sender: a hybrid PDF (Factur-X / ZUGFeRD 2.x, or a PDF carrying `xrechnung.xml`) or a standalone XML in UN/CEFACT CII or UBL 2.1. The XML must name XRechnung 3.0, EN 16931 or a Factur-X / ZUGFeRD 2.x profile as its specification identifier (BT-24); UBL only for EN 16931 and XRechnung. It is validated with the KoSIT validator, and a PDF as received with veraPDF's PDF/A-3b profile: the same validators and rules as for the invoices this API generates. Answers a Render object with no files: `result.valid` is the verdict, `result.document` what was found and `result.conformance` the reports. Not checked: the Factur-X XMP metadata, the attachment's relationship, whether the pages match the XML, signatures, and whether the invoice is correct under tax law. A verdict, valid or invalid, is 1 billed render on every plan; a check that reaches none (422) and test calls are free. Test calls count against the test-mode renders per minute and are limited to 25 per workspace and UTC day; at most 4 checks run at once per workspace (fewer when the plan allows fewer concurrent sync renders), sync and async alike. There is no `filename` or `delivery`; `mode`, `webhook`, `reference`, `metadata` and `test` behave as on `POST /v1/renders`.

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`): EInvoiceValidationRequest

| Field | Type | Description |
|---|---|---|
| `metadata` | object or null |  |
| `mode` | "sync" \| "async" |  |
| `priority` | "normal" \| "low" |  |
| `reference` | string or null |  |
| `source` (required) | PdfSourceSpec | Exactly one of `url`, `render_id` (+ optional `file_id`), `upload_id` or `data_uri`. |
| `test` | boolean or null |  |
| `timeout_behavior` | "continue" \| "cancel" |  |
| `webhook` | WebhookSpec or null |  |

Responses:

- `200` The check finished (`status=succeeded`); `result` holds the verdict.
- `202` Async check accepted, or the sync timeout was exceeded (`Location: /v1/renders/{id}`).
- `400` Malformed or invalid request (`errors[]` with JSON pointers), e.g. a `filename` or `delivery` (unknown fields), or a source that is neither a PDF nor an XML.
- `401` Missing, invalid, expired or revoked credentials.
- `402` Render limit reached (`render_limit_reached`).
- `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` Source render or upload not found (`render_not_found`, `upload_not_found`).
- `408` Sync timeout exceeded and the check was canceled (`timeout_behavior=cancel`).
- `409` A request with this Idempotency-Key is still in progress.
- `410` The source render has no PDF or XML file any more (`file_expired`).
- `413` A `data_uri` over 5 MB (`payload_too_large`).
- `422` The check reached no verdict (`render_id`, `render_error`; nothing billed): `einvoice_not_found` (neither a PDF nor an XML, a PDF without `factur-x.xml`, `xrechnung.xml` or `zugferd-invoice.xml`, or an XML that isn't a CII or UBL invoice), `einvoice_unsupported` (an invoice this check doesn't cover, e.g. Peppol BIS Billing 3.0, ZUGFeRD 1.0 or 2.0, or XRechnung before 3.0; the message names what was found), `einvoice_validation_unavailable` (a validator gave no verdict in time; retry later), `pdf_password_required`, `invalid_pdf_source`, and for `url` sources `url_not_allowed`, `asset_fetch_failed` and `payload_too_large`. Also `idempotency_key_reused` and `render_canceled`. An invalid invoice is not an error: it answers `200` with `result.valid: false`.
- `429` `rate_limited` (the request rate, the test renders per minute, or 25 test checks per UTC day) or `concurrency_limited` (as many checks running as the workspace may run at once); `Retry-After`.
- `503` Region degraded (`Retry-After`).
