# API changelog

> Changes to the TimeTracking REST API, webhooks, CLI and MCP server, newest first.

URL: https://timetracking.tech/developers/api/changelog
Last updated: 2026-10-24

## Late hours and reminders — October 2026

- **`late` in `GET /org/week`.** Rows get `late` (boolean), `kpis.late` counts people, and `deadline` gives the deadline of the payroll period containing the week (`date`, `minute`, `passed`).
- **Notifications for employees.** `GET /me/notifications` (items + unread count) and `POST /me/notifications/read`.
- **Reminder settings.** `GET /org/reminders` and `PUT /org/reminders` (admin): deadline weekday + time, in-app reminders on/off, WhatsApp follow-up on/off and delay (default Monday 09:00, WhatsApp after 90 minutes). Reminders never go by email.

## 1.1.0 update — October 2026 (fixes)

- **API key scope `admin`.** It implies `write`. Admin keys can lock periods, manage webhooks (incl. deliveries, test, replay, rotate-secret) and kiosk devices, anonymize people, and list/revoke API keys. No API key can create keys or change office roles (403 `Not available with an API key`). Admin keys are created with `POST /api-keys` and an admin user token.
- **Read keys** can now list `/leave`, `/expenses`, `/shifts` and `/inbox`. Export preview (`POST /exports`) still needs a write or admin key.
- **`Idempotency-Key` on every authenticated write route**, including `/exports`, `/days/approve`, `/approval-links`, `/periods/lock`, `/weeks/submit`, `/conflicts/{id}/resolve` and `/import`.
- **Events.** `person.*` and `placement.*` fire from every API create/update path (`POST`, `PATCH`, by-external, batch; `DELETE` → `*.updated` with `active:false`). Payloads now carry only the ID. New events `client.created`, `client.updated`, `conflict.resolved` (21 in total).
- **Webhook retries.** Exactly 7 delivery attempts (retries after 1 m, 5 m, 30 m, 2 h, 6 h, 12 h).
- **Windows-1252.** `GET /exports/runs/{id}/file` delivers mappings with `encoding: "windows-1252"` as Windows-1252 (Latin-1 bytes; unsupported characters → `?`).
- **Claims on exported/locked days** are refused with 423 before anything is stored. New message: `This day is exported or locked; book a correction in an open period`.
- **Client by-external upserts** keep their external reference on repeat calls.
- **People write responses** no longer include `kiosk_pin_hash`.
- **Kiosk PINs** are exactly 6 digits. The MCP tool and Claude Skill descriptions now say that approval links are emailed, and that `record_hours` returns 423 for exported days.

## 1.1.0 — October 2026

**Master data sync**
- `PUT /people/by-external/{source}/{ref}`, `PUT /clients/by-external/{source}/{ref}`, `PUT /placements/by-external/{source}/{ref}`: idempotent upsert by your own system's ID. Placements accept `personExternalRef` / `clientExternalRef` from the same source. Responses include `external_source`, `external_ref` and `created`.
- `GET`, `PATCH` and `DELETE` on `/people/{id}`, `/clients/{id}` and `/placements/{id}`. `PATCH` takes the full object. `DELETE` deactivates people and placements; a client can only be deleted when it has no placements (otherwise 409).
- Batch endpoints `POST /people/batch`, `/clients/batch`, `/placements/batch`, `/claims/batch`: up to 500 items, results per row (`{ok, failed, results}`).

**Reads**
- Cursor pagination (`limit`, `cursor`, `updated_since` → `{items, next_cursor}`) on `/people`, `/clients`, `/placements`. Without those parameters the v1 full-array response is unchanged.
- `GET /days`: resolved hours over any date range, with filters on status, person, placement, client and `updated_since`.
- `GET /claims`: raw claims over a date range.
- `GET /exports/runs`, `GET /exports/runs/{id}` (pay lines, warnings, mapping snapshot), `GET /exports/runs/{id}/file` (the committed file).

**Webhooks**
- New events: `person.created`, `person.updated`, `placement.created`, `placement.updated`, `claim.created`, `expense.decided`, `leave.cancelled`, `webhook.test` (`client.*` and `conflict.resolved` followed in the 1.1.0 update).
- `GET /webhooks/{id}/deliveries`, `POST /webhooks/{id}/test`, `POST /webhooks/{id}/rotate-secret`, `POST /webhook-deliveries/{id}/replay`.
- The spec now has a `webhooks` section with the event envelope schema.

**Reliability and security**
- `Idempotency-Key` header on writes (24 h replay, `idempotent-replayed: true`). See [idempotency](https://timetracking.tech/developers/api/idempotency) for the routes that do not honour it yet.
- Rate limit of 600 requests per minute per API key (429 + `Retry-After: 60`).
- Invalid JSON bodies return 422 instead of 500.
- Client approval now requires an emailed code when the client has an approver contact (`POST /client/approve/{token}/code`, `/verify` → `proof`, header `x-approval-proof`).
- Webhook URLs must be public HTTPS. Private and loopback addresses are rejected and redirects are not followed.

**Spec**
- OpenAPI 3.1 spec version `1.1.0`: 64 paths, `operationId`s, response schemas, error schema, examples.

**Dashboard (related)**
- Admins can edit export mappings ("Exportformaten") in the dashboard: copy a preset, edit columns, code tables and validation, set a default.

## 1.0.0 — October 2026

- First public API: 44 paths covering hours (`/org/week`, `/claims`, `/weeks/submit`, `/days/approve`, `/conflicts`), client approval links, exports (preview/commit), period lock, master data (`/people`, `/clients`, `/placements`, `/import`), rosters, leave, expenses, inbox, kiosk, employee self-service (`/me/*`), API keys and webhooks.
- 10 webhook events signed with `tt-signature` (HMAC-SHA256).
- CLI `@timetracking/cli` (`tt`), MCP server `@timetracking/mcp` (18 tools), Claude Skill `timetracking`.

## Planned

- Export-mapping CRUD over the API (today the dashboard only).
- OAuth2 for marketplace apps.
- Sandbox organisations and test keys.
- TypeScript and Python SDKs.
- Bulk export feed for BI.
- CLI and MCP commands for the v1.1 endpoints (use `tt api` meanwhile).
