Skip to main content

Overview

Exports are asynchronous. You create an export job, poll it until the artifact is ready, then download the file before the signed URL expires. The only export type currently available is DSFinV-K (Germany, KassenSichV). Additional types for other regimes will be added as those regimes are enabled.

Export types

TypeDescription
dsfinvkGermany (KassenSichV) — DSFinV-K archive containing the CSV files, index.xml, and GDPdU DTD mandated by the German tax authority
DSFinV-K exports are per-register: every request must specify register_id, and the register must be on the KassenSichV regime.

Requesting an export

Every export requires a type, a time range (from, to), and — for DSFinV-K — a register_id.
curl -X POST https://sandbox.api.openfiskal.com/v1/exports \
  -H "Authorization: Bearer of_test_deu_abc123..." \
  -H "X-OpenFiskal-Merchant: merchant_01HXYZ" \
  -H "Idempotency-Key: dsfinvk-2026-03" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "dsfinvk",
    "register_id": "reg_01HABC",
    "from": "2026-03-01T00:00:00Z",
    "to": "2026-03-31T23:59:59Z"
  }'
The resulting TAR archive contains the full DSFinV-K dataset: cashpointclosing.csv, transactions.csv, lines.csv, payment.csv, vat.csv, and the other mandated files alongside index.xml and the GDPdU DTD.

Synchronous validation at create time

POST /exports validates the request before enqueuing the job. The window is silently clamped to the register’s fiscalized lifetime (max(from, fiscalized_at) to min(to, decommissioned_at ?? now)) and the following checks run before the response is returned:
StatusCodeWhen
400 bad_requestregister_id_required_for_dsfinvkregister_id is missing
422 validation_errorvalidation_errorRegister is not on the KassenSichV regime
422 validation_errorexport_dsfinvk_no_closed_sessionsClamped window contains no closed sessions on the register
422 validation_errorexport_dsfinvk_build_pendingA closed session in the window has no DSFinV-K cashpoint-closing yet — retry shortly
export_dsfinvk_build_pending is transient: the build pipeline runs asynchronously after session_close, so a fresh request can land before every closed session has been compiled. Retrying a few seconds later is the right response.

Polling and download

If validation passes, the job is enqueued and the response carries status: "pending":
{
  "id": "exp_01JDEF",
  "type": "dsfinvk",
  "status": "pending",
  "register_id": "reg_01HABC",
  "from": "2026-03-01T00:00:00Z",
  "to": "2026-03-31T23:59:59Z",
  "download_url": null,
  "error": null,
  "created_at": "2026-03-31T12:00:00Z",
  "completed_at": null
}
Poll GET /exports/{exportId} until status reaches completed:
{
  "id": "exp_01JDEF",
  "type": "dsfinvk",
  "status": "completed",
  "register_id": "reg_01HABC",
  "from": "2026-03-01T00:00:00Z",
  "to": "2026-03-31T23:59:59Z",
  "download_url": "https://storage.googleapis.com/...",
  "error": null,
  "created_at": "2026-03-31T12:00:00Z",
  "completed_at": "2026-03-31T12:00:42Z"
}
If the job fails, status is failed and the response carries an error object:
{
  "id": "exp_01JDEF",
  "type": "dsfinvk",
  "status": "failed",
  "error": {
    "message": "Build pipeline failed for session ses_01HZ.",
    "details": null
  },
  "completed_at": "2026-03-31T12:00:42Z"
}

Retention

download_url is a signed URL that expires 7 days after completed_at, matching the bucket lifecycle rule that deletes the artifact at the same point. Copy each artifact to your own durable storage before then. If the URL has expired, you can re-create the export for the same window.

Limitations today

  • DSFinV-K is the only export type currently available
  • There is no list endpoint; track the export IDs you create
  • AT (DEP7/RKSV) and IT (RT) export types will be added when those regimes ship