Skip to main content

Documentation Index

Fetch the complete documentation index at: https://dev.openfiskal.com/llms.txt

Use this file to discover all available pages before exploring further.

April 30, 2026
BreakingAddition
Fiscalization API
Register sessions: new operation types + session-bound POS operationsThree new operation types model the cash-drawer shift on a fiscalized register:
  • session_open — start a shift with a counted opening float
  • session_cash_adjustment — record mid-shift cash movement (drop, pay-in, correction)
  • session_close — end the shift with a merchant-counted closing balance
All three flow through POST /operations (no separate sessions endpoint) and carry the same resource_version / ETag mechanics as goods-movement operations. They are born status: "completed" — there is no PATCH .../complete step for session events.Breaking — POS goods-movement now requires an open session. Sending POST /operations with source: "POS" on a register that has no open session is rejected with 409 no_open_session. Open the register’s session with session_open before posting POS sales, returns, or exchanges. At most one open session per register; opening a second while one is open returns 409 session_invalid_state.New field — session_id on operation responses. Every operation response now carries session_id on the envelope. For POS goods-movement, it’s the session the operation was rung up during. For session-event variants, it’s the session being opened/adjusted/closed. For ONLINE goods-movement (no register), it’s null.Breaking — GET /operations/{id} is now a discriminated union on type. Six variants: SaleOperation, ReturnOperation, ExchangeOperation, SessionOpenOperation, SessionCashAdjustmentOperation, SessionCloseOperation. Each variant carries only the fields meaningful to its type — SESSION_* responses no longer include zero-padded pretax_amount / total_amount / line_items / payments / fiscal_information, and goods-movement responses no longer include null session_*_details placeholders. SALE responses also drop the always-null related_operation_id and external_related_operation.See Sessions for the full walkthrough.Update integrators that issue POS operations to bracket each shift with session_open / session_close before your next release.
April 30, 2026
Breaking
Fiscalization API
Merchant tax_id removed; Italian fiscal_identity reshapedThe top-level Merchant.tax_id field has been removed from create, update, and response shapes. Tax identifiers now live exclusively on fiscal_identity, where they can vary by country.The Italian fiscal_identity object (country_code: "ITA") has been replaced:
  • Removed (both optional): vat_id, codice_fiscale.
  • Added (all required): tax_number (Codice Fiscale — 11 numeric digits or 16 alphanumeric characters), vat_number (Partita IVA — 11 numeric digits), fisconline_user (16 alphanumeric characters; the Codice Fiscale of the person delegated to access the Agenzia delle Entrate portal), fisconline_password, fisconline_pin.
  • legal_entity_type (COMPANY | INDIVIDUAL) is unchanged.
The German (DEU) and Austrian (AUT) fiscal_identity shapes are unchanged.Update integrator code that creates or updates Italian merchants, and stop sending the top-level tax_id field for all merchants, before your next release.
April 29, 2026
Addition
Fiscalization API
New endpoints: POST /exports, GET /exports/{exportId}Two new endpoints expose asynchronous fiscal export jobs.POST /exports enqueues a job and returns 202 Accepted with { id, type, status: "pending", register_id?, from, to, created_at }. Required body fields: type (dsfinvk is the first available type), from and to (ISO 8601 date-times). Optional register_id scopes the export to a single register; when omitted, the export covers all eligible registers under the merchant for the matching fiscal regime.GET /exports/{exportId} returns the job. Once status is completed, download_url is a signed URL to fetch the artifact. When status is failed, error.message (and optional error.details) describes why.Both endpoints require the X-OpenFiskal-Merchant header.
April 29, 2026
Addition
Fiscalization API
external_related_operation accepted on returns/exchangesPOST /operations with type: "return" or type: "exchange" now accepts a new optional field, external_related_operation, for cases where the original sale was never ingested into OpenFiskal (typically during platform migration before backfill).
{
  "type": "return",
  "external_related_operation": {
    "description": "Return against order from external platform.",
    "external_operation_id": "shopify-order-4711"
  }
}
  • Mutually exclusive with related_operation_id — exactly one must be set on a return or exchange.
  • Both fields on the nested object are required strings.
  • The same field is echoed on the operation response.
Use related_operation_id when the original sale exists in OpenFiskal; use external_related_operation otherwise.
April 23, 2026
Breaking
Fiscalization API
Sign convention enforced on total_amount and line_items[].total_amountPOST /operations now rejects payloads whose amount signs do not match Operation.type:
  • sale: total_amount and every line_items[].total_amount must be >= 0.
  • return: total_amount and every line_items[].total_amount must be <= 0.
  • exchange: no sign constraint (an exchange may net positive, negative, or zero).
Zero is permitted on both sale (freebie) and return (zero-value return). Violations return 422 Unprocessable Entity.Sign is the only on-wire signal Fiskaly’s TSE has to distinguish a sale from a return signature, so OpenFiskal enforces it before signing.Update return flows that previously sent positive amounts on type: "return" to send non-positive amounts before your next release.
April 23, 2026
Breaking
Fiscalization API
fiscal_identities[].country renamed to country_code; DE fields now requiredThe discriminator field on every fiscal_identity entry has been renamed from country to country_code. This applies to all three country variants (DEU, AUT, ITA) on both the create/update payload and the merchant response. Payloads that send country will reject.For DEU fiscal identities, tax_number (Steuernummer) and vat_id (USt-IdNr) are now both required. Previously both were optional. AUT and ITA requirements are unchanged.Update integrator code that creates or parses merchant fiscal_identities before your next release.
April 23, 2026
Addition
Fiscalization API
OpenAPI JSON now served at /openapi-jsonThe current production OpenAPI spec is now served at:
  • Production: https://api.openfiskal.com/openapi-json
  • Sandbox: https://sandbox.api.openfiskal.com/openapi-json
The previous Swagger-default path /docs-json is preserved as a 301 redirect to the new path. Import the new URL into Postman, Insomnia, or an OpenAPI code generator to scaffold a client.The OpenAPI spec always matches the live API implementation.
April 23, 2026
Breaking
Fiscalization API
Operation.status enum corrected; 412 payload includes expected_resource_versionThe Operation.status enum has been corrected from 'open' | 'completed' | 'cancelled' to 'open' | 'completed' | 'voided'. Operations that you PATCH /operations/{id}/void resolve to status: "voided", not cancelled. There were never any operations with status: "cancelled" in production — the OpenAPI value was wrong.412 Precondition Failed error bodies now include details.expected_resource_version alongside details.current_resource_version. The message field is the literal string "Resource version mismatch." (previously "The supplied If-Match value is stale.").Update Operation.status parsers to accept voided, and update any UI that surfaces the precondition_failed error message string.
April 23, 2026
Breaking
Fiscalization API
Operation type refund renamed to returnThe Operation.type enum now uses return instead of refund for operations where goods come back from the customer. The valid values are sale | return | exchange.OpenFiskal now distinguishes goods movement from money movement: operations model goods (sale/return/exchange), refund is reserved for money movement (a negative payment transaction on an operation) and is not an operation type. This unlocks flows the old terminology could not express cleanly — return with store credit (goods back, no money), goodwill refund (money back, no goods), or partial refunds on kept items.
  • POST /operations with type: "refund" will now reject. Use type: "return".
  • Response shapes now return type: "return" for what was previously type: "refund".
  • Payment.status enum is unchanged — refunded is still the correct status for a payment that has been reversed, because it describes money movement.
Update integrator code that creates or parses return/refund operations before your next release.
April 23, 2026
Breaking
Fiscalization API
KassenSichV schema changes
  • FiscalInformationKassenSichVVerification: renamed tse_serial to tss_serial_number and client_id to pos_client_serial_number. Both remain required.
  • FiscalInformationKassenSichVEndEvent: added required public_key (string).
  • FiscalInformationKassenSichVStartEvent: removed transaction_counter and signature. signed_at is now the only required field.
Update integrations that submit or parse KassenSichV fiscal information before your next release.
April 23, 2026
Clarification
Fiscalization API
Country code casingClarified that the country field on Address and on the legal entity schema must be an ISO 3166-1 alpha-3 code in uppercase (for example, DEU). No behavior change; existing uppercase values continue to validate.
April 19, 2026
Addition
Fiscalization API
New endpoint: POST /registers/{registerId}/decommissionPermanently retires a fiscalized register. The endpoint calls the underlying TSE provider to decommission the register’s fiscal components and returns the updated register with decommissionedAt populated. Currently DE/KassenSichV only; AT/IT will follow as those regimes ship publicly.Conflicts return 409 decommission_conflict:
  • Register has not been fiscalized.
  • Register has already been decommissioned.
A decommissioned register cannot be re-fiscalized — create a new register for that location instead.