Skip to main content

Overview

A register is the logical checkout or terminal that produces operations inside a location. In the current public API, a register stores identity, routing, and fiscal-provisioning metadata that you must keep stable over time.
Today, fiscalization is supported only for locations in Germany (country_code: "DEU", KassenSichV). Calls to POST /registers/{id}/fiscalize for AT or IT locations return 422 validation_error. AT (RKSV) and IT (RT) support is in development — see the country-specific guides for the planned shape.

Register states

Two enums describe a register’s lifecycle: status (active | inactive) and fiscalization_status (not_fiscalized | pending | failed | fiscalized | decommissioned).
[not_fiscalized] ──► [pending] ──► [fiscalized] ──► [decommissioned]

                          └──► [failed]
  • not_fiscalized — the register exists but has not been fiscalized; it cannot accept operations
  • pending — fiscalization has been enqueued and is running in the background
  • failed — fiscalization terminated with an error; you can retry by calling fiscalize again
  • fiscalized — fiscal components are provisioned (TSS + client for KassenSichV) and the register can accept operations
  • decommissioned — the register has been retired; historical data is preserved but no new operations can be created
The fiscal regime is derived from the location’s country, not the merchant’s. A single merchant can operate registers across multiple regimes (once non-DEU regimes are enabled).

Commissioning a register

1. Prerequisite: merchant must have fiscal_identities

Before fiscalizing a register, the parent merchant must have a fiscal_identities[] entry for the location’s country. A merchant is created with at least legal_name, country_code, and address; fiscal identities can be supplied at creation or added later.
curl -X PATCH https://api.openfiskal.com/v1/merchants/merchant_01HXYZ \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fiscal_identities": [
      {
        "country_code": "DEU",
        "tax_number": "21/815/08150",
        "vat_id": "DE123456789"
      }
    ]
  }'
country_code is uppercase ISO 3166-1 alpha-3 (DEU, AUT, ITA). Without a matching fiscal identity for the location’s country, POST /registers/{id}/fiscalize returns 422 validation_error. Fiscal identity shape varies by country — see the schema reference.

2. Create the register

curl -X POST https://api.openfiskal.com/v1/registers \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-OpenFiskal-Merchant: merchant_01HXYZ" \
  -H "Content-Type: application/json" \
  -d '{
    "location_id": "loc_01HXYZ",
    "name": "Kasse 2",
    "external_id": "store-berlin-kasse-2"
  }'
A new register is created with fiscalization_status: "not_fiscalized".

3. Fiscalize the register

Call POST /registers/{id}/fiscalize. This is asynchronous — the endpoint returns 202 Accepted and provisioning runs in the background.
curl -X POST https://api.openfiskal.com/v1/registers/reg_01HXYZ/fiscalize \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-OpenFiskal-Merchant: merchant_01HXYZ"
Poll GET /registers/{id} until fiscalization_status is fiscalized before sending operations. The nested fiscalization.fiscalized_at timestamp is set at the same time. If fiscalization_status becomes failed, the response body includes an error message; you can call fiscalize again to retry. Errors:
  • 422 validation_error — the location is not in DEU, or the merchant is missing a German fiscal identity
  • 409 register_already_fiscalized — the register is already fiscalized, or a fiscalization is already in progress

Updating a register

Use PATCH /registers/{registerId} to rename the register or update its external mapping:
curl -X PATCH https://api.openfiskal.com/v1/registers/reg_01HXYZ \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-OpenFiskal-Merchant: merchant_01HXYZ" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Kasse 2 - Front Counter",
    "external_id": "store-berlin-kasse-2-updated"
  }'

Decommissioning

Use POST /registers/{id}/decommission to retire a fiscalized register. This tears down the regime-specific fiscal components and sets fiscalization_status to decommissioned. Historical operations and signatures are preserved.
curl -X POST https://api.openfiskal.com/v1/registers/reg_01HXYZ/decommission \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-OpenFiskal-Merchant: merchant_01HXYZ"
Errors:
  • 409 register_invalid_fiscal_state — the register is not fiscalized, or has already been decommissioned
  • 422 validation_error — the register is not a KassenSichV register, or its TSS/client metadata is incomplete

Deleting a register

DELETE /registers/{id} returns 204 No Content. Deletion is permitted only for registers that have never been fiscalized and have no operations attached.
curl -X DELETE https://api.openfiskal.com/v1/registers/reg_01HXYZ \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-OpenFiskal-Merchant: merchant_01HXYZ"
409 register_has_dependencies is returned if the register has operations or has been fiscalized. Use decommission for any register that has been fiscalized — deletion is intended for registers created in error.

Operational guidance

  • Keep external_id aligned with the register identifier in your own POS platform
  • Capture the operator identity at runtime on the operation, not on the register resource
  • Do not recycle a register for a different physical checkout if you need clean audit history
  • Prefer decommissioning over deletion when you want to preserve historical references

Listing and lookup

Use GET /registers to list registers in the current merchant. Use GET /registers/{registerId} when you need the current representation for a specific register.

Next steps