Reviews
Reviews run a set of automated compliance and plausibility checks over the workmonths of your employees — for example missing checkouts, undocumented absences, overlapping workdays, or violations of German working-time law (ArbZG). Each problem the checks detect is reported as a finding, so you can resolve suspicious data before payroll. Findings are computed on the fly from the current data and are never stored: re-running a review after a correction immediately reflects the fix.
If your API token is restricted to specific permissions, it needs the
matching scope for each operation: reviews:view for all review endpoints
(findings, checks, and groups), and finding-suppression:view,
finding-suppression:edit, or finding-suppression:delete for reading,
writing, or deleting suppression rules. Requests without the required
permission return 403 Forbidden.
The Finding Object
A finding is one concrete problem detected by one check on one employee's workmonth. Findings are read-only computation results — they have no ID and cannot be modified through the API.
- Name
code- Type
- string
- Description
Identifier of the check that produced the finding, e.g.
insufficient-break. The authoritative list of codes active for your organization is returned by the checks endpoint.
- Name
group- Type
- string
- Description
The finding group the check belongs to:
missing-data,conflicts,legal-violations, oranomalies. See the groups endpoint for display labels.
- Name
severity- Type
- string
- Description
Either
errororwarning. All built-in checks currently reporterror.
- Name
date- Type
- string (YYYY-MM-DD) or null
- Description
The day within the workmonth the finding refers to.
nullis possible in the schema for month-level findings, but every built-in check sets a date.
- Name
references- Type
- array of [type, id] pairs
- Description
The records the finding is based on, each as a two-element array of an object type and its UUID. The first entry always references the
employee, the second theworkmonth, followed by the specific records that triggered the finding (e.g.workdayortimespanentries).
- Name
context- Type
- object
- Description
Check-specific machine-readable values behind the finding, e.g.
required_break_secondsforinsufficient-break. Empty object for checks without additional data.
- Name
details- Type
- string
- Description
Human-readable German summary with the concrete values interpolated, e.g.
Arbeitszeit: 9h 15min · Pause: 15min (gefordert: 45min). Empty string for checks whose title already says everything.
Run a Review
Run all configured checks over the workmonths of a given calendar month and return the resulting findings. The review covers every employee of your organization that has a workmonth for the requested month; employees without tracked data in that month produce no findings. Findings are sorted by date, severity, and code.
The response is not paginated — findings always contains the complete
result. Both query parameters are required; omitting either returns
400 Bad Request.
Suppression rules are not applied by this endpoint: the response contains all findings, including those an administrator has hidden in the Zeitstrom app. If you want to mirror the app's view, fetch the suppression rules and filter the findings yourself.
Query Parameters
- Name
year- Type
- integer
- Description
Calendar year of the workmonths to review, e.g.
2026. Required.
- Name
month- Type
- integer
- Description
Calendar month of the workmonths to review,
1–12. Required.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/reviews/reviews/?year=2026&month=5" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"year": 2026,
"month": 5,
"findings": [
{
"code": "incomplete-workday",
"group": "missing-data",
"severity": "error",
"date": "2026-05-12",
"references": [
["employee", "508d5250-7399-4b65-a574-3da53d9ddc25"],
["workmonth", "1d5be0ea-9f0c-4b0e-8a2f-64c7013274e8"],
["workday", "c9a3f1de-20b6-4a8e-b1d4-7e2f90a6c315"]
],
"context": {},
"details": ""
},
{
"code": "insufficient-break",
"group": "legal-violations",
"severity": "error",
"date": "2026-05-15",
"references": [
["employee", "508d5250-7399-4b65-a574-3da53d9ddc25"],
["workmonth", "1d5be0ea-9f0c-4b0e-8a2f-64c7013274e8"],
["workday", "f4b8c2a1-6d3e-49f7-8c05-1a9e6b2d4c73"]
],
"context": {
"net_working_seconds": 33300,
"actual_break_seconds": 900,
"required_break_seconds": 2700
},
"details": "Arbeitszeit: 9h 15min · Pause: 15min (gefordert: 45min)"
}
]
}
List Checks
List the check definitions active for your organization. This is the authoritative source for valid finding codes: by default all built-in checks run, but organizations can configure a subset (and per-check options), in which case this endpoint reflects exactly the checks a review executes.
The built-in checks are incomplete-workday, unfiled-absence,
pending-absence-application, overlapping-workdays, unbalanced-worktime,
future-workday, insufficient-break, excessive-daily-hours,
insufficient-rest-period, excessive-weekly-hours,
zero-duration-timespan, and excessive-session-fragmentation.
Each entry contains:
- Name
value- Type
- string
- Description
The check identifier — the same value findings carry in their
codefield.
- Name
group- Type
- string
- Description
The finding group the check belongs to.
- Name
title- Type
- string
- Description
Short German display label of the check.
- Name
description- Type
- string
- Description
Long-form German explanation of what the check detects.
- Name
config- Type
- object
- Description
Organization-specific configuration options for the check. Empty object unless your organization has customized the check.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/reviews/reviews/checks/" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"checks": [
{
"value": "incomplete-workday",
"group": "missing-data",
"title": "Unvollständiger Arbeitstag",
"description": "An einem vergangenen Arbeitstag fehlt die Abmeldung. Der Mitarbeiter hat sich nicht ausgestempelt, sodass die Arbeitszeit für diesen Tag nicht abgeschlossen werden kann.",
"config": {}
},
{
"value": "insufficient-break",
"group": "legal-violations",
"title": "Unzureichende Pausenzeit",
"description": "An einem Arbeitstag wurde die gesetzlich vorgeschriebene Mindestpause gemäß §4 Arbeitszeitgesetz nicht eingehalten (30 Minuten ab 6 Stunden Arbeit, 45 Minuten ab 9 Stunden).",
"config": {}
}
]
}
List Finding Groups
List the four finding groups with their German display labels. Groups categorize findings by the kind of problem: missing data, conflicting records, suspected legal violations, and statistical anomalies.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/reviews/reviews/groups/" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"groups": [
{
"value": "missing-data",
"title": "Fehlende Daten",
"description": "Fehlende oder unvollständige Erfassungen, die nicht ohne manuelle Nacharbeit ausgewertet werden können."
},
{
"value": "conflicts",
"title": "Konflikte",
"description": "Erfassungen, die sich gegenseitig widersprechen oder zeitlich überlappen und vor der Lohnabrechnung aufgelöst werden müssen."
},
{
"value": "legal-violations",
"title": "Gesetze",
"description": "Erfassungen, die mutmaßlich gegen gesetzliche Vorgaben verstoßen (z. B. Arbeitszeitgesetz) und arbeitsrechtlich geprüft werden sollten."
},
{
"value": "anomalies",
"title": "Auffälligkeiten",
"description": "Statistisch ungewöhnliche Erfassungsmuster, die auf Tipp- oder Gerätefehler hindeuten und manuell überprüft werden sollten."
}
]
}
The Suppression Object
A suppression is a stored rule saying "hide findings of this check code, for this employee (or all employees), in this date range". The Zeitstrom app creates one when an administrator dismisses a finding.
The server only stores suppression rules — it never applies them. The
review endpoint returns unfiltered findings, and filtering
happens client-side. A finding is suppressed by a rule when the rule's
code equals the finding's code, the rule's employee_id is null or
matches the employee in the finding's references, and the finding's
date falls within valid_from–valid_to (inclusive; a null valid_to
never expires).
- Name
id- Type
- string (UUID)
- Description
Unique identifier for the suppression rule. Read-only.
- Name
code- Type
- string
- Description
The check code the rule suppresses, e.g.
insufficient-break. Must be one of the registered check codes — any built-in code is accepted, even if your organization is configured to run only a subset of checks (see the checks endpoint); unknown codes return a400validation error.
- Name
employee_id- Type
- string (UUID) or null
- Description
UUID of the employee the rule is limited to, or
nullfor an organization-wide rule that applies to all employees.
- Name
valid_from- Type
- string (YYYY-MM-DD)
- Description
First day the rule applies to, inclusive. Required.
- Name
valid_to- Type
- string (YYYY-MM-DD) or null
- Description
Last day the rule applies to, inclusive.
nullmakes the rule permanent. Must not be beforevalid_from.
- Name
created_at- Type
- string (ISO 8601, local time)
- Description
When the rule was created. Read-only.
- Name
modified_at- Type
- string (ISO 8601, local time)
- Description
When the rule was last modified. Read-only.
List all Suppressions
Retrieve a paginated list of your organization's suppression rules. API
tokens see every rule of the organization. To filter the findings of a
monthly review, request the rules overlapping that month, e.g.
?daterange=2026-05-01|2026-05-31.
Query Parameters
- Name
ids- Type
- string
- Description
Filter by rule IDs (UUIDs), pipe-separated. Invalid UUIDs are ignored.
- Name
daterange- Type
- string
- Description
Two dates separated by a pipe,
YYYY-MM-DD|YYYY-MM-DD. Returns only rules whose validity interval overlaps the given range. Either side may be empty (2026-05-01|or|2026-05-31). Permanent rules (valid_toisnull) are treated as open-ended.
- Name
valid_from__lte- Type
- string (YYYY-MM-DD)
- Description
Only rules whose
valid_fromis on or before the given date.
- Name
valid_until__gte- Type
- string (YYYY-MM-DD)
- Description
Only rules whose
valid_tois on or after the given date. Permanent rules (valid_toisnull) are always included.
- Name
limit- Type
- integer
- Description
Number of results per page. Defaults to 100, maximum 1000.
- Name
offset- Type
- integer
- Description
Number of results to skip for pagination. Defaults to 0.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/reviews/suppressions/?daterange=2026-05-01|2026-05-31" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "7f3d2a10-5b7e-4c93-9a41-2f8c6de01b57",
"code": "insufficient-break",
"employee_id": "508d5250-7399-4b65-a574-3da53d9ddc25",
"valid_from": "2026-05-15",
"valid_to": "2026-05-15",
"created_at": "2026-05-16T09:21:05",
"modified_at": "2026-05-16T09:21:05"
},
{
"id": "a1c94b7e-08d2-4f65-b3a9-5e716c20d848",
"code": "excessive-session-fragmentation",
"employee_id": null,
"valid_from": "2026-04-01",
"valid_to": null,
"created_at": "2026-04-03T14:04:12",
"modified_at": "2026-04-03T14:04:12"
}
]
}
Retrieve a Suppression
Get a single suppression rule by its ID.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/reviews/suppressions/7f3d2a10-5b7e-4c93-9a41-2f8c6de01b57/" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Create a Suppression
Create a new suppression rule. Creation is idempotent on
(code, employee_id, valid_from): if a rule with the same combination
already exists, the API returns the existing rule with status 200 instead
of creating a duplicate — the existing rule's valid_to is preserved and
the submitted valid_to is ignored. A newly created rule returns status
201.
- Name
code- Type
- string
- Description
One of the registered check codes. Required.
- Name
employee_id- Type
- string (UUID) or null
- Description
Employee to limit the rule to; omit or pass
nullfor an organization-wide rule.
- Name
valid_from- Type
- string (YYYY-MM-DD)
- Description
First day the rule applies to, inclusive. Required.
- Name
valid_to- Type
- string (YYYY-MM-DD) or null
- Description
Last day the rule applies to, inclusive. Omit or pass
nullfor a permanent rule.
Request
curl -X POST "https://api.zeitstrom.com/api/v2/reviews/suppressions/" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"code": "insufficient-break",
"employee_id": "508d5250-7399-4b65-a574-3da53d9ddc25",
"valid_from": "2026-05-15",
"valid_to": "2026-05-15"
}'
Response
{
"id": "7f3d2a10-5b7e-4c93-9a41-2f8c6de01b57",
"code": "insufficient-break",
"employee_id": "508d5250-7399-4b65-a574-3da53d9ddc25",
"valid_from": "2026-05-15",
"valid_to": "2026-05-15",
"created_at": "2026-05-16T09:21:05",
"modified_at": "2026-05-16T09:21:05"
}
Update a Suppression
Update individual fields of an existing suppression rule. Only PATCH is
supported; full PUT replacement returns 405 Method Not Allowed.
Request
curl -X PATCH "https://api.zeitstrom.com/api/v2/reviews/suppressions/7f3d2a10-5b7e-4c93-9a41-2f8c6de01b57/" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"valid_to": "2026-05-31"
}'
Delete a Suppression
Delete a suppression rule. Previously suppressed findings become visible
again in clients that apply the rules. On success, the API returns status
204 with no content.
Request
curl -X DELETE "https://api.zeitstrom.com/api/v2/reviews/suppressions/7f3d2a10-5b7e-4c93-9a41-2f8c6de01b57/" \
-H "Authorization: Token <YOUR_API_TOKEN>"