API scope
The OpenFiskal API currently supports server-to-server communication only.
Do not embed API keys in POS devices, mobile apps, browsers, or other client-side surfaces.
API key creation
Create API keys at console.openfiskal.com. Each key is tenant-scoped and country-scoped.
Store the key in your secrets manager. Treat it like any other production secret.
Keys follow the pattern of_{environment}_{country}_{random} where:
environment is test (sandbox) or live (production)
country is the lowercase ISO 3166-1 alpha-3 country code (e.g. deu, aut)
random is the opaque secret portion
Examples:
of_test_deu_abcdefgh12345678 — sandbox key for Germany
of_live_deu_… — production key for Germany
of_test_aut_… — sandbox key for Austria
The embedded country scopes every request. A deu key cannot create merchants in Austria.
Use the standard authorization header
Although the credential is an API key, the API uses the standard HTTP bearer pattern:
-H "Authorization: Bearer of_live_deu_abc123..."
This keeps the API compatible with standard API tooling, gateways, proxies, and security middleware.
Merchant scoping
For every merchant-scoped request, also send:
-H "X-OpenFiskal-Merchant: merchant_01HXYZ"
This header must contain the OpenFiskal merchant ID, not the API key.
Together, a typical merchant-scoped request looks like this:
curl https://api.openfiskal.com/v1/operations \
-H "Authorization: Bearer of_live_deu_abc123..." \
-H "X-OpenFiskal-Merchant: merchant_01HXYZ"
Merchant-scoped resources include:
- Locations
- Registers
- Operations
You do not need X-OpenFiskal-Merchant when you create, update, delete, or read the merchant itself.
Response envelope
Single-resource endpoints return the resource object directly. List endpoints wrap the array in a data field:
{
"data": [
{ "id": "merchant_01HXYZ", "legal_name": "Mustermann GmbH", "..." : "..." },
{ "id": "merchant_01HABC", "legal_name": "Beispiel AG", "..." : "..." }
]
}
This applies to GET /merchants, GET /registers, and GET /locations. Single-resource responses (GET /merchants/{id}, POST /operations, etc.) return the object at the top level without a data wrapper.
Error responses always use the error envelope, regardless of the endpoint.
Idempotency
For mutating requests that create or finalize state, send an Idempotency-Key header so retries remain safe:
curl -X POST https://api.openfiskal.com/v1/operations \
-H "Authorization: Bearer of_live_deu_abc123..." \
-H "X-OpenFiskal-Merchant: merchant_01HXYZ" \
-H "Idempotency-Key: op-order-1001-start" \
-H "Content-Type: application/json" \
-d '{ "...": "..." }'
Use idempotency keys on every POST /operations, POST /operations/{id}/complete, and POST /operations/{id}/void request.
The platform retains keys for at least 24 hours. Reusing the same key with a different payload returns 409 idempotency_key_conflict.
Recommended handling
- Return
401 when authentication is missing or invalid.
- Return
403 when the API key is valid but not allowed to access the requested tenant, country, or merchant.
- Return
412 Precondition Failed when an operation update, completion, or cancellation uses a stale If-Match value.
- Return
429 Too Many Requests with Retry-After when the caller exceeds 500 requests/second per API key.
Next step
Continue with Getting started for the full onboarding and operation flow.