POST /v1/generate
Generate an e-invoice from invoice data: EN 16931 UBL or CII, Peppol, hybrid PDF, or a national XML format (FatturaPA FPR12, Facturae, e-SLOG, KSeF FA(3)).
Create an e-invoice from JSON data in one API call.
Before Beliq returns the result, it validates your invoice against the rules that apply to the chosen standard. For EN 16931–based formats that means XSD, EN 16931 Schematron, and CIUS/profile Schematron where applicable. For Italy FatturaPA (standard: "fatturapa") validation is authority XSD only (no EN 16931 Schematron layer). If validation fails, you get a 422 INVALID_INVOICE response with details.
Quick copy examples
Generate XML:
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"standard": "xrechnung",
"profile": "xrechnung",
"output": "xml",
"invoice": {
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"buyerReference": "04011000-12345-03",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"email": "billing@acme.example",
"contactName": "Anna Beispiel",
"phone": "+49 30 1234567",
"address": { "street": "Musterstraße 1", "city": "Berlin", "postalCode": "10115", "countryCode": "DE" }
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"address": { "street": "Beispielweg 42", "city": "Bonn", "postalCode": "53113", "countryCode": "DE" }
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00 }
],
"paymentMeans": {
"typeCode": "58",
"iban": "DE89370400440532013000"
},
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00
}
}'import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'xrechnung',
profile: 'xrechnung',
output: 'xml',
invoice: {
number: 'INV-2026-001',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
buyerReference: '04011000-12345-03',
seller: {
name: 'Acme GmbH',
vatId: 'DE123456789',
email: 'billing@acme.example',
contactName: 'Anna Beispiel',
phone: '+49 30 1234567',
address: { street: 'Musterstraße 1', city: 'Berlin', postalCode: '10115', countryCode: 'DE' },
},
buyer: {
name: 'Bundesministerium für Beispiele',
vatId: 'DE987654321',
address: { street: 'Beispielweg 42', city: 'Bonn', postalCode: '53113', countryCode: 'DE' },
},
lines: [
{
description: 'IT consulting, April 2026',
quantity: 20,
unitCode: 'HUR',
unitPrice: 120.00,
lineTotal: 2400.00,
vatRate: 19,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 19, taxableAmount: 2400.00, taxAmount: 456.00 }],
paymentMeans: { typeCode: '58', iban: 'DE89370400440532013000' },
totalNetAmount: 2400.00,
totalTaxAmount: 456.00,
totalGrossAmount: 2856.00,
},
});
// `xml` is the same document curl writes to stdout.
console.log(generated.xml);import os
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="xrechnung",
profile="xrechnung",
output="xml",
invoice={
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"buyerReference": "04011000-12345-03",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"email": "billing@acme.example",
"contactName": "Anna Beispiel",
"phone": "+49 30 1234567",
"address": {
"street": "Musterstraße 1",
"city": "Berlin",
"postalCode": "10115",
"countryCode": "DE",
},
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"address": {
"street": "Beispielweg 42",
"city": "Bonn",
"postalCode": "53113",
"countryCode": "DE",
},
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00}],
"paymentMeans": {"typeCode": "58", "iban": "DE89370400440532013000"},
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00,
},
)
# `xml` is the same document curl writes to stdout.
print(generated.xml)Generate PDF:
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"standard": "zugferd",
"profile": "en16931",
"output": "pdf",
"invoice": {
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"address": { "street": "Musterstraße 1", "city": "Berlin", "postalCode": "10115", "countryCode": "DE" }
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"address": { "street": "Beispielweg 42", "city": "Bonn", "postalCode": "53113", "countryCode": "DE" }
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00 }
],
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00
}
}' \
--output invoice.pdfimport { writeFile } from 'node:fs/promises';
import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'zugferd',
profile: 'en16931',
output: 'pdf',
invoice: {
number: 'INV-2026-001',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
seller: {
name: 'Acme GmbH',
vatId: 'DE123456789',
address: { street: 'Musterstraße 1', city: 'Berlin', postalCode: '10115', countryCode: 'DE' },
},
buyer: {
name: 'Bundesministerium für Beispiele',
vatId: 'DE987654321',
address: { street: 'Beispielweg 42', city: 'Bonn', postalCode: '53113', countryCode: 'DE' },
},
lines: [
{
description: 'IT consulting, April 2026',
quantity: 20,
unitCode: 'HUR',
unitPrice: 120.00,
lineTotal: 2400.00,
vatRate: 19,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 19, taxableAmount: 2400.00, taxAmount: 456.00 }],
totalNetAmount: 2400.00,
totalTaxAmount: 456.00,
totalGrossAmount: 2856.00,
},
});
await writeFile('invoice.pdf', generated.bytes);import os
from pathlib import Path
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="zugferd",
profile="en16931",
output="pdf",
invoice={
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"address": {
"street": "Musterstraße 1",
"city": "Berlin",
"postalCode": "10115",
"countryCode": "DE",
},
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"address": {
"street": "Beispielweg 42",
"city": "Bonn",
"postalCode": "53113",
"countryCode": "DE",
},
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00}],
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00,
},
)
Path("invoice.pdf").write_bytes(generated.content)Request
POST /v1/generate
Content-Type: application/json
Authorization: Bearer <api-key>Request body
| Field | Type | Required | Description |
|---|---|---|---|
standard |
string | required | E-invoice standard. One of: xrechnung, zugferd, facturx, peppol-bis, fatturapa (Italy FatturaPA ordinaria FPR12 XML), facturae (Spain Facturae 3.2.2 XML), eslog (Slovenia e-SLOG 2.0 XML), ksef (Poland KSeF FA(3) XML, ordinary VAT invoices in PLN; see the scope); the four national formats use XSD validation only, not EN 16931 UBL/CII |
profile |
string | optional | Compliance profile. Valid values depend on standard; see Profile compatibility for the full matrix and the per-standard default. A profile that does not belong to the chosen standard is rejected with 422 PROFILE_STANDARD_MISMATCH. |
output |
string | required | Output format. xml for raw XML, or pdf. For ZUGFeRD / Factur-X, pdf is a hybrid PDF/A-3 with embedded XML; for the XML-only standards (xrechnung, peppol-bis, fatturapa, facturae, eslog, ksef), pdf is a visualization PDF and requires a template or pdfTemplateId. |
invoice |
object | required | Invoice data (see Invoice object below) |
verify |
boolean | optional | When true (default), the engine validates output before returning it. Set false to skip post-generation validation (not recommended). The response then reports "valid": false alongside "verified": false, because nothing looked at the document, so nothing can call it valid. See Reading valid and verified. |
template |
string | optional | Set to "standard" to render the built-in styled invoice layout for pdf output. Required to get a visualization PDF from an XML-only standard; for ZUGFeRD / Factur-X the hybrid’s visible page gets this layout whether you set it or not, unless a pdfTemplateId replaces it. See Styling the PDF. |
pdfTemplateId |
string | optional | Render the PDF from one of your stored custom templates, designed in the dashboard. The value is the template’s short ref (a k3d-9mp-style code shown next to it in the dashboard), not a raw UUID. Takes precedence over template. Requires an authenticated request (the template is org-scoped). Honoured for any pdf output. |
Profile compatibility
profile is not a free enum: each standard accepts its own set, and a pair outside this table is rejected with 422 PROFILE_STANDARD_MISMATCH whose details.allowedProfiles repeats the accepted column for the standard you sent. Omit profile to get the default.
| Standard | Accepted profile values |
Default |
|---|---|---|
xrechnung |
xrechnung |
xrechnung |
zugferd |
minimum, basicwl, basic, en16931, extended |
en16931 |
facturx |
minimum, basicwl, basic, en16931, extended, extended-ctc-fr |
en16931 |
peppol-bis |
peppol, romania-ro-cius, netherlands-nlcius |
peppol |
fatturapa |
ordinaria |
ordinaria |
facturae |
ordinaria |
ordinaria |
eslog |
eracun |
eracun |
ksef |
fa3 |
fa3 |
extended-ctc-fr is the AFNOR XP Z12-012 France CTC overlay and exists on facturx only, because ZUGFeRD has no branded counterpart to map it onto. It is returned as XML only: with output: "pdf" the request is rejected with the same 422 PROFILE_STANDARD_MISMATCH, and details.allowedProfiles then lists the facturx profiles that can be returned as a hybrid PDF (minimum, basicwl, basic, en16931, extended). The Peppol CIUS profiles are country overlays on the same UBL document: romania-ro-cius for Romania RO_CIUS, netherlands-nlcius for NLCIUS. See Slovenia e-SLOG for eracun and Poland KSeF FA(3) for fa3.
Standard and output combinations
PDF output comes in two kinds. ZUGFeRD / Factur-X produce a hybrid PDF/A-3 with the legal XML embedded inside it. The XML-only standards have no hybrid form, so a PDF request returns a visualization PDF: a human-readable rendering of the same validated invoice, with no embedded XML (the legal artifact stays the XML; request it with output: "xml"). A visualization PDF requires a template or pdfTemplateId. The response’s x-pdf-kind header tells you which you received.
| Standard | XML output | PDF output | XML syntax |
|---|---|---|---|
xrechnung |
CII D16B | Visualization PDF (needs template) |
CII (D16B). No request field picks UBL; convert writes it |
zugferd |
CII D22B | Hybrid PDF/A-3 with embedded CII XML | CII (D22B, ZUGFeRD 2.x) |
facturx |
CII D22B | Hybrid PDF/A-3 with embedded CII XML | CII (D22B, Factur-X 1.09.2) |
peppol-bis |
UBL 2.1 | Visualization PDF (needs template) |
UBL |
fatturapa |
FPR12 (Italy FatturaPA ordinaria XML) | Visualization PDF (needs template) |
Authority XSD graph, not EN 16931 UBL/CII |
facturae |
Facturae 3.2.2 (Spain ordinaria XML) | Visualization PDF (needs template) |
Authority XSD graph, not EN 16931 UBL/CII |
eslog |
e-SLOG 2.0 (Slovenia eracun XML) | Visualization PDF (needs template) |
Authority XSD graph, not EN 16931 UBL/CII |
ksef |
KSeF FA(3) (Poland VAT invoice XML) | Visualization PDF (needs template) |
Authority XSD graph, not EN 16931 UBL/CII |
Invoice object
Each field below opens with the EN 16931 business term it
carries, so you can search this page for a term number directly: BT-31, BG-23.
A BT is a single business term and a BG a group of them. Where a term differs
by party, both numbers are given, because the Party and Address objects are
shared between seller and buyer.
A few fields carry no term, and say so rather than being given a number that looks
official: the FatturaPA, Facturae, e-SLOG and KSeF namespaces are national extensions,
and franceCtc is a Beliq switch. A term that does not appear anywhere on this
page has no field yet, and
EN 16931 field coverage is the list of which ones
those are: all 164 business terms the standard defines, each with its field or
with nothing.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
number |
string | required | 1–200 chars | BT-1. Invoice / credit-note number |
issueDate |
string | required | YYYY-MM-DD |
BT-2. Issue date |
dueDate |
string | optional | YYYY-MM-DD |
BT-9. Payment due date |
vatPointDate |
string | optional | YYYY-MM-DD, not together with vatPointDateCode |
BT-7. VAT point date: the date the VAT becomes accountable, when you know it and it is not the issue date. cbc:TaxPointDate on UBL. On CII it is ram:TaxPointDate on the first ram:ApplicableTradeTax only, because CII-SR-461 allows one. Sending it together with vatPointDateCode is a 400 VALIDATION_ERROR on UBL and CII output (BR-CO-03). |
vatPointDateCode |
string | optional | "3", "35" or "432", not together with vatPointDate |
BT-8. VAT point date code, for when the date is not known yet: 3 the invoice date, 35 the delivery date, 432 the payment date. These are the UNTDID 2005 codes BR-CL-06 lists for UBL, which writes the code as sent to cac:InvoicePeriod/cbc:DescriptionCode. BR-CL-06 takes UNTDID 2475 on CII, so Beliq writes 5, 29 or 72 there, as ram:DueDateTypeCode on the first ram:ApplicableTradeTax. |
invoicingPeriod |
object | optional | startDate, endDate: YYYY-MM-DD, at least one of the two |
BG-14, with startDate as BT-73 and endDate as BT-74. The period the invoice bills, such as a month of service. cac:InvoicePeriod on UBL, ram:ApplicableHeaderTradeSettlement/ram:BillingSpecifiedPeriod on CII. An object with neither date is a 400 (BR-CO-19), and on UBL and CII output so is an end before the start (BR-29). |
currencyCode |
string | required | 3 chars (ISO 4217) | BT-5. Currency code, e.g. EUR |
taxCurrencyCode |
string | optional | 3 chars (ISO 4217), not equal to currencyCode |
BT-6. VAT accounting currency, when you account VAT in a currency other than the invoice’s. A Romanian invoice in any currency but RON needs RON here (BR-RO-030). Send it together with taxTotalInAccountingCurrency; either one alone, or a value equal to currencyCode, is a 400. Emitted on UBL and CII outputs except Factur-X MINIMUM, which has no slot for it; fatturapa, facturae and eslog ignore it. |
taxTotalInAccountingCurrency |
number | optional | Required with taxCurrencyCode |
BT-111. Total VAT amount in the taxCurrencyCode currency. Beliq does not convert: send the figure your accounting uses. Emitted as a second cac:TaxTotal on UBL and a second ram:TaxTotalAmount on CII. |
documentType |
string | optional | "invoice" (default) or "creditnote" |
BT-3. Discriminates between an Invoice and a CreditNote, and sets the default type code, 380 or 381; typeCode below sets another. Supported when standard accepts CreditNote payloads: peppol-bis, facturx, xrechnung, zugferd, and eslog (e-SLOG emits document type code 381 in S_BGM). fatturapa, facturae and ksef accept invoices only: use documentType: "invoice" or omit the field. See DOCUMENT_TYPE_STANDARD_MISMATCH, the format overview, and Peppol Credit notes. |
typeCode |
string | optional | 2 or 3 digits, a code documentType admits |
BT-3. The UNTDID 1001 document type code, when it is not the default: 384 for a corrected invoice, 389 for a self-billed invoice, 326 for a partial invoice. documentType still picks the document and this picks the code within it: ram:TypeCode on CII, cbc:InvoiceTypeCode or cbc:CreditNoteTypeCode on UBL. The code has to be one UBL admits for that document type (BR-CL-01 splits UNTDID 1001 between Invoice and CreditNote, with 81 in both). Beliq holds CII to the same split, so any other code is a 400 VALIDATION_ERROR on either syntax. The CIUS lists are narrower, and validation checks them: Peppol BIS Billing 3.0 takes a shorter list with no 389 (PEPPOL-EN16931-P0100, P0101) and keeps 326 and 384 to a German seller and buyer (P0112), and XRechnung warns outside 326, 380, 381, 384, 389, 875, 876 and 877 (BR-DE-17). Accepted on facturx, zugferd, xrechnung and peppol-bis. fatturapa, facturae and eslog write their own document type, so typeCode there is a 422 DOCUMENT_TYPE_STANDARD_MISMATCH rather than a document without it. |
precedingInvoiceReference |
object | optional, required on a peppol-bis credit note |
id: 1-200 chars (the earlier invoice’s number); issueDate (optional): YYYY-MM-DD |
BG-3, with id as BT-25 and issueDate as BT-26. The invoice issued earlier that this document refers to: the one a credit note corrects, or the one a corrected invoice (typeCode 384) replaces. Written on every document type, as cac:BillingReference / cac:InvoiceDocumentReference on UBL outputs (Peppol BIS Billing 3.0) and ram:InvoiceReferencedDocument on CII outputs (XRechnung, ZUGFeRD, Factur-X). The Factur-X and ZUGFeRD minimum profile has no slot for it and drops it. eslog, fatturapa, facturae and ksef write it nowhere, so they answer 400 VALIDATION_ERROR when it is sent. A peppol-bis credit note without it is a 400 VALIDATION_ERROR. That is Beliq’s rule: the Peppol BIS Schematron does not require the reference, and no other ruleset requires it on a credit note either, so elsewhere a credit note without one verifies. On a corrected invoice XRechnung (BR-DE-26) and Peppol (DE-R-026) warn without it, and the French CTC (BR-FR-CO-04) rejects the document. The block needs its id (BR-55). |
buyerReference |
string | optional | Max 200 chars | BT-10. Buyer’s reference (required for XRechnung B2G) |
orderReference |
string | optional | Max 200 chars | BT-13. Purchase order reference |
salesOrderReference |
string | optional | 1-200 chars | BT-14. Sales order reference, the seller’s own order number. cac:OrderReference/cbc:SalesOrderID on UBL, ram:SellerOrderReferencedDocument/ram:IssuerAssignedID on CII. On UBL it cannot stand alone: cac:OrderReference/cbc:ID, the purchase order reference, is mandatory in the schema. So without an orderReference Beliq writes NA there, the value the Peppol BIS syntax binding gives for this case. NA is a placeholder in the slot of BT-13 and your buyer’s software reads it as the purchase order reference, so send a real orderReference when you have one. It does not count as one: a peppol-bis invoice still needs buyerReference or orderReference (PEPPOL-EN16931-R003) and is a 400 with neither. CII has no such constraint and writes no placeholder. |
contractReference |
string | optional | 1-200 chars | BT-12. Contract reference. cac:ContractDocumentReference/cbc:ID on UBL, ram:ContractReferencedDocument/ram:IssuerAssignedID on CII. |
projectReference |
string | optional | 1-200 chars | BT-11. Project reference. cac:ProjectReference/cbc:ID on a UBL invoice. A UBL credit note has no such element, so there it is a cac:AdditionalDocumentReference with document type code 50, which UBL-SR-43 allows on a credit note only. On CII it is ram:SpecifiedProcuringProject/ram:ID, with the fixed text Project reference in the ram:Name the schema requires beside it; EN 16931 has no term for that name. |
receivingAdviceReference |
string | optional | 1-200 chars | BT-15. Receiving advice reference. cac:ReceiptDocumentReference/cbc:ID on UBL, ram:ReceivingAdviceReferencedDocument/ram:IssuerAssignedID in the CII delivery block. It needs no delivery object. |
despatchAdviceReference |
string | optional | 1-200 chars | BT-16. Despatch advice reference. cac:DespatchDocumentReference/cbc:ID on UBL, ram:DespatchAdviceReferencedDocument/ram:IssuerAssignedID in the CII delivery block. It needs no delivery object. |
tenderReference |
string | optional | 1-200 chars | BT-17. Tender or lot reference. cac:OriginatorDocumentReference/cbc:ID on UBL, a ram:AdditionalReferencedDocument with type code 50 on CII. |
invoicedObjectIdentifier |
object | optional | id: required, 1-200 chars; schemeId (optional): 1-10 chars |
BT-18, with schemeId as BT-18-1. Invoiced object identifier: what the invoice is for, such as a meter or a subscription number. A cac:AdditionalDocumentReference with document type code 130 and the scheme as @schemeID on UBL, a ram:AdditionalReferencedDocument with type code 130 and the scheme as ram:ReferenceTypeCode on CII. schemeId comes from the UNTDID 1153 code list (BR-CL-07), which validation checks. |
buyerAccountingReference |
string | optional | 1-200 chars | BT-19. Buyer accounting reference, such as the buyer’s cost centre. cbc:AccountingCost on UBL, ram:ReceivableSpecifiedTradeAccountingAccount/ram:ID on CII. |
supportingDocuments |
SupportingDocument[] | optional | Max 50 items | BG-24. Additional supporting documents, such as a timesheet or a usage report: a reference, and optionally a URL, an attached file or both. Written in the order sent. |
note |
string | optional | Max 5000 chars | BT-22. Free-text note |
seller |
Party | required | BG-4. Seller/supplier details. For standard: "peppol-bis", must include either peppol or a vatId + supported address.countryCode so Beliq can derive the Peppol electronic-address. standard: "xrechnung" takes any of the three: peppol, email, or vatId + country. Both reject a party that resolves to none of them, with 400 VALIDATION_ERROR whose message names the party and the fields. |
|
buyer |
Party | required | BG-7. Buyer/customer details. Same electronic-address requirement as seller. |
|
payee |
Payee | optional | BG-10. The party paid when it is not the seller, such as a factoring company. Omit it when the seller is paid. With a payee, UBL writes the SEPA creditor identifier (paymentMeans.creditorId) on the payee rather than on the seller. |
|
taxRepresentative |
TaxRepresentative | optional | BG-11. The party that accounts for VAT on the seller’s behalf, typically for a seller not established in the country of supply. | |
lines |
InvoiceLine[] | required | Min 1 item | BG-25. Invoice line items |
taxSummary |
TaxSummary[] | optional in the schema, required in practice | One entry per vatCategoryCode / vatRate pair used on the lines |
BG-23. VAT summary per category. The request schema accepts its absence, but EN 16931 does not: BR-CO-18 requires at least one VAT breakdown group, so with verify at its default of true an invoice without it is rejected 422 INVALID_INVOICE on every EN 16931–based standard. Omit it only together with verify: false, which returns an unverified document. |
delivery |
Delivery | optional | BG-13. Delivery information: who received the goods or services, where, and when. delivery.date is the actual delivery date, BT-72. |
|
paymentMeans |
PaymentMeans | optional | BG-16. Payment method details | |
paymentTerms |
string | optional | Max 500 chars | BT-20. Payment terms description |
allowances |
DocumentAllowanceCharge[] | optional | Max 50 | BG-20. Amounts taken off the whole invoice rather than off one line, such as a volume rebate. cac:AllowanceCharge with a cbc:ChargeIndicator of false on UBL, ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeAllowanceCharge on CII, and their sum is written to BT-107 (cbc:AllowanceTotalAmount, ram:AllowanceTotalAmount). Each entry needs a VAT category, so it also changes the VAT breakdown you send in taxSummary. |
charges |
DocumentAllowanceCharge[] | optional | Max 50 | BG-21. The same, added to the invoice rather than taken off it, such as packaging or freight. The indicator is true and the sum is written to BT-108 (cbc:ChargeTotalAmount, ram:ChargeTotalAmount). |
totalNetAmount |
number | required | BT-106. The sum of the line net amounts, and only that: do not fold allowances or charges into it. Beliq derives BT-109, the invoice total without VAT, as totalNetAmount minus the allowances plus the charges (BR-CO-13), and writes that to cbc:TaxExclusiveAmount and ram:TaxBasisTotalAmount. With neither list the two numbers are equal, which is what every document sent before this field existed carries. |
|
totalTaxAmount |
number | required | BT-110. Total VAT amount | |
totalGrossAmount |
number | required | BT-112. Total including VAT. Unchecked on an invoice with no allowances or charges; with either, it must equal the derived BT-109 plus totalTaxAmount to within two cents (BR-CO-15), or the request is a 400. It is not the amount due: Beliq derives BT-115 as totalGrossAmount minus paidAmount plus roundingAmount (BR-CO-16) and writes that to cbc:PayableAmount and ram:DuePayableAmount. With neither field sent the two are equal, which is what every document sent before those fields existed carries. |
|
paidAmount |
number | optional | BT-113. The sum already paid in advance, which comes off the amount due. cbc:PrepaidAmount on UBL, ram:TotalPrepaidAmount on CII. No rule restricts its sign, so neither does Beliq. |
|
roundingAmount |
number | optional | BT-114. The amount added to the amount due to round it, positive or negative, for example -0.02. cbc:PayableRoundingAmount on UBL, ram:RoundingAmount on CII. |
|
franceCtc |
boolean | optional | French CTC mode, on Factur-X and ZUGFeRD output. Beliq then writes BT-23: your businessProcessId, or B1 when you leave it out. With verify: true (the default), the check that follows runs the FNFE-MPE BR-FR-CTC Flux 2 overlay, and the EXTENDED-CTC-FR overlay too on the extended and extended-ctc-fr profiles, because the document carries that code, as the validation pipeline describes. No document Beliq generates passes them today, so that request is refused with 422 INVALID_INVOICE and the failing rules listed; What Beliq covers today says which. With verify: false, no overlay runs. Sent as true with any other standard (xrechnung, peppol-bis, fatturapa, facturae, eslog or ksef), the request is refused with a 400, because Beliq writes no French CTC document there; false is the same as leaving the field out. To check a document you already have, send franceCtc=true to POST /v1/validate. |
|
businessProcessId |
string | optional | S8, B8, or M8 |
BT-23. An AFNOR XP Z12-012 cadre de facturation code; the three accepted here are the multi-vendor codes. Written on Factur-X and ZUGFeRD output when franceCtc is true or the profile is extended-ctc-fr. Left out, those documents carry B1. Any other request that sends it, every other standard included, is refused with a 400. |
italy |
object | optional | Italy FatturaPA routing and document defaults when standard is "fatturapa". See Italy (FatturaPA) fields. |
|
spain |
object | optional | Spain Facturae routing and document defaults when standard is "facturae". See Spain (Facturae) fields. |
|
slovenia |
object | optional | Slovenia e-SLOG namespace when standard is "eslog". Intentionally empty today; reserved for future Slovenia-specific fields. |
|
poland |
object | optional | Poland KSeF FA(3) document defaults when standard is "ksef". See Poland (KSeF) fields. |
paidAmount and roundingAmount change the amount due, so a standard that cannot
carry them refuses them rather than stating the wrong sum. The FatturaPA, Facturae,
e-SLOG and KSeF FA(3) builders state totalGrossAmount as the amount due and have no slot for
either, so with those standards a value other than 0 is a 400 VALIDATION_ERROR.
On Factur-X and ZUGFeRD, basicwl and basic carry paidAmount but declare no
rounding amount, so a roundingAmount other than 0 is a 400 there that names
en16931 and extended, which carry it. minimum carries neither and drops both,
but still states the amount due they produce.
payee and taxRepresentative reach UBL and CII output only; the FatturaPA,
Facturae, e-SLOG and KSeF FA(3) builders do not read them. On Factur-X and ZUGFeRD they reach
basicwl and up, and minimum, which declares neither party, drops both.
vatPointDate, vatPointDateCode, invoicingPeriod, the line’s invoicingPeriod,
the eight references from salesOrderReference to buyerAccountingReference
and supportingDocuments reach UBL and CII output only. The FatturaPA, Facturae, e-SLOG and KSeF FA(3)
builders do not read them, so those documents are the same with or without them,
and the checks below do not run there. peppol-bis and xrechnung write all of
them. On Factur-X and ZUGFeRD a field needs a profile whose schema declares its
element, and is dropped below that:
| Term | Fields | minimum |
basicwl |
basic |
en16931 and up |
|---|---|---|---|---|---|
| BG-14, BT-8, BT-12, BT-16, BT-19 | invoicingPeriod, vatPointDateCode, contractReference, despatchAdviceReference, buyerAccountingReference |
dropped | written | written | written |
| BG-26 | invoicingPeriod on a line |
dropped | no lines | written | written |
| BT-7, BT-11, BT-14, BT-15, BT-17, BT-18 | vatPointDate, projectReference, salesOrderReference, receivingAdviceReference, tenderReference, invoicedObjectIdentifier |
dropped | dropped | dropped | written |
| BG-24 | supportingDocuments |
dropped | dropped | dropped | written |
On facturx, zugferd, xrechnung and peppol-bis, Beliq checks the two VAT
point fields and the invoice’s period on every profile, including one that drops
them. vatPointDate together with vatPointDateCode (BR-CO-03) and a period
that ends before it starts (BR-29) are a 400 VALIDATION_ERROR. A line’s period
is checked where lines are written, so not on minimum and basicwl.
Italy (FatturaPA) fields
Use the optional invoice.italy object with standard: "fatturapa" and profile: "ordinaria" (or omit profile; it defaults to ordinaria). Fields are forwarded to the engine and should follow the official formato FatturaPA documentation.
| Field | Type | Description |
|---|---|---|
codiceDestinatario |
string | SDI routing code (typically 7 characters; use 0000000 for PEC-based routing per your process). |
regimeFiscale |
string | Seller fiscal regime code (e.g. RF01, RF19). |
progressivoInvio |
string | Transmission progressive id (e.g. 00001). |
idTrasmittente |
object | Optional { "country": "IT", "id": "..." } VAT override; defaults from seller vatId when omitted. |
tipoDocumento |
string | Document type code (e.g. TD01). |
condizioniPagamento |
string | Payment terms code (TP01 / TP02). |
modalitaPagamento |
string | Payment means code (e.g. MP01, MP05). |
esigibilitaIVA |
string | VAT chargeability (e.g. I). |
causale |
string[] | Optional Causale lines on the Italian document. |
For Italian addresses, use seller.address.region / buyer.address.region (or province) for the Provincia code when present in your data (2–3 characters).
Spain (Facturae) fields
Use the optional invoice.spain object with standard: "facturae" and profile: "ordinaria" (or omit profile; it defaults to ordinaria). All fields are optional. The five codes in the first rows each take one value, the invoice Beliq builds, and an omitted code writes that same value; any other value answers 400 VALIDATION_ERROR. Fields are forwarded to the engine and should follow the official Facturae format documentation.
| Field | Type | Description |
|---|---|---|
modality |
string | I, a single invoice. Beliq builds no batch (L). |
invoiceIssuerType |
string | EM, issued by the seller. Beliq builds no invoice issued by the recipient (RE) or a third party (TE). |
invoiceDocumentType |
string | FC, a complete invoice. Beliq builds no simplified (FA) or self-billed (AF) invoice. |
invoiceClass |
string | OO, an original invoice. Beliq builds no other class of the Facturae XSD. |
taxTypeCode |
string | 01, VAT (IVA). The engine writes the code on every line as an output tax, so it takes no other: some codes, such as 04 (IRPF), are taxes withheld. |
languageName |
string | ISO 639-1 language code, e.g. es (default), en, ca, eu, gl. |
batchIdentifier |
string | Batch identifier; defaults to BELIQ-{invoice.number}. |
seller / buyer |
object | Optional per-party overrides: { "personTypeCode": "J" | "F", "residenceTypeCode": "R" | "U" | "E" }. Auto-derived from the party VAT and address country when omitted. |
Provide Spanish-resident party vatId as a NIF/CIF (9 characters, optional ES prefix). PersonTypeCode (J legal / F natural) and ResidenceTypeCode (R Spain / U EU·EEA / E third country) are auto-derived; resident parties emit an AddressInSpain block, non-residents an OverseasAddress.
Poland (KSeF) fields
Use the optional invoice.poland object with standard: "ksef" (profile fa3, the default). Every field is optional and has a default. Flags take "1" (yes) or "2" (no), the FA(3) TWybor1_2 values. The Poland KSeF FA(3) reference states what the builder covers and refuses.
| Field | Type | Description |
|---|---|---|
adnotacje |
object | Overrides for the Adnotacje markers P_16 (cash accounting), P_17 (self-billing), P_18 (reverse charge), P_18A (split payment) and P_23 (simplified triangular procedure). Each defaults to "2". P_18 and P_23 take "2" only: Beliq builds no reverse-charge lines and no second buyer, so a "1" answers 400 VALIDATION_ERROR. |
jst |
string | Podmiot2/JST: the buyer is a subordinate unit of a local-government unit. "2" only: a "1" needs a Podmiot3 with role 8, which Beliq does not build, and answers 400 VALIDATION_ERROR. |
gv |
string | Podmiot2/GV: the buyer is a VAT-group member. "2" only: a "1" needs a Podmiot3 with role 10, which Beliq does not build, and answers 400 VALIDATION_ERROR. |
placeOfIssue |
string | Place of issue, written as P_1M. Up to 256 characters. Not written when omitted. |
dataWytworzenia |
string | Creation timestamp, written as DataWytworzeniaFa. Defaults to the time Beliq generates the document, in UTC. |
The seller’s vatId must be a Polish NIP (10 digits, PL prefix optional). The buyer’s is a Polish NIP or absent.
Party object
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name |
string | required | 1–200 chars | BT-27 on the seller, BT-44 on the buyer. Legal name |
vatId |
string | optional | 2-letter country prefix + 2–18 alphanumeric chars | BT-31 on the seller, BT-48 on the buyer. VAT identification number, e.g. DE123456789 |
taxId |
string | optional | Max 30 chars | BT-32 on the seller. The registration a seller holds with a tax authority that is not a VAT number. ram:SpecifiedTaxRegistration/ram:ID[@schemeID="FC"] on CII, cac:PartyTaxScheme with cac:TaxScheme/cbc:ID of FC on UBL. EN 16931 has no buyer term for it. On the buyer, the CII and UBL builders write it in the same place, except on Factur-X and ZUGFeRD basicwl, basic, en16931 and extended: the FNFE-MPE rules of those profiles (FX-SCH-A-000427, FX-SCH-A-000497, FX-SCH-A-000570 and BR-FXEXT-03) allow the buyer a VAT registration only, so a buyer taxId there is a 400 naming the rule. FatturaPA reads the buyer’s value as the codice fiscale and not the seller’s; Facturae, e-SLOG and KSeF FA(3) do not read the field. |
registrationId |
string | optional | Max 50 chars | BT-30 on the seller, BT-47 on the buyer. The company’s entry in an official business register (a German HRB number, a Danish CVR, a Swedish organisationsnummer), not the VAT number, which is vatId. Emitted on every standard: ram:SpecifiedLegalOrganization/ram:ID on CII, cac:PartyLegalEntity/cbc:CompanyID on UBL. Send it whenever vatCategoryCode is O: BR-O-02 forbids every VAT identifier there, and BR-CO-26 still requires the seller to be identifiable. |
email |
string | optional | Max 254 chars, valid email | BT-43 on the seller, BT-58 on the buyer. Email address (required for XRechnung) |
phone |
string | optional | Max 30 chars | BT-42 on the seller, BT-57 on the buyer. Phone number |
address |
Address | required | BG-5 on the seller, BG-8 on the buyer. Postal address | |
contactName |
string | optional | Max 200 chars | BT-41 on the seller, BT-56 on the buyer. Contact person name |
peppol |
PeppolEndpoint | optional | BT-34 on the seller, BT-49 on the buyer. Party electronic-address. Honoured on every standard. Required for standard: "peppol-bis" and "xrechnung" if Beliq cannot derive one from email or vatId + country. |
Peppol endpoint object
For Peppol BIS Billing 3.0, every party needs an electronic-address that uniquely identifies it on the Peppol Network.
XRechnung needs one too (BT-34 and BT-49, enforced by rules KoSIT bundles into the XRechnung Schematron), and it accepts a plain email as well: Beliq emits that as scheme EM. A peppol block is the stronger choice when the invoice will travel over Peppol, because a participant identifier is the form the network can resolve.
The block is read on every standard, not only peppol-bis. Beliq resolves each party’s address in this order, and the standard you pick changes only what happens when none of the rungs resolve:
| Standard | 1. peppol |
2. email (EAS EM) |
3. vatId + country |
Nothing resolves |
|---|---|---|---|---|
peppol-bis |
yes | no, a mailbox is not resolvable on the network | yes | 400 |
xrechnung |
yes | yes | yes | 400 |
zugferd, facturx |
yes | yes | no | element omitted |
A schemeId Beliq does not recognise is rejected on every standard, so a typo cannot ship as an unroutable address. That check fires only on a peppol block you send.
| Field | Type | Required | Description |
|---|---|---|---|
schemeId |
string | required | BT-34-1 on the seller, BT-49-1 on the buyer. Peppol EAS code (e.g. 9930 for German VAT, 9957 for French VAT, 0184 for Danish DK:CVR). See the official EAS code list. |
id |
string | required | BT-34 on the seller, BT-49 on the buyer. The actual identifier under that scheme (often the VAT number, sometimes a national company-registry number). |
Address object
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
street |
string | optional | Max 500 chars | BT-35 on the seller, BT-50 on the buyer. Street and house number |
additionalStreet |
string | optional | Max 500 chars | BT-36 on the seller, BT-51 on the buyer. Additional address line |
city |
string | required | Max 200 chars | BT-37 on the seller, BT-52 on the buyer. City |
postalCode |
string | required | Max 20 chars | BT-38 on the seller, BT-53 on the buyer. Postal/ZIP code |
countryCode |
string | required | 2 chars (ISO 3166-1 alpha-2) | BT-40 on the seller, BT-55 on the buyer. Country code, e.g. DE |
countrySubentity |
string | optional | Max 10 chars | BT-39 on the seller, BT-54 on the buyer. Country subdivision: the state, province or Bundesland the address sits in. This is the field EN 16931 defines for a subdivision, so send it rather than state. Both reach the same element and countrySubentity wins where both are sent. |
state |
string | optional | Max 200 chars | State or province as free text. Emitted as the country subdivision (BT-39 / BT-54 / BT-79) when countrySubentity is absent: cbc:CountrySubentity on UBL, ram:CountrySubDivisionName on CII. Prefer countrySubentity, which is the field EN 16931 defines and the one Romania’s BR-RO-110 / BR-RO-111 check. Factur-X MINIMUM restricts the address to the country code and carries neither. |
region |
string | optional | 2–3 chars | Italian provincia / region code; used for FatturaPA Provincia. |
province |
string | optional | 2–3 chars | Alias for region when mapping Italian addresses. |
Invoice line object
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
description |
string | required | 1–1000 chars | BT-153. Item description |
quantity |
number | required | > 0 | BT-129. Quantity |
unitCode |
string | required | 1–10 chars | BT-130. UN/ECE Recommendation 20 unit code (e.g. HUR for hours, C62 for units) |
unitPrice |
number | required | ≥ 0 | BT-146. Price per unit. EN 16931 calls this the item net price, so it is the price after any discount. To show the discount, send grossPrice and priceDiscount as well. |
lineTotal |
number | required | BT-131. Line total: quantity × unitPrice, or quantity × unitPrice ÷ priceBaseQuantity when you send one, plus any charges and minus any allowances on the line (PEPPOL-EN16931-R120). Beliq does not compute it for you. On a line carrying either list it checks your figure against that formula to within two cents and answers 400 when it does not match; on a line carrying neither it is yours unchecked, as before. |
|
vatRate |
number | required | 0–100 | BT-152. VAT rate as percentage. Dropped from the output when vatCategoryCode is O: BR-O-05 forbids a rate on a line that is not subject to VAT. Send 0 there; the field stays required. |
vatCategoryCode |
string | required | 1–10 chars | BT-151. VAT category code (e.g. S for standard rate) |
itemId |
string | optional | Max 50 chars | BT-155. Seller’s item identifier: cac:Item/cac:SellersItemIdentification/cbc:ID on UBL, ram:SpecifiedTradeProduct/ram:SellerAssignedID on CII. On Factur-X and ZUGFeRD it needs the en16931 profile or higher: the BASIC profile schema stops at the item name, so the value is dropped below that. |
buyerItemId |
string | optional | Max 50 chars | BT-156. Buyer’s own article number for the line: cac:Item/cac:BuyersItemIdentification/cbc:ID on UBL, ram:SpecifiedTradeProduct/ram:BuyerAssignedID on CII. Same Factur-X profile floor as itemId. |
grossPrice |
number | optional | ≥ 0 | BT-148. Item gross price: the price per unit before the price discount. cac:Price/cac:AllowanceCharge/cbc:BaseAmount on UBL, ram:GrossPriceProductTradePrice/ram:ChargeAmount on CII. unitPrice must equal grossPrice minus priceDiscount to the cent (PEPPOL-EN16931-R046), or the request is a 400. Sent without a discount it must equal unitPrice, and UBL writes a discount of 0.00, because its price allowance has no optional amount. |
priceDiscount |
number | optional | ≥ 0, needs grossPrice |
BT-147. Item price discount: what is taken off grossPrice to reach unitPrice, per unit. cac:Price/cac:AllowanceCharge/cbc:Amount on UBL, ram:AppliedTradeAllowanceCharge/ram:ActualAmount inside the CII gross price. A discount without a grossPrice is a 400, because there is nothing to take it off. For a discount on the whole line rather than on the unit price, use allowances (BG-27) below. |
priceBaseQuantity |
number | optional | > 0 | BT-149. The number of units unitPrice and grossPrice are stated for, for example 100 for a price per hundred. cac:Price/cbc:BaseQuantity on UBL; on CII, ram:BasisQuantity on the net price, and on the gross price when you send one. Its unit, BT-150, is not a separate field: Beliq writes the line’s unitCode, because PEPPOL-EN16931-R130 requires the two to be equal. Omitted, the price is per one unit. |
standardItemId |
object | optional | id: required, 1-200 chars; schemeId: required, 1-10 chars |
BT-157, with schemeId as BT-157-1. An identifier for the item under a registered scheme, such as a GTIN with schemeId 0160. cac:Item/cac:StandardItemIdentification/cbc:ID on UBL, ram:SpecifiedTradeProduct/ram:GlobalID on CII. schemeId comes from the ISO 6523 ICD code list (BR-CL-21), which validation checks. |
classifications |
object[] | optional | Max 20. Each: code: required, 1-200 chars; listId: required, 1-10 chars; listVersionId (optional): 1-50 chars |
BT-158, with listId as BT-158-1 and listVersionId as BT-158-2. Item classifications, such as a customs tariff number with listId HS. cac:Item/cac:CommodityClassification/cbc:ItemClassificationCode on UBL, ram:DesignatedProductClassification/ram:ClassCode on CII. listId comes from the UNTDID 7143 code list (BR-CL-13), which validation checks. |
originCountryCode |
string | optional | 2 chars (ISO 3166-1 alpha-2) | BT-159. Country the item comes from. cac:Item/cac:OriginCountry/cbc:IdentificationCode on UBL, ram:OriginTradeCountry/ram:ID on CII. |
attributes |
object[] | optional | Max 50. Each: name: required, 1-200 chars; value: required, 1-1000 chars |
BG-32, with name as BT-160 and value as BT-161. Item attributes, such as a colour or a size. cac:Item/cac:AdditionalItemProperty on UBL, ram:ApplicableProductCharacteristic on CII. |
allowances |
LineAllowanceCharge[] | optional | Max 50 | BG-27. Amounts taken off this line as a whole, such as a loyalty discount. cac:AllowanceCharge on the UBL line with a cbc:ChargeIndicator of false, ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge on CII. Not the same thing as priceDiscount, which comes off the unit price: these change what lineTotal has to be, and Beliq checks it (see the lineTotal row). Sub-lines carry the field too. |
charges |
LineAllowanceCharge[] | optional | Max 50 | BG-28. The same, added to the line rather than taken off it. The indicator is true. |
invoicingPeriod |
object | optional | startDate, endDate: YYYY-MM-DD, at least one of the two |
BG-26, with startDate as BT-134 and endDate as BT-135. The period this line covers. cac:InvoicePeriod on the UBL line, ram:SpecifiedLineTradeSettlement/ram:BillingSpecifiedPeriod on CII. An object with neither date is a 400 (BR-CO-20), and on UBL and CII output so is an end before the start (BR-30). When the invoice has an invoicingPeriod too, a line period that starts before it or ends after it is a 400 there as well. PEPPOL-EN16931-R110 and R111 are the rules, which only Peppol BIS and XRechnung enforce; Beliq applies them on every UBL and CII output, so the same request does not pass on one standard and fail on another. Sub-lines carry the field too, and a sub-line’s period is not held to the invoice’s. Output reach and profile floors are in the table under the invoice object. |
The nine fields from grossPrice to charges reach UBL and CII output only; the
FatturaPA, Facturae, e-SLOG and KSeF FA(3) builders do not read them, except that all four refuse
allowances and charges (see the document allowance and charge
object). On Factur-X and ZUGFeRD,
grossPrice, priceDiscount, priceBaseQuantity, standardItemId, allowances and
charges reach every profile that has lines, from basic up (minimum and basicwl
carry no lines). classifications, originCountryCode and attributes need the
en16931 profile or higher: the basic schema stops at the item’s identifier and name,
so they are dropped below that.
Document allowance and charge object
One entry in the invoice’s allowances (BG-20) or charges (BG-21) list.
Both lists take the same object; which list an entry sits in is what says whether
it lowers or raises the invoice total, so there is no indicator field to set and
no way to send a charge as an allowance by mistake. Allowances are written before
charges in the output.
Three things Beliq refuses at the door, because JSON Schema cannot express them,
each returning 400 VALIDATION_ERROR with a message that names the rule:
baseAmountandpercentageare a pair. One without the other isPEPPOL-EN16931-R041orR042, both fatal on Peppol and XRechnung.- With both,
amountmust equalbaseAmount × percentage ÷ 100to within two cents (R040). Beliq checks the two-decimal figures the document will carry, not the ones you sent, because that is what the rule reads: apercentageof2.375is written as2.38, and on a base of1000.00those two readings are five cents apart. - An entry needs a
reasonor areasonCode(BR-33,BR-38, restated asBR-CO-21andBR-CO-23). An entry with neither is rejected by every ruleset, so Beliq does not build the document.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
amount |
number | required | ≥ 0 | BT-92 on an allowance, BT-99 on a charge. The amount without VAT. cbc:Amount on UBL, ram:ActualAmount on CII. A negative value is a 400: the two lists carry the sign, so a negative allowance is a charge in the wrong list, and the totals still add up, which is why nothing downstream would catch it. |
baseAmount |
number | optional | ≥ 0, pairs with percentage |
BT-93 / BT-100. The amount the percentage applies to. cbc:BaseAmount on UBL, ram:BasisAmount on CII. |
percentage |
number | optional | 0–100, pairs with baseAmount |
BT-94 / BT-101. cbc:MultiplierFactorNumeric on UBL, ram:CalculationPercent on CII. |
reason |
string | optional | 1–1000 chars, this or reasonCode |
BT-97 / BT-104. Why the amount is there, in words, for example Annual volume rebate. cbc:AllowanceChargeReason on UBL, ram:Reason on CII. |
reasonCode |
string | optional | 1–10 chars, this or reason |
BT-98 / BT-105. The same reason as a code: UNCL 5189 for an allowance (BR-CL-19), UNCL 7161 for a charge (BR-CL-20). Validation checks the code list; the request schema only checks that you sent something. |
vatCategoryCode |
string | required | 1–10 chars | BT-95 / BT-102. The VAT category the amount is taxed under, for example S. Required, not optional: BR-32 and BR-37 demand it, and the Factur-X basicwl profile schema declares the element mandatory, so an entry without one could not be built there at all. Its value has to appear in your taxSummary, because the allowance or charge moves that category’s taxable amount. |
vatRate |
number | optional | 0–100 | BT-96 / BT-103. The rate for that category. Written as 0 when you leave it out, so send it for any category that carries a rate. Dropped when vatCategoryCode is O, which is not subject to VAT. |
These reach UBL and CII output only. The FatturaPA, Facturae, e-SLOG and KSeF FA(3) builders
write allowances and charges at neither level, so with standard: "fatturapa", "facturae",
"eslog" or "ksef" an invoice or line that carries allowances or charges is a
400 VALIDATION_ERROR whose message names the lists, rather than a document without them. On Factur-X and ZUGFeRD
they reach basicwl and up. The minimum
profile declares no allowance element, so the detail is dropped there, but the total
it feeds is not: minimum still states the derived BT-109 with the allowances and
charges applied.
Line allowance and charge object
One entry in a line’s allowances (BG-27) or charges (BG-28) list. The
same object as the document level one minus the VAT category: EN 16931 gives these
two groups no VAT term, because the line’s own vatCategoryCode (BT-151) applies.
The same three refusals apply, under BR-42 and BR-44 for the reason, and a line
carrying either list also has its lineTotal checked against
PEPPOL-EN16931-R120.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
amount |
number | required | ≥ 0 | BT-136 on an allowance, BT-141 on a charge. The amount without VAT, off or on the line as a whole. |
baseAmount |
number | optional | ≥ 0, pairs with percentage |
BT-137 / BT-142. |
percentage |
number | optional | 0–100, pairs with baseAmount |
BT-138 / BT-143. |
reason |
string | optional | 1–1000 chars, this or reasonCode |
BT-139 / BT-144. For example Loyalty discount. |
reasonCode |
string | optional | 1–10 chars, this or reason |
BT-140 / BT-145. UNCL 5189 (BR-CL-19) or UNCL 7161 (BR-CL-20). |
Same output reach as the document level object, except that these need a profile
that has lines: basic and up on Factur-X and ZUGFeRD.
Supporting document object
One additional supporting document (BG-24): a reference, and optionally a
description, a URL the document can be fetched from, an attached file, or both a
URL and a file. A cac:AdditionalDocumentReference with no document type code on
UBL, a ram:AdditionalReferencedDocument with type code 916 on CII.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
id |
string | required | 1-200 chars | BT-122. Supporting document reference. cbc:ID on UBL, ram:IssuerAssignedID on CII. A reference of spaces, tabs or line breaks alone is a 400 VALIDATION_ERROR (BR-52). |
description |
string | optional | 1-1000 chars | BT-123. Supporting document description. cbc:DocumentDescription on UBL, ram:Name on CII. |
externalLocation |
string | optional | 1-2048 chars | BT-124. External document location: a URL the document can be fetched from. cac:Attachment/cac:ExternalReference/cbc:URI on UBL, ram:URIID on CII. XRechnung wants it to start with a URL scheme, such as https: (BR-TMP-2). |
attachment |
object | optional | content: required, base64; mimeCode: required, 1-100 chars; filename: required, 1-255 chars |
BT-125. Attached document: the file itself, with its mime code and its filename. cac:Attachment/cbc:EmbeddedDocumentBinaryObject on UBL, ram:AttachmentBinaryObject on CII, each with @mimeCode and @filename. |
attachment.content is the file as base64: the standard alphabet, padded with =.
Whitespace between characters is accepted and is left out of the document. Content
that does not decode, or decodes to no bytes, is a 400 VALIDATION_ERROR, and so is
a mimeCode or a filename of whitespace alone. Beliq makes these checks on every
UBL and CII output, including the Factur-X and ZUGFeRD profiles that drop the
group.
Size. An attachment counts toward the request body limit of 1 MiB
(request size limits), on XML and on
PDF output alike. Base64 takes four characters for every three bytes of the file,
so a file can be at most three quarters of that limit, less the invoice around it.
A larger body is a 413 and is not read.
Mime codes. BR-CL-24 allows application/pdf, image/png, image/jpeg,
text/csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet and
application/vnd.oasis.opendocument.spreadsheet. Beliq does not check mimeCode
against that list itself: validation does, so with verify on, any other code is a
422 INVALID_INVOICE. The one exception is application/xml on the Factur-X and
ZUGFeRD extended profile, whose own code list has it.
Filenames. XRechnung refuses two attachments with the same filename
(BR-DE-22), and so does Peppol BIS between a German seller and a German buyer
(DE-R-022). Both rules compare the names as written, so two names that differ
only in case pass.
More than one document on CII. A CII invoice with several supporting documents
is valid. The EN 16931 CII rules CII-SR-475 and CII-SR-476 still raise a
warning when more than one of them has a description, or more than one has an
attached file, because they count across the whole invoice
(eInvoicing-EN16931 issue 508).
POST /v1/generate returns them with the document: in validationResult.warnings
of the JSON envelope, as warnings on CII
and Factur-X and as information on XRechnung, and counted on the x-validation
header of a binary response.
Payee object
The party paid when it is not the seller (BG-10). Omit the whole object when
the seller is paid. A name or registrationId equal to the seller’s is a
400 VALIDATION_ERROR, because BR-17 requires the payee to be a different party
and UBL-SR-19 to UBL-SR-21 compare the names on UBL. Beliq refuses it on every
UBL and CII output, including the Factur-X profiles whose copy of BR-17 does not
catch it.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name |
string | required | 1-200 chars | BT-59. Payee name. cac:PayeeParty/cac:PartyName/cbc:Name on UBL, ram:PayeeTradeParty/ram:Name on CII. |
identifier |
object | optional | id: required, 1-200 chars; schemeId (optional): 1-10 chars, not SEPA |
BT-60, with schemeId as BT-60-1. An identifier for the payee, such as a GLN with schemeId 0088. UBL writes it to cac:PayeeParty/cac:PartyIdentification/cbc:ID with any scheme, and validation checks the scheme against the ISO 6523 ICD list (BR-CL-10). On CII a scheme from that list goes to ram:PayeeTradeParty/ram:GlobalID; any other scheme, or none, sends the identifier to the unqualified ram:ID without it. SEPA is a 400: the SEPA creditor identifier is BT-90, sent as paymentMeans.creditorId, and a document carries one (UBL-SR-29). |
registrationId |
string | optional | Max 50 chars | BT-61. The payee’s entry in an official business register, as registrationId is on a party. cac:PayeeParty/cac:PartyLegalEntity/cbc:CompanyID on UBL, ram:PayeeTradeParty/ram:SpecifiedLegalOrganization/ram:ID on CII. |
Tax representative object
The party that accounts for VAT on the seller’s behalf (BG-11). All three fields
are required, by BR-18, BR-19, BR-20 and BR-56. The Factur-X profiles allow
this party one tax registration, its VAT identifier, so there is no taxId, contact
or electronic address here.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name |
string | required | 1-200 chars | BT-62. Tax representative name. cac:TaxRepresentativeParty/cac:PartyName/cbc:Name on UBL, ram:SellerTaxRepresentativeTradeParty/ram:Name on CII. |
vatId |
string | required | 2-letter country prefix + 2-18 alphanumeric chars | BT-63. Tax representative VAT identification number, e.g. DE123456789. cac:PartyTaxScheme/cbc:CompanyID with tax scheme VAT on UBL, ram:SpecifiedTaxRegistration/ram:ID with schemeID="VA" on CII. |
address |
DeliveryAddress | required | countryCode required |
BG-12, with street as BT-64, additionalStreet as BT-65, city as BT-66, postalCode as BT-67, countrySubentity as BT-68 and countryCode as BT-69. The tax representative’s postal address, in the shape of a deliver-to address: only the country is required (BR-20), and UBL writes no empty city or postal code. |
Tax summary object
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
vatCategoryCode |
string | required | 1–10 chars | BT-118. VAT category code |
vatRate |
number | required | 0–100 | BT-119. VAT rate as percentage |
taxableAmount |
number | required | BT-116. Taxable amount for this category | |
taxAmount |
number | required | BT-117. Tax amount for this category | |
exemptionReasonText |
string | optional | Max 1000 chars | BT-120. Why this category carries no VAT, in words, for example Reverse charge. EN 16931 requires a reason on every category other than standard rate: BR-AE-10, BR-E-10, BR-G-10, BR-IC-10 and BR-O-10 each demand this field or exemptionReasonCode, so with verify at its default of true an AE, E, G, K or O breakdown carrying neither is rejected 422 INVALID_INVOICE. |
exemptionReasonCode |
string | optional | Max 100 chars | BT-121. The same reason as a code from the VATEX code list, for example VATEX-EU-AE. Either this or exemptionReasonText satisfies the rules above, and sending both is allowed. |
Delivery object
The deliver-to party, place and date. Only the EN 16931 standards carry it (peppol-bis,
xrechnung, facturx, zugferd); FatturaPA, Facturae, e-SLOG and KSeF FA(3) output leave it out. On Factur-X and ZUGFeRD the minimum profile declares no
delivery elements at all, so the whole object is dropped there.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name |
string | optional | Max 200 chars | BT-70. Deliver-to party name: cac:DeliveryParty/cac:PartyName/cbc:Name on UBL, ram:ShipToTradeParty/ram:Name on CII. |
locationId |
object | optional | id: required, max 200 chars; schemeId (optional): max 10 chars |
BT-71, with schemeId as BT-71-1. Identifier of the place the goods or services went to, such as a GLN. UBL writes it to cac:DeliveryLocation/cbc:ID with any scheme. On CII a scheme from the ISO 6523 ICD list (four digits starting with 0, e.g. 0088 for GLN) goes to ram:ShipToTradeParty/ram:GlobalID; any other scheme, or none, sends the identifier to the unqualified ram:ID without it, because BR-CL-26 rejects a non-ICD scheme on GlobalID. |
date |
string | optional | YYYY-MM-DD |
BT-72. Actual delivery date: cbc:ActualDeliveryDate on UBL, ram:ActualDeliverySupplyChainEvent on CII. BR-IC-11 requires it or an invoicing period on an intra-community supply (vatCategoryCode K). So send date or the invoice’s invoicingPeriod: with verify at its default of true a K invoice with neither is rejected 422 INVALID_INVOICE. |
address |
DeliveryAddress | optional | BG-15. Deliver-to address, with BT-75 to BT-80 below. BR-IC-12 requires at least its country on an intra-community supply. |
Delivery address object
Its own shape rather than the Address object: only countryCode is
required, because EN 16931 requires only the country in a deliver-to address, while the
seller and buyer addresses must carry a city and postal code. It has no state, region
or province; send a subdivision as countrySubentity. The tax representative’s
address takes the same shape under its own term numbers, BT-64 to BT-69: see the
tax representative object.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
street |
string | optional | Max 500 chars | BT-75. Deliver-to street and house number |
additionalStreet |
string | optional | Max 500 chars | BT-76. Additional deliver-to address line |
city |
string | optional | Max 200 chars | BT-77. Deliver-to city |
postalCode |
string | optional | Max 20 chars | BT-78. Deliver-to postal/ZIP code |
countrySubentity |
string | optional | Max 10 chars | BT-79. Deliver-to country subdivision: the state, province or Bundesland |
countryCode |
string | required | 2 chars (ISO 3166-1 alpha-2) | BT-80. Deliver-to country code, e.g. FR |
Payment means object
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
typeCode |
string | required | 1–10 chars | BT-81. UNTDID 4461 payment means code (e.g. 30 for credit transfer, 58 for SEPA) |
iban |
string | optional | Max 34 chars | BT-84. IBAN |
bic |
string | optional | Max 11 chars | BT-86. BIC/SWIFT code |
bankName |
string | optional | Max 200 chars | Bank name. Accepted but never emitted: EN 16931 declares no bank-name business term, and the nearest UBL slot is discouraged by UBL-CR-429, so emitting it would add a warning to every document. |
paymentReference |
string | optional | Max 200 chars | BT-83. Payment reference / remittance information |
information |
string | optional | Max 200 chars | BT-82. Payment means text, e.g. SEPA credit transfer. UBL has no element for it and writes it as the name attribute on cbc:PaymentMeansCode; CII writes ram:Information. On Factur-X and ZUGFeRD it needs the en16931 profile or higher: the basic and basicwl schemas declare no Information, so the value is dropped below that. |
mandateReference |
string | optional | Max 200 chars | BT-89. SEPA direct debit mandate reference, part of BG-19: cac:PaymentMandate/cbc:ID on UBL, ram:SpecifiedTradePaymentTerms/ram:DirectDebitMandateID on CII. |
creditorId |
string | optional | Max 200 chars | BT-90. SEPA creditor identifier of the party collecting the direct debit, part of BG-19. Written on a party, not inside the payment means. On UBL it is cac:PartyIdentification/cbc:ID with schemeID="SEPA" on the payee when you send one and on the seller otherwise; BR-DE-30 and DE-R-030 accept either. On CII it is ram:CreditorReferenceID in the header settlement. |
debitedAccountId |
string | optional | Max 34 chars, an IBAN | BT-91. The buyer’s account the direct debit is taken from, part of BG-19: cac:PaymentMandate/cac:PayerFinancialAccount/cbc:ID on UBL, ram:PayerPartyDebtorFinancialAccount/ram:IBANID on CII. Send an IBAN. The request schema checks only the length, but CII has an IBAN slot and nothing else for this term. |
information, mandateReference, creditorId and debitedAccountId reach UBL and CII
output only; the FatturaPA, Facturae, e-SLOG and KSeF FA(3) builders do not read them.
Response
Because the body is usually raw bytes, generate reports the validation verdict and the ruleset seal (x-validation, x-ruleset-sha256, x-ruleset-artifacts) in headers. See the Response headers reference.
XML output (output: "xml")
When output is "xml", the response body is XML. Response headers may include x-schematron-version, present only where CEN’s EN 16931 pack judged the generated document: it is absent for the Factur-X MINIMUM, BASIC WL, BASIC and EXTENDED profiles, which their own Factur-X pack judges in its place. FatturaPA responses are validated against the authority XSD graph only (see validation artifacts). The X-Version-Block response header (compact JSON) carries the full set of artifact versions in play: the same fields as the POST /v1/validate body, minus the ruleset-selection fields (rulesetChannel, rulesetFellBack), since generate always uses the current bundled artifacts and does not support Beliq-Ruleset pinning.
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" ...>
...
</rsm:CrossIndustryInvoice>PDF output (output: "pdf")
When output is "pdf", the response body is a PDF. The x-pdf-kind response header tells you which kind you received:
HTTP/1.1 200 OK
Content-Type: application/pdf
x-pdf-kind: hybrid
x-schematron-version: 1.3.16x-pdf-kind: hybrid(ZUGFeRD / Factur-X): a PDF/A-3 file with the legal invoice XML embedded inside it for system processing. This is the compliance artifact. Before it is returned, veraPDF checks the file.x-pdf-kind: visualization(XML-only standards): a human-readable rendering of the invoice with no embedded XML. It is a convenience view, not a compliance artifact; fetch the legal document separately withoutput: "xml". Returned only when you supply atemplateorpdfTemplateId.
The PDF/A check on a hybrid PDF
After the XML is embedded, the engine runs veraPDF 1.30.3 on the finished file and returns the file only when veraPDF reports no violation of its PDF/A-3b profile. The check runs on every ZUGFeRD and Factur-X PDF this endpoint builds, also with verify: false, which skips the validation of the XML only.
- A violation ends the request with
422 PDFA_VIOLATION. The answer lists the rules veraPDF reported, no PDF comes back, and the quota unit is refunded. - A check that could not finish, because veraPDF did not answer in time or failed, ends the request with
503 ENGINE_UNAVAILABLE. No PDF is returned unchecked. - What a pass says: this version of veraPDF found no violation of its PDF/A-3b profile in the file. It does not say that every recipient’s validator accepts the file.
- Test mode: a test-mode PDF goes through the same check and is watermarked after it. The watermarked file does not pass veraPDF’s PDF/A-3b profile.
Styling the PDF
A hybrid PDF always carries a rendered invoice page. Without template and without pdfTemplateId that page is Beliq’s built-in layout. Choose the layout with one of:
template: "standard": Beliq’s built-in invoice layout, and the default for a hybrid PDF. This is also what the free generator uses. For XML-only standards it is required to produce a visualization PDF.pdfTemplateId: "k3d-9mp": one of your own PDF templates, designed visually in the dashboard (logo, colours, fonts, layout). The value is the template’s short ref, shown next to it in the dashboard. Org-scoped, so the request must be authenticated; takes precedence overtemplate. See the PDF template errors for the reference failures.
In every case the invoice data (parties, lines, totals) is bound by Beliq from the invoice you sent, and the template only controls presentation. The page is drawn from the same invoice data as the XML but is not compared with it: the page renderer and the XML builder each round amounts on their own, and the text of a read-only template field prints as you typed it.
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"standard": "facturx",
"output": "pdf",
"template": "standard",
"invoice": {
"number": "FA-2026-0123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Exemple SARL",
"vatId": "FR12345678901",
"address": { "street": "12 Rue de la Paix", "city": "Paris", "postalCode": "75002", "countryCode": "FR" }
},
"buyer": {
"name": "Client SAS",
"vatId": "FR98765432109",
"address": { "street": "8 Avenue des Champs-Élysées", "city": "Paris", "postalCode": "75008", "countryCode": "FR" }
},
"lines": [
{
"description": "Prestation de conseil, Avril 2026",
"quantity": 5,
"unitCode": "DAY",
"unitPrice": 800.00,
"lineTotal": 4000.00,
"vatRate": 20,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 20, "taxableAmount": 4000.00, "taxAmount": 800.00 }
],
"totalNetAmount": 4000.00,
"totalTaxAmount": 800.00,
"totalGrossAmount": 4800.00
}
}' \
--output invoice.pdfimport { writeFile } from 'node:fs/promises';
import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'facturx',
output: 'pdf',
template: 'standard',
invoice: {
number: 'FA-2026-0123',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
seller: {
name: 'Exemple SARL',
vatId: 'FR12345678901',
address: { street: '12 Rue de la Paix', city: 'Paris', postalCode: '75002', countryCode: 'FR' },
},
buyer: {
name: 'Client SAS',
vatId: 'FR98765432109',
address: {
street: '8 Avenue des Champs-Élysées',
city: 'Paris',
postalCode: '75008',
countryCode: 'FR',
},
},
lines: [
{
description: 'Prestation de conseil, Avril 2026',
quantity: 5,
unitCode: 'DAY',
unitPrice: 800.00,
lineTotal: 4000.00,
vatRate: 20,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 20, taxableAmount: 4000.00, taxAmount: 800.00 }],
totalNetAmount: 4000.00,
totalTaxAmount: 800.00,
totalGrossAmount: 4800.00,
},
});
await writeFile('invoice.pdf', generated.bytes);import os
from pathlib import Path
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="facturx",
output="pdf",
template="standard",
invoice={
"number": "FA-2026-0123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"seller": {
"name": "Exemple SARL",
"vatId": "FR12345678901",
"address": {
"street": "12 Rue de la Paix",
"city": "Paris",
"postalCode": "75002",
"countryCode": "FR",
},
},
"buyer": {
"name": "Client SAS",
"vatId": "FR98765432109",
"address": {
"street": "8 Avenue des Champs-Élysées",
"city": "Paris",
"postalCode": "75008",
"countryCode": "FR",
},
},
"lines": [
{
"description": "Prestation de conseil, Avril 2026",
"quantity": 5,
"unitCode": "DAY",
"unitPrice": 800.00,
"lineTotal": 4000.00,
"vatRate": 20,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 20, "taxableAmount": 4000.00, "taxAmount": 800.00}],
"totalNetAmount": 4000.00,
"totalTaxAmount": 800.00,
"totalGrossAmount": 4800.00,
},
)
Path("invoice.pdf").write_bytes(generated.content)JSON envelope (Accept: application/json)
Ask for the envelope and you get the document and its verdict in one response instead of bytes plus headers. Send Accept: application/json, and Beliq answers with a JSON body carrying the document base64-encoded in data.output alongside the full validationResult, including rulesetSha256 and rulesetArtifacts, the values the hash verification procedure recomputes.
validationResult is the verdict validation reached on the generated document, the same result POST /v1/validate returns for those bytes. A document can be valid and still carry warnings. verificationTier, verificationBadge and verificationBadgeLabel say how deep the check went for the rules that judged it. All three are left out, rather than guessed, in two cases: when a rule set that judged the document has no tier on record, and with verify: false, where no rule set ran. Verification tiers names documents the catalog holds no tier for.
Which representation you get is decided by the Accept header alone: the envelope is returned when application/json ranks above the document’s own media type (application/xml or application/pdf). Send no Accept header, or one that prefers the document type, and the body is the raw document with the same verdict in the response headers.
The data.format field names the document’s syntax: "cii" for XRechnung, ZUGFeRD and Factur-X, "ubl" for Peppol BIS Billing 3.0, and for the national formats "fatturapa", "facturae", "eslog" or "poland_ksef_fa3".
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"standard": "xrechnung",
"profile": "xrechnung",
"output": "xml",
"invoice": {
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"buyerReference": "04011000-12345-03",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"email": "billing@acme.example",
"contactName": "Anna Beispiel",
"phone": "+49 30 1234567",
"address": { "street": "Musterstraße 1", "city": "Berlin", "postalCode": "10115", "countryCode": "DE" }
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"address": { "street": "Beispielweg 42", "city": "Bonn", "postalCode": "53113", "countryCode": "DE" }
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00 }
],
"paymentMeans": {
"typeCode": "58",
"iban": "DE89370400440532013000"
},
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00
}
}'import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
// `seal: true` sends Accept: application/json and unpacks the envelope:
// the document bytes, their sha256, and the full validation verdict.
const generated = await beliq.generate({
standard: 'xrechnung',
profile: 'xrechnung',
output: 'xml',
invoice: {
number: 'INV-2026-001',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
buyerReference: '04011000-12345-03',
seller: {
name: 'Acme GmbH',
vatId: 'DE123456789',
email: 'billing@acme.example',
contactName: 'Anna Beispiel',
phone: '+49 30 1234567',
address: { street: 'Musterstraße 1', city: 'Berlin', postalCode: '10115', countryCode: 'DE' },
},
buyer: {
name: 'Bundesministerium für Beispiele',
vatId: 'DE987654321',
address: { street: 'Beispielweg 42', city: 'Bonn', postalCode: '53113', countryCode: 'DE' },
},
lines: [
{
description: 'IT consulting, April 2026',
quantity: 20,
unitCode: 'HUR',
unitPrice: 120.00,
lineTotal: 2400.00,
vatRate: 19,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 19, taxableAmount: 2400.00, taxAmount: 456.00 }],
paymentMeans: { typeCode: '58', iban: 'DE89370400440532013000' },
totalNetAmount: 2400.00,
totalTaxAmount: 456.00,
totalGrossAmount: 2856.00,
},
seal: true,
});
console.log(generated.sha256, generated.validationResult?.valid);
console.log(generated.meta.rulesetSha256, generated.meta.rulesetArtifacts);import os
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
# `seal=True` sends Accept: application/json and unpacks the envelope:
# the document bytes, their sha256, and the full validation verdict.
generated = beliq.generate(
standard="xrechnung",
profile="xrechnung",
output="xml",
invoice={
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"buyerReference": "04011000-12345-03",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"email": "billing@acme.example",
"contactName": "Anna Beispiel",
"phone": "+49 30 1234567",
"address": {
"street": "Musterstraße 1",
"city": "Berlin",
"postalCode": "10115",
"countryCode": "DE",
},
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"address": {
"street": "Beispielweg 42",
"city": "Bonn",
"postalCode": "53113",
"countryCode": "DE",
},
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00}],
"paymentMeans": {"typeCode": "58", "iban": "DE89370400440532013000"},
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00,
},
seal=True,
)
print(generated.sha256, generated.validation_result.valid)
print(generated.meta.ruleset_sha256, generated.meta.ruleset_artifacts){
"success": true,
"data": {
"invoiceId": "",
"format": "cii",
"standard": "xrechnung",
"profile": "xrechnung",
"output": "PD94bWwgdmVyc2lvbj0nMS4wJy4uLg==",
"validationResult": {
"valid": true,
"verified": true,
"format": "cii",
"schematronVersion": "1.3.16",
"ciusVersion": "XRechnung-2.6.0",
"rulesetSha256": "40e47719482fbd95264fc4c06cd644b37f466c254e1f207dadfae1727a82e85c",
"rulesetArtifacts": [
{ "key": "en16931_cii_schematron", "version": "1.3.16", "fileSha256": "0b234dea..." },
{ "key": "xrechnung_schematron", "version": "XRechnung-2.6.0", "fileSha256": "30e64d8b..." }
],
"errors": [],
"warnings": []
}
}
}Reading valid and verified
valid means verified as valid. Read it together with verified:
verified |
valid |
Meaning |
|---|---|---|
true |
true |
A ruleset ran and the document passed. |
true |
false |
A ruleset ran and the document failed. errors says why. |
false |
false |
No ruleset ran, because you sent verify: false. errors and warnings are empty because nothing looked, and there is no rulesetSha256 because no artifact executed. |
verified: false never means the document is bad. It means Beliq has no opinion, because you asked it not to form one.
If you gate a deployment on this response, gate on valid. It is false for both “we checked and it failed” and “we did not check”, so an unverified document stops your pipeline instead of shipping. If you want to treat those two cases differently, branch on verified first.
Error responses
| HTTP Status | Error Code | When |
|---|---|---|
| 400 | VALIDATION_ERROR |
Request body fails JSON schema validation (missing fields, wrong types, constraint violations), with details.fields; or the engine refuses a value the schema allows, such as a rule this page names, with no details and the reason in message |
| 422 | INVALID_INVOICE |
Invoice data is structurally valid but fails validation (EN 16931 / CIUS Schematron for UBL/CII, or authority XSD for fatturapa) |
| 422 | VALIDATION_ERROR |
The engine refused the request before validating anything, such as invoice lines whose subLines nest deeper than 64 levels. No details; the message names the reason where Beliq knows it. |
| 422 | PROFILE_STANDARD_MISMATCH |
The chosen profile is not allowed for the chosen standard (for example profile: "extended" with standard: "peppol-bis"). The error details includes standard, profile, and allowedProfiles. |
| 422 | DOCUMENT_TYPE_STANDARD_MISMATCH |
documentType: "creditnote" with a standard that does not accept CreditNote payloads (for example fatturapa), or a typeCode with a standard that writes its own document type (fatturapa, facturae, eslog, ksef). details: standard plus either documentType and creditNoteCapableStandards, or typeCode and typeCodeCapableStandards. |
| 400 | PDF_TEMPLATE_AUTH_REQUIRED |
pdfTemplateId was sent on an unauthenticated request (stored templates are org-scoped). Use your API key, or template: "standard". |
| 404 | PDF_TEMPLATE_NOT_FOUND |
The referenced pdfTemplateId does not exist in your organization. |
| 422 | PDF_TEMPLATE_INVALID |
The stored template definition could not be parsed, or fails the checks the dashboard designer applies on save. The message names the field at fault; fix it in the designer and save. |
| 422 | PDFA_VIOLATION |
A hybrid PDF was built and veraPDF reported a violation of its PDF/A-3b profile in it. The PDF is not returned and the quota unit is refunded. details.failedRules lists the rules: see PDFA_VIOLATION details |
| 413 | VALIDATION_ERROR |
Request body is larger than this endpoint’s 1 MiB size limit. The cap is enforced before the body is read, so nothing was validated and no quota unit is spent. A body within the limit that the engine refuses as too large to process is also a 413, and its message says so: that body was read, and a live key’s quota unit is refunded |
| 500 | INTERNAL_ERROR |
The PDF could not be produced: its page could not be rendered, or the engine could not build the hybrid PDF on that page. Nothing is returned, the quota unit is refunded, and error.incidentId names the incident |
| 503 | ENGINE_UNAVAILABLE |
The validation engine is temporarily unavailable |
| 503 | DATABASE_UNAVAILABLE |
Beliq’s database could not serve the request. Retry after Retry-After. Quota refunds says whether a spent unit comes back |
422 INVALID_INVOICE example
When business rule validation fails, the error includes the full validation result in details:
{
"success": false,
"error": {
"code": "INVALID_INVOICE",
"message": "Invoice validation failed with 2 errors",
"details": {
"validationResult": {
"valid": false,
"format": "cii",
"schematronVersion": "1.3.16",
"errors": [
{
"ruleId": "BR-DE-15",
"severity": "error",
"location": "/rsm:CrossIndustryInvoice/...",
"message": "An XRechnung invoice must contain the buyer reference (BT-10)."
}
],
"warnings": []
}
}
}
}Full example
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"standard": "xrechnung",
"profile": "xrechnung",
"output": "xml",
"invoice": {
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"buyerReference": "04011000-12345-03",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"email": "billing@acme.example",
"contactName": "Anna Beispiel",
"phone": "+49 30 1234567",
"address": {
"street": "Musterstraße 1",
"city": "Berlin",
"postalCode": "10115",
"countryCode": "DE"
}
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"email": "rechnung@beispiel.example",
"address": {
"street": "Beispielweg 42",
"city": "Bonn",
"postalCode": "53113",
"countryCode": "DE"
}
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00 }
],
"paymentMeans": {
"typeCode": "58",
"iban": "DE89370400440532013000",
"bic": "COBADEFFXXX"
},
"paymentTerms": "Net 30 days",
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00
}
}'import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'xrechnung',
profile: 'xrechnung',
output: 'xml',
invoice: {
number: 'INV-2026-001',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
buyerReference: '04011000-12345-03',
seller: {
name: 'Acme GmbH',
vatId: 'DE123456789',
email: 'billing@acme.example',
contactName: 'Anna Beispiel',
phone: '+49 30 1234567',
address: { street: 'Musterstraße 1', city: 'Berlin', postalCode: '10115', countryCode: 'DE' },
},
buyer: {
name: 'Bundesministerium für Beispiele',
vatId: 'DE987654321',
email: 'rechnung@beispiel.example',
address: { street: 'Beispielweg 42', city: 'Bonn', postalCode: '53113', countryCode: 'DE' },
},
lines: [
{
description: 'IT consulting, April 2026',
quantity: 20,
unitCode: 'HUR',
unitPrice: 120.00,
lineTotal: 2400.00,
vatRate: 19,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 19, taxableAmount: 2400.00, taxAmount: 456.00 }],
paymentMeans: { typeCode: '58', iban: 'DE89370400440532013000', bic: 'COBADEFFXXX' },
paymentTerms: 'Net 30 days',
totalNetAmount: 2400.00,
totalTaxAmount: 456.00,
totalGrossAmount: 2856.00,
},
});
// `xml` is the same document curl writes to stdout.
console.log(generated.xml);import os
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="xrechnung",
profile="xrechnung",
output="xml",
invoice={
"number": "INV-2026-001",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"buyerReference": "04011000-12345-03",
"seller": {
"name": "Acme GmbH",
"vatId": "DE123456789",
"email": "billing@acme.example",
"contactName": "Anna Beispiel",
"phone": "+49 30 1234567",
"address": {
"street": "Musterstraße 1",
"city": "Berlin",
"postalCode": "10115",
"countryCode": "DE",
},
},
"buyer": {
"name": "Bundesministerium für Beispiele",
"vatId": "DE987654321",
"email": "rechnung@beispiel.example",
"address": {
"street": "Beispielweg 42",
"city": "Bonn",
"postalCode": "53113",
"countryCode": "DE",
},
},
"lines": [
{
"description": "IT consulting, April 2026",
"quantity": 20,
"unitCode": "HUR",
"unitPrice": 120.00,
"lineTotal": 2400.00,
"vatRate": 19,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 19, "taxableAmount": 2400.00, "taxAmount": 456.00}],
"paymentMeans": {"typeCode": "58", "iban": "DE89370400440532013000", "bic": "COBADEFFXXX"},
"paymentTerms": "Net 30 days",
"totalNetAmount": 2400.00,
"totalTaxAmount": 456.00,
"totalGrossAmount": 2856.00,
},
)
# `xml` is the same document curl writes to stdout.
print(generated.xml)Italy FatturaPA ordinaria (FPR12) example
Beliq can emit FatturaPA ordinaria XML (standard: "fatturapa", default profile ordinaria). FatturaPA is Schema-checked: validation runs against the Agenzia delle Entrate’s official XSD schema graph, and no machine-readable business rules are published for the format, so XSD structural validation is the highest check any client-side tool can run for it. The FatturaPA format reference covers what backs that verdict, and how verification works defines the tiers. Beliq does not submit to Italy’s SDI interchange: you remain responsible for signing, transmission, and channel operation with your provider.
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"standard": "fatturapa",
"profile": "ordinaria",
"output": "xml",
"invoice": {
"number": "123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"italy": { "codiceDestinatario": "ABC1234", "regimeFiscale": "RF19" },
"seller": {
"name": "Alpha SRL",
"vatId": "IT01234567890",
"address": {
"street": "Via Roma 1",
"city": "Sassari",
"postalCode": "07100",
"countryCode": "IT",
"region": "SS"
}
},
"buyer": {
"name": "Beta SpA",
"taxId": "09876543210",
"address": {
"street": "Via Torino 2",
"city": "Roma",
"postalCode": "00145",
"countryCode": "IT",
"region": "RM"
}
},
"lines": [
{
"description": "Supply",
"quantity": 5,
"unitCode": "C62",
"unitPrice": 1,
"lineTotal": 5,
"vatRate": 22,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{
"vatCategoryCode": "S",
"vatRate": 22,
"taxableAmount": 5,
"taxAmount": 1.1
}
],
"paymentMeans": { "typeCode": "58", "iban": "IT60X0542811101000000123456" },
"totalNetAmount": 5,
"totalTaxAmount": 1.1,
"totalGrossAmount": 6.1
}
}'import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'fatturapa',
profile: 'ordinaria',
output: 'xml',
invoice: {
number: '123',
issueDate: '2026-04-13',
dueDate: '2026-05-13',
currencyCode: 'EUR',
italy: { codiceDestinatario: 'ABC1234', regimeFiscale: 'RF19' },
seller: {
name: 'Alpha SRL',
vatId: 'IT01234567890',
address: {
street: 'Via Roma 1',
city: 'Sassari',
postalCode: '07100',
countryCode: 'IT',
region: 'SS',
},
},
buyer: {
name: 'Beta SpA',
taxId: '09876543210',
address: {
street: 'Via Torino 2',
city: 'Roma',
postalCode: '00145',
countryCode: 'IT',
region: 'RM',
},
},
lines: [
{
description: 'Supply',
quantity: 5,
unitCode: 'C62',
unitPrice: 1,
lineTotal: 5,
vatRate: 22,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 22, taxableAmount: 5, taxAmount: 1.1 }],
paymentMeans: { typeCode: '58', iban: 'IT60X0542811101000000123456' },
totalNetAmount: 5,
totalTaxAmount: 1.1,
totalGrossAmount: 6.1,
},
});
// `xml` is the same document curl writes to stdout.
console.log(generated.xml);import os
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="fatturapa",
profile="ordinaria",
output="xml",
invoice={
"number": "123",
"issueDate": "2026-04-13",
"dueDate": "2026-05-13",
"currencyCode": "EUR",
"italy": {"codiceDestinatario": "ABC1234", "regimeFiscale": "RF19"},
"seller": {
"name": "Alpha SRL",
"vatId": "IT01234567890",
"address": {
"street": "Via Roma 1",
"city": "Sassari",
"postalCode": "07100",
"countryCode": "IT",
"region": "SS",
},
},
"buyer": {
"name": "Beta SpA",
"taxId": "09876543210",
"address": {
"street": "Via Torino 2",
"city": "Roma",
"postalCode": "00145",
"countryCode": "IT",
"region": "RM",
},
},
"lines": [
{
"description": "Supply",
"quantity": 5,
"unitCode": "C62",
"unitPrice": 1,
"lineTotal": 5,
"vatRate": 22,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 22, "taxableAmount": 5, "taxAmount": 1.1}],
"paymentMeans": {"typeCode": "58", "iban": "IT60X0542811101000000123456"},
"totalNetAmount": 5,
"totalTaxAmount": 1.1,
"totalGrossAmount": 6.1,
},
)
# `xml` is the same document curl writes to stdout.
print(generated.xml)Peppol BIS Billing 3.0 example
For cross-border EU invoicing over the Peppol Network, set standard: "peppol-bis". Both parties need a Peppol electronic-address (or a vatId + country Beliq can map to the standard EAS scheme), and the invoice must carry either a buyerReference or orderReference.
curl -X POST https://api.beliq.eu/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"standard": "peppol-bis",
"output": "xml",
"invoice": {
"number": "INV-2026-042",
"issueDate": "2026-04-13",
"currencyCode": "EUR",
"buyerReference": "PO-2026-042",
"seller": {
"name": "Acme SARL",
"vatId": "FR12345678901",
"peppol": { "schemeId": "9957", "id": "FR12345678901" },
"address": {
"street": "12 Rue de Exemple",
"city": "Paris",
"postalCode": "75001",
"countryCode": "FR"
}
},
"buyer": {
"name": "Voorbeeld B.V.",
"vatId": "NL123456789B01",
"peppol": { "schemeId": "9944", "id": "NL123456789B01" },
"address": {
"street": "Voorbeeldlaan 1",
"city": "Amsterdam",
"postalCode": "1011AB",
"countryCode": "NL"
}
},
"lines": [
{
"description": "Cloud subscription, April 2026",
"quantity": 1,
"unitCode": "MON",
"unitPrice": 500.00,
"lineTotal": 500.00,
"vatRate": 21,
"vatCategoryCode": "S"
}
],
"taxSummary": [
{ "vatCategoryCode": "S", "vatRate": 21, "taxableAmount": 500.00, "taxAmount": 105.00 }
],
"totalNetAmount": 500.00,
"totalTaxAmount": 105.00,
"totalGrossAmount": 605.00
}
}'import { Beliq } from '@beliq/sdk';
const beliq = new Beliq({ apiKey: process.env.BELIQ_API_KEY! });
const generated = await beliq.generate({
standard: 'peppol-bis',
output: 'xml',
invoice: {
number: 'INV-2026-042',
issueDate: '2026-04-13',
currencyCode: 'EUR',
buyerReference: 'PO-2026-042',
seller: {
name: 'Acme SARL',
vatId: 'FR12345678901',
peppol: { schemeId: '9957', id: 'FR12345678901' },
address: { street: '12 Rue de Exemple', city: 'Paris', postalCode: '75001', countryCode: 'FR' },
},
buyer: {
name: 'Voorbeeld B.V.',
vatId: 'NL123456789B01',
peppol: { schemeId: '9944', id: 'NL123456789B01' },
address: { street: 'Voorbeeldlaan 1', city: 'Amsterdam', postalCode: '1011AB', countryCode: 'NL' },
},
lines: [
{
description: 'Cloud subscription, April 2026',
quantity: 1,
unitCode: 'MON',
unitPrice: 500.00,
lineTotal: 500.00,
vatRate: 21,
vatCategoryCode: 'S',
},
],
taxSummary: [{ vatCategoryCode: 'S', vatRate: 21, taxableAmount: 500.00, taxAmount: 105.00 }],
totalNetAmount: 500.00,
totalTaxAmount: 105.00,
totalGrossAmount: 605.00,
},
});
// `xml` is the same document curl writes to stdout.
console.log(generated.xml);import os
from beliq import Beliq
beliq = Beliq(api_key=os.environ["BELIQ_API_KEY"])
generated = beliq.generate(
standard="peppol-bis",
output="xml",
invoice={
"number": "INV-2026-042",
"issueDate": "2026-04-13",
"currencyCode": "EUR",
"buyerReference": "PO-2026-042",
"seller": {
"name": "Acme SARL",
"vatId": "FR12345678901",
"peppol": {"schemeId": "9957", "id": "FR12345678901"},
"address": {
"street": "12 Rue de Exemple",
"city": "Paris",
"postalCode": "75001",
"countryCode": "FR",
},
},
"buyer": {
"name": "Voorbeeld B.V.",
"vatId": "NL123456789B01",
"peppol": {"schemeId": "9944", "id": "NL123456789B01"},
"address": {
"street": "Voorbeeldlaan 1",
"city": "Amsterdam",
"postalCode": "1011AB",
"countryCode": "NL",
},
},
"lines": [
{
"description": "Cloud subscription, April 2026",
"quantity": 1,
"unitCode": "MON",
"unitPrice": 500.00,
"lineTotal": 500.00,
"vatRate": 21,
"vatCategoryCode": "S",
},
],
"taxSummary": [{"vatCategoryCode": "S", "vatRate": 21, "taxableAmount": 500.00, "taxAmount": 105.00}],
"totalNetAmount": 500.00,
"totalTaxAmount": 105.00,
"totalGrossAmount": 605.00,
},
)
# `xml` is the same document curl writes to stdout.
print(generated.xml)See the Peppol BIS Billing 3.0 reference for what fields Beliq emits and what the validator checks.