

# E-Invoice (ZUGFeRD / XRechnung)

Business customers often need a structured, machine-readable invoice instead of a
receipt. anybill can turn a receipt sent via [`POST /v3/bill`](https://developer.anybill.de/vendor_api/bill_endpoints)
into an e-invoice in the **ZUGFeRD** format (PDF with embedded XML) or the
**XRechnung** format (XML). The POS does not call an additional endpoint: it marks the
receipt as an e-invoice and can optionally pass the customer data it already knows. The
buyer adds missing recipient data on the receipt page and downloads the e-invoice there.

## How it works

1. anybill activates the e-invoice module for the merchant (see the note below).
2. The POS sends the receipt with `POST /v3/bill` and sets
   `bill.misc.extension:anybill.receiptType` to `EInvoice`. Optionally, it adds the
   customer data from its CRM in `bill.misc.extension:anybill.merchantCustomObject`
   (see [below](#sending-customer-data-from-the-pos-merchantcustomobject)).
3. The buyer opens the receipt URL, e.g. by scanning the QR code. The receipt page offers
   to complete the e-invoice data.
4. The buyer selects the format (ZUGFeRD or XRechnung) and enters the invoice recipient:
   name, email address, phone number and address, and optionally a VAT ID, a Leitweg-ID
   and a scheme ID.
5. anybill builds the e-invoice from the receipt data and the recipient data. The buyer
   downloads it from the receipt page as a ZUGFeRD PDF or as an XRechnung XML file.

The recipient data can be entered only once per receipt. A second attempt is rejected,
so the e-invoice that was issued cannot be changed afterwards.

> **Warning**
> The e-invoice module has to be enabled per merchant on the anybill side, both on
> Staging and on Production. If it is relevant for your integration, please contact
> `dev@anybill.de` or your anybill contact person.


## Marking a receipt as e-invoice

Set the receipt type in the anybill extension of the `misc` object:

```json
{
  "storeId": "3QT1su7Wtl",
  "bill": {
    "head": { "...": "..." },
    "data": { "...": "..." },
    "security": { "...": "..." },
    "misc": {
      "extension:anybill": {
        "receiptType": "EInvoice"
      }
    }
  }
}
```

- `receiptType` accepts `Receipt` (default), `DeliveryNote` and `EInvoice`. The string
  name is recommended; the integer value `2` is accepted as well.
- Set `EInvoice` on every receipt for which the buyer should be able to request an
  e-invoice. Receipts sent with `Receipt` show no e-invoice option on the receipt page.
- The merchant can also have all of its receipts marked as e-invoices by default. In that
  case anybill sets `EInvoice` on every incoming receipt of the merchant, regardless of
  the value the POS sends.

The e-invoice is requested on the page behind the receipt URL. It is therefore available
for anonymous receipts, for which `POST /v3/bill` returns a response of type `url`
(see [Response objects](https://developer.anybill.de/vendor_api/bill_endpoints#response-objects)). Receipts that are
assigned to a consumer directly via `userIdentification.externalId` have no receipt URL
and are not offered as e-invoices.

## Sending customer data from the POS (`merchantCustomObject`)

::: info Planned
`merchantCustomObject` is not processed by the Vendor API yet. Until it is available, the
API accepts receipts that contain the field and ignores it. Please contact
`dev@anybill.de` or your anybill contact person before you rely on it.
:::

Many POS systems already know the business customer at checkout, e.g. from a scanned
customer card or a CRM lookup. Data such as the company name, the invoice address, the
customer's VAT ID or an order reference is usually not part of the receipt schema.
`bill.misc.extension:anybill.merchantCustomObject` transports this data together with
the receipt, so that the buyer does not have to enter it on the receipt page.

The object is a small container with three fields:

| Field | Type | Description |
| --- | --- | --- |
| `type` | string | Identifier of the content structure, chosen by the POS system. Use a stable name that includes a version, e.g. `examplepos.customer.v1`, and change the version when the structure changes. |
| `contentType` | string | Format of `content`, e.g. `application/json` or `application/xml`. |
| `content` | string | The data itself as text. JSON content is sent as a serialised (escaped) string, not as a nested JSON object. |

**The structure of `content` is entirely up to the POS system.** anybill does not
prescribe field names, nesting, naming conventions or a format. Send the data the way
your POS or CRM already holds it; there is no need to convert it into an anybill model.
anybill sets up the mapping from your structure to the e-invoice fields together with
you, once per `type`. Content with a `type` for which no mapping exists is ignored for
the e-invoice.

Example: a POS system that holds the following customer record for the buyer

```json
{
  "customerNumber": "K-104711",
  "companyName": "Example Trading GmbH",
  "contactPerson": "Erika Example",
  "invoiceEmail": "invoices@example-trading.de",
  "invoiceAddress": {
    "street": "Sample Street 12",
    "postalCode": "10115",
    "city": "Berlin",
    "countryCode": "DE"
  },
  "vatId": "DE123456789",
  "purchaseOrderReference": "PO-2026-0815"
}
```

sends it as the `content` of the `merchantCustomObject`:

```json
{
  "storeId": "3QT1su7Wtl",
  "bill": {
    "head": { "...": "..." },
    "data": { "...": "..." },
    "security": { "...": "..." },
    "misc": {
      "extension:anybill": {
        "receiptType": "EInvoice",
        "merchantCustomObject": {
          "type": "examplepos.customer.v1",
          "contentType": "application/json",
          "content": "{\"customerNumber\":\"K-104711\",\"companyName\":\"Example Trading GmbH\",\"contactPerson\":\"Erika Example\",\"invoiceEmail\":\"invoices@example-trading.de\",\"invoiceAddress\":{\"street\":\"Sample Street 12\",\"postalCode\":\"10115\",\"city\":\"Berlin\",\"countryCode\":\"DE\"},\"vatId\":\"DE123456789\",\"purchaseOrderReference\":\"PO-2026-0815\"}"
        }
      }
    }
  }
}
```

Important rules:
- `merchantCustomObject` is optional and only relevant for receipts with `receiptType`
  `EInvoice`.
- It complements the receipt, it does not replace it: seller, line items, VAT and totals
  are always taken from the regular receipt fields described
  [below](#receipt-content-used-for-the-e-invoice).
- Keep `type` and the structure of `content` stable across all stores and POS versions
  that send the same data, so that one mapping covers all of them.
- `content` contains personal data. Send only what the e-invoice needs and leave out
  unrelated CRM data such as credit limits, loyalty balances or marketing attributes.
- If data is missing in `content`, the buyer can still complete it on the receipt page.

## Receipt content used for the e-invoice

The e-invoice is built from the receipt as stored by anybill. The following fields
determine its content, so they must be complete and consistent for e-invoice receipts:

| E-invoice element | Taken from |
| --- | --- |
| Invoice number | `bill.head.number`. If it is missing, the anybill receipt id is used, so send the POS receipt number. |
| Invoice date and delivery date | `bill.head.date` |
| Seller name, address and VAT ID | `bill.head.seller` (`name`, `vatId`, `address.street`, `address.postalCode`, `address.city`). If `seller` is omitted, the store data stored at anybill is used. |
| Line items | Every default line in `bill.data.lines`: `text`, `item.quantity` and the first entry of `vatAmounts` (`percentage`, `exclVat`, `inclVat`). Net and gross unit prices are derived from these amounts and the quantity. |
| Allowances | Every discount line in `bill.data.lines`: `text`, `fullAmountInclVat` and `vatAmounts[0].percentage`. |
| VAT breakdown and totals | Recalculated per VAT rate from the net amounts of the item lines minus the allowances. |
| Payment | The e-invoice is marked as paid: the prepaid amount equals the total, the amount due is 0. |

Important rules:
- Every default line carries exactly one `vatAmounts` entry with `percentage`, `exclVat`
  and `inclVat` for the whole line (after line discounts). Lines without `vatAmounts` lead
  to wrong amounts on the e-invoice.
- Receipt-level discounts that should appear as allowances are sent as discount lines
  (`extension:anybill.type` = `discount`) with a negative `fullAmountInclVat` and the
  VAT rate in `vatAmounts`.
- The recalculated totals have to match `bill.data.vatAmounts` and
  `bill.data.fullAmountInclVat` of the receipt. Check this with a few receipts that
  combine several VAT rates and discounts.
- Text lines and key/value lines are shown on the PDF receipt but are not part of the
  structured invoice data.
- E-invoices are currently generated in EUR for stores in Germany. All items are reported
  in the standard VAT category with their percentage; receipts with tax-exempt items
  (0 %) are not suitable for e-invoices yet.

## Testing on Staging

1. Ask anybill to enable the e-invoice module for your Staging merchant.
2. Send a receipt with `receiptType` `EInvoice` to `https://vendor.stg.anybill.de/api/v3/bill`
   without `userIdentification` (see [curl examples](https://developer.anybill.de/vendor_api/bill_endpoints#curl-examples)).
3. Open the `url` from the response, complete the e-invoice data and download both a
   ZUGFeRD PDF and an XRechnung XML.
4. Compare the invoice number, seller, line items, VAT breakdown and total with the
   receipt sent by the POS.
