> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openfiskal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a TSE export

> Germany (KassenSichV). Produces the TSE export: the signed Log Messages themselves, per BSI TR-03151. This is the second artefact a Kassennachschau asks for, alongside DSFinV-K, and it describes the security device rather than the cash register.

Asynchronous: returns `202 Accepted` with `status: pending`. Poll `GET /exports/{exportId}` until `status` is `completed` (then `download_url` is set) or `failed`.

**Scope is the device, not the register.** A Swissbit TSE serves every register at the same business premises and offers no filtered export, so the archive contains their log messages too. Each `.log` entry is reproduced exactly as the device wrote it, under the filename the device gave it; only the containing archive is assembled by OpenFiskal, because a vendor export is incremental and no single one spans a requested period.



## OpenAPI

````yaml /api-reference/reporting-openapi.yaml post /exports/tse
openapi: 3.0.0
info:
  title: OpenFiskal reporting API
  description: |-
    Country-specific fiscal export endpoints for compliance reporting.

    Exports are asynchronous: create a job, poll until ready, then download
    the artifact before the retention deadline.
  version: 1.1.0
  contact: {}
  license:
    name: Proprietary
servers:
  - url: https://api.openfiskal.com/v1
    description: Production
  - url: https://sandbox.api.openfiskal.com/v1
    description: Sandbox
security: []
tags:
  - name: Exports
    description: Create and inspect asynchronous fiscal export jobs.
paths:
  /exports/tse:
    post:
      tags:
        - Exports
      summary: Create a TSE export
      description: >-
        Germany (KassenSichV). Produces the TSE export: the signed Log Messages
        themselves, per BSI TR-03151. This is the second artefact a
        Kassennachschau asks for, alongside DSFinV-K, and it describes the
        security device rather than the cash register.


        Asynchronous: returns `202 Accepted` with `status: pending`. Poll `GET
        /exports/{exportId}` until `status` is `completed` (then `download_url`
        is set) or `failed`.


        **Scope is the device, not the register.** A Swissbit TSE serves every
        register at the same business premises and offers no filtered export, so
        the archive contains their log messages too. Each `.log` entry is
        reproduced exactly as the device wrote it, under the filename the device
        gave it; only the containing archive is assembled by OpenFiskal, because
        a vendor export is incremental and no single one spans a requested
        period.
      operationId: ExportsController_createTse
      parameters:
        - name: X-OpenFiskal-Merchant
          in: header
          description: Merchant identifier returned by the merchants resource.
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTseExportDto'
      responses:
        '202':
          description: Export job enqueued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Export'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDto'
              examples:
                default:
                  summary: invalid_request
                  value:
                    code: invalid_request
                    message: The request body is malformed.
                    retryable: false
        '401':
          description: Authentication failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDto'
              examples:
                default:
                  summary: unauthorized
                  value:
                    code: unauthorized
                    message: Authentication failed.
                    retryable: false
        '403':
          description: >-
            Authenticated caller is not allowed to access the requested tenant,
            country, or merchant.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDto'
              examples:
                default:
                  summary: forbidden
                  value:
                    code: forbidden
                    message: The authenticated caller cannot access this resource.
                    retryable: false
        '404':
          description: Register not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDto'
              examples:
                default:
                  summary: not_found
                  value:
                    code: not_found
                    message: The requested resource does not exist.
                    retryable: false
        '422':
          description: >-
            The register was on no TSE in the window
            (`export_tse_no_device_in_window`), no log messages are archived for
            it yet (`export_tse_archive_pending`), or the register is not on the
            KassenSichV regime (`validation_error`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorDto'
              examples:
                default:
                  summary: regime_validation_failed
                  value:
                    code: regime_validation_failed
                    message: The payload violates regime-specific validation rules.
                    retryable: false
      security:
        - BearerAuth: []
components:
  schemas:
    CreateTseExportDto:
      type: object
      properties:
        from:
          type: string
          format: date-time
          example: '2026-03-01T00:00:00.000Z'
        to:
          type: string
          format: date-time
          example: '2026-03-31T23:59:59.000Z'
        register_id:
          type: string
          example: reg_01HABC
          description: >-
            Register whose signing device to export. NOT the scope: the register
            resolves to the TSE(s) it signed on during the window, and the
            archive covers those devices in full. A Swissbit TSE is shared by
            every register at the same business premises and offers no filtered
            export, so the archive contains their log messages too. A window
            spanning a device change resolves to both devices.
      required:
        - from
        - to
        - register_id
    Export:
      type: object
      properties:
        id:
          type: string
        type:
          allOf:
            - $ref: '#/components/schemas/ExportType'
        status:
          type: string
          enum:
            - pending
            - completed
            - failed
        register_id:
          type: string
          nullable: true
        from:
          type: string
          format: date-time
        to:
          type: string
          format: date-time
        download_url:
          type: string
          nullable: true
          description: >-
            Signed URL to download the export artifact. Present only when status
            is `completed`.
        error:
          nullable: true
          description: Failure information. Present only when status is `failed`.
          allOf:
            - $ref: '#/components/schemas/ExportError'
        coverage:
          nullable: true
          description: >-
            What the artifact covers. TSE exports only, and only once
            `completed`. Absent for other export types and while the export is
            still pending.
          allOf:
            - $ref: '#/components/schemas/TseExportCoverageDto'
        created_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          nullable: true
      required:
        - id
        - type
        - status
        - from
        - to
        - created_at
    ErrorDto:
      type: object
      properties:
        code:
          type: string
          description: Stable machine-readable error code.
          example: invalid_request
        message:
          type: string
          description: Human-readable explanation of the error.
        retryable:
          type: boolean
          description: Whether retrying the request is safe.
        details:
          type: object
          description: Additional structured context for the error.
          additionalProperties: true
      required:
        - code
        - message
        - retryable
    ExportType:
      type: string
      enum:
        - dsfinvk
        - tse
    ExportError:
      type: object
      properties:
        message:
          type: string
          description: Human-readable failure description.
        details:
          type: object
          nullable: true
          description: >-
            Structured error payload (e.g. provider error response). Shape
            varies by export type.
      required:
        - message
    TseExportCoverageDto:
      type: object
      properties:
        tse_serial_numbers:
          description: >-
            Every security device that contributed. More than one when the
            window spans a device swap. A Swissbit TSE serves every till at a
            location, so an archive scoped to one register contains its
            neighbours at the same premises.
          type: array
          items:
            type: string
        signature_counter_first:
          type: number
          nullable: true
          description: Lowest signature counter present.
        signature_counter_last:
          type: number
          nullable: true
          description: Highest signature counter present.
        log_message_count:
          type: number
          description: How many log messages the archive contains.
        covered_from:
          type: string
          format: date-time
          nullable: true
          description: >-
            Log time of the earliest message inside, not the requested window
            start.
        covered_to:
          type: string
          format: date-time
          nullable: true
          description: Log time of the latest message inside, not the requested window end.
        covers_requested_window:
          type: boolean
          description: >-
            Whether coverage reached the requested end of the window. False
            means the archive stops early because the security device could not
            be drained in time. It does NOT mean the window was empty: a quiet
            period legitimately contains no messages while still being fully
            covered.
        last_drained_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            When log messages were last drained off the device, i.e. how current
            this archive is.
        fresh_drain:
          description: >-
            What draining was attempted when the archive was compiled.
            `not_needed` means the window closed before the data we already
            held, so the device was never contacted.
          allOf:
            - $ref: '#/components/schemas/TseExportFreshDrain'
        gapless:
          type: boolean
          description: >-
            Whether the signature counters present form an unbroken run. A gap
            means a drain was lost, and because a vendor export is destructive
            it cannot be recovered.
      required:
        - tse_serial_numbers
        - log_message_count
        - covers_requested_window
        - fresh_drain
        - gapless
    TseExportFreshDrain:
      type: string
      enum:
        - not_needed
        - completed
        - timed_out
        - failed
      description: >-
        What draining was attempted when the archive was compiled. `not_needed`
        means the window closed before the data we already held, so the device
        was never contacted.
  securitySchemes:
    BearerAuth:
      scheme: bearer
      bearerFormat: API key
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.