Skip to content

Request an integration

Tell us which system you want to connect. We review every request weekly and publish a step-by-step guide or build the connection.

Data model

The TimeTracking entities (organisation, person, client, placement, claim, day, conflict, leave, expense, shift, export run, period) and how they relate.

Last updated: · Markdown version

Everything belongs to one organisation (org). An API key, webhook or user session never sees another org's data.

Organisation
├── Person ───────────┐            (employee / flex worker; employee_number, email, active)
├── Client ──┐        │            (approval_mode office|client|both, mail_domains, contacts)
│            └── Placement ◄───────┘   person × client, starts_on … ends_on, ref
│                  ├── Claim*      raw hours from one source (append-only)
│                  ├── Day         one resolved value per placement per date (timesheet_day)
│                  │     └── Conflict   when claims disagree (candidates → office picks one)
│                  ├── Shift       planned work (roster), draft → published
│                  └── Expense     km, travel_time, public_transport, parking, meal, other
├── Leave request    person, leave type, starts_on … ends_on, minutes_per_day
├── Export mapping   JSON recipe for a payroll file (presets + org-specific)
├── Export run       an immutable, committed payroll file + pay lines
└── Period           a locked date range (week, four_weeks, semi_month, month)

Entities

Entity API resource Key fields (responses are snake_case) Notes
Person /people id, employee_number, first_name, last_name, email, phone, locale, active, user_id, external_source, external_ref employee_number is the payroll key and must be digits for the SD Worx preset. user_id is set once the person has app access.
Client /clients id, name, external_ref, external_source, approval_mode, mail_domains, client_contacts[] approval_mode decides who must approve hours (see status lifecycle). mail_domains links inbound email to the client.
Placement /placements id, person_id, client_id, ref, role_title, starts_on, ends_on, active, external_source, external_ref Hours are always recorded on a placement and a date. ref is your placement number and appears in exports as placementRef.
Claim /claims id, placement_id, work_date, source, minutes, start_min, end_min, break_min, note, confidence, source_ref, created_at One raw input. Never edited; a newer claim from the same source replaces the older one. See sources and conflicts.
Day /days, /org/week id, placement_id, person_id, work_date, minutes, start_min, end_min, break_min, status, resolution, has_conflict, claim_ids, approved_by_office_at, approved_by_client, approved_by_client_at, export_run_id, version, updated_at Derived from claims. minutes is null while the day is in conflict. version increases with every change.
Conflict /conflicts id, dayId, workDate, personName, clientName, candidates[{claimId, source, minutes}] Resolved with POST /conflicts/{id}/resolve {claimId}.
Leave request /leave id, person_id, leave_type_id, starts_on, ends_on, minutes_per_day, status (requested, approved, rejected, cancelled) Leave types per org: vacation, sick, special, unpaid by default (/leave/types).
Expense /expenses id, person_id, placement_id, work_date, kind, km, minutes, amount_cents, status (submitted, approved, rejected, exported) km is priced with the placement's per_km component. Without one, amount_cents is 0.
Shift /shifts id, client_id, placement_id (null = open shift), work_date, start_min, end_min, break_min, status (draft, published), requires_approval A plan only. Shifts never become hours by themselves.
Shift request /shift-requests id, kind (claim, swap), shift_id, requester, target (swap), target_shift_id (exchange), status (pending_colleague, pending_planner, approved, rejected, declined, cancelled) Claims of open shifts and swaps between colleagues. Only an approved request changes the roster.
Export run /exports/runs id, mapping_id, mapping_snapshot, starts_on, ends_on, row_count, content_hash, pay_lines, warnings Immutable and reproducible. The file is at /exports/runs/{id}/file.
Period (POST /periods/lock) kind, starts_on, ends_on, locked_at See periods and locking.

Identifiers

  • TimeTracking IDs are UUIDs. Store them in your system.
  • External IDs (v1.1) give every person, client and placement an optional (external_source, external_ref) pair. Examples: ("bullhorn", "12345"), ("carerix", "PL-555"). Upsert by that pair with PUT /people/by-external/{source}/{ref} (also /clients/... and /placements/...). A placement can point at its person and client by their external refs (personExternalRef, clientExternalRef) from the same source. See the API reference.
  • Older natural keys that still work: employee_number (people; the CSV import matches on it), placement ref (the CSV import matches on it), client name (the CSV import matches case-insensitively).

Units and time

  • Durations are integer minutes. Money is integer cents. Dates are YYYY-MM-DD in the org's timezone (default Europe/Amsterdam).
  • start_min and end_min are minutes after midnight, from 0 to 1439. A shift that ends at or before its start crosses midnight. It belongs to the date it started on.
  • Weeks are ISO weeks (Monday–Sunday). Endpoints that take week accept any date inside the week.

Request vs response naming

Request bodies use camelCase (placementId, workDate, startMin). Most responses return database rows in snake_case (placement_id, work_date, start_min). Aggregated views (/org/week, /conflicts, /client/approve/{token}, export preview) use camelCase. The API reference shows the real shape of every response.

Roles

Role Typical user Can do
owner, admin Agency management Everything, including API keys, office users, webhooks, period lock, kiosk devices, export formats, GDPR erasure
office, planner Intercedent / planner Master data, hours, approvals, exports, rosters, leave and expense decisions
accountant External accountant Read only
employee Flex worker Own hours (app/kiosk), own leave, expenses, availability
client (no account) Client contact Approve, correct or reject via a magic link

API keys act as accountant (read scope), office (write) or admin + office (admin). No key can create keys or change office roles. See authentication.