
# Bill Endpoints

This page covers the routes that send receipts to anybill and how a receipt is
linked to a consumer. The structure of the receipt payload itself is described
in the [Bill Data Model](https://developer.anybill.de/vendor_api/bill_data_model), and worked examples for
discounts, returns and custom sections in
[Bill Examples](https://developer.anybill.de/vendor_api/bill_examples).

## Endpoints
The receipt controller offers four routes:
- <b>POST</b> `/v3/bill/url`: Pre-register a receipt ID and get the receipt URL (QR code) in advance.
  - POST [Staging Swagger](https://vendor.stg.anybill.de/api/swagger/index.html#/Bill/post_v3_bill_url) | [Production Swagger](https://vendor.anybill.de/api/swagger/index.html#/Bill/post_v3_bill_url)
- <b>POST</b> `/v3/bill`: Send receipt to anybill.
  - POST [Staging Swagger](https://vendor.stg.anybill.de/api/swagger/index.html#/Bill/AddBillV3) | [Production Swagger](https://vendor.anybill.de/api/swagger/index.html#/Bill/AddBillV3)
- <b>DELETE</b> `/v3/bill/{billId}`: Cancel a receipt based on the billId.
  - DELETE [Staging Swagger](https://vendor.stg.anybill.de/api/swagger/index.html#/Bill/delete_v3_bill__billId_) | 
[Production Swagger](https://vendor.anybill.de/api/swagger/index.html#/Bill/delete_v3_bill__billId_)
- <b>POST</b> `/v3/bill/{billId}/printed`: Adds a printed timestamp to the receipt.
  - POST [Staging Swagger](https://vendor.stg.anybill.de/api/swagger/index.html#/Bill/post_v3_bill__billId__printed) | 
[Production Swagger](https://vendor.anybill.de/api/swagger/index.html#/Bill/post_v3_bill__billId__printed)

### Detailed Endpoint Description
Staging Environment: [SwaggerUI](https://vendor.stg.anybill.de/api/swagger/index.html#/Bill)<br>
Production Environment: [SwaggerUI](https://vendor.anybill.de/api/swagger/index.html#/Bill)

### Request
The store ID must be sent in the body of both `POST /v3/bill/url` and `POST /v3/bill`.
`POST /v3/bill/url` optionally accepts a `buyerInformation` object; `POST /v3/bill` takes
the receipt itself in `bill` (see [Bill Data Model](https://developer.anybill.de/vendor_api/bill_data_model)).

```
POST /v3/bill
```

``` json
{
  "storeId": "3QT1su7Wtl",
  "userIdentification": { "externalId": "optional, see below" },
  "bill": { ... } // see Bill Data Model / Swagger
}
```

### Response
> **Tip: Both routes return a json object with the receipt id and, unless the receipt was assigned to a known user, the url from which the QR code can be generated.**
> ``` json
> {
>    "type": "url",
>    "url": "url to receipt",
>    "billId": "Id of the receipt"
> }
> ```

### Status codes
The **Retry** column is the behaviour a POS system has to implement for each code; the common rules
(backoff, attempts, idempotency, token refresh on 401) are described in the
[Retry Policy Guidelines](https://developer.anybill.de/vendor_api/#retry-policy-guidelines). None of the bill endpoints returns 429.

**`POST /v3/bill`**

| Status | When | Body | Retry |
| --- | --- | --- | --- |
| 200 | Receipt stored. | JSON, see above | – |
| 400 | Payload invalid (schema or business rules). | problem details with `errors` and `traceId` | no – fix the payload |
| 401 | Token missing, expired or invalid. | empty or plain text | refresh the token, resend once |
| 403 | Missing scope or API user permission. | plain text | no |
| 404 | Unknown `storeId` (plain text); `bill.id` not pre-registered (`pregeneratedbill-notfound`); user not found. | plain text or problem details | no |
| 409 | A receipt with this `bill.id` already exists. | plain text `Bill with id … already exists` | no – already delivered |
| 503 | A downstream service failed. | empty | yes – exponential backoff, same `bill.id` |
| 504 | The receipt could not be stored in time (storage temporarily saturated); the receipt was **not** stored. | empty | yes – exponential backoff, same `bill.id` |
| 500 / 502 | Unexpected server error or gateway problem. | empty or plain text | yes – exponential backoff, same `bill.id` |

**`POST /v3/bill/url`**

| Status | When | Body | Retry |
| --- | --- | --- | --- |
| 200 | Receipt id registered. | JSON with `billId` and `url` | – |
| 400 | Payload invalid, or the registration failed for a business reason. | problem details with `traceId` | no – fix the payload; if the body reports no validation error, log it and contact anybill |
| 401 | Token missing, expired or invalid. | empty or plain text | refresh the token, resend once |
| 403 | Missing scope or API user permission. | plain text | no |
| 404 | Unknown `storeId`. | plain text | no |
| 500 / 502 / 503 / 504 | Temporary server or gateway problem. | empty or plain text | yes – exponential backoff; a second registration for the same sale is harmless as long as the POS keeps only the `billId` it finally sends |

**`DELETE /v3/bill/{billId}`** and **`POST /v3/bill/{billId}/printed`**

| Status | When | Body | Retry |
| --- | --- | --- | --- |
| 204 (`DELETE`) / 200 (`printed`) | Accepted. `DELETE` always answers 204 – an unknown `billId` is not reported. | empty / `billId` | – |
| 400 (`printed`) | The receipt could not be marked as printed (business rule). | problem details with `traceId` | no |
| 401 | Token missing, expired or invalid. | empty or plain text | refresh the token, resend once |
| 403 (`printed`) | Missing scope or API user permission. | plain text | no |
| 404 (`printed`) | Unknown `billId`. | plain text | no |
| 500 / 502 / 503 / 504 | Temporary server or gateway problem. | empty or plain text | yes – exponential backoff; both operations are idempotent |

### curl examples

All routes take the access token from [Authentication](https://developer.anybill.de/vendor_api/authentication)
as a Bearer token. The examples use the [Staging](https://developer.anybill.de/vendor_api/environments) base URL
`https://vendor.stg.anybill.de/api`; all routes live below the `/api` prefix.

Pre-register a receipt ID (for a QR code before payment, or to make the
later `POST /v3/bill` idempotent):

``` bash
curl -X POST 'https://vendor.stg.anybill.de/api/v3/bill/url' \
  -H 'Authorization: Bearer <access_token>' \
  -H 'Content-Type: application/json' \
  -d '{ "storeId": "3QT1su7Wtl" }'
```

Send a receipt whose payload is stored in `receipt.json`:

``` bash
curl -X POST 'https://vendor.stg.anybill.de/api/v3/bill' \
  -H 'Authorization: Bearer <access_token>' \
  -H 'Content-Type: application/json' \
  -d @receipt.json
```

Cancel a receipt (204 when the cancellation was accepted) and record a later paper print:

``` bash
curl -X DELETE 'https://vendor.stg.anybill.de/api/v3/bill/<billId>' \
  -H 'Authorization: Bearer <access_token>'

curl -X POST 'https://vendor.stg.anybill.de/api/v3/bill/<billId>/printed' \
  -H 'Authorization: Bearer <access_token>'
```

The POST `/v3/bill`-route can be used to add following types of receipts.
- <b>Anonymous Receipts</b>:
  - This is the case if the POS **not** provide a user identifier as a value in `userIdentification.externalId` - e.g. via QR code scan of a loyalty card of the consumer.<br>
    Example:
    ```json
    { "url": "https://getmy.anybill.de/{billId}" }
    ```
- <b>User Receipts</b>:
  - This is the case if the POS provides a value in `userIdentification.externalId`, e.g. the loyalty/crm identifier scanned at the POS. Here, anybill can use this information to e.g. assign the receipt automatically to the consumer's app account, use it for analytics, insights and actions in Purchase Intelligence or many other use cases.

If the user identification object or all its property are null, the receipt will be treated as anonymous.

## Response objects
> **Tip: The /v3/bill endpoint returns different response objects.**
>
> 1. When no `userIdentification.externalId` has been provided in the request:
> ``` json
> // UrlBillResponseDto
> {
>    "type": "url",
>    "url": "url to receipt",
>    "billId": "Id of the receipt"
> }
> ```
> ---
> 2. When a value in `userIdentification.externalId` has been provided in the request and the receipt was matched with an external user (e.g. receipt was assigned to a user account to make it visible in the merchant's app) - without requiring a QR code.:
> ``` json
> // ExternalIdResponseDto
> {
>    "type": "externalId",
>    "isAssigned": true,
>    "billId": "Id of the receipt"
> }
> ```
> ---
> 💡 `isAssigned` will always be true if `type` is `externalId`. If `userIdentification.externalId` has been defined, and no match could be made, the response is of type `url`.
>
> Two further `type` values exist for legacy assignment paths and have the same shape as
> `ExternalIdResponseDto` (`billId`, `isAssigned: true`): `userId` (receipt matched via the
> deprecated `userIdentification.userId`) and `bankCard` (receipt matched via a bank card
> registered by the consumer). New integrations only need to handle `url` and `externalId`,
> but should treat any response with `isAssigned: true` as "no QR code required".

## User identification
If a receipt with a link to a known consumer should be added, the property `userIdentification.externalId` must be set with the identifier value.

- The `externalId` of the consumer is an identifier from a marchant's system like CRM (customer number), Loyalty. The maximum length is 256 characters.

## Transparent user creation via externalId
Historically, anybill required merchants to first create an anybill user via the Partner Platform API, in order to link an `externalId`-Identifier to it later.

After popular demand, this requirement has been removed:<br>
If the provided ``userIdentification.externalId`` is not yet known to anybill, anybill internally creates an anonymous anybill user automatically and the receipt is assigned to it.<br>
No pre-registration or creation of an internal anybill user is required anymore.<br>
On subsequent receipts with the same `userIdentification.externalId` value, the existing user is reused.<br>
The same ``userIdentification.externalId`` can later be passed to the [Partner Platform API token endpoint](https://developer.anybill.de/partner_platform_api/api_v3.html#request-a-token-recommended) to obtain an SDK token for that user.

> **Warning**
> The "Transparent user creation via externalId" - flow has to be manually enabled per merchant on the anybill side. If it is relevant for your integration, please contact `dev@anybill.de` or your anybill contact person.

> **Warning: Deprecated useridentification fields**
> The previously available `userIdentification.userId` (anybill user id) and `userIdentification.loyaltyCardBarcode` fields are deprecated and will be removed in a future revision. Use `userIdentification.externalId` for all new integrations.

## Self-generated Receipt Id
The Vendor API optionally offers the possibility that the POS system generates a Receipt ID (UUID) independently, prior to sending the receipt data.

> **Warning**
> The "Self-generated Receipt Id" - feature has to be manually enabled per merchant on the anybill side. If it is relevant for your integration, please contact `dev@anybill.de` or your anybill contact person.

> **Warning: If a self-generated Receipt Id already exists**
> If the self-generated receipt UUID already exists in the anybill system, the request is
> rejected with **HTTP 409 Conflict**. The body is a plain string, not a problem-details object:
>
> ```
> Bill with id 5e952ea6-167d-4001-95d9-a759204c2943 already exists
> ```
>
> Treat a 409 as "this receipt has already been stored" and do not retry it.

> **Warning: If the feature is not enabled**
> If `bill.id` is set but the id was neither pre-registered via `POST /v3/bill/url` nor is
> the feature enabled for the merchant, the API answers with **HTTP 404** and the problem
> details `{ "type": "pregeneratedbill-notfound", "title": "PreGeneratedBill could not be found.", "status": 404 }`.

## Cancelling a receipt
A receipt is cancelled with `DELETE /v3/bill/{billId}`. The `billId` is part of the request path.

> **Tip**
> The response returns status code 204 as soon as the cancellation has been accepted. The
> cancellation itself is processed asynchronously, so an unknown `billId` is not reported
> back to the caller; make sure to send the id that was returned by `POST /v3/bill` or
> `POST /v3/bill/url`.

## Required Fields
These fields are validated against the OpenAPI schema; the business rules described
in the [Bill Data Model](https://developer.anybill.de/vendor_api/bill_data_model) apply on top of them. Fields
listed as required once the surrounding object is sent belong to an optional part
of the payload — omitting that part entirely is fine, including it makes the listed
fields mandatory.

For `bill.security.fiscalization` the OpenAPI schema only marks `type` as required.
The fields that are actually mandatory depend on the fiscalization type and are
validated server-side; see [Fiscalization](https://developer.anybill.de/vendor_api/fiscalization).

<!-- vendor-api:required:start -->

*Generated from the [production OpenAPI specification](https://vendor.anybill.de/api/swagger/v3/swagger.json) (API version 3.0) on 3 September 2026.*

### POST /v3/bill/url

Request body: `RegisterBillIdDto`

**Always required**

| Field | Type | Description |
| --- | --- | --- |
| `storeId` | string, non-empty | Id of the Store that issues the bill in the future |

### POST /v3/bill

Request body: `AddBillDto`

**Always required**

| Field | Type | Description |
| --- | --- | --- |
| `storeId` | string, 1–36 chars | The id of the store of the vendor in which the transaction was done. |
| `bill` | `BillDto` | The definition of a bill based on the version '1.0.0' of the DFKA. |
| `bill.head` | `HeadDto` | Head data of the bill. |
| `bill.head.date` | string (date-time) | Date of invoice. |
| `bill.data` | `DataDto` | Bill data. |
| `bill.data.currency` | string, exactly 3 chars | This field defines the currency to be used for all document data if no other currency is explicitly specified. Must be a valid ISO 4217 currency code… |
| `bill.data.fullAmountInclVat` | number (double) | The total gross amount of the receipt. A precision of 2 decimal places is used. |
| `bill.security` | `SecurityDto` | Data to secure the receipt via TSE. |

**Required once the surrounding optional object is sent**

| Object | Position in the request body | Required fields |
| --- | --- | --- |
| `BillDiscountDto` | `bill.data.extension:anybill.discounts[]` | `id`, `type` |
| `DefaultLineDto` | `bill.data.lines[]` | `text`, `item`, `extension:anybill` |
| `TextLineDto` | `bill.data.lines[]` | `text`, `extension:anybill` |
| `DiscountLineDto` | `bill.data.lines[]` | `text`, `extension:anybill` |
| `KeyValueLineDto` | `bill.data.lines[]` | `type` |
| `AnybillDefaultLineExtensionDto` | `bill.data.lines[].extension:anybill` | `sequenceNumber` |
| `AnybillTextLineExtensionDto` | `bill.data.lines[].extension:anybill` | `sequenceNumber` |
| `AnybillDiscountLineExtensionDto` | `bill.data.lines[].extension:anybill` | `sequenceNumber` |
| `AnybillCustomLineExtensionDto` | `bill.data.lines[].extension:anybill` | `sequenceNumber` |
| `ItemDto` | `bill.data.lines[].item` | `number`, `quantity`, `pricePerUnit` |
| `LineVatAmountDto` | `bill.data.lines[].vatAmounts[]` | `percentage`, `inclVat`, `exclVat`, `vat` |
| `PaymentTypeInformationDto` | `bill.data.paymentTypes[]` | `name`, `amount`, `extension:anybill` |
| `AnybillPaymentTypeInformationExtensionDto` | `bill.data.paymentTypes[].extension:anybill` | `type` |
| `DataVatAmountDto` | `bill.data.vatAmounts[]` | `percentage`, `inclVat`, `exclVat`, `vat` |
| `SellerDto` | `bill.head.seller` | `name` |
| `SellerAddressDto` | `bill.head.seller.address` | `street`, `postalCode`, `city` |
| `BasicAdditionalReceiptDto` | `bill.misc.additionalReceipts[]` | `type`, `contentType` |
| `VendorAdditionalReceiptDto` | `bill.misc.additionalReceipts[]` | `type`, `contentType` |
| `AfterSalesCouponDto` | `bill.misc.extension:anybill.afterSalesCoupons[]` | `title`, `codeType`, `code` |
| `FranceSpecificAttributesDto` | `bill.misc.extension:anybill.countrySpecificAttributes` | `type` |
| `LoyaltyCouponingInformationDto` | `bill.misc.extension:anybill.couponingInformation` | `type` |
| `CustomSectionDto` | `bill.misc.extension:anybill.customSections[]` | `position`, `section`, `data` |
| `TseDto` | `bill.security.fiscalization` | `type` |
| `SwedenFiscalizationDto` | `bill.security.fiscalization` | `type` |
| `RksvDto` | `bill.security.fiscalization` | `type` |
| `SecurityInformationDto` | `bill.security.fiscalization` | `type` |
| `BoiTvaDto` | `bill.security.fiscalization` | `type` |
| `TBaiDto` | `bill.security.fiscalization` | `type` |
| `PortugalFiscalizationDto` | `bill.security.fiscalization` | `type` |
| `AdditionalRksvDataDto` | `bill.security.fiscalization.additionalData` | `displayName`, `value` |
| `AdditionalBoiTvaDataTextDto` | `bill.security.fiscalization.additionalData[]` | `type` |
| `AdditionalBoiTvaDataKeyValueDto` | `bill.security.fiscalization.additionalData[]` | `type` |
| `SecurityInformationDataDto` | `bill.security.fiscalization.data[]` | `displayed`, `displayName`, `value` |
| `AdditionalTseDataDto` | `bill.security.fiscalization.extension:anybill.additionalTseData` | `displayName`, `value` |

### DELETE /v3/bill/{billId}

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| `billId` | path parameter | string (uuid) | The bills id to be deleted. |

### POST /v3/bill/{billId}/printed

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| `billId` | path parameter | string (uuid) | The bill id where the timestamp to add. |

<!-- vendor-api:required:end -->

