Time Tracking
Track working time by creating check-in and check-out events. This page covers the app-based timestamp API, which is the primary method for programmatic time tracking. For managing existing time records, see the Timespans, Workdays, and Workmonths endpoints.
Overview
There are two ways to track time via the API:
- App Timestamps (this page) - Create punch events with an intent-based API (
checkin,checkout, orauto). This is the recommended approach for integrating external time clocks or apps. - Employee Check-in/Check-out - Use the Employees endpoint to check employees in and out by their ID.
The App Timestamp Object
An app timestamp records a single punch event. It is returned by the create, list, and retrieve endpoints.
- Name
id- Type
- string (UUID)
- Description
Server-generated unique identifier for the punch. This is not the client-supplied
idsent on create.
- Name
created_at- Type
- string (ISO 8601)
- Description
Timestamp when the record was created.
- Name
timestamp_id- Type
- string (UUID) or null
- Description
The working-time timestamp created from this punch, or
nullif the punch could not be applied (seeerror).
- Name
employee_id- Type
- string (UUID)
- Description
The employee this punch belongs to.
- Name
device_id- Type
- string (UUID) or null
- Description
The hardware terminal that created the punch.
nullfor punches created with an API token.
- Name
intent- Type
- string
- Description
One of
auto,checkin, orcheckout.
- Name
time- Type
- string (ISO 8601)
- Description
The punch time in local time (Europe/Berlin), without a timezone offset.
- Name
error- Type
- object or null
- Description
nullif the punch was applied successfully. If the punch could not be converted into working time, this contains the validation error. Always check this field — see the note below.
- Name
meta- Type
- object or null
- Description
Client-supplied JSON metadata.
- Name
project_id- Type
- string (UUID) or null
- Description
The project stored on the punch record.
nullunless explicittag_assignmentswere sent alongsideproject_idon create.
- Name
tag_assignments- Type
- array
- Description
Project tag assignments recorded on this punch. Each entry contains
tag_id(project UUID),type(relativeorabsolute), andvalue. Note that project and tag assignments submitted on create are applied to the resulting timespan, not echoed here — this list is usually empty. Read the effective assignments via the Timespans endpoint.
- Name
employee_comment- Type
- string or null
- Description
Comment provided by the employee.
Create an App Timestamp
Create a punch event for an employee. Use intent: checkin to start a working session, intent: checkout to end it, or intent: auto to let the server decide: if the employee has an open timespan they are checked out, otherwise they are checked in.
- Name
intent- Type
- string
- Description
One of
auto,checkin, orcheckout. Required.
- Name
employee_id- Type
- string (UUID)
- Description
The employee to punch in or out. Required.
- Name
time- Type
- string (ISO 8601)
- Description
The punch time, interpreted as local time (Europe/Berlin). Do not include a timezone offset. Required unless
time_utcis provided.
- Name
time_utc- Type
- string (ISO 8601)
- Description
The punch time in UTC. When provided, the server converts it to local time and populates
timeautomatically. Optional.
- Name
id- Type
- string
- Description
Client-generated identifier for this punch, at most 64 characters. Used for deduplication — see Retries and Idempotency. Not echoed back; the
idin the response is a server-generated UUID. Optional, but recommended.
- Name
project_id- Type
- string (UUID)
- Description
Project to book the resulting working time on. It is applied to the created timespan as a single
relativetag assignment of 100%, which you can read back via the Timespans endpoint. Iftag_assignmentsis also given, those assignments take precedence. Optional.
- Name
tag_assignments- Type
- array
- Description
Project tag assignments for the resulting timespan. Each entry contains
tag_id(project UUID),type(relativeorabsolute), andvalue(number). Forrelativeassignments,valuemust be between 0 and 100. Optional.
- Name
employee_comment- Type
- string
- Description
Comment by the employee. Stored on the punch and copied to the resulting timespan. Optional.
- Name
meta- Type
- object
- Description
Arbitrary JSON metadata stored with the punch. Currently only persisted when a client-supplied
idis included in the same request. Optional.
A failed punch still returns 201 Created. If the punch could not be
converted into working time (for example, a checkout without an open
timespan), the failure is reported in the error field of the response
body and timestamp_id is null. Always inspect error — checking the
HTTP status code alone is not sufficient.
Request (check-in)
curl -X POST "https://api.zeitstrom.com/api/v2/devices/app-timestamps/" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"intent": "checkin",
"employee_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"time": "2024-06-20T08:00:00",
"id": "clock-7-punch-000123",
"project_id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890"
}'
Request (check-out, UTC time)
curl -X POST "https://api.zeitstrom.com/api/v2/devices/app-timestamps/" \
-H "Authorization: Token <YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"intent": "checkout",
"employee_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"time_utc": "2024-06-20T15:00:00",
"id": "clock-7-punch-000124",
"employee_comment": "Left early for a doctor appointment"
}'
Response (201, punch applied)
{
"id": "b7d2f8a1-4c6e-4b2a-9f3d-2e5a8c1b7d90",
"created_at": "2024-06-20T08:00:03",
"timestamp_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"employee_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"device_id": null,
"intent": "checkin",
"time": "2024-06-20T08:00:00",
"error": null,
"meta": null,
"project_id": null,
"tag_assignments": [],
"employee_comment": null
}
Response (201, punch failed)
{
"id": "c8e3a9b2-5d7f-4c3b-8a4e-3f6b9d2c8ea1",
"created_at": "2024-06-21T17:00:02",
"timestamp_id": null,
"employee_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"device_id": null,
"intent": "checkout",
"time": "2024-06-21T17:00:00",
"error": {
"detail": "Error when adding checkout timestamp. No open timespan exists."
},
"meta": null,
"project_id": null,
"tag_assignments": [],
"employee_comment": null
}
Retries and Idempotency
Create requests may be retried safely. A request is treated as a duplicate and does not create a second punch when one of the following matches an existing record:
- The client-supplied
id(recommended — generate a stable id per punch, at most 64 characters). - A
local_idkey insidemeta, if noidwas sent. - The combination of
employee_id,time, andintent, if neither of the above was sent.
For a duplicate, the endpoint responds with 201 Created and returns the existing record instead of creating a new one. The tag assignments of the existing punch (and its timespan) are replaced with the values in the request — retrying without the original project_id or tag_assignments removes existing project assignments, so always retry with the exact same request body.
Unknown Employees
If employee_id does not match an employee of the authenticated caller's institution, the request is rejected with 400 Bad Request and nothing is stored. The error is reported under the employee_id key:
Response (400, unknown employee)
{
"employee_id": [
"Object with uid=a1b2c3d4-e5f6-7890-abcd-ef1234567890 does not exist."
]
}
Artemis terminals are the exception. They sync an offline queue and retry a rejected punch indefinitely, so a punch referencing an employee that no longer exists on the server would block the queue forever. For requests authenticated as a device whose model starts with Artemis, this one case is therefore acknowledged with 200 OK so the terminal can discard the punch. The body carries the same error detail as the 400 above, and nothing is stored — no app timestamp is created and no working time is booked.
The 200 acknowledgement applies only to Artemis devices and only to the
unknown-employee case. Every other validation error still returns 400 for
Artemis devices, and all other clients — including other device models and
token-authenticated users — always receive 400 for an unknown employee.
Because this response carries no punch record, it is distinguishable from a
successful create by its status code (200 rather than 201) and by the
absence of an id field.
List all App Timestamps
Retrieve a paginated list of punch events. Use this to read back submitted punches, for example to reconcile an external time clock.
Query Parameters
- Name
ids- Type
- string
- Description
Filter by app timestamp IDs, pipe-separated.
- Name
limit- Type
- integer
- Description
Number of results per page (default 100, maximum 1000).
- Name
offset- Type
- integer
- Description
Pagination offset.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/devices/app-timestamps/?limit=100" \
-H "Authorization: Token <YOUR_API_TOKEN>"
Response
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "b7d2f8a1-4c6e-4b2a-9f3d-2e5a8c1b7d90",
"created_at": "2024-06-20T08:00:03",
"timestamp_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"employee_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"device_id": null,
"intent": "checkin",
"time": "2024-06-20T08:00:00",
"error": null,
"meta": null,
"project_id": null,
"tag_assignments": [],
"employee_comment": null
}
]
}
Retrieve an App Timestamp
Get details of a specific punch event by its server-generated UUID.
Request
curl -X GET "https://api.zeitstrom.com/api/v2/devices/app-timestamps/b7d2f8a1-4c6e-4b2a-9f3d-2e5a8c1b7d90/" \
-H "Authorization: Token <YOUR_API_TOKEN>"