REST API

Time entries

Log and adjust manual time on tasks and subtasks.

A time entry records work time against a task or subtask. Manual entries are posted via this API; entries produced by the in-app timer are server-generated and not creatable via REST.

Endpoints

MethodPathNotes
GET/api/v1/time-entriesList with filters. Cursor pagination.
POST/api/v1/time-entriesLog a manual entry. Accepts Idempotency-Key.
GET/api/v1/time-entries/{id}Single entry with user, task, subtask.
PATCH/api/v1/time-entries/{id}Edit description, start time, duration.
DELETE/api/v1/time-entries/{id}Delete the entry.

The in-app timer endpoints (start, stop, switch) are intentionally not exposed via REST in v1.

TimeEntry model

{
  "id": "e1…",
  "organizationId": "...",
  "userId": "u1…",
  "taskId": "t1…",
  "subtaskId": null,
  "description": "Initial wiring",
  "startedAt": "2026-05-19T13:00:00.000Z",
  "endedAt":   "2026-05-19T14:30:00.000Z",
  "durationSeconds": 5400,
  "source": "manual",
  "autoStopped": false,
  "createdAt": "...",
  "updatedAt": "..."
}
FieldNotes
sourcemanual (this API) or timer (in-app start/stop).
autoStoppedtrue when the 8h-cap sweeper persisted a timer-driven entry.
endedAtAlways startedAt + durationSeconds — recomputed by the server on update.

Each entry belongs to exactly one of taskId or subtaskId (XOR). The parent is immutable after creation.

Listing entries

GET /api/v1/time-entries?userId=...&startDate=2026-05-01&endDate=2026-05-31
ParamTypeNotes
userIdUUIDOne member's entries.
taskIdUUIDDirect task entries.
subtaskIdUUIDSubtask entries.
projectIdUUIDEntries on tasks/subtasks of one project.
startDateISO datetimeInclusive lower bound on startedAt.
endDateISO datetimeInclusive upper bound on startedAt.
cursorUUIDFrom a previous response.
limitint 1–100Default 50.

Returns { data, pagination: { nextCursor } }. Entries are filtered by project visibility — standard members may not see entries on tasks they cannot access.

Logging a manual entry

POST /api/v1/time-entries
Content-Type: application/json
Idempotency-Key: ...

{
  "taskId": "t1…",
  "startedAt": "2026-05-19T13:00:00.000Z",
  "durationSeconds": 5400,
  "description": "Initial wiring"
}

Required:

FieldTypeConstraint
Exactly one of taskId or subtaskIdUUIDSending both, or neither, returns 422.
startedAtISO datetime
durationSecondsint1 – 86 400 (≤ 24 h).

Optional:

FieldTypeConstraint
descriptionstring≤ 1000 chars.

Response: 201 Created with the entry. The created entry is always attributed to the API key's user.

Editing an entry

PATCH /api/v1/time-entries/{id}
{ "durationSeconds": 7200 }

Caller must be one of:

  • The entry's author, or
  • An organization owner / admin, or
  • A project manager on the entry's parent project.

Allowed fields: description, startedAt, durationSeconds. Updating startedAt or durationSeconds recomputes endedAt.

Deleting an entry

DELETE /api/v1/time-entries/{id}

Returns { "data": { "success": true } }. Same authorization rules as edit.

Common precondition failures

CodeCause
422Body sent both taskId and subtaskId, or neither.
403Caller can read the entry but cannot edit/delete it.
404Cross-org id, or entry belongs to a task the caller cannot access.

On this page