CodeB eForms Server by Aloaha

E-invoice API E-invoice API: ZUGFeRD and XRechnung from JSON.

One API call turns structured invoice data into a legally compliant electronic invoice: a PDF/A-3 that people read like any PDF, with the invoice data embedded as XML according to EN 16931 (ZUGFeRD / Factur-X). With a buyer reference (Leitweg-ID) the invoice meets the XRechnung rules for German public authorities.

The endpoint fills the invoice form of your server and submits it, so the invoice is sealed, signed if configured, and e-mailed like an invoice entered in the browser.

How it works

  1. Your software sends POST /api/v1/einvoices with a bearer token (see Getting a bearer token) and the invoice as JSON.
  2. The server checks the data, calculates missing totals and maps every value to the fields of its invoice form (by default the form zugferd).
  3. The form is submitted through the normal form processing. It creates the EN 16931 XML (Cross Industry Invoice, ZUGFeRD / Factur-X profile EN 16931, written following the KoSIT rules used for XRechnung), embeds it into a PDF/A-3 and seals the PDF.
  4. The PDF goes back to your software (as Base64 in JSON, or as the file itself with Accept: application/pdf) and, like the web form, by e-mail to the business owner of the form and to the e-mail addresses in the invoice (seller and buyer).

"action": "preview" stops after step 2: you receive the filled invoice form as PDF, nothing is sealed and no e-mail is sent. Use it to check a layout or your mapping.

Smallest request

Invoice number, seller, buyer and at least one line are required. The invoice date defaults to today, the currency to the form's preset (EUR on the sample form), and all totals are calculated.

curl -X POST https://forms.example.com/api/v1/einvoices \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -H "Accept: application/pdf" \
  -o invoice.pdf -d '{
  "invoice": { "number": "2026-0042", "taxPercent": 19 },
  "seller":  { "name": "Example Supplies GmbH", "street": "Musterstrasse 1", "postCode": "10115", "town": "Berlin", "country": "DE", "vatId": "DE123456789" },
  "buyer":   { "name": "Example Hotel AG", "street": "Seestrasse 1", "postCode": "12345", "town": "Musterstadt", "country": "DE" },
  "items":   [ { "name": "Consulting (hours)", "quantity": 4, "netPrice": 120 } ]
}'

Complete example (XRechnung)

An invoice to a German public authority, with Leitweg-ID, contact data, delivery date and SEPA payment. Dates are ISO 8601 (yyyy-MM-dd; dd.MM.yyyy is accepted too), amounts are numbers with a dot as decimal separator.

{
  "action": "submit",
  "invoice": {
    "number": "2026-0042", "date": "2026-10-11", "currency": "EUR",
    "dueDate": "2026-10-25", "deliveryDate": "2026-10-09", "paymentTerms": "14 days net",
    "buyerReference": "04011000-12345-34", "buyerOrderReference": "PO-7781",
    "taxPercent": 19, "taxCategory": "S", "note": "Thank you for your order."
  },
  "seller": { "name": "Example Supplies GmbH", "contactName": "Erika Muster", "street": "Musterstrasse 1",
              "postCode": "10115", "town": "Berlin", "country": "DE", "phone": "+49 30 1234567",
              "email": "billing@example.com", "vatId": "DE123456789" },
  "buyer":  { "name": "City of Musterstadt", "contactName": "Max Beispiel", "street": "Rathausplatz 1",
              "postCode": "12345", "town": "Musterstadt", "country": "DE", "email": "invoices@example.org" },
  "payment": { "iban": "DE02120300000000202051", "bic": "BYLADEM1001", "accountName": "Example Supplies GmbH" },
  "items": [
    { "name": "Consulting (hours)", "quantity": 4, "netPrice": 120, "sellerAssignedId": "C-100" },
    { "name": "Travel flat rate", "netPrice": 80 }
  ]
}

Field reference

Every JSON field, the EN 16931 business term (BT) it fills and the field name on the invoice form. Required fields are marked.

JSONMeaningEN 16931Form field
invoice.number requiredInvoice numberBT-1InvoiceID
invoice.dateInvoice date (default: today)BT-2date
invoice.currencyCurrency, ISO 4217 (EUR, CHF, …)BT-5InvoiceCurrencyCode
invoice.dueDatePayment due dateBT-9DueDate
invoice.buyerReferenceBuyer reference; for XRechnung the Leitweg-IDBT-10BuyerReference
invoice.buyerOrderReferencePurchase order number of the buyerBT-13BuyerOrderReference
invoice.paymentTermsPayment terms as textBT-20PaymentTerms
invoice.noteInvoice noteBT-22InvoiceNote
invoice.deliveryDateActual delivery dateBT-72DeliveryDate
invoice.paymentReferenceRemittance information (only if the form has the field)BT-83PaymentReference
invoice.taxPercentVAT rate in percent for the whole invoiceBT-152 / BT-119TAXPercent
invoice.taxCategoryVAT category: S, Z, E, AE or G (see below)BT-151 / BT-118TaxCategory
invoice.taxExemptionReasonReason for E, AE, GBT-120TaxExemptionReason
seller.name requiredSeller nameBT-27SellerName
seller.street, street2Address linesBT-35, BT-36SellerStreet1, SellerStreet2
seller.postCode, town, countryPost code, town, country (ISO 3166-1, e.g. DE)BT-38, BT-37, BT-40SellerPostCode, SellerTown, SellerCountry
seller.vatIdVAT identification numberBT-31SellerVAT
seller.contactName, phoneContact person and phoneBT-41, BT-42SellerPersonName, SellerPhone
seller.emailSeller e-mail as electronic addressBT-34SellerEmail
buyer.name requiredBuyer nameBT-44BuyerName
buyer.street, street2, postCode, town, countryBuyer addressBT-50 to BT-55BuyerStreet1 … BuyerCountry
buyer.vatIdBuyer VAT identification numberBT-48BuyerVAT
buyer.contactName, phoneContact at the buyerBT-56, BT-57BuyerPersonName, BuyerPhone
buyer.emailBuyer e-mail as electronic addressBT-49BuyerEmail
payment.iban, bic, accountNameBank account for the SEPA credit transferBT-84, BT-86, BT-85IBAN, BIC, AccountName
items[].name requiredItem nameBT-153ItemName1, ItemName2, …
items[].quantityQuantity (default 1, unit C62 = piece)BT-129BilledQuantity1, …
items[].netPrice requiredNet unit priceBT-146NetPriceProductTradePrice1, …
items[].lineTotalLine net amount (default: quantity × net price)BT-131LineTotalAmount1, …
items[].sellerAssignedIdSeller's item number (only if the form has the field)BT-155SellerAssignedID1, …
totals.lineTotal, taxTotal, grandTotalTotals; calculated when missingBT-106, BT-110, BT-112LineTotalAmount, TaxTotalAmount, GrandTotalAmount

Amounts, VAT and rounding

  • Line amount = quantity × net price, rounded to 2 decimals (half away from zero), unless you send lineTotal.
  • Sum of lines = sum of the line amounts; it is also the taxable amount and the total without VAT.
  • VAT = sum of lines × taxPercent / 100, rounded to 2 decimals. Total = sum of lines + VAT; the amount due equals the total.
  • Totals you send in totals win over the calculation, so you can pass the exact figures of your accounting system.
  • One VAT rate applies to the whole invoice. For invoices with several VAT rates, send one invoice per rate or ask us about the ZUGFeRD Pro SDK.
  • Numbers: 1234.5 or "1234.50". A comma is refused, so "12,50" can never become 1250.

VAT categories

  • S standard rate (default). With a rate of 0 it becomes Z.
  • Z zero rated goods.
  • E exempt from VAT; without taxExemptionReason the reason "Steuerfreie Leistung" is used.
  • AE reverse charge (exemption code VATEX-EU-AE); default reason "Steuerschuldnerschaft des Leistungsempfängers".
  • G export outside the EU (VATEX-EU-G).

For E, AE and G the rate is set to 0.

Payment

With an iban the invoice carries a SEPA credit transfer (payment means code 58) with BIC and account name. Without an IBAN the payment means is "not defined" (code 1). Payment terms (paymentTerms) and due date (dueDate) are written in any case; without a due date the invoice date is used.

XRechnung checklist

Invoices to German public authorities must follow XRechnung. Send at least:

  • invoice.buyerReference = the Leitweg-ID of the authority (without it the server writes a generated reference, which an authority will reject).
  • seller.email and buyer.email (electronic addresses), seller.contactName, seller.phone.
  • seller.vatId, complete addresses with country codes, invoice.dueDate or paymentTerms.
  • Payment data (payment.iban) if the authority pays by transfer.

The XML is written following the KoSIT rules. Check your first invoices once with the KoSIT validator or a viewer of your choice.

The answer

201 Created with the submission ID, the PDF and the totals that were used:

HTTP/1.1 201 Created
{
  "submissionId": "7f3c2a9e0d5b4e1fa2c8b6d4e9f01a23",
  "formId": "zugferd",
  "action": "submit",
  "status": "submitted",
  "pdf": { "fileName": "zugferd.pdf", "contentType": "application/pdf", "size": 152331,
           "sha256": "…", "eInvoice": true, "data": "JVBERi0xLjc…" },
  "totals": { "lineTotal": 560.00, "taxTotal": 106.40, "grandTotal": 666.40, "currency": "EUR" },
  "notOnForm": [ "PaymentReference", "SellerAssignedID1", "SellerAssignedID2" ]
}
  • pdf.eInvoice is true when the e-invoice XML is embedded in the PDF.
  • notOnForm lists values the chosen form has no field for (they are not part of the invoice).
  • With Accept: application/pdf (or "returnPdf": "binary") the answer is the PDF itself; the header X-Submission-Id carries the ID. "returnPdf": "none" leaves out the PDF data.
  • "action": "preview" answers 200 with the filled, unsent invoice.

Using your own invoice form

By default the server uses its invoice form (setting Form for e-invoices, preset zugferd). Send "formId" to use another one, for example an invoice form with your letterhead. The form must be released and needs fields with the names in the field reference above; lines are numbered from 1 (or from 0). The number of ItemName… fields is the maximum number of lines: the sample form has 8.

Design the form in the editor, name the fields as listed, release it, then check the mapping with "action": "preview". GET /api/v1/forms/{formId}/fields shows the field names of a form.

Limits and errors

Errors come as problem details (application/problem+json); see also the error list of the API.

StatusCodeMeaning
422validation_failedA required value is missing (number, seller or buyer name, line name or price), a date or number cannot be read, or a value does not fit the form (e.g. unknown currency or country in a drop-down).
422too_many_itemsMore lines than the form has room for.
422not_an_invoice_formThe chosen form has no invoice line fields.
403role_requiredCreating invoices needs the role user or admin.
404 / 409form_not_found, form_not_releasedThe invoice form does not exist for this token, or is not released.
429rate_limited, daily_limitToo many requests, or the daily cap of API submissions is reached.
502form_processing_failedThe invoice could not be created or sent; nothing was delivered.

Questions and answers

Which ZUGFeRD profile does the API create?

The EN 16931 profile (called COMFORT in ZUGFeRD 1), Cross Industry Invoice XML embedded in a PDF/A-3, identical to Factur-X. The XML is written following the KoSIT rules that XRechnung uses.

How do I create an XRechnung?

Send the Leitweg-ID of the public authority as invoice.buyerReference and fill in the e-mail addresses and contact data of seller and buyer. The API then creates an EN 16931 invoice that meets the XRechnung rules, embedded in the PDF.

Can I send the totals of my accounting system?

Yes. Values in totals (lineTotal, taxTotal, grandTotal) and items[].lineTotal win over the calculation.

Is the invoice e-mailed automatically?

Yes, like the invoice web form: to the business owner of the form and to the e-mail addresses in the data. Use "action": "preview" to get the PDF without sending.

Can an invoice have several VAT rates?

Not through this endpoint: one rate applies to the whole invoice. Send one invoice per rate, or use the ZUGFeRD Pro SDK for complex invoices.

Create your first e-invoice

Ask for test credentials and try the e-invoice API on our online server.

Last updated: