Identifiers
Every resource id is a string of the form <prefix>_<value>. The prefix names the resource type, so passing an id of the wrong type is rejected with 422 validation_error (invalid_request) instead of silently resolving the wrong resource.
Prefixes
Section titled “Prefixes”| Prefix | Resource | Example |
|---|---|---|
task_ |
task | task_6594a1b2c3d4e5f6a7b8c9d0 |
subtask_ |
subtask | composite — see below |
time_log_ |
time log | composite — see below |
event_ |
scheduled event | event_6594a1b2c3d4e5f6a7b8c9e0 |
proj_ |
project | proj_6594a1b2c3d4e5f6a7b8c9a0 |
user_ |
workspace member | user_6594a1b2c3d4e5f6a7b8c9b0 |
tag_ |
tag | tag_6594a1b2c3d4e5f6a7b8c9c0 |
task_status_ |
task status | task_status_6594a1b2c3d4e5f6a7b8c9d2 |
task_type_ |
task type | task_type_6594a1b2c3d4e5f6a7b8c9d3 |
event_type_ |
event type | event_type_6594a1b2c3d4e5f6a7b8c9d4 |
proj_status_ |
project status | proj_status_6594a1b2c3d4e5f6a7b8c9d5 |
cf_ |
custom field | cf_6594a1b2c3d4e5f6a7b8c9d6 |
cf_option_ |
custom field option | cf_option_6594a1b2c3d4e5f6a7b8c9d7 |
attachment_ |
attachment | attachment_6594a1b2c3d4e5f6a7b8c9d8 |
chat_message_ |
chat message | chat_message_6594a1b2c3d4e5f6a7b8c9d9 |
Most resources use the simple <prefix>_<value> shape. Two things add extra parts: subtasks/time logs (which encode their parent task) and recurring occurrences (which append a date).
Composite ids: subtasks & time logs
Section titled “Composite ids: subtasks & time logs”A subtask or time log is always addressed together with its parent task, so its id carries both — the child first, then the parent task:
subtask_<child>_<parent task>time_log_<child>_<parent task>For a task task_6594a1b2c3d4e5f6a7b8c9d0:
| Resource | Example id |
|---|---|
| subtask | subtask_6594a1b2c3d4e5f6a7b8c9d1_6594a1b2c3d4e5f6a7b8c9d0 |
| time log | time_log_6594a1b2c3d4e5f6a7b8c9d2_6594a1b2c3d4e5f6a7b8c9d0 |
The trailing 6594a1b2c3d4e5f6a7b8c9d0 is the parent task’s value. It’s still a single opaque string — you pass the whole thing as one id, you don’t assemble it from parts.
Recurring tasks & events
Section titled “Recurring tasks & events”A recurring series has a plain id — task_<value> or event_<value> — which addresses the whole series (read it, edit the rule, delete every occurrence).
A single occurrence of that series is addressed by appending the occurrence’s start time (UTC, YYYYMMDDTHHMMSSZ):
task_<series>_<date> e.g. task_6594a1b2c3d4e5f6a7b8c9d0_20260113T090000Zevent_<series>_<date> e.g. event_6594a1b2c3d4e5f6a7b8c9e0_20260113T090000ZAnything that belongs to an occurrence carries the same date suffix after the composite part — so a subtask or time log of an occurrence looks like:
subtask_6594a1b2c3d4e5f6a7b8c9d1_6594a1b2c3d4e5f6a7b8c9d0_20260113T090000Ztime_log_6594a1b2c3d4e5f6a7b8c9d2_6594a1b2c3d4e5f6a7b8c9d0_20260113T090000ZWhich id to use
Section titled “Which id to use”| You want to… | Use |
|---|---|
| Read/update/delete the entire series | the plain series id — task_<series> |
| Read/update/delete a single occurrence | the occurrence id — task_<series>_<date> |
An update or delete always affects exactly the id you send — the whole series, or the one occurrence. Spanning edits (“this and following” / “all”) are not available yet.
Why this matters in practice
Section titled “Why this matters in practice”Because you treat every id as opaque, the same endpoints work regardless of the shape. GET /tasks/{id} accepts a plain task id or an occurrence id — you don’t special-case the format, and you don’t need to know which one you hold. Read ids from responses, store them whole, and send them back exactly as received.