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:

  1. App Timestamps (this page) - Create punch events with an intent-based API (checkin, checkout, or auto). This is the recommended approach for integrating external time clocks or apps.
  2. 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 id sent 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 null if the punch could not be applied (see error).

  • 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. null for punches created with an API token.

  • Name
    intent
    Type
    string
    Description

    One of auto, checkin, or checkout.

  • 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

    null if 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. null unless explicit tag_assignments were sent alongside project_id on create.

  • Name
    tag_assignments
    Type
    array
    Description

    Project tag assignments recorded on this punch. Each entry contains tag_id (project UUID), type (relative or absolute), and value. 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.


POST/api/v2/devices/app-timestamps/

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, or checkout. 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_utc is 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 time automatically. 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 id in 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 relative tag assignment of 100%, which you can read back via the Timespans endpoint. If tag_assignments is 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 (relative or absolute), and value (number). For relative assignments, value must 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 id is included in the same request. Optional.

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:

  1. The client-supplied id (recommended — generate a stable id per punch, at most 64 characters).
  2. A local_id key inside meta, if no id was sent.
  3. The combination of employee_id, time, and intent, 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.


GET/api/v2/devices/app-timestamps/

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
    }
  ]
}

GET/api/v2/devices/app-timestamps/:id/

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>"

Was this page helpful?