---
title: "Create a ZUGFeRD / Factur-X hybrid electronic invoice"
method: POST
path: "/api2/invoice"
tags: ["Invoice"]
---

# Create a ZUGFeRD / Factur-X hybrid electronic invoice

`POST /api2/invoice`

## Request

- Base URL: `https://selectpdf.com`
- URL: `https://selectpdf.com/api2/invoice`
- Auth: none declared

Converts a URL or HTML into a ZUGFeRD / Factur-X hybrid electronic invoice: the visible invoice is produced by the normal conversion pipeline as a PDF/A-3 document, and the invoice XML is embedded into it as an associated file with the metadata invoice software looks for.

multipart/form-data only - the invoice XML is uploaded as a file part named `zugferd_xml`. Every /api2/convert parameter applies here as well, plus the zugferd_* fields.

`pdf_standard` must be a PDF/A-3 level and defaults to `pdfa3a`, the accessible level, which the standards recommend because it also makes the visible invoice readable by assistive technology. Because pdfa3a is a tagged standard, a request that does not specify an engine is promoted to Chromium and the engine used is returned in X-SelectPdf-Engine.

There is no variant that attaches the XML to an existing PDF you upload: the invoice XML can only be embedded into a document created as PDF/A-3.

## Request body `multipart/form-data`

- InvoiceParameters: Parameters for HTML→PDF conversion. Most fields are optional and have engine-defined defaults; only `key` and (one of) `url`/`html` are required.
  - `key` string, uuid, required: License key. Required for `/api2/convert`; ignored on `/api2/convert/demo`.
  - `async` boolean: If true, submit asynchronously and return 202 + a Job-Id header. Poll `/api2/asyncjob`.
  - `url` string: Web URL to convert. Required if `html` is empty. Mutually exclusive with `html`.
  - `html` string: Raw HTML string to convert. Required if `url` is empty.
  - `base_url` string: Base URL used to resolve relative paths inside `html`.
  - `pdf_name` string: Filename suggested via `Content-Disposition` (default: `Document.pdf`).
  - `page_size` 'A0' | 'A1' | 'A2' | 'A3' | 'A4' | 'A5' | 'A6' | 'A7' | 'A8' | 'Letter' | 'HalfLetter' | 'Ledger' | 'Legal': Output page size.
  - `page_orientation` 'Portrait' | 'Landscape'
  - `page_width` integer: Custom page width in points (1 pt = 1/72 in). Overrides `page_size` when both `page_width` and `page_height` are non-zero.
  - `page_height` integer: Custom page height in points.
  - `margin_top` integer: Top margin in points.
  - `margin_right` integer: Right margin in points.
  - `margin_bottom` integer: Bottom margin in points.
  - `margin_left` integer: Left margin in points.
  - `engine` 'WebKit' | 'Restricted' | 'Blink' | 'Chromium': Rendering engine. `WebKit` (default) — broadest compatibility. `Restricted` — WebKit with limited JS. `Blink` — older Chromium fork. `Chromium` — modern Chromium/CEF (recommended for new integrations, required by the demo endpoint).
  - `protocol` integer: TLS protocol selector for fetching `url`. 0 = default (negotiate).
  - `web_page_width` integer: Browser viewport width in pixels used while rendering.
  - `web_page_height` integer: Viewport height in pixels. 0 = automatic (engine picks based on content).
  - `min_load_time` integer: Minimum time (seconds) the engine waits after page load before producing the PDF (lets late-loading scripts settle).
  - `max_load_time` integer: Hard ceiling (seconds) for page load. On the demo endpoint this is clamped to 15.
  - `use_css_print` boolean: Honor CSS `@media print` rules instead of `@media screen`.
  - `background_color` string: PDF page background color (e.g. `#FFFFFF`).
  - `draw_html_background` boolean: If false, the HTML's own backgrounds are stripped (transparent PDF).
  - `disable_javascript` boolean
  - `disable_internal_links` boolean: Suppress in-document anchor hyperlinks.
  - `disable_external_links` boolean: Suppress hyperlinks pointing outside the document.
  - `render_on_timeout` boolean: If `max_load_time` expires, render whatever loaded instead of failing.
  - `keep_images_together` boolean: Avoid splitting images across page breaks.
  - `scale_images` boolean
  - `single_page_pdf` boolean: Produce a single tall page sized to fit the entire content.
  - `page_breaks_enhanced_algorithm` boolean
  - `doc_title` string: PDF metadata: title.
  - `doc_subject` string
  - `doc_keywords` string
  - `doc_author` string
  - `doc_add_creation_date` boolean
  - `doc_language` string: Natural language of the document (e.g. "en-US", "de-DE"), written as the PDF /Lang entry and onto tagged structure elements. Defaults to en-US.
  - `tagged` boolean: Produce a tagged, accessible PDF: a logical structure tree covering headings, paragraphs, lists, tables, figures with alternate text, links and reading order. Requires engine=Blink or engine=Chromium - the WebKit engines cannot produce a structure tree. When the engine is not specified it is promoted to Chromium automatically and reported in the X-SelectPdf-Engine response header. Also forces viewer_display_doc_title, which accessible PDF requires.
  - `pdf_standard` 'full' | 'pdfa' | 'pdfa2b' | 'pdfa3a' | 'pdfa3b' | 'pdfa3u' | 'pdfx' | 'pdfsiqq_a' | 'pdfsiqq_b': PDF conformance target. full (default) uses the complete PDF feature set. pdfa/pdfa2b/pdfa3b/pdfa3u are archival levels; pdfa3a is the accessible level of PDF/A-3 and implies a tagged document, so it carries the same engine requirement as tagged. pdfx is for graphics exchange; pdfsiqq_a and pdfsiqq_b are the digital-signature profiles.
  - `viewer_page_layout` 0 | 1 | 2 | 3 | 4 | 5: PDF viewer page layout: 0=SinglePage, 1=OneColumn (default), 2=TwoColumnLeft, 3=TwoColumnRight, 4=TwoPageLeft, 5=TwoPageRight.
  - `viewer_page_mode` 0 | 1 | 2 | 3 | 4 | 5: PDF viewer page mode: 0=UseNone (default), 1=UseOutlines, 2=UseThumbs, 3=FullScreen, 4=UseOC, 5=UseAttachments.
  - `viewer_center_window` boolean
  - `viewer_display_doc_title` boolean
  - `viewer_fit_window` boolean
  - `viewer_hide_menu_bar` boolean
  - `viewer_hide_toolbar` boolean
  - `viewer_hide_window_ui` boolean
  - `show_header` boolean: Render a header band on each page sourced from `header_url` or `header_html`.
  - `header_display_on_first_page` boolean
  - `header_display_on_odd_pages` boolean
  - `header_display_on_even_pages` boolean
  - `header_height` integer: Header band height in points.
  - `header_url` string: URL whose rendered output becomes the page header.
  - `header_html` string: Inline HTML used as the page header (alternative to `header_url`).
  - `header_base_url` string
  - `header_web_page_width` integer
  - `header_web_page_height` integer
  - `show_footer` boolean
  - `footer_display_on_first_page` boolean
  - `footer_display_on_odd_pages` boolean
  - `footer_display_on_even_pages` boolean
  - `footer_display_on_last_page` boolean
  - `footer_height` integer
  - `footer_url` string
  - `footer_html` string
  - `footer_base_url` string
  - `footer_web_page_width` integer
  - `footer_web_page_height` integer
  - `page_numbers` boolean: Render page numbers in the footer band.
  - `page_numbers_first` integer: Page number assigned to the first page (lets you offset numbering).
  - `page_numbers_offset` integer: Number of leading pages to suppress numbering on.
  - `page_numbers_template` string: Template using `{page_number}` and `{total_pages}` placeholders.
  - `page_numbers_font_name` string
  - `page_numbers_font_size` integer
  - `page_numbers_alignment` 1 | 2 | 3: 1=Left, 2=Center, 3=Right.
  - `page_numbers_color` string: Hex color for the page numbers (e.g. `#000000`).
  - `page_numbers_pos_y` integer: Vertical position of page numbers in points from the bottom.
  - `pdf_bookmarks_selectors` string: Semicolon-separated CSS selectors. Matched elements become PDF bookmarks.
  - `pdf_hide_elements` string: Semicolon-separated CSS selectors. Matched elements are hidden before rendering.
  - `pdf_show_only_element_id` string: Render only the element with this `id` (everything else hidden).
  - `pdf_web_elements_selectors` string: Semicolon-separated CSS selectors whose bounding boxes are reported back via `X-SelectPdf-Web-Elements` (sync) or `/api2/webelements` (async).
  - `user_password` string: Password required to open the PDF. Rejected by the demo endpoint.
  - `owner_password` string: Password required to modify / print the PDF. Rejected by the demo endpoint.
  - `auth_username` string: HTTP Basic-Auth username used when fetching `url`.
  - `auth_password` string
  - `cookies` object: Cookie name → value map sent when fetching `url` (JSON body only).
  - `cookies_string` string: Query-string-encoded cookies (form / GET equivalent of `cookies`).
  - `startup_mode` string: Engine startup mode hint (`automatic`, `manual`).
  - `skip_decoding` boolean: If true, treat the URL as already-decoded (do not re-percent-decode). Internal default for forwarded calls.
  - `raw_parameters` string: Optional JSON blob containing this entire object. When present, the receiver deserializes it and ignores all other form fields. Used by the SDK's remote-worker proxy.
  - `response_content_type` 0 | 1: 0 = `binary/octet-stream` (default, makes browsers download). 1 = `application/pdf` (browsers may render inline).
  - `zugferd_profile` 'minimum' | 'basic_wl' | 'basic' | 'en16931' | 'extended' | 'xrechnung', required: Required. How much of the EN 16931 semantic model the embedded XML carries. minimum and basic_wl are not complete invoices. xrechnung is the German public-sector profile, and its embedded file is named xrechnung.xml rather than factur-x.xml.
  - `zugferd_relationship` 'data' | 'alternative' | 'source' | 'supplement': How the XML relates to the visible invoice page. Defaults per profile: alternative for minimum and basic_wl (the page carries more than the XML), data for the rest (the XML and the page carry the same content, which is mandatory in Germany for basic, en16931, extended and xrechnung). minimum or basic_wl combined with data is rejected.
  - `zugferd_schema` 'facturx10' | 'zugferd20': Metadata schema identifying the invoice. zugferd20 is deprecated and only for recipients that still require it.

## Response `200`

Hybrid invoice PDF returned in the response body.

## Other responses

- `202`: Async accepted. Poll `/api2/asyncjob` with the returned `X-SelectPdf-Job-Id`.
- `400`: Missing url/html or zugferd_xml, unknown zugferd_* value, a pdf_standard that is not a PDF/A-3 level, or a profile/relationship pair the standards do not allow.
- `401`: License key missing, invalid or not active.
- `405`: Method not allowed - the invoice endpoint is POST multipart only.
- `429`: Too many concurrent requests for this account.
- `499`: Conversion error.

## Changes

- **2026-09-25** `9a48026f4fc2`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/selectpdf/apis/selectpdf-rest-api/changes/api2/invoice/post.md)

---

[API](https://skmtc.dev/selectpdf/apis/selectpdf-rest-api.md) - [All operations](https://skmtc.dev/selectpdf/apis/selectpdf-rest-api/llms.txt) - [OpenAPI document](https://skmtc.dev/selectpdf/apis/selectpdf-rest-api/revisions/9a48026f4fc2?raw)
