Exports
The exports API generates data exports in formats compatible with payroll and accounting systems. Exports can be generated synchronously for small datasets or asynchronously for large ones.
Overview
Exports combine time tracking data from employees, timespans, and absences into structured output. Four exporter engines are available, each running under its own URL:
| Exporter | Description | config parameter |
|---|---|---|
generic | Flexible exporter with configurable columns, row types, and filters. See the Generic Reporting API. | Must be omitted. |
sage | Fixed layout compatible with Sage payroll software. | Must be omitted. |
datev | Fixed layout compatible with DATEV payroll software (common in Germany). | Required: Steuerberaternummer|Mandantennummer. |
multi | Combines multiple generic export configurations into one request. See Multi-Export. | Required: JSON array of export configurations. |
Exporter names are lowercase and case-sensitive: generic, sage, datev, multi.
Exports only include employees visible to the authenticated user — for example, department leaders only export data for employees of their departments. Employees archived before the start of the export period are excluded automatically.
List Available Exporters
Returns a map of exporter names to their endpoint URLs. Query parameters are ignored on this route; exports are generated on the per-exporter detail routes below.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/exports/" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"sage": "https://api.zeitstrom.com/api/v2/exports/sage/",
"datev": "https://api.zeitstrom.com/api/v2/exports/datev/",
"generic": "https://api.zeitstrom.com/api/v2/exports/generic/",
"multi": "https://api.zeitstrom.com/api/v2/exports/multi/"
}
Run an Export
Generate an export with the exporter named in the path, e.g. /api/v2/exports/generic/ or /api/v2/exports/datev/.
Query Parameters
- Name
daterange- Type
- string
- Description
Date range for the export:
YYYY-MM-DD|YYYY-MM-DD. Required.
- Name
export_format- Type
- string
- Description
Output format:
csv,json,table,plain, orxlsx. Defaults tocsv. Thecsvformat accepts additional options such ascsv:delimiter>%3b, see CSV Format Options.
- Name
response_only- Type
- boolean
- Description
When
true, the response body is the raw export itself, served with the format's content type — i.e. a direct file download. Whenfalse(the default), the export is wrapped in a JSON envelope containing the request configuration and the data (see below).
- Name
types- Type
- string
- Description
Row types to include, pipe-separated (generic exporter). See Row Types.
- Name
columns- Type
- string
- Description
Columns to include, pipe-separated (generic exporter). See Column Customization.
- Name
config- Type
- string
- Description
Exporter-specific configuration. Required for
datevandmulti, must be omitted forgenericandsage(see the table above).
- Name
employee_ids- Type
- string
- Description
Restrict the export to specific employees, pipe-separated UUIDs. Duplicate or unknown IDs are rejected with a
400validation error.
- Name
employee_group_ids- Type
- string
- Description
Restrict the export to specific departments, pipe-separated UUIDs. When combined with
employee_ids, employees matching either list are included.
- Name
filter- Type
- string
- Description
Additional employee filters as
key=valuepairs. Multiple filters are combined with|in a singlefilterparameter. See Filtering.
- Name
skip_zero_rows- Type
- boolean
- Description
Skip rows with zero values (generic exporter). Defaults to
true. Thesageanddatevexporters ignore this parameter.
- Name
prefix- Type
- string
- Description
Base64-encoded text prepended to the output. Only supported for the
csv,plain, andtableformats.
- Name
is_async- Type
- boolean
- Description
Generate the export in the background. Defaults to
false. See Asynchronous Exports.
With response_only=true the endpoint behaves like a file download:
Direct CSV Download
curl -X GET "https://api.zeitstrom.com/api/v2/exports/generic/?daterange=2024-06-01|2024-06-30&types=credit-time:hours&columns=first-name|last-name|value&export_format=csv&response_only=true" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-o export-june.csv
Without response_only, the report is wrapped in a JSON envelope that echoes the validated request configuration:
JSON Envelope
curl -X GET "https://api.zeitstrom.com/api/v2/exports/generic/?daterange=2024-06-01|2024-06-30&types=credit-time:hours&columns=first-name|last-name|value&export_format=json" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"request": {
"is_async": false,
"skip_zero_rows": true,
"exporter": "generic",
"export_format": "json",
"daterange": ["2024-06-01", "2024-06-30"],
"employee_ids": null,
"types": ["credit-time:hours"],
"columns": ["first-name", "last-name", "value"],
"response_only": false,
"prefix": null,
"filter": null
},
"response": [
{ "first-name": "Max", "last-name": "Mustermann", "value": 152.5 },
{ "first-name": "Erika", "last-name": "Musterfrau", "value": 148.25 }
]
}
Export Formats
| Format | Content-Type (response_only=true) | Description |
|---|---|---|
csv | text/csv | Comma-separated values. Delimiter and header row are configurable, see CSV Format Options. |
json | application/json | JSON array of objects. |
xlsx | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | Excel spreadsheet. |
table | text/plain | Formatted ASCII table. |
plain | text/plain | Plain text output. |
Binary formats (xlsx) are rejected with a 400 validation error unless
response_only=true is set, because binary content cannot be embedded in
the JSON envelope. This also applies to asynchronous exports.
The Sage Exporter
Produces a fixed-layout wage record export for Sage payroll. It takes no config or columns parameters — the layout is predefined. The types parameter may optionally contain pipe-separated wage type codes (e.g. types=301|400) to restrict the output to those rows.
With export_format=csv the output is semicolon-delimited and includes a header row with the columns MDNr;AbrMon;AbrJahr;ANNr;LANr;Dat;Kost;KoTr;AA;Anz;Betrag;Zuschlag;Text. The accounting month (AbrMon) and year (AbrJahr) are taken from the start of the daterange, ANNr is the employee's accounting number, Kost is the employee's department name, and Anz is the count formatted with a decimal comma. Employees without an accounting number are omitted.
Each row carries one wage type code in LANr:
| Code | Content |
|---|---|
301 | Sunday work hours. |
305 | Night work hours (23:00–06:00). |
360 | Vacation days, one row per day (Dat holds the day of month). |
157 | Vacation day total per employee. |
402 | Vacation hours total per employee. |
99001 | Sick leave and education/training days, one row per day. |
158 | Sick day total per employee. |
403 | Sick hours total per employee. |
424 | Education/training hours total per employee. |
400 | Planned working hours for the period. |
401 | Recorded (tracked) working hours for the period. |
Request
curl -X GET "https://api.zeitstrom.com/api/v2/exports/sage/?daterange=2024-06-01|2024-06-30&export_format=csv&response_only=true" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-o sage-june.csv
The DATEV Exporter
Produces a wage record export for DATEV payroll. It requires a config parameter containing the tax advisor number (Steuerberaternummer) and client number (Mandantennummer), pipe-separated. Both values must be numeric, otherwise the request fails with a 400 validation error.
With export_format=csv the output is semicolon-delimited without a header row. The first row identifies the file: advisor number, client number, and the accounting month as MM/YYYY (taken from the start of the daterange). Each following row contains the employee's accounting number (Personalnummer), a wage type code, and the count formatted with a decimal comma. Employees without an accounting number and zero-value rows are omitted.
| Code | Content |
|---|---|
1000 | Recorded (tracked) working hours. |
8560 | Vacation days. |
1602 | Vacation hours. |
8570 | Sick days. |
1652 | Sick hours. |
1015 | Public holiday hours. |
Request
curl -X GET "https://api.zeitstrom.com/api/v2/exports/datev/?config=12345|67890&daterange=2024-06-01|2024-06-30&export_format=csv&response_only=true" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-o datev-june.csv
Discovery Endpoints
Each exporter route exposes four discovery endpoints that return human-readable reference pages (HTML, no authentication required) describing the building blocks of the Generic Reporting API:
| Endpoint | Content |
|---|---|
GET /api/v2/exports/generic/columns/ | Available columns. |
GET /api/v2/exports/generic/types/ | Available row types. |
GET /api/v2/exports/generic/modifiers/ | Available value modifiers. |
GET /api/v2/exports/generic/filters/ | Available filters. |
See Discovery Endpoints for details on how columns, types, modifiers, and filters are used.
Asynchronous Exports
For large datasets, add is_async=true to any export request. Instead of the export itself, the endpoint returns a background task:
Start Async Export
curl -X GET "https://api.zeitstrom.com/api/v2/exports/generic/?daterange=2024-01-01|2024-12-31&types=credit-time:hours&columns=first-name|last-name|value&export_format=xlsx&response_only=true&is_async=true" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"id": "9f2b6c1e-4a3d-4b7e-9c0a-1d2e3f4a5b6c",
"created_at": "2024-06-30T06:15:00",
"finished_at": null,
"status": "created",
"target": null
}
The request parameters are validated up front exactly like a synchronous export — in particular, xlsx still requires response_only=true.
Repeating the same request with identical parameters within 12 hours does not start a new export; it returns the current state of the existing task. This is also how you poll for completion: send the same request again until status is finished. status is one of created, in_progress, finished, or error.
Once finished, target contains a presigned download URL for the generated file, valid for 12 hours:
Finished Task
{
"id": "9f2b6c1e-4a3d-4b7e-9c0a-1d2e3f4a5b6c",
"created_at": "2024-06-30T06:15:00",
"finished_at": "2024-06-30T06:16:42",
"status": "finished",
"target": "https://zeitstrom-exports.s3.eu-central-1.amazonaws.com/…/9f2b6c1e-4a3d-4b7e-9c0a-1d2e3f4a5b6c.xlsx?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=43200&X-Amz-Signature=…"
}
You can also track background tasks through the asynchronous tasks endpoints described below.
The Asynchronous Task Object
- Name
id- Type
- string (UUID)
- Description
Unique identifier for the task.
- Name
status- Type
- string
- Description
One of
created,in_progress, orfinished. Tasks that failed with an error are hidden from these endpoints.
- Name
label- Type
- string or null
- Description
Optional human-readable label.
- Name
description- Type
- string or null
- Description
Optional human-readable description.
- Name
action- Type
- string
- Description
The kind of background job. Exports started via
is_async=trueusegeneric_export.
- Name
created_at- Type
- string (ISO 8601)
- Description
Timestamp when the task was created.
- Name
started_at- Type
- string (ISO 8601) or null
- Description
Timestamp when processing started, or
nullif still queued.
- Name
finished_at- Type
- string (ISO 8601) or null
- Description
Timestamp when processing finished, or
nullwhile pending.
- Name
result- Type
- object or null
- Description
Result data of the task. For exports this holds an internal storage reference to the generated file — to obtain a download URL, use the
targetfield returned by the export endpoint.
List Asynchronous Tasks
Retrieve a paginated list of your own background tasks. Only tasks started by the authenticated user are returned.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/asynchronous-tasks/tasks/" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "9f2b6c1e-4a3d-4b7e-9c0a-1d2e3f4a5b6c",
"status": "finished",
"label": null,
"description": null,
"action": "generic_export",
"created_at": "2024-06-30T06:15:00",
"started_at": "2024-06-30T06:15:05",
"finished_at": "2024-06-30T06:16:42",
"result": {
"file": "i-3f9c2d71-58a4-4c0e-9b12-7e6a1f0d4c88/u-b4d9e2a6-1c35-47f8-8a90-52c7e3b1d6f4/2024/06/30/9f2b6c1e-4a3d-4b7e-9c0a-1d2e3f4a5b6c.xlsx"
}
}
]
}
Retrieve an Asynchronous Task
Get the current state of a specific task.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/asynchronous-tasks/tasks/9f2b6c1e-4a3d-4b7e-9c0a-1d2e3f4a5b6c/" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Delete an Asynchronous Task
Delete an export task. For finished exports, the generated file is removed from storage as well, invalidating previously issued download URLs.
Request
curl -X DELETE "https://api.zeitstrom.com/api/v2/asynchronous-tasks/tasks/9f2b6c1e-4a3d-4b7e-9c0a-1d2e3f4a5b6c/" \
-H "Authorization: Token <YOUR_API_TOKEN>"