Developers
REST API
Automate TimeWave over a simple HTTP API: projects, tasks, time entries and the timer. The same engine the MCP server runs on.
Base URL
https://timewave.cloud/apiAuthentication
Send an API key in the Authorization: Bearer tw_… header. Create and revoke keys in Account & API keys. A key acts as you and can never do more than you can.
curl https://timewave.cloud/api/v1/tasks \
-H "Authorization: Bearer tw_your_key_here"Each key carries scopes. A request missing the required scope returns 403.
readRead projects, tasks, time & timer statustasksManage tasks (create, edit, move, comment)timerRun the timer & log timeEndpoints
Everything below is generated from the openapi.json the API itself serves, so these docs cannot drift from the code.
Auth
/v1/auth/loginExchange email and password for an API keyno keyRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| email* | string | |
| password* | string | |
| totp | string | Six-digit code, or a backup code, when the account has 2FA |
| deviceName | string | Shown in the key list. Defaults to "Mobile app". |
| orgId | string | Required only when the account belongs to more than one organisation |
/v1/auth/logoutRevoke the API key used for this callno keyAccount
/v1/meWho this API key belongs toread/v1/me/summaryYour own hours and earnings for a windowreadQuery parameters
| Field | Type | Description |
|---|---|---|
| from | string | Defaults to the first of the current month |
| to | string | Inclusive. Defaults to the end of the current month |
/v1/me/avatarUpload your profile pictureread/v1/me/avatarRemove your profile pictureread/v1/avatars/{userId}Somebody's profile pictureread/v1/notificationsWhat happened while you were not lookingreadQuery parameters
| Field | Type | Description |
|---|---|---|
| unread | boolean | Only the ones not read yet |
| limit | integer | (default 50) |
/v1/notifications/{id}/readMark one as readread/v1/notifications/read-allClear the badgeread/v1/devicesEverything holding a key for youread/v1/devices/pushRegister this device for pushreadRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| token* | string | The FCM registration token for this install |
/v1/devices/pushStop pushing to this deviceread/v1/devices/{id}Revoke a keyread/v1/membersList members — the source of assigneeIdreadProjects
/v1/projectsList projects with their kanban columnsreadTasks
/v1/tasksList tasksreadQuery parameters
| Field | Type | Description |
|---|---|---|
| projectId | string | |
| status | "open" | "done" | "all" | (default all) |
| assigneeId | string | A user id, "me" for the caller, or "none" for unassigned tasks. |
/v1/tasksCreate a tasktasksRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| projectId* | string | |
| title* | string | |
| description | string | null | |
| priority | "LOW" | "NORMAL" | "HIGH" | "URGENT" | (default NORMAL) |
| assigneeId | string | null | A userId from /v1/members |
| estimateMinutes | integer | null | |
| dueDate | string | null | |
| column | string | Column name or id. Defaults to the first column. |
/v1/tasks/{id}One task, with checklist and activityread/v1/tasks/{id}Update a tasktasksRequest bodyapplication/json
Every field is optional. Send null to clear a nullable one; omit it to leave it alone.
| Field | Type | Description |
|---|---|---|
| title | string | |
| description | string | null | |
| priority | "LOW" | "NORMAL" | "HIGH" | "URGENT" | |
| assigneeId | string | null | |
| estimateMinutes | integer | null | |
| dueDate | string | null |
/v1/tasks/{id}Delete a tasktasks/v1/tasks/{id}/moveMove a task to a kanban columntasksRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| column* | string | Column name or id, within the task's own project |
/v1/tasks/{id}/completeMark a task done, or reopen ittasksRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| done | boolean | false reopens(default true) |
/v1/tasks/{id}/commentsComment on a tasktasksRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| body* | string | Comment text |
/v1/tasks/{id}/checklistAdd a checklist itemtasksRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| text* | string |
/v1/tasks/{id}/checklist/{itemId}Tick or untick a checklist itemtasksRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| done | boolean | (default true) |
/v1/tasks/{id}/checklist/{itemId}Remove a checklist itemtasksTime
/v1/time-entriesList time entriesreadQuery parameters
| Field | Type | Description |
|---|---|---|
| projectId | string | |
| taskId | string | |
| from | string | Inclusive, YYYY-MM-DD |
| to | string | Exclusive, YYYY-MM-DD |
| limit | integer | (default 50) |
/v1/time-entriesLog time that has already happenedtimerRequest bodyapplication/json
Give the length as either durationSeconds or durationMinutes, and the day as date or startedAt.
| Field | Type | Description |
|---|---|---|
| durationSeconds | integer | |
| durationMinutes | number | |
| date | string | YYYY-MM-DD; recorded at midday that day |
| startedAt | string | |
| projectId | string | null | |
| taskId | string | null | Attaching the task is what makes the time show up against it |
| description | string | null | |
| billable | boolean | (default true) |
| tracked | boolean | The time was measured by a clock rather than typed in — for a client that ran its own timer while it could not reach the server. Recorded as tracked rather than manual, so the entry is not marked as handwritten on a timesheet.(default false) |
/v1/time-entries/{id}One time entryread/v1/time-entries/{id}Edit a time entrytimerRequest bodyapplication/json
Every field is optional. Edited entries are flagged as such in the UI.
| Field | Type | Description |
|---|---|---|
| durationSeconds | integer | |
| durationMinutes | number | |
| date | string | YYYY-MM-DD |
| startedAt | string | |
| description | string | null | |
| projectId | string | null | |
| taskId | string | null | |
| billable | boolean |
/v1/time-entries/{id}Delete a time entrytimerTimer
/v1/timerWhether a timer is running, and for how longread/v1/timer/startStart the trackertimerRequest bodyapplication/json
All optional. A running timer is stopped first — only one can run at a time.
| Field | Type | Description |
|---|---|---|
| taskId | string | null | Starting on a task fills in its project and description |
| projectId | string | null | |
| description | string | null | |
| startedAt | string | When the timer was really started. For a client that was offline at the time; omit it and the timer starts now. Clamped to the past, and refused if that week's timesheet is locked. |
/v1/timer/stopStop the running timertimerRequest bodyapplication/json
Optional. Without a body the timer stops now, which is what an online client means.
| Field | Type | Description |
|---|---|---|
| endedAt | string | When the timer was really stopped, for a client that could not say so at the time. Clamped into [startedAt, now]. Not treated as an edit — the entry keeps its provenance. |
Knowledge
/v1/docsDocuments you can see, newest firstdocsQuery parameters
| Field | Type | Description |
|---|---|---|
| q | string | Match on the title. Bodies are not searched — see the note in doc-service. |
| projectId | string | |
| parentId | string | Children of one document, or `root` for the top of the tree |
| limit | integer | (default 50) |
/v1/docsCreate a documentdocsRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| title* | string | |
| body | string | Markdown. Defaults to a heading made from the title. |
| kind | "REFERENCE" | "WIKI" | "TASK" | |
| visibility | "PRIVATE" | "RESTRICTED" | "ORG" | Defaults to PRIVATE. A document created by an integration is no more visible than one created by hand. |
| projectId | string | null | |
| parentId | string | null |
/v1/docs/{id}One document, with its Markdowndocs/v1/docs/{id}Change the title, the body, or who sees itdocsRequest bodyapplication/json
Only the fields sent are touched. The previous body is kept as a version.
| Field | Type | Description |
|---|---|---|
| title | string | |
| body | string | Markdown, in full |
| visibility | "PRIVATE" | "RESTRICTED" | "ORG" | Author only |
/v1/docs/{id}Delete a document. Author only.docs/v1/docs/{id}/attachmentsFiles on a documentdocs/v1/docs/{id}/attachmentsAttach a filedocs/v1/docs/{id}/attachments/{attachmentId}Remove a file from a documentdocs/v1/docs/{id}/versionsWhat this document said beforedocsQuery parameters
| Field | Type | Description |
|---|---|---|
| limit | integer | (default 50) |
/v1/docs/{id}/versions/{versionId}One old version, in fulldocsTimesheets
/v1/timesheetsYour recent weeks and what happened to themreadQuery parameters
| Field | Type | Description |
|---|---|---|
| limit | integer | How many weeks back, counting the current one(default 8) |
/v1/timesheets/{week}One week, day by day and project by projectread/v1/timesheets/{week}/submitHand the week intimer/v1/timesheets/{week}/withdrawTake it back before anyone reviews ittimerSecrets
/v1/secretsThere is no reading of the vaultsecrets/v1/secretsPut a secret in, or add a version to one that existssecretsRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| name* | string | Matched without regard to case: writing `session_secret` over `SESSION_SECRET` adds a version to the one that is there rather than making a twin. |
| value | string | The secret. Up to 8 KB — this is not a file store. |
| reference | string | Instead of `value`: where the secret is actually kept, e.g. "1Password, vault Ops, item «prod db»". Nothing sensitive is stored. |
| note | string | What this is and where it is used. Appears in lists — not secret. |
| warning | string | Shown next to the value whenever a person reveals it. For what breaks if this is rotated. |
/v1/secrets/generateGenerate a secret, store it, and return it this oncesecretsRequest bodyapplication/json
| Field | Type | Description |
|---|---|---|
| name* | string | |
| length | integer | (default 32) |
| alphabet | "alnum" | "symbols" | "hex" | `alnum` leaves out characters that get misread off a screen (0/O, 1/l/I). |
| note | string | |
| warning | string |
Prefer an AI assistant? The same actions are available over MCP.