The workflow is workspace-wide: one set of kinds, states, priorities, and labels for every project. Tickets reference them by id, so read the workflow once and cache the ids before creating or filtering tickets. SAQ has no state machine; any state can be chosen by an actor who may change state.
GET /api/w/{slug}/workflow
The whole workflow. Token: yes, read. Archived kinds, states, and priorities are not listed.
Request
curl https://saq.no/api/w/acme/workflow \
-H 'Authorization: Bearer saq_YOUR_TOKEN'
Response 200 (Workflow)
{
"kinds": [
{
"id": "01924c3e-0001-7000-8000-000000000001",
"key": "bug",
"name": "Bug",
"position": 2
}
],
"priorities": [
{
"id": "01924c3e-0003-7000-8000-000000000002",
"key": "medium",
"name": "Medium",
"position": 2
}
],
"states": [
{
"id": "01924c3e-0002-7000-8000-000000000001",
"key": "backlog",
"name": "Backlog",
"category": "open",
"position": 0,
"reopenTarget": true
},
{
"id": "01924c3e-0002-7000-8000-000000000005",
"key": "done",
"name": "Done",
"category": "closed",
"position": 4,
"reopenTarget": false
}
],
"labels": [
{ "id": "01924c3e-0006-7000-8000-000000000001", "name": "frontend" }
],
"inboundKindId": "01924c3e-0001-7000-8000-000000000004",
"defaultPriorityId": "01924c3e-0003-7000-8000-000000000002",
"customerResolveStateId": "01924c3e-0002-7000-8000-000000000005",
"reopenWindowDays": 14
}
| Field | Meaning |
|---|---|
kinds[] (Kind) |
id, key, name, position |
priorities[] (Priority) |
id, key, name, position; ordered lowest first |
states[] (State) |
id, key, name, category (open or closed), position, reopenTarget (exactly one open state) |
labels[] (Label) |
id, name |
inboundKindId |
Kind given to tickets started by email or by client users |
defaultPriorityId |
Priority given to new tickets |
customerResolveStateId |
The closed state a regular client user may move their own ticket to, or null |
reopenWindowDays |
Days after closing during which an email reply reopens a ticket (0–365) |
PATCH /api/w/{slug}/workflow
Change the workflow settings. Token: no (browser session only). Owner or Admin.
Body (UpdateWorkflowSettings), all optional: inboundKindId (uuid), defaultPriorityId (uuid), customerResolveStateId (uuid or null; must be a closed state), reopenWindowDays (integer 0–365). Response 200 (Workflow).
Kinds, states, priorities, and labels
All operations below are browser-session only, Owner or Admin. Keys are normalised (trimmed, lower-cased, spaces and hyphens become underscores) and must match ^[a-z][a-z0-9_]{1,31}$; a key is fixed after creation. Names are 1–60 characters. Archiving hides an item from the workflow but keeps existing tickets intact.
| Operation | Body | Response |
|---|---|---|
POST /workflow/kinds |
CreateKind: key, name |
201 Kind |
PATCH /workflow/kinds/{id} |
UpdateKind: name?, position? (integer ≥ 0) |
200 { "ok": true } |
DELETE /workflow/kinds/{id} |
200 { "ok": true } (archived; refused for the inbound kind or the last kind) |
|
POST /workflow/priorities |
key, name (same shape as CreateKind) |
201 Priority |
PATCH /workflow/priorities/{id} |
name?, position? |
200 { "ok": true } |
DELETE /workflow/priorities/{id} |
200 { "ok": true } (archived; refused for the default priority or one in use) |
|
POST /workflow/states |
CreateState: key, name, category (open or closed) |
201 State |
PATCH /workflow/states/{id} |
UpdateState: name?, category?, position?, reopenTarget? |
200 { "ok": true } |
DELETE /workflow/states/{id} |
200 { "ok": true } (archived; refused while tickets are in it or it is the reopen target) |
|
POST /workflow/labels |
LabelInput: name (unique per workspace) |
201 Label |
PATCH /workflow/labels/{id} |
LabelInput: name |
200 { "ok": true } (renamed) |
DELETE /workflow/labels/{id} |
200 { "ok": true } (deleted) |
Paths are relative to /api/w/{slug}.
| Error | Status | When |
|---|---|---|
forbidden |
403 | Not Owner or Admin, or an API token ("This action is not available to API tokens") |
invalid |
400 | Validation failed (key or name format, unknown category) |
conflict |
409 | Duplicate key or name, or an archive refused by the rules above |
not_found |
404 | Unknown id |