Documentation menu
These are pre-release docs from the main branch.

API reference

18 operations in timers. Raw spec: openapi.json.

GET/api/v1/time-entries

GET /api/time-entries

Parameters

NameInTypeRequiredDescription
ticket_idquery—No
user_idquery—No
sincequery—No
limitqueryintegerNo

Responses

StatusDescription
200

Security: bearer

POST/api/v1/time-entries

POST /api/time-entries — manual entry (no timer).

Request body

CreateTimeEntryRequest

Responses

StatusDescription
200

Security: bearer

POST/api/v1/time-entries/approvals/decide

POST /api/time-entries/approvals/decide — bulk approve or bulk reject (`special:approve_time`). Only entries currently in the queue apply; every other id comes back with a per-item outcome. Emits one `time_entry.approval_*` event per applied entry.

Write-gate symmetry with `submit` and `reopen_entry`: an approver never signs off their own time. A self-owned id comes back as `own_entry` and is never transitioned; an owner or admin keeps the override, so a one-person org can still decide.

Request body

BulkDecisionRequest

Responses

StatusDescription
200
422unknown rejection reason_code

Security: bearer

GET/api/v1/time-entries/approvals/queue

GET /api/time-entries/approvals/queue — the approver queue (submitted entries by default). Approvers (`special:approve_time`) see the org queue and can filter `decided_by` for their own decision history; everyone else sees only their own submissions.

Parameters

NameInTypeRequiredDescription
statusquery—NoFilter by approval state; defaults to `submitted` (the queue).
user_idquery—NoNarrow to one submitter.
decided_byquery—NoPer-approver decision history: entries this approver decided.
limitqueryintegerNo

Responses

StatusDescription
200

Security: bearer

GET/api/v1/time-entries/{id}/approvals

GET /api/time-entries/:id/approvals — the append-only decision trail (`seq` ascending). Approvers and owner/admins read any trail; other users only their own entries'.

Parameters

NameInTypeRequiredDescription
idpathstringYes

Responses

StatusDescription
200
404entry not visible in scope (not_found)

Security: bearer

POST/api/v1/time-entries/{id}/fix

POST /api/time-entries/:id/fix — apply one verdict's fix to a queued entry (`special:approve_time`).

This is the server side of the queue's one-click fix: adopt the factual description the server assembled from the ticket, or cut the minutes that another entry of the same person already claimed. The entry stays in the queue afterwards — the approver still presses Approve, because a fix clears an objection and it does not sign anybody's time off.

Parameters

NameInTypeRequiredDescription
idpathstringYes

Request body

FixEntryRequest

Responses

StatusDescription
200
404entry not visible in scope (rls_sparse)
409entry locked by invoicing (time_entry_locked)
422entry not in the queue, or the fix is not allowed

Security: bearer

POST/api/v1/time-entries/{id}/reopen

POST /api/time-entries/:id/reopen — move a rejected entry back to draft (owner or admin) so it can be corrected and resubmitted.

Parameters

NameInTypeRequiredDescription
idpathstringYes

Responses

StatusDescription
200
409entry locked by invoicing (time_entry_locked)
422only rejected entries can be reopened

Security: bearer

POST/api/v1/time-entries/{id}/submit

POST /api/time-entries/:id/submit — the entry owner (or an admin) pushes a draft/rejected entry into the approver queue.

Parameters

NameInTypeRequiredDescription
idpathstringYes

Request body

SubmitEntryRequest

Responses

StatusDescription
200
404entry not visible in scope (rls_sparse)
409entry locked by invoicing (time_entry_locked)
422entry not in a submittable state

Security: bearer

GET/api/v1/time-gaps

GET /api/time-gaps?user_id= — manager-scoped report for one member. Owner/admin only; everyone else uses `/api/time-gaps/me`.

Parameters

NameInTypeRequiredDescription
fromquery—NoInclusive local-day start (YYYY-MM-DD). Defaults to yesterday.
toquery—NoInclusive local-day end (YYYY-MM-DD). Defaults to `from`.
user_idquery—NoManager report only: whose days. Requires owner/admin.

Responses

StatusDescription
200

Security: bearer

GET/api/v1/time-gaps/me

GET /api/time-gaps/me — the caller's day-level gap report (defaults to yesterday in the caller's timezone).

Parameters

NameInTypeRequiredDescription
fromquery—NoInclusive local-day start (YYYY-MM-DD). Defaults to yesterday.
toquery—NoInclusive local-day end (YYYY-MM-DD). Defaults to `from`.
user_idquery—NoManager report only: whose days. Requires owner/admin.

Responses

StatusDescription
200

Security: bearer

GET/api/v1/time-settings

GET /api/time-settings — org time-discipline knobs (admin).

Responses

StatusDescription
200

Security: bearer

PUT/api/v1/time-settings

PUT /api/time-settings — update the org's time-discipline knobs (admin).

Request body

UpdateTimeSettingsRequest

Responses

StatusDescription
200

Security: bearer

GET/api/v1/timers/active

GET /api/timers/active — the caller's running session (at most one).

Responses

StatusDescription
200

Security: bearer

POST/api/v1/timers/pause

POST /api/timers/pause — pauses the active (or given) session, recording the reason on the segment.

Request body

PauseTimerRequest

Responses

StatusDescription
200

Security: bearer

POST/api/v1/timers/resume

POST /api/timers/resume — resumes a paused session with a new segment.

Request body

PauseTimerRequest

Responses

StatusDescription
200

Security: bearer

POST/api/v1/timers/start

POST /api/timers/start — starts (or switches to) a timer. If another session is running it is auto-paused with reason `switched` and stays in the working set; the DB's partial unique index is the backstop. Instant-first (IF1/IF2): idempotency-keyed and read-your-write.

Request body

StartTimerRequest

Responses

StatusDescription
200
404ticket not visible in scope (rls_sparse)
409idempotency key reused

Security: bearer

POST/api/v1/timers/stop

POST /api/timers/stop — stops the session and materializes a time entry (rounded up to the minute) in the same transaction.

Request body

StopTimerRequest

Responses

StatusDescription
200
404session not visible in scope (rls_sparse)
409version conflict or idempotency key reused

Security: bearer

GET/api/v1/timers/working-set

GET /api/timers/working-set — recent sessions (running first): the docked working set the UI renders.

Responses

StatusDescription
200

Security: bearer