Skip to main content

Overview

A register is a POS device in OpenFiskal — a terminal, kiosk, or logical endpoint that processes operations. A fiscal unit is the link between that register and a fiscal compliance capability (TSE in Germany, RKSV certificate in Austria, RT device in Italy). Creating a register is cheap — it’s just metadata. Provisioning a fiscal unit is what initializes the expensive fiscal device. This separation lets you:
  • Manage the fiscal device independently from the POS device
  • Replace a fiscal device without creating a new register
  • Track the full history of fiscal devices bound to a register

Register states

Registers have two states:
[active] ──► [archived]
  • active: The register exists and can accept operations (when it has an active fiscal unit).
  • archived: Permanently retired. Cannot be undone.
A register starts in active state with no fiscal unit (active_fiscal_unit: null). It becomes fiscally operational once a fiscal unit is provisioned.

Fiscal unit lifecycle

A fiscal unit tracks the provisioning, operation, and retirement of a single fiscal device instance:
provisioning ──► active ──► decommissioned

                 error ──► active (recover)

                 decommissioned
  • provisioning: The fiscal device is being initialized (TSE setup, RT activation, RKSV key registration). Automatic — transitions to active on success.
  • active: The fiscal device is initialized and ready to sign operations. This is the only state that accepts sales, refunds, closings, and other fiscal events.
  • error: The fiscal device encountered a failure (e.g. TSE hardware fault, RT communication error). Recoverable via POST /fiscal-units/:id/recover.
  • decommissioned: The fiscal unit has been permanently retired. Fiscal deregistration has been triggered with the relevant authority. Cannot be undone.

Commissioning

1

Create the register

A register belongs to a location. Provide a label and the jurisdiction it operates in.
curl -X POST https://api.openfiskal.com/v1/locations/loc_01HXYZ/registers \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Kasse 2",
    "jurisdiction": "DE"
  }'
{
  "id": "reg_01HXYZ",
  "object": "register",
  "label": "Kasse 2",
  "jurisdiction": "DE",
  "state": "active",
  "active_fiscal_unit": null,
  "location_id": "loc_01HXYZ",
  "created_at": "2026-02-26T10:00:00Z"
}
The register is active but has no fiscal unit — it cannot process operations yet.
2

Create a fiscal unit

Provisioning a fiscal unit initializes the jurisdiction-specific fiscal device:
  • Germany: Initializes the TSE, establishes the signature chain
  • Italy: Activates the RT device with the Agenzia delle Entrate
  • Austria: Establishes the RKSV signature chain, registers the AES key with FinanzOnline
curl -X POST https://api.openfiskal.com/v1/registers/reg_01HXYZ/fiscal-units \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ"
{
  "object": "fiscal_unit_response",
  "fiscal_unit": {
    "id": "fu_01HXYZ",
    "object": "fiscal_unit",
    "register_id": "reg_01HXYZ",
    "state": "active",
    "jurisdiction": "DE",
    "fiscal_registration": {
      "regime": "tse",
      "tse_serial": "abc123def456",
      "client_id": "Kasse 2",
      "signature_algorithm": "ecdsa-plain-SHA384",
      "time_format": "utcTime",
      "registered_at": "2026-02-26T10:00:00Z"
    },
    "replaces": null,
    "replaced_by": null,
    "provisioned_at": "2026-02-26T10:00:00Z",
    "decommissioned_at": null,
    "created_at": "2026-02-26T10:00:00Z"
  },
  "register": {
    "id": "reg_01HXYZ",
    "object": "register",
    "state": "active",
    "active_fiscal_unit": { "..." : "..." }
  },
  "register_api_key": null,
  "credential_issued": false
}
The fiscal unit is now active and the register is ready to accept operations.
For device-direct integrations (EV chargers, unattended kiosks), pass issue_register_credential: true to receive a register-scoped API key. For server-side integrations, the platform API key already covers all register operations.
3

Start sending heartbeats

Once the fiscal unit is active, the register should send periodic heartbeats (every 30–60 seconds) so OpenFiskal can monitor its health.
curl -X POST https://api.openfiskal.com/v1/registers/reg_01HXYZ/heartbeat \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ" \
  -H "Content-Type: application/json" \
  -d '{
    "timestamp": "2026-02-26T10:05:00Z",
    "sequence": 1,
    "status": "operational",
    "software": {
      "pos_vendor": "Acme POS",
      "pos_version": "3.2.1"
    }
  }'
The status field in the heartbeat is self-reported by the register. OpenFiskal derives its own operational status from heartbeat frequency:
StatusMeaning
operationalHeartbeat received within expected interval
degradedRegister self-reported degraded status
offlineNo heartbeat for 2x expected interval
staleNo heartbeat for an extended period
Use GET /registers/:id/status to check a register’s operational status and list its currently open operations.

Monitoring

Register status

The status endpoint provides liveness information and the authoritative list of open operations:
curl https://api.openfiskal.com/v1/registers/reg_01HXYZ/status \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ"
{
  "register_id": "reg_01HXYZ",
  "status": "operational",
  "last_heartbeat_at": "2026-02-26T14:30:00Z",
  "open_operations": [
    {
      "id": "op_01ABC",
      "type": "sale",
      "started_at": "2026-02-26T14:25:00Z"
    }
  ],
  "software": {
    "pos_vendor": "Acme POS",
    "pos_version": "3.2.1"
  }
}

Fleet status

To check all registers at a location in one call:
curl https://api.openfiskal.com/v1/locations/loc_01HXYZ/registers/status \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ"
This returns the status of every register at the location — useful for dashboards and alerting.

Error recovery

If a fiscal device fails (TSE hardware fault, RT communication error), the fiscal unit transitions to error. Operations on the register will be rejected until the fiscal unit is recovered. To recover, call the recover endpoint:
curl -X POST https://api.openfiskal.com/v1/fiscal-units/fu_01HXYZ/recover \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ"
If the underlying device issue has been resolved, the fiscal unit returns to active. If the device is still unreachable, the call will fail and the fiscal unit remains in error.
Operations that were in-flight when the device failed remain in open state. Check GET /registers/:id/status for open operations and either complete or cancel them once the device recovers.

Replacing a fiscal unit

When a fiscal device reaches end-of-life, is replaced, or needs to be swapped — use the atomic replace endpoint. The register ID stays the same, so POS routing is unaffected.
curl -X POST https://api.openfiskal.com/v1/registers/reg_01HXYZ/fiscal-units/replace \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "TSE hardware end-of-life"
  }'
{
  "object": "fiscal_unit_replacement",
  "old_binding": {
    "id": "fu_01HXYZ",
    "state": "decommissioned",
    "replaced_by": "fu_02HXYZ",
    "decommissioned_at": "2026-02-26T15:00:00Z"
  },
  "new_binding": {
    "id": "fu_02HXYZ",
    "state": "active",
    "replaces": "fu_01HXYZ",
    "provisioned_at": "2026-02-26T15:00:01Z"
  },
  "register": {
    "id": "reg_01HXYZ",
    "state": "active",
    "active_fiscal_unit": { "id": "fu_02HXYZ", "..." : "..." }
  }
}
All open operations must be completed or cancelled before replacing. The old fiscal unit’s operations remain in the system for audit purposes.

Viewing fiscal unit history

To see all fiscal units (past and present) for a register:
curl https://api.openfiskal.com/v1/registers/reg_01HXYZ/fiscal-units \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ"

Decommissioning

Decommissioning a fiscal unit

To permanently retire a fiscal unit without replacing it:
curl -X POST https://api.openfiskal.com/v1/fiscal-units/fu_01HXYZ/decommission \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Location closing"
  }'
This triggers jurisdiction-specific fiscal deregistration. The register remains active and can have a new fiscal unit provisioned later.

Archiving a register

When a register is permanently retired — hardware replaced, location closed, or no longer needed:
curl -X POST https://api.openfiskal.com/v1/registers/reg_01HXYZ/deactivate \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ"
This archives the register and decommissions any active fiscal unit. The register transitions to archived state.
Archiving is permanent and cannot be undone. Any active register API key is automatically revoked. All open operations must be completed or cancelled first — the call returns 409 Conflict otherwise.

Credential management

For device-direct integrations, register API keys may need rotation:
curl -X POST https://api.openfiskal.com/v1/registers/reg_01HXYZ/credentials/rotate \
  -H "Authorization: Bearer $API_KEY" \
  -H "OpenFiskal-Organization: org_01HXYZ"
The previous key is revoked immediately. The new key is returned in the response and must be provisioned to the device over a secure channel.
Rotate credentials when a device is compromised, replaced, or as part of routine security hygiene. Always ensure the new key is provisioned before the old device goes offline.

Backward compatibility

The POST /registers/:id/activate endpoint is deprecated but continues to work. Under the hood, it creates a fiscal unit. The register response includes deprecated fiscal_state and fiscal_registration fields derived from the active fiscal unit. New integrations should use the fiscal units API directly.

Next steps