Tasks
Everything on the task board, over REST.
Every field on the admin Tasks page is reachable through
/api/tasks. Calls require a Bearer token and inherit
the caller's RBAC — if you can see a task in the admin, your token
can read it; if you can't, it won't. Timestamps are ISO-8601 UTC;
errors are JSON.
Resource shape
A task row looks like this on the wire:
{
"id": 1042,
"org_id": 1,
"title": "Review Q2 roadmap",
"description": "Walk through the draft with the product team",
"status": "in_progress",
"priority": "high",
"position": 0,
"label": null,
"category_code": "general",
"effort": "m",
"task_type": "task",
"assigned_employee_id": 17,
"assigned_team_id": null,
"assigned_to": null,
"parent_task_id": null,
"initiative_id": 4,
"due_at": "2026-05-10T17:00:00Z",
"reminder_offset": "1d",
"tags": ["q2", "product"],
"created_at": "2026-04-21T14:44:12.123Z",
"updated_at": "2026-04-21T14:44:12.123Z",
"created_by": 42,
"updated_by": 42,
"deleted_at": null
} Enum fields
| Field | Values |
|---|---|
status | todo, in_progress, reviewing, blocked, done, cancelled |
priority | low, medium, high, urgent |
effort | xs, s, m, l, xl, xxl |
task_type | feature, epic, story, task, question |
category_code | From the task_category enum: general, system_error, bug, improvement, documentation, release_notes |
reminder_offset | 5m, 10m, 15m, 30m, 1h, 2h, 4h, 1d, 2d, 5d, 10d |
Three assignee columns, one assignment
A task is assigned to exactly one of assigned_employee_id, assigned_team_id, or assigned_to (the raw users FK for non-employee actors). The admin UI picks the right column based on the lookup the user opens; the API enforces the "one of" rule on write.
Endpoint summary
| Method | Path | Purpose |
|---|---|---|
GET | /api/tasks | List with filters |
GET | /api/tasks/:id | Fetch one task |
POST | /api/tasks | Create |
PATCH | /api/tasks/:id | Partial update |
POST | /api/tasks/:id/move | Kanban move (status + position, reconciles adjacent sort) |
DELETE | /api/tasks/:id | Soft-delete (sets deleted_at) |
GET | /api/tasks/:taskId/comments | List comments, chronological |
POST | /api/tasks/:taskId/comments | Create a comment (optional parent_id for reply) |
PATCH | /api/tasks/:taskId/comments/:id | Edit author's own comment |
DELETE | /api/tasks/:taskId/comments/:id | Soft-delete a comment |
List tasks
curl 'https://api.wrk.ing/api/tasks?status=in_progress&assigned_to_me=true' \
-H "Authorization: Bearer $WRKING_TOKEN" Query parameters
| Parameter | Type | Effect |
|---|---|---|
status | enum | Filter by single status value |
label | string | Exact match on the free-text label field |
category_code | enum | Exact match on the category_code enum |
due_before | ISO 8601 | Tasks with due_at strictly before this timestamp |
assigned_to_me | boolean | Tasks where any of the three assignee columns resolves to the caller |
initiative_id | integer | Tasks linked to a specific initiative |
parent_task_id | integer | Children of a given epic or parent task |
limit / offset | integer | Pagination |
Create a task
curl -X POST https://api.wrk.ing/api/tasks \
-H "Authorization: Bearer $WRKING_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Review Q2 roadmap",
"description": "Walk through the draft with the product team",
"priority": "high",
"due_at": "2026-05-10T17:00:00Z",
"reminder_offset": "1d",
"assigned_employee_id": 17
}'
A successful create returns 201 Created with the full task row, fires
task.post_create on the event stream, and triggers the
triage-task prompt hook — a light AI pass that suggests a priority level,
a category, and an ideal-owner description based on the task text.
Update a task
curl -X PATCH https://api.wrk.ing/api/tasks/1042 \
-H "Authorization: Bearer $WRKING_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "status": "done" }'
Any writable field can be included. Setting status to done
emits the task.completed lifecycle event in addition to the usual
task.post_update — downstream automations (celebration posts, reporting
rollups) subscribe to the former.
Move a task on the kanban
curl -X POST https://api.wrk.ing/api/tasks/1042/move \
-H "Authorization: Bearer $WRKING_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "status": "in_progress", "position": 0 }'
Use this rather than PATCH when you need the server to re-sort
adjacent tasks. position is interpreted as the zero-indexed target
slot in the target column; the server reconciles the surrounding rows in the
same transaction.
Soft-delete a task
curl -X DELETE https://api.wrk.ing/api/tasks/1042 \
-H "Authorization: Bearer $WRKING_TOKEN"
Returns 204 No Content. deleted_at is stamped and the
record drops out of every query that does not explicitly include deleted rows.
Child rows (reminders, linked comments, event entries) are NOT cascaded — if you
need a hard purge, use the admin bulk-cleanup tool rather than this endpoint.
Threaded comments
Each task carries a discussion thread. Comments are flat rows with an optional
parent_id that lets the client assemble a reply tree of any depth —
the server does not enforce nesting rules.
curl -X POST https://api.wrk.ing/api/tasks/1042/comments \
-H "Authorization: Bearer $WRKING_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body": "Picked this up — checking the logs now.", "parent_id": null }'
Every comment records author_user_id, created_at, and
updated_at so edit history is available to reviewers. Soft-delete
works the same way as on tasks.
Lifecycle events
The tasks resource emits the following lifecycle events:
| Event | When |
|---|---|
task.post_create | A new task is inserted (REST, admin UI, workflow, or pack seed). |
task.post_update | Any field changes, including status moves. |
task.completed | Status transitions into done. |
task.comment.created | A new comment is posted on a task. |
Prompt hooks on tasks
Two prompt templates ship wired to the task lifecycle. Both return structured JSON, which downstream UI can render directly as badges, blocker chips, or owner suggestions without client-side parsing.
| Template | Hook | Behaviour |
|---|---|---|
triage-task | task.post_create | Suggests a priority level, a short category label, and a one-sentence description of the ideal owner. |
detect-task-blockers | task.post_update | Evaluates stall signals (overdue, no assignee, unresolved dependencies, repeated status thrashing) and proposes unblocking actions. |
Both templates are editable through the admin UI under AI → Prompts, and can be disabled per-org without touching code.