Authentication
How to authenticate to the TimeTracking API with org API keys (read, write or admin scope) or user access tokens, what each credential may do, and how to create, rotate and revoke keys.
Last updated: · Markdown version
Every /api/v1 request carries a bearer credential:
Authorization: Bearer tt_live_…
| Credential | Scopes as stored | Acts as | Use for |
|---|---|---|---|
| Read key | ["read"] |
role accountant (read-only) |
BI, reporting, read-only assistants |
| Write key | ["read","write"] |
role office |
Integrations, iPaaS, CLI, MCP |
| Admin key | ["read","admin","write"] (admin implies write) |
roles admin + office |
Automations that also lock periods, manage webhooks or kiosk devices |
| User access token | — | the signed-in user's own roles in the org | First-party apps, creating API keys, managing office users, employee self-service (/me/*) |
Keys look like tt_live_ followed by 32 characters.
Public exceptions:
- The client approval endpoints
/client/approve/{token}…take noAuthorizationheader. The token in the URL is the credential. /api/v1/openapi.jsonis public.
Create a key
An admin (role owner or admin) creates read and write keys in "Regels & koppelingen" → "API-sleutels" (tick "Mag ook schrijven" for write). Admin-scope keys can only be created over the API, with an admin user token. The dashboard has no option for them yet:
curl -s -X POST "$TT/api-keys" -H "Authorization: Bearer $ADMIN_USER_TOKEN" -H "content-type: application/json" \
-d '{"name":"Payroll automation","scopes":["read","admin"]}'
# → {"data":{"key":"tt_live_…"}} shown once; only a SHA-256 hash is stored
scopesis any ofread,write,admin. It defaults to["read"].- Asking for
adminaddswriteautomatically. The captured key list shows"scopes":["read","admin","write"]. nameis 1–80 characters.- No API key can create keys or change office roles, not even an admin key. Such calls return 403
{"code":"forbidden","message":"Not available with an API key"}.
List and revoke keys with an admin user token or an admin key:
curl -s "$TT/api-keys" -H "Authorization: Bearer $ADMIN_USER_TOKEN"
# → [{"id":"02292779-…","name":"docs-v12 admin","prefix":"tt_live_JV2m","scopes":["read","admin","write"],"last_used_at":null,"revoked_at":null,"created_at":"…"}]
curl -s -X DELETE "$TT/api-keys/02292779-e533-4e02-8220-84a964e85b4f" -H "Authorization: Bearer $ADMIN_USER_TOKEN"
# → {"data":{"revoked":true}}
last_used_at is updated at most once a minute. A key stops working automatically when its creator loses the owner/admin role in the org (for example after leaving). Create integration keys from a long-lived admin account.
Roles and what a credential can do
| Operation | read key | write key | admin key | office user | admin user | employee token |
|---|---|---|---|---|---|---|
GET /org/week, /conflicts, /days, /claims |
yes | yes | yes | yes | yes | — (use /me/week) |
GET /people, /clients, /placements (+ /{id}) |
yes | yes | yes | yes | yes | — |
GET /leave, /expenses, /shifts, /inbox, /leave/types |
yes | yes | yes | yes | yes | own leave/expenses |
GET /exports/runs, /exports/runs/{id}, /file |
yes | yes | yes | yes | yes | — |
POST /exports (preview and commit) |
403 | yes | yes | yes | yes | — |
| Create/update/upsert/batch/deactivate people, clients, placements; claims; approvals; leave/expense decisions; shifts; import | 403 (API key is read-only) |
yes | yes | yes | yes | own claims/leave/expenses only |
POST /periods/lock; webhooks (create, list, delete, deliveries, test, replay, rotate-secret); POST /kiosk-devices; POST /people/{id}/anonymize; list/revoke API keys |
403 | 403 (Admin role required) |
yes | 403 | yes | — |
| Create API keys; add/remove office roles | 403 | 403 | 403 (Not available with an API key) |
403 | yes | — |
/me/* |
403 | 403 | 403 (No employee profile in this organisation) |
if they have a person profile | same | yes |
How enforcement works:
- A read key that sends any
POST/PUT/PATCH/DELETEgets403 {"code":"forbidden","message":"API key is read-only"}. This happens before the endpoint runs. It also applies toPOST /exportswith"mode":"preview", which is why export preview needs a write or admin key. - Admin-only endpoints check the role. Write keys get
403 Admin role required.
User access tokens
First-party apps sign in with an email code (Supabase OTP). The access token works on every endpoint the user's roles allow. When a user belongs to several orgs, send x-org-id: <org uuid> to choose one; otherwise the oldest membership is used. API keys are always bound to one org and ignore x-org-id.
Security practices
- Store keys in a secret manager or environment variable (
TT_API_KEY). Never commit them or put them in URLs. - Use one key per integration so you can revoke it alone. The key name shows up in the key list.
- Give each key the least scope it needs. Use
readfor reporting and read-only assistants,writefor syncs, andadminonly for automations that must lock periods or manage webhooks. - Rotate a key by creating the new one, deploying it, then revoking the old one. Keys have no expiry.
- All traffic is HTTPS. Key, webhook, lock and export actions are written to the audit log ("Audit log").
Errors
| Status | code |
Typical message |
|---|---|---|
| 401 | unauthenticated |
Missing bearer token · Invalid or revoked API key · Invalid token |
| 403 | forbidden |
API key is read-only · Admin role required · Not available with an API key · Office role required · No employee profile |
| 429 | rate_limited |
Rate limit of 600 requests per minute exceeded (see rate limits) |
Planned: OAuth2 for marketplace apps, and sandbox/test keys. Today every key is a live key for one org.