Daily Reports
Daily reports (Tagesberichte) document what happened on a construction site or project on a single calendar day: who was on site and for how long, the weather, subcontractors, activities, material usage, comments, photos, and signatures. A report is identified by the combination of a project and a date — it is not a stored object of its own, but materializes from the individual entries recorded for that day, either authored on site in the mobile app or filled in automatically from time tracking.
If your API token is restricted to specific permissions, it needs the
matching scope for each operation: daily_reports:view for all GET
requests, and daily_reports:edit for the autofill and photo-upload-token
endpoints. Autofilling a report that has already been submitted or approved
additionally requires daily_reports:approve. Requests without the
required permission return 403 Forbidden.
Daily reports are authored — and their status changed (submitted, approved, reopened) — in the Zeitstrom web and mobile apps. Through the API you can read reports and their entries, trigger the time-tracking autofill, download PDFs, and request photo upload tokens. Creating entries and changing a report's status are not currently available for API tokens.
The Report Object
A report is the group of all entries that share a project and a date.
Reports only exist for projects that have daily reports enabled in the
project's settings, and only for days that have at least one entry. The
tag_id is the project's id as returned by the
Projects API.
Every report has a computed status describing its position in the review lifecycle:
draft— the report is being worked on and can be edited on site.submitted— the site crew handed the report in for review. Only supervisors (users with the approve permission) may still change it.closed— the report was approved. Likesubmitted, it is locked for regular editors.
- Name
id- Type
- string
- Description
Synthetic identifier of the report in the form
<tag_id>|<date>, e.g.3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31|2024-06-18. Read-only.
- Name
date- Type
- string (YYYY-MM-DD)
- Description
The calendar day the report covers.
- Name
tag_id- Type
- string (UUID)
- Description
The project the report belongs to.
- Name
status- Type
- string
- Description
Computed report status:
draft,submitted, orclosed.
Field Configurations
Which fields a daily report contains is configurable per organization, and
the configuration is versioned by date. Your organization keeps a list of
configurations, each with a valid_from date; the configuration that applies
to a report is the one with the most recent valid_from on or before the
report's date (a configuration becomes active on its valid_from day). If no
custom configuration exists, a default form applies with these fields:
| Field id | Type | Label (German) |
|---|---|---|
weather | weather | Witterung |
employee-working-times | employee-working-times | Mitarbeitende |
subcontractors | subcontractors | Nachunternehmen |
activities | activities | Tätigkeiten |
materials | string | Material- / Geräteeinsatz |
comments | string | Bemerkungen / Behinderungen |
photos | image | Fotos |
signatures | signature | Unterschriften |
Versioning has two consequences you will notice in the API:
- Every entry is interpreted and validated against the configuration that is active on the entry's date, not the one active today. Historical reports keep the form they were written with, even after the organization changes its report layout.
- Entries whose field id does not exist in the configuration active for their date (for example, a field that was later removed) are omitted from entry listings and PDFs — they have no schema to render.
Use the field-types endpoint to discover the available field types and how entries of each type are grouped.
The Entry Object
Entries are append-only: nothing is ever updated in place. Each entry
belongs to a logical group identified by its group_id, which combines the
report's date and tag_id with type-specific keys (for example, one group
per employee for working times, or one group per author-and-text for
comments). The most recent entry of a group is its current value; older
entries are the group's history. An entry with burned: true is a tombstone
that marks its group as deleted.
Entries written by the system — the time-tracking autofill and the automatic
weather capture — have author_id: null; the affected employee is carried in
on_behalf_of_id. Manually authored entries carry the author, and
on_behalf_of_id names the person the entry is about (e.g. who signed, or
whose working time was corrected).
- Name
id- Type
- string (UUID)
- Description
Unique identifier of the entry. Read-only.
- Name
group_id- Type
- string
- Description
Pipe-separated grouping key, starting with
dateandtag_idfollowed by the field type's grouping values. Read-only.
- Name
group_count- Type
- integer
- Description
Number of entries in this entry's group that match the request's filters, including tombstones — filtering by
idsexcludes the group's other entries from the count. Only present in list responses. Read-only.
- Name
field_id- Type
- string
- Description
Id of the report field the entry belongs to, as defined in the active field configuration (e.g.
comments).
- Name
type- Type
- string
- Description
The field's type:
weather,employee-working-times,subcontractors,activities,string,image, orsignature.
- Name
date- Type
- string (YYYY-MM-DD)
- Description
The report day the entry belongs to.
- Name
tag_id- Type
- string (UUID)
- Description
The project the entry belongs to.
- Name
author_id- Type
- string (UUID) or null
- Description
The user who authored the entry, or
nullfor system-generated entries (autofill, weather capture).
- Name
author_name- Type
- string or null
- Description
Full name of the author, or
null.
- Name
on_behalf_of_id- Type
- string (UUID) or null
- Description
The user the entry is about (e.g. the employee whose hours are recorded, or the person who signed), or
null.
- Name
on_behalf_of_name- Type
- string or null
- Description
Full name of the
on_behalf_ofuser, ornull.
- Name
burned- Type
- boolean
- Description
truemarks the entry as a tombstone: the group it belongs to should be treated as deleted if the tombstone is the group's latest entry.
- Name
submitted_at- Type
- string (ISO 8601, local time) or null
- Description
When the entry reached the server, e.g.
2024-06-18T16:42:07.nullfor system-generated entries.
- Name
created_at- Type
- string (ISO 8601, local time)
- Description
When the entry was stored. Read-only.
- Name
modified_at- Type
- string (ISO 8601, local time)
- Description
When the entry was last modified. Read-only.
Type-specific value fields
In addition to the common properties above, each entry carries the value fields of its type:
weather—time(string, a clock time such as08:00),temperature,precipitation,cloud_cover(each a number ornull), andwind(a[speed, direction]pair with the direction in degrees0–359, ornull). Grouped bytime, so a report holds one weather row per configured time slot.employee-working-times—hours(number between0and24). Grouped byon_behalf_of_id: one row per employee and day.subcontractors—name(string),employees(integer),hours(number ornull),comment(string ornull). Grouped byon_behalf_of_idandname.activities—text(string). Grouped byon_behalf_of_idandtext, so the same activity text for the same person deduplicates.string—value(string). Used by the defaultmaterialsandcommentsfields. Grouped byon_behalf_of_idandvalue.image—image_id(string),image_key(string ornull, the S3 object key from the photo upload flow),image_url(string ornull— a pre-signed download URL derived fromimage_key, valid for one hour),latitude/longitude(numbers ornull), andtaken_at(string ornull). Grouped byon_behalf_of_idandimage_id.signature—image(string, adata:image/...data URL of the signature). Grouped byon_behalf_of_id: one signature per person per report.
List all Reports
Retrieve a paginated list of report descriptors, one per project and date that has at least one entry. Results are ordered by date descending, then by project id, and cover only projects that have daily reports enabled and that your token is allowed to see.
Query Parameters
- Name
date_from- Type
- string (YYYY-MM-DD)
- Description
Only include reports on or after this date. Invalid values are ignored.
- Name
date_to- Type
- string (YYYY-MM-DD)
- Description
Only include reports on or before this date. Invalid values are ignored.
- Name
projects- Type
- string
- Description
Restrict to specific projects by passing a pipe-separated list of project ids (UUIDs). Invalid UUIDs are dropped from the list; if no valid id remains, the result is empty.
- Name
status- Type
- string
- Description
Pipe-separated set of statuses to keep, e.g.
status=submitted|closed. Valid values aredraft,submitted, andclosed; unknown values are ignored, and an empty filter returns all reports.
- 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/daily-reports/reports/?date_from=2024-06-17&date_to=2024-06-18&status=draft|submitted" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31|2024-06-18",
"date": "2024-06-18",
"tag_id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31",
"status": "submitted"
},
{
"id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31|2024-06-17",
"date": "2024-06-17",
"tag_id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31",
"status": "draft"
}
]
}
List Field Types
Retrieve the available field types and the keys entries of each type are
grouped by. Every group_by list starts with the common date and tag_id
keys, followed by the type's own grouping values.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/daily-reports/reports/field-types/" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"count": 7,
"next": null,
"previous": null,
"results": [
{ "id": "weather", "group_by": ["date", "tag_id", "time"] },
{ "id": "employee-working-times", "group_by": ["date", "tag_id", "on_behalf_of_id"] },
{ "id": "subcontractors", "group_by": ["date", "tag_id", "on_behalf_of_id", "name"] },
{ "id": "activities", "group_by": ["date", "tag_id", "on_behalf_of_id", "text"] },
{ "id": "string", "group_by": ["date", "tag_id", "on_behalf_of_id", "value"] },
{ "id": "image", "group_by": ["date", "tag_id", "on_behalf_of_id", "image_id"] },
{ "id": "signature", "group_by": ["date", "tag_id", "on_behalf_of_id"] }
]
}
Retrieve Report Status
Get the current status of a single report. A report without any recorded
status transition is a draft.
Query Parameters
- Name
tag- Type
- string (UUID)
- Description
The project id. Required. An unknown or inaccessible project returns a
400validation error.
- Name
date- Type
- string (YYYY-MM-DD)
- Description
The report date. Required.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/daily-reports/reports/status/?tag=3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31&date=2024-06-18" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"tag_id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31",
"date": "2024-06-18",
"status": "submitted"
}
Autofill a Report
Compute and store report entries from the day's time tracking on the
project. Only fields whose active configuration carries
autofill_from_tracking and whose type is employee-working-times or
activities are filled — with the default configuration these
are employee-working-times (each employee's tracked hours on the project,
rounded to two decimals) and activities (one entry per distinct tracking
comment and employee).
The operation creates entries as a side effect. System-written entries
have author_id: null. The autofill is idempotent: repeated calls converge
to the same state, unchanged values are skipped, and a value that was
manually corrected by a user is never overwritten.
Autofilling a report that is submitted or closed requires the
daily_reports:approve permission; without it the request returns
403 Forbidden.
- Name
tag- Type
- string (UUID)
- Description
The project id. Required. An unknown or inaccessible project returns a
400validation error.
- Name
date- Type
- string (YYYY-MM-DD)
- Description
The report date. Required.
- Name
field- Type
- string
- Description
Optional field id to restrict the autofill to a single field, e.g.
activities. A field that is not autofillable results infilled: [].
Request
curl -X POST "https://api.zeitstrom.com/api/v2/daily-reports/reports/autofill/" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"tag": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31",
"date": "2024-06-18"
}'
Response
{
"tag_id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31",
"date": "2024-06-18",
"filled": ["employee-working-times", "activities"]
}
Download a Report PDF
Render a single report as a print-friendly PDF. The response streams the PDF
binary (Content-Type: application/pdf) with a filename of the form
Tagesbericht-<project code>-<date>.pdf. The PDF contains the fields of the
configuration active for the report's date, with the report's status shown
in the header.
Query Parameters
- Name
tag- Type
- string (UUID)
- Description
The project id. Required. An unknown or inaccessible project returns a
400validation error.
- Name
date- Type
- string (YYYY-MM-DD)
- Description
The report date. Required.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/daily-reports/reports/pdf/?tag=3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31&date=2024-06-18" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-o "Tagesbericht-2024-06-18.pdf"
List all Entries
Retrieve a paginated list of report entries, projected through the field
configuration active for each entry's date. Entries of fields that no longer
exist in the active configuration are omitted. To reconstruct the current
content of a report, request grouped=1 for a single project and date and
treat groups whose latest entry is burned: true as deleted.
Query Parameters
- Name
tags- Type
- string
- Description
Restrict to specific projects by passing a pipe-separated list of project ids (UUIDs). If any id is invalid or refers to a project you cannot see, the result is empty.
- Name
daterange- Type
- string
- Description
Inclusive date range in the form
YYYY-MM-DD|YYYY-MM-DD, e.g.daterange=2024-06-18|2024-06-18. Both dates are required; a malformed or half-open range yields an empty result.
- Name
grouped- Type
- string
- Description
Set
grouped=1to return only the most recent entry per group. The returnedgroup_countstill reflects the full group size.
- Name
ids- Type
- string
- Description
Restrict to specific entries by passing a pipe-separated list of entry ids (UUIDs). Invalid UUIDs are dropped from the list; if no valid id remains, the result is empty.
- 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/daily-reports/entries/?tags=3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31&daterange=2024-06-18|2024-06-18&grouped=1" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"group_id": "2024-06-18|3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31|508d5250-7399-4b65-a574-3da53d9ddc25",
"id": "6b0f2d84-3c9e-4f17-8a52-b1d4e7c90a63",
"field_id": "employee-working-times",
"type": "employee-working-times",
"created_at": "2024-06-18T17:02:11",
"modified_at": "2024-06-18T17:02:11",
"submitted_at": null,
"date": "2024-06-18",
"tag_id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31",
"author_id": null,
"on_behalf_of_id": "508d5250-7399-4b65-a574-3da53d9ddc25",
"author_name": null,
"on_behalf_of_name": "Anna Schmidt",
"burned": false,
"hours": 7.75,
"group_count": 1
},
{
"group_id": "2024-06-18|3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31|e7c9a4d2-1f38-4b6a-9c05-8d2f7b3e6a14|Lieferung Schalholz verspätet",
"id": "9d47c1f0-5e2b-4a86-b3f9-0c61d8a24e57",
"field_id": "comments",
"type": "string",
"created_at": "2024-06-18T16:42:09",
"modified_at": "2024-06-18T16:42:09",
"submitted_at": "2024-06-18T16:42:07",
"date": "2024-06-18",
"tag_id": "3f2b8c1e-9a47-4d05-b8a1-6c2d94e07f31",
"author_id": "e7c9a4d2-1f38-4b6a-9c05-8d2f7b3e6a14",
"on_behalf_of_id": "e7c9a4d2-1f38-4b6a-9c05-8d2f7b3e6a14",
"author_name": "Jonas Weber",
"on_behalf_of_name": "Jonas Weber",
"burned": false,
"value": "Lieferung Schalholz verspätet",
"group_count": 1
}
]
}
Get a Photo Upload Token
Generate a pre-signed upload token for a daily-report photo (at most 5 MB).
The response contains a pre-signed S3 url and form fields, valid for 12
hours. Upload the photo as a multipart/form-data POST to url, including
all fields plus the file itself. The returned fields.key is the object
key that photo entries store as their image_key; when entries are read,
the server signs it back into a temporary image_url download link. Keys
are validated to lie inside your organization's upload namespace.
- Name
employee_id- Type
- string (UUID)
- Description
The employee the photo belongs to. Must be an active (non-archived) employee of your organization. Required.
- Name
filename- Type
- string
- Description
Name of the file, used as part of the storage key.
- Name
filetype- Type
- string
- Description
MIME type of the file (e.g.
image/jpeg), used to derive the file extension.
- Name
filesize- Type
- integer
- Description
Size of the file in bytes. Validated against the 5 MB limit.
Request
curl -X POST "https://api.zeitstrom.com/api/v2/daily-reports/entries/upload-photo-token/" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"employee_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"filename": "betonage-nord",
"filetype": "image/jpeg",
"filesize": 2048576
}'
Response
{
"url": "https://s3.eu-central-1.amazonaws.com/zeitstrom-uploads",
"fields": {
"key": "i-f4a5b6c7-d8e9-0123-fabc-456789012345/e-a1b2c3d4-e5f6-7890-abcd-ef1234567890/daily-reports/2024/06/18/0d3e2b1a-4c5d-6e7f-8901-234567890abc/2024-06-18_4f2a_betonage-nord.jpg",
"AWSAccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"policy": "eyJleHBpcmF0aW9uIjogIjIwMjQtMDYtMTlUMDY6MzA6MDBaIiwgImNvbmRpdGlvbnMiOiBbXX0=",
"signature": "hV0kwGx0ZQKgQnJ1zW0m9dEXAMPLE"
}
}