Boards and teams
Board configuration, membership, the team structures that own boards, and the grants of manage_structure (KAIROS-T-0337).
boards
Section titled “boards”GET /api/boards
Section titled “GET /api/boards”List boards (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
limit |
query | no | integer |
Page size (default 50, max 200). |
offset |
query | no | integer |
Rows to skip (default 0). |
| Response | Body | Meaning |
|---|---|---|
200 |
ListEnvelope_Board |
Page of boards |
401 |
ErrorEnvelope |
Missing/invalid token |
POST /api/boards
Section titled “POST /api/boards”Create a board seeded with the system default columns/transitions for
its level (KAIROS-A-0002). An organization admin, or manage_structure
on the organization (KAIROS-T-0337). A grant on one board does not count:
the new board is not that board.
A delivery board needs a team (COLLIERY-T-0230). A request for a
delivery board with no team_id is a 422. The board of a task decides
its team, and a request to a board with no team goes to nobody. The
check is in kairos_db::boards::create_board, which every entry point
shares.
A strategy or initiative board has a team (KAIROS-T-0440,
KAIROS-A-0026). It is the team_id of the request. With no team_id,
Kairos makes an empty team <level>-<slug> with its charter. An admin
adds people to it. Board members and grants still work.
An ADR board can have a team (COLLIERY-T-3102). That board holds the
delivery ADRs of the team. Its code_prefix must be the
prefix of the delivery board of the team. If not, the request is a 422
VALIDATION with details.field = code_prefix and
details.expected. An ADR board with no team_id is a board of the
organization.
A team has one ADR board. A request for a second one is a 422
TEAM_HAS_ADR_BOARD, and the refusal names the board that the team has.
A team has one delivery board (COLLIERY-T-0240). A request for a
delivery board for a team that has a live delivery board is a 422
TEAM_HAS_DELIVERY_BOARD. The refusal names the board that the team
has. A deleted board does not count.
A slug must have the form of a board slug (COLLIERY-T-0258). It must
match ^[a-z][a-z0-9_-]{1,62}$, and it cannot have the form of a UUID.
If not, the request is a 422 VALIDATION with details.field = slug.
A live board has its slug alone (COLLIERY-T-0255). A request with the
slug of a live board is a 409 CONFLICT. The refusal names the slug
and the board that has it (details.slug, details.board). A deleted
board does not keep its slug.
Each board has a short-code prefix, code_prefix (COLLIERY-T-3099). It
is required, and it never changes. An item on the board gets the code
{code_prefix}-{type letter}-{number}. The number comes from the
sequence of the prefix and the type.
A prefix that does not match ^[A-Z][A-Z0-9]{1,9}$ is a 422
VALIDATION with details.field = code_prefix.
Boards can share a prefix when they hold different types. The level
gives the types. A prefix that a live board of the same level has is a
409 CONFLICT. The refusal names the prefix and the board that has it
(details.code_prefix, details.board).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
Idempotency-Key |
header | no | string, nullable |
Optional. A key that you choose for this write: 8 to 128 characters of letters, digits, ‘.’, ‘_’, ‘:’ and ‘-’ (a UUID is a good key). Send it when you may retry the request. For 24 hours, a request with the same key and the same arguments writes nothing and gives the first status and body again, with the header Idempotent-Replayed: true. The same key with other arguments is refused with REQUEST_KEY_REUSED (KAIROS-A-0065). |
Request body (required): application/json, CreateBoardRequest
| Response | Body | Meaning |
|---|---|---|
201 |
BoardDetail |
Created, with the seeded configuration |
403 |
ErrorEnvelope |
Not an org admin, and no manage_structure on the organization |
409 |
ErrorEnvelope |
A live board has the slug, or a live board of the same level has the prefix; details.board names it; or REQUEST_KEY_REUSED: the Idempotency-Key was used for a different request |
422 |
ErrorEnvelope |
Bad level/team reference, a slug that does not have the form of a board slug, a code_prefix that is absent or does not match the rule, a delivery board with no team, a strategy or initiative board with a team, the prefix of a team ADR board that is not the prefix of the team, TEAM_HAS_DELIVERY_BOARD, or TEAM_HAS_ADR_BOARD |
GET /api/boards/{id}
Section titled “GET /api/boards/{id}”Board detail: the board plus its columns and transitions (open tenant-wide).
The path takes the slug or the id of the board (COLLIERY-T-0265). An unknown slug and an unknown id are a 404.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
include_removed_columns |
query | no | boolean |
Also return the columns that have been REMOVED from this board, each carrying removed_at (default false — a removed column is not part of the board and must not render on one, KAIROS-T-0161). The one legitimate caller is a reader holding an ARCHIVED item that still points at such a column: “which column was this put away in?” has to stay answerable (KAIROS-A-0020, KAIROS-T-0164). |
| Response | Body | Meaning |
|---|---|---|
200 |
BoardDetail |
The board with columns and transitions |
404 |
ErrorEnvelope |
Unknown board |
DELETE /api/boards/{id}
Section titled “DELETE /api/boards/{id}”Soft-delete a board. Only allowed when NO workflow item references it
(422 BOARD_NOT_EMPTY otherwise — the T-0010 empty rule applied at
board scope). Requires configure_boards on the board.
A board that is the owner of a live document is not deleted
(COLLIERY-T-0269): 422 BOARD_OWNS_DOCUMENTS. A document always has
an owner. Name a different board for each document, or archive it.
The only delivery board of a team is not deleted (COLLIERY-T-0241): 422
LAST_DELIVERY_BOARD. A team always has a delivery board. To remove
the board, delete the team (DELETE /api/teams/{id}), which removes
the team and its board together. This check comes before the check for
live items, because no retry can pass it.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Soft-deleted |
403 |
ErrorEnvelope |
Missing capability |
404 |
ErrorEnvelope |
Unknown board |
422 |
ErrorEnvelope |
BOARD_NOT_EMPTY, LAST_DELIVERY_BOARD, or BOARD_OWNS_DOCUMENTS |
PATCH /api/boards/{id}
Section titled “PATCH /api/boards/{id}”Update board settings (name/slug). Requires configure_boards on the
board.
The team of a board does not change (COLLIERY-T-0230, COLLIERY-T-0243).
A team_id that is not the team of the board is a 422
BOARD_TEAM_IS_FIXED, and the update writes nothing. To give work to a
different team, move the task (POST /api/tasks/{code}/move).
The server accepts a team_id equal to the team of the board, and
changes nothing. A client can thus send back the team_id that it
read. That team_id is not a field to update: the body must have name
or slug.
A new slug must have the form of a board slug (COLLIERY-T-0258). If
not, the request is a 422 VALIDATION, and the update writes nothing.
A board with a slug from before the rule keeps that slug. An update of
the name of that board passes.
A slug that a different live board has is a 409 CONFLICT, and the
update writes nothing (COLLIERY-T-0255). The refusal names the slug and
the board that has it. A board can keep its slug in an update.
The body has the fields name, slug, team_id, parent_gate,
owner_gate and blockers_gate only. A different field of the board (id, board_level) is a 422
VALIDATION that names the field (COLLIERY-T-0249).
parent_gate sets a board policy of a delivery board (KAIROS-T-0641).
With the policy on, a task moves into a claims column only while its
parent initiative is active. On a board of a different level, the field
is a 422 VALIDATION.
owner_gate sets a board policy of an initiative board (KAIROS-T-0643).
With the policy on, an initiative moves into its Active column only with
an owner. On a board of a different level, the field is a 422
VALIDATION.
blockers_gate sets a board policy of a delivery board (KAIROS-T-0565).
With the policy on, a blocked task does not move into a claims column
or a done column. On a board of a different level, the
field is a 422 VALIDATION.
The short-code prefix of a board does not change (COLLIERY-T-3099). A
body with code_prefix is a 422 CODE_PREFIX_IS_FIXED that says so
(COLLIERY-T-3101), and the update writes nothing.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
Request body (required): application/json, UpdateBoardRequest
| Response | Body | Meaning |
|---|---|---|
200 |
Board |
Updated |
403 |
ErrorEnvelope |
Missing capability |
404 |
ErrorEnvelope |
Unknown board |
409 |
ErrorEnvelope |
A live board has the slug; details.board names it |
422 |
ErrorEnvelope |
No field to update, BOARD_TEAM_IS_FIXED, or CODE_PREFIX_IS_FIXED |
GET /api/boards/{id}/agent-triage
Section titled “GET /api/boards/{id}/agent-triage”Who decides the triage of intake on the board (KAIROS-T-0428). A person who belongs to the board reads it.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
| Response | Body | Meaning |
|---|---|---|
200 |
AgentTriage |
The setting |
403 |
ErrorEnvelope |
The caller does not belong to the board |
404 |
ErrorEnvelope |
Unknown board |
PUT /api/boards/{id}/agent-triage
Section titled “PUT /api/boards/{id}/agent-triage”Let agents decide the triage of intake on the board, or not
(KAIROS-T-0428). Off: Kairos refuses an agent’s move of intake with 403
AGENT_TRIAGE_OFF. The agent proposes with a note. Needs
configure_boards.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
Request body (required): application/json, SetAgentTriageRequest
| Response | Body | Meaning |
|---|---|---|
200 |
AgentTriage |
The setting |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board |
POST /api/boards/{id}/archive-completed
Section titled “POST /api/boards/{id}/archive-completed”Archive each live task in the done columns of a board (KAIROS-T-0363, “Archive completed”). A cancelled task is in a done column, so it goes too. A restore brings back each task, as for each archived item.
Each task goes through the one archive of the server
(cascade::archive_item). Each rule of an archive of one task
applies: the edit rule, the cascade, the claim and the history.
ONE TRANSACTION: the call archives each task, or it archives none. A refusal of one task (a 403 of the edit rule) refuses the call.
Requires manage_tasks on the board (an organization admin has it):
the capability that archives each task of the board. The creator of a
task can archive that task one at a time. A board that is not a
delivery board holds no tasks: 422 NOT_DELIVERY_BOARD.
?older_than_days=N archives only the done tasks that entered their
done column at least N days ago (KAIROS-T-0649). The time of entry is
the last move of the task, or its creation. N is a whole number from 1
to 36500. Another value is a 422 VALIDATION with details.field =
older_than_days.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
older_than_days |
query | no | integer |
Archive only the done tasks that entered their done column at least this many days ago: a whole number from 1 to 36500. With no value, the call archives each done task. |
| Response | Body | Meaning |
|---|---|---|
200 |
ArchiveCompletedResponse |
The archived tasks: the count and the codes. A count of 0 when the done columns are empty |
403 |
ErrorEnvelope |
Missing manage_tasks on the board |
404 |
ErrorEnvelope |
Unknown board |
422 |
ErrorEnvelope |
NOT_DELIVERY_BOARD, or VALIDATION for an older_than_days out of range |
GET /api/boards/{id}/columns
Section titled “GET /api/boards/{id}/columns”List a board’s columns in position order (open tenant-wide).
The path takes the slug or the id of the board (COLLIERY-T-0265). An unknown slug and an unknown id are a 404.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
| Response | Body | Meaning |
|---|---|---|
200 |
array of BoardColumn |
Columns in position order |
404 |
ErrorEnvelope |
Unknown board |
POST /api/boards/{id}/columns
Section titled “POST /api/boards/{id}/columns”Add a column (T-0010 rules: unique name and position). Requires
configure_boards on the board.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
Idempotency-Key |
header | no | string, nullable |
Optional. A key that you choose for this write: 8 to 128 characters of letters, digits, ‘.’, ‘_’, ‘:’ and ‘-’ (a UUID is a good key). Send it when you may retry the request. For 24 hours, a request with the same key and the same arguments writes nothing and gives the first status and body again, with the header Idempotent-Replayed: true. The same key with other arguments is refused with REQUEST_KEY_REUSED (KAIROS-A-0065). |
Request body (required): application/json, CreateColumnRequest
| Response | Body | Meaning |
|---|---|---|
201 |
BoardColumn |
Created |
403 |
ErrorEnvelope |
Missing capability |
404 |
ErrorEnvelope |
Unknown board |
409 |
ErrorEnvelope |
REQUEST_KEY_REUSED: the Idempotency-Key was used for a different request |
422 |
ErrorEnvelope |
DUPLICATE_COLUMN_NAME / DUPLICATE_COLUMN_POSITION / VALIDATION |
DELETE /api/boards/{id}/columns/{col_id}
Section titled “DELETE /api/boards/{id}/columns/{col_id}”Remove a column — a soft delete (KAIROS-T-0161). Only allowed when no
LIVE item occupies it; the T-0010 rule surfaces as 422
COLUMN_NOT_EMPTY. Archived cards may stay behind and keep reporting
the column they were put away in. Requires configure_boards.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
col_id |
path | yes | string |
Column id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Removed (soft: archived cards keep its name; its transition edges are kept but no longer apply) |
403 |
ErrorEnvelope |
Missing capability |
404 |
ErrorEnvelope |
Unknown board/column |
422 |
ErrorEnvelope |
COLUMN_NOT_EMPTY (details.item_count) |
PATCH /api/boards/{id}/columns/{col_id}
Section titled “PATCH /api/boards/{id}/columns/{col_id}”Rename and/or move a column (T-0010 rules; moving reorders the board’s
columns around the new position). Requires configure_boards.
This route also sets the flags is_done and claims (KAIROS-T-0359).
A person who moves a task into a column with claims gets the claim of
the task. When the flag goes off, the claims of the tasks in the column
end.
It also sets the WIP limit of the column (wip_limit, KAIROS-T-0371): a
number above 0, or null to remove it. Kairos does not refuse a move into
a column over its limit. The answer of the move has a warning in the
header Kairos-Warning.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
col_id |
path | yes | string |
Column id (UUID) |
Request body (required): application/json, UpdateColumnRequest
| Response | Body | Meaning |
|---|---|---|
200 |
BoardColumn |
Updated |
403 |
ErrorEnvelope |
Missing capability |
404 |
ErrorEnvelope |
Unknown board/column |
422 |
ErrorEnvelope |
DUPLICATE_COLUMN_NAME / VALIDATION |
GET /api/boards/{id}/dispatch-rules
Section titled “GET /api/boards/{id}/dispatch-rules”The dispatch rules of a board (KAIROS-T-0385). A person who belongs to the board reads them.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
| Response | Body | Meaning |
|---|---|---|
200 |
array of DispatchRule |
The rules of the board |
403 |
ErrorEnvelope |
The caller does not belong to the board |
404 |
ErrorEnvelope |
Unknown board |
POST /api/boards/{id}/dispatch-rules
Section titled “POST /api/boards/{id}/dispatch-rules”Make a dispatch rule. A task can enter the column and match the
filter. Then Kairos sends one signed delivery to the target. Needs
configure_boards on the board.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
Idempotency-Key |
header | no | string, nullable |
Optional. A key that you choose for this write: 8 to 128 characters of letters, digits, ‘.’, ‘_’, ‘:’ and ‘-’ (a UUID is a good key). Send it when you may retry the request. For 24 hours, a request with the same key and the same arguments writes nothing and gives the first status and body again, with the header Idempotent-Replayed: true. The same key with other arguments is refused with REQUEST_KEY_REUSED (KAIROS-A-0065). |
Request body (required): application/json, CreateDispatchRuleRequest
| Response | Body | Meaning |
|---|---|---|
201 |
DispatchRule |
The rule |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board, target or repository |
409 |
ErrorEnvelope |
REQUEST_KEY_REUSED: the Idempotency-Key was used for a different request |
422 |
ErrorEnvelope |
VALIDATION: an unknown column, task type or metadata definition |
DELETE /api/boards/{id}/dispatch-rules/{rule_id}
Section titled “DELETE /api/boards/{id}/dispatch-rules/{rule_id}”Remove a dispatch rule. Its deliveries stay in the log. Needs
configure_boards on the board.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
rule_id |
path | yes | string |
The id (UUID) of the rule |
| Response | Body | Meaning |
|---|---|---|
200 |
DispatchRule |
The rule that was removed |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board or rule |
GET /api/boards/{id}/flow
Section titled “GET /api/boards/{id}/flow”The flow metrics of a board for a range of days (KAIROS-T-0372). They are the cycle time, the throughput per week, the work in progress and the cumulative flow. A cancelled task counts apart from the done items. The path takes the slug or the id of the board.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
from |
query | no | string |
The first day of the range, YYYY-MM-DD. |
to |
query | no | string |
The last day of the range, YYYY-MM-DD. |
| Response | Body | Meaning |
|---|---|---|
200 |
BoardFlow |
The flow metrics of the range |
404 |
ErrorEnvelope |
Unknown board |
422 |
ErrorEnvelope |
VALIDATION: a date that is not YYYY-MM-DD, from after to, or more than 366 days |
GET /api/boards/{id}/items
Section titled “GET /api/boards/{id}/items”One page of the items on the board, grouped by column (columns in
position order; every entity type — strategies, initiatives, tasks,
ADRs). Open tenant-wide. ?repository= narrows the tasks
(KAIROS-T-0104).
The route has pages (COLLIERY-T-0261). limit is 200 by default and
1000 at most. total is the number of items after the filters, on all
pages. Each column is in each page. children_progress and
blocks_summary have the items of the page.
The order of the items is: the position of the column, then the type, then the short code. The order of the types is: strategy, initiative, task, ADR.
?include_deleted=true adds the archived cards back, in the column
each was put away in and marked with archived_at (KAIROS-T-0159).
That is an audit view, not a board view — “what was in Done last
quarter?” rather than “what is on the board now?”. The opt-in does not
change the counts. The blocks summary counts live rows only: ADR-20
rule 5 says archived work is not live work. The children-progress
rollup counts an archived child by the column that it was archived
from (KAIROS-T-0571): from a done column as done, from another column
in removed.
blocks_summary counts only the blocks edges that can still block
(COLLIERY-T-0214). Done work does not block, and nothing blocks done
work. An edge with either end in a terminal column (is_done) adds to
neither card. The edge stays on the relationship list of each item,
with a mark on the done end.
Each item is a card (KAIROS-T-0602). A card has no content,
created_by or updated_by. ?fields=full adds them: then the
response has the shape that the route had before cards. The item route
of a card gives its content.
?code=<short_code> gives the card of one item (KAIROS-T-0615). The
page then has that card, or no card when no card of the board has the
code. The columns, their counts and the maps are as for a page. A live
board reads one card in this way after an event of that item.
Each card has entered_column_at and notes_count (KAIROS-T-0649).
entered_column_at is the time of the last move of the card, or the
time of its creation. notes_count is the number of its notes. The
page query reads the two for the cards of the page only.
?done_limit=N keeps the last N cards of each done column, by
entered_column_at (KAIROS-T-0649). The other columns keep each card.
item_count stays the count of the full column, and total counts
the cards after the limit. ?code= applies after the limit. N must be
at least 1. Another value is a 422 VALIDATION with details.field =
done_limit.
The path takes the slug or the id of the board (COLLIERY-T-0265). An unknown slug and an unknown id are a 404.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
repository |
query | no | string |
Narrow the TASKS to those bound to this repository (slug or UUID). Other entity types are unaffected. Unknown repository → 422. |
include_deleted |
query | no | boolean |
Include archived (put-away) cards, each marked with archived_at (KAIROS-A-0020 rule 2). Default false — a board is a live board unless the reader says otherwise (rule 3). |
limit |
query | no | integer |
The number of items on a page (default 200, maximum 1000). The server changes a larger value to 1000. |
offset |
query | no | integer |
The number of items to skip (default 0). |
team |
query | no | string |
Narrow the STRATEGIES and the INITIATIVES to those of this team (slug or UUID), from tasks or set by hand (KAIROS-T-0321). Tasks and ADRs are unaffected. Unknown team → 422. Not with no_team. |
no_team |
query | no | boolean |
Narrow the STRATEGIES and the INITIATIVES to those with no team (KAIROS-T-0321). Tasks and ADRs are unaffected. Not with team. |
with_metadata |
query | no | boolean |
Add item_metadata to the response: the metadata values of each item of the page (KAIROS-T-0368). Default false. |
fields |
query | no | string (card, full) |
card (the default): the cards have no content, created_by or updated_by. full: the cards have them, as before cards (KAIROS-T-0602). An other value is refused. |
code |
query | no | string |
Only the card with this short code (KAIROS-T-0615). The page then has one card, or no card when the board has no such card. A live board reads one card with it after an event of that item. |
done_limit |
query | no | integer |
Only the last N cards of each done column, by the time that each card entered the column (KAIROS-T-0649). The other columns keep each card. item_count stays the count of the full column. At least 1. |
| Response | Body | Meaning |
|---|---|---|
200 |
BoardItemsResponse |
One page of the items, grouped by column |
404 |
ErrorEnvelope |
Unknown board |
GET /api/boards/{id}/transitions
Section titled “GET /api/boards/{id}/transitions”List a board’s allowed transitions (open tenant-wide).
The path takes the slug or the id of the board (COLLIERY-T-0265). An unknown slug and an unknown id are a 404.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
| Response | Body | Meaning |
|---|---|---|
200 |
array of BoardTransition |
Transition edges |
404 |
ErrorEnvelope |
Unknown board |
POST /api/boards/{id}/transitions
Section titled “POST /api/boards/{id}/transitions”Add a transition edge (T-0010 rules: endpoints on the board, distinct,
not duplicate). Requires configure_boards.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
Request body (required): application/json, CreateTransitionRequest
| Response | Body | Meaning |
|---|---|---|
201 |
BoardTransition |
Created |
403 |
ErrorEnvelope |
Missing capability |
404 |
ErrorEnvelope |
Unknown board |
422 |
ErrorEnvelope |
DUPLICATE_TRANSITION / VALIDATION |
DELETE /api/boards/{id}/transitions/{transition_id}
Section titled “DELETE /api/boards/{id}/transitions/{transition_id}”Remove a transition edge by id. Requires configure_boards.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
transition_id |
path | yes | string |
Transition id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Removed |
403 |
ErrorEnvelope |
Missing capability |
404 |
ErrorEnvelope |
Unknown board/transition |
GET /api/boards/{id}/webhook-deliveries
Section titled “GET /api/boards/{id}/webhook-deliveries”The delivery log of a board, newest first: each delivery with its
status and its tries. A person who belongs to the board reads it.
before (the id of a delivery) gives the next page: the deliveries
older than that one (KAIROS-T-0584).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
target_id |
query | no | string |
Only the deliveries of this target (id). |
rule_id |
query | no | string |
Only the deliveries of this rule (id). |
limit |
query | no | integer |
The newest deliveries to give, 1 to 200 (50). |
before |
query | no | string |
The id of a delivery of the log: the page has the deliveries older than it (KAIROS-T-0584). |
| Response | Body | Meaning |
|---|---|---|
200 |
array of WebhookDelivery |
The deliveries, newest first |
403 |
ErrorEnvelope |
The caller does not belong to the board |
404 |
ErrorEnvelope |
Unknown board or target, or before is not a delivery of the log |
422 |
ErrorEnvelope |
VALIDATION: a limit out of range, or an id that is not a UUID |
GET /api/boards/{id}/webhook-targets
Section titled “GET /api/boards/{id}/webhook-targets”The webhook targets of a board (KAIROS-T-0384). A person who belongs to the board reads them. A person who cannot configure the board gets each URL with no query.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
| Response | Body | Meaning |
|---|---|---|
200 |
array of WebhookTarget |
The targets of the board |
403 |
ErrorEnvelope |
The caller does not belong to the board |
404 |
ErrorEnvelope |
Unknown board |
POST /api/boards/{id}/webhook-targets
Section titled “POST /api/boards/{id}/webhook-targets”Make a webhook target on a board. Kairos makes the secret, and shows it
in this answer only. Needs configure_boards on the board, and
KAIROS_SECRETS_KEY on the deployment.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
Request body (required): application/json, CreateWebhookTargetRequest
| Response | Body | Meaning |
|---|---|---|
201 |
CreatedWebhookTarget |
The target, and its secret (shown this one time) |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board |
422 |
ErrorEnvelope |
VALIDATION: a bad name, a URL that is not http(s), or a private address |
501 |
ErrorEnvelope |
SECRETS_NOT_CONFIGURED: the deployment has no KAIROS_SECRETS_KEY |
DELETE /api/boards/{id}/webhook-targets/{target_id}
Section titled “DELETE /api/boards/{id}/webhook-targets/{target_id}”Remove a webhook target of a board, with its dispatch rules and its
delivery log. Needs configure_boards on the board.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
target_id |
path | yes | string |
The id (UUID) of the target |
| Response | Body | Meaning |
|---|---|---|
200 |
WebhookTarget |
The target that was removed |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board or target |
POST /api/boards/{id}/webhook-targets/{target_id}/enable
Section titled “POST /api/boards/{id}/webhook-targets/{target_id}/enable”Turn a webhook target on again, with its failed tries in a row at 0.
Kairos queues the skipped deliveries of the last 30 days again, oldest
first (KAIROS-T-0577); redelivered counts them. Needs
configure_boards on the board.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
target_id |
path | yes | string |
The id (UUID) of the target |
| Response | Body | Meaning |
|---|---|---|
200 |
WebhookTarget |
The target, on, with the count of the skipped deliveries queued again |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board or target |
POST /api/boards/{id}/webhook-targets/{target_id}/redeliver
Section titled “POST /api/boards/{id}/webhook-targets/{target_id}/redeliver”Queue the skipped deliveries of a webhook target again
(KAIROS-T-0577). Kairos takes each one of the last 30 days, oldest
first. With since, it takes only the events at or after that time.
Each delivery keeps its id. The target must be on. Needs
configure_boards on the board, as enable.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
target_id |
path | yes | string |
The id (UUID) of the target |
since |
query | no | string |
Only the deliveries of events at or after this time (RFC 3339). With no value: each skipped delivery of the last 30 days. |
| Response | Body | Meaning |
|---|---|---|
200 |
WebhookTarget |
The target, with the count of the skipped deliveries queued again |
400 |
ErrorEnvelope |
VALIDATION: an unknown query parameter |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board or target |
409 |
ErrorEnvelope |
CONFLICT: the target is off; turn it on with enable |
422 |
ErrorEnvelope |
VALIDATION: since is not an RFC 3339 timestamp |
POST /api/boards/{id}/webhook-targets/{target_id}/test
Section titled “POST /api/boards/{id}/webhook-targets/{target_id}/test”Send a test delivery (the event ping) to a webhook target. Needs
configure_boards on the board.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
target_id |
path | yes | string |
The id (UUID) of the target |
| Response | Body | Meaning |
|---|---|---|
201 |
WebhookDelivery |
The delivery, queued (or skipped when the target is off) |
403 |
ErrorEnvelope |
Missing configure_boards |
404 |
ErrorEnvelope |
Unknown board or target |
board-members
Section titled “board-members”GET /api/boards/{id}/members
Section titled “GET /api/boards/{id}/members”List a board’s members and their capability grants (open tenant-wide — A-0006 auditability).
The path takes the slug or the id of the board (COLLIERY-T-0265). An unknown slug and an unknown id are a 404.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the board |
| Response | Body | Meaning |
|---|---|---|
200 |
array of BoardMember |
Members with their capabilities |
404 |
ErrorEnvelope |
Unknown board |
POST /api/boards/{id}/members
Section titled “POST /api/boards/{id}/members”Add a member with capabilities (T-0011 grants; duplicate grant → 409).
Requires administer_members on the board (or org admin).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
Request body (required): application/json, AddBoardMemberRequest
| Response | Body | Meaning |
|---|---|---|
201 |
BoardMember |
Granted |
403 |
ErrorEnvelope |
Missing administer_members |
404 |
ErrorEnvelope |
Unknown board |
409 |
ErrorEnvelope |
A capability was already granted |
422 |
ErrorEnvelope |
Unknown user or capability outside the A-0006 vocabulary |
DELETE /api/boards/{id}/members/{user_id}
Section titled “DELETE /api/boards/{id}/members/{user_id}”Remove a member: revoke ALL their capabilities on the board (T-0011
revokes, one activity row each). Requires administer_members (or org
admin).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
user_id |
path | yes | string |
User id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
RemoveBoardMemberResponse |
All grants revoked |
403 |
ErrorEnvelope |
Missing administer_members |
404 |
ErrorEnvelope |
Unknown board, or user is not a member |
PATCH /api/boards/{id}/members/{user_id}
Section titled “PATCH /api/boards/{id}/members/{user_id}”Replace a member’s capability set (revokes what is absent, grants what
is new — each change is a T-0011 grant/revoke with its activity row).
Requires administer_members on the board (or org admin).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Board id (UUID) |
user_id |
path | yes | string |
User id (UUID) |
Request body (required): application/json, ReplaceCapabilitiesRequest
| Response | Body | Meaning |
|---|---|---|
200 |
BoardMember |
The member’s new capability set |
403 |
ErrorEnvelope |
Missing administer_members |
404 |
ErrorEnvelope |
Unknown board, or user is not a member |
422 |
ErrorEnvelope |
Capability outside the A-0006 vocabulary |
GET /api/members/{user_id}/grants
Section titled “GET /api/members/{user_id}/grants”The grants of one person on the boards that the caller administers (KAIROS-T-0413). The answer also gives the teams of the person.
An organization admin sees each live board. A holder of
administer_members sees only the boards where it holds it. teams is
null unless the caller can change team members.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
user_id |
path | yes | string |
User id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
UserGrants |
The grants of the person on each board that the caller administers |
403 |
ErrorEnvelope |
The caller administers no board |
404 |
ErrorEnvelope |
The user is not a member of the organization |
PATCH /api/members/{user_id}/grants
Section titled “PATCH /api/members/{user_id}/grants”Change the grants of one person on one or more boards, in ONE transaction (KAIROS-T-0413).
Each entry of changes names a board. It gives the capabilities to
grant and the stored grants to revoke.
The caller must administer each board. A board that the caller cannot administer refuses all of the change (403). The refusal names the board. A grant must apply at the level of the board (422).
A grant that the person has already refuses all of the change (409).
A revoke of a grant that the person does not have refuses it too (404).
Each grant and each revoke writes its activity row. The answer is the
new view, as GET gives it.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
user_id |
path | yes | string |
User id (UUID) |
Request body (required): application/json, ChangeUserGrantsRequest
| Response | Body | Meaning |
|---|---|---|
200 |
UserGrants |
All the changes were applied; the new grants |
403 |
ErrorEnvelope |
The caller cannot administer a board of the change; no change was applied |
404 |
ErrorEnvelope |
Unknown board or user, or a revoke of a grant that the person does not have |
409 |
ErrorEnvelope |
A grant that the person has already |
422 |
ErrorEnvelope |
No change, a board two times, or a capability that does not apply at the level of the board |
structure-grants
Section titled “structure-grants”GET /api/structure-grants
Section titled “GET /api/structure-grants”List each grant of manage_structure (open tenant-wide).
| Response | Body | Meaning |
|---|---|---|
200 |
array of StructureGrant |
The grants: the grants at the organization first, then the grants on live boards |
401 |
ErrorEnvelope |
Missing/invalid token |
POST /api/structure-grants
Section titled “POST /api/structure-grants”Grant manage_structure to a person or a service account, on the
organization (no board) or on one board. Only an organization admin
can grant it. A holder of manage_structure cannot grant it. A second
grant at the same scope is a 409.
Request body (required): application/json, CreateStructureGrantRequest
| Response | Body | Meaning |
|---|---|---|
201 |
StructureGrant |
Granted |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Unknown board |
409 |
ErrorEnvelope |
The principal has the grant at this scope already |
422 |
ErrorEnvelope |
No member of the organization has the reference |
DELETE /api/structure-grants/{id}
Section titled “DELETE /api/structure-grants/{id}”Revoke a grant of manage_structure. Only an organization admin can
revoke it.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The id of the grant (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
StructureGrant |
Revoked; the body is the grant that was revoked |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Unknown grant |
GET /api/standup-groups
Section titled “GET /api/standup-groups”Each stand-up group of the organization, by name, with its people. Each member of the organization reads each group.
| Response | Body | Meaning |
|---|---|---|
200 |
StandupGroupList |
Each group, by name |
401 |
ErrorEnvelope |
Missing/invalid token |
POST /api/standup-groups
Section titled “POST /api/standup-groups”Create a stand-up group. Each member of the organization can. The name is unique in the organization, with no regard to case. Each person must be a person of the organization: a user id, an email or a user name.
Request body (required): application/json, CreateStandupGroupRequest
| Response | Body | Meaning |
|---|---|---|
201 |
StandupGroup |
The new group |
401 |
ErrorEnvelope |
Missing/invalid token |
409 |
ErrorEnvelope |
A different group has the name |
422 |
ErrorEnvelope |
A name with no characters or too many, or a person who is not a person of the organization |
GET /api/standup-groups/{id}
Section titled “GET /api/standup-groups/{id}”One stand-up group, with its people.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The id (UUID) of the group |
| Response | Body | Meaning |
|---|---|---|
200 |
StandupGroup |
The group |
401 |
ErrorEnvelope |
Missing/invalid token |
404 |
ErrorEnvelope |
Unknown group |
DELETE /api/standup-groups/{id}
Section titled “DELETE /api/standup-groups/{id}”Delete a stand-up group and its people. Only the person who created the group can delete it. The answer is the group before the delete.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The id (UUID) of the group |
| Response | Body | Meaning |
|---|---|---|
200 |
StandupGroup |
The group that was deleted |
401 |
ErrorEnvelope |
Missing/invalid token |
403 |
ErrorEnvelope |
The caller did not create the group |
404 |
ErrorEnvelope |
Unknown group |
PATCH /api/standup-groups/{id}
Section titled “PATCH /api/standup-groups/{id}”Change the name, the people, or both, of a stand-up group. Each member
of the organization can edit each group. people is the full list
after the change.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The id (UUID) of the group |
Request body (required): application/json, UpdateStandupGroupRequest
| Response | Body | Meaning |
|---|---|---|
200 |
StandupGroup |
The group after the change |
401 |
ErrorEnvelope |
Missing/invalid token |
404 |
ErrorEnvelope |
Unknown group |
409 |
ErrorEnvelope |
A different group has the name |
422 |
ErrorEnvelope |
No field to change, a bad name, or a person who is not a person of the organization |
GET /api/standup-groups/{id}/people/{user_id}
Section titled “GET /api/standup-groups/{id}/people/{user_id}”The stop of one person of a stand-up group: the work of the person by ownership on each board, in two lanes.
- Initiatives: the initiatives that the person owns, of each team.
- Tasks: the tasks on each board that the person, or an agent key of the person, claims.
Any member of the organization can read the stop of any person of a group.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The id (UUID) of the group |
user_id |
path | yes | string |
The id (UUID) of a person of the group |
| Response | Body | Meaning |
|---|---|---|
200 |
MyWork |
The two lanes of the work of the person |
401 |
ErrorEnvelope |
Missing/invalid token |
404 |
ErrorEnvelope |
Unknown group, or the person is not in the group |
GET /api/teams
Section titled “GET /api/teams”List teams (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
limit |
query | no | integer |
Page size (default 50, max 200). |
offset |
query | no | integer |
Rows to skip (default 0). |
| Response | Body | Meaning |
|---|---|---|
200 |
ListEnvelope_Team |
Page of teams |
401 |
ErrorEnvelope |
Missing/invalid token |
POST /api/teams
Section titled “POST /api/teams”Create a team AND its delivery board (seeded from the system delivery
defaults, slug {slug}-delivery) in one transaction. An organization admin,
or manage_structure on the organization (KAIROS-T-0337).
The slug must match ^[a-z][a-z0-9_-]{1,62}$, and it cannot have the
form of a UUID (COLLIERY-T-0260). If not, the request is a 422
VALIDATION with details.field = slug.
A live board can have the slug {slug}-delivery already
(COLLIERY-T-0255). Then the request is a 409 CONFLICT that names that
board, and the server creates no team.
code_prefix is the short-code prefix of the delivery board
(COLLIERY-T-3099). It is required. A prefix that does not match
^[A-Z][A-Z0-9]{1,9}$ is a 422 VALIDATION with details.field =
code_prefix. A prefix that a live delivery board has is a 409
CONFLICT that names that board. In each case the server creates no
team.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
Idempotency-Key |
header | no | string, nullable |
Optional. A key that you choose for this write: 8 to 128 characters of letters, digits, ‘.’, ‘_’, ‘:’ and ‘-’ (a UUID is a good key). Send it when you may retry the request. For 24 hours, a request with the same key and the same arguments writes nothing and gives the first status and body again, with the header Idempotent-Replayed: true. The same key with other arguments is refused with REQUEST_KEY_REUSED (KAIROS-A-0065). |
Request body (required): application/json, CreateTeamRequest
| Response | Body | Meaning |
|---|---|---|
201 |
Team |
Created; delivery_board_id names the team’s new board |
403 |
ErrorEnvelope |
Not an org admin, and no manage_structure on the organization |
409 |
ErrorEnvelope |
A live team has the slug, a live board has the slug of the delivery board, or a live delivery board has the prefix; or REQUEST_KEY_REUSED: the Idempotency-Key was used for a different request |
422 |
ErrorEnvelope |
Bad team_type, the slug does not have the form of a slug, or the code_prefix is absent or does not match the rule |
GET /api/teams/by-slug/{slug}
Section titled “GET /api/teams/by-slug/{slug}”One live team by SLUG (open tenant-wide; KAIROS-T-0083 — the web
client resolves /teams/:slug here instead of scanning the list).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
slug |
path | yes | string |
Team slug |
| Response | Body | Meaning |
|---|---|---|
200 |
Team |
The team |
404 |
ErrorEnvelope |
Unknown slug |
GET /api/teams/{id}
Section titled “GET /api/teams/{id}”Get one team (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
Team |
The team |
404 |
ErrorEnvelope |
Unknown team |
DELETE /api/teams/{id}
Section titled “DELETE /api/teams/{id}”Soft-delete a team and its delivery board together. The board must be
empty (422 BOARD_NOT_EMPTY — the T-0010 empty rule). An organization
admin, or manage_structure on the organization (KAIROS-T-0337).
A team of old data can have 2 or more live delivery boards. The delete applies the rule to each board, and it removes each board with the team (COLLIERY-T-0250). The refusal names the board that is not empty.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Team and delivery board soft-deleted |
403 |
ErrorEnvelope |
Not an org admin, and no manage_structure on the organization |
404 |
ErrorEnvelope |
Unknown team |
422 |
ErrorEnvelope |
BOARD_NOT_EMPTY, or BOARD_OWNS_DOCUMENTS |
PATCH /api/teams/{id}
Section titled “PATCH /api/teams/{id}”Update a team (name/slug/team_type). An organization admin, or
manage_structure on the organization (KAIROS-T-0337). The delivery
board’s name/slug are independent and unchanged.
A new slug must match ^[a-z][a-z0-9_-]{1,62}$, and it cannot have the
form of a UUID (COLLIERY-T-0260). If not, the request is a 422
VALIDATION with details.field = slug. A team with a slug from
before the rule keeps that slug.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
Request body (required): application/json, UpdateTeamRequest
| Response | Body | Meaning |
|---|---|---|
200 |
Team |
Updated |
403 |
ErrorEnvelope |
Not an org admin, and no manage_structure on the organization |
404 |
ErrorEnvelope |
Unknown team |
409 |
ErrorEnvelope |
Slug already in use |
422 |
ErrorEnvelope |
Bad team_type, empty body, or the new slug does not have the form of a slug |
GET /api/teams/{id}/links
Section titled “GET /api/teams/{id}/links”The team’s in-flight forge links (KAIROS-T-0101): links whose item is a task of this team, or an item on the team’s delivery board, or whose repository is attributed to the team. Open tenant-wide.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
state |
query | no | string |
Comma-separated states; defaults to open,draft — the panel’s question is “what is in flight”, not merged history. |
limit |
query | no | integer |
Result cap (default 100). |
| Response | Body | Meaning |
|---|---|---|
200 |
array of TeamLink |
In-flight links, newest first |
404 |
ErrorEnvelope |
Unknown team |
GET /api/teams/{id}/members
Section titled “GET /api/teams/{id}/members”List a team’s members (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
array of TeamMember |
Members |
404 |
ErrorEnvelope |
Unknown team |
POST /api/teams/{id}/members
Section titled “POST /api/teams/{id}/members”Add a member to a team. An organization admin, or manage_structure
on the organization (KAIROS-T-0337).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
Request body (required): application/json, AddTeamMemberRequest
| Response | Body | Meaning |
|---|---|---|
201 |
TeamMember |
Added |
403 |
ErrorEnvelope |
Not an org admin, and no manage_structure on the organization |
404 |
ErrorEnvelope |
Unknown team |
409 |
ErrorEnvelope |
Already a member |
422 |
ErrorEnvelope |
Unknown user |
DELETE /api/teams/{id}/members/{user_id}
Section titled “DELETE /api/teams/{id}/members/{user_id}”Remove a member from a team. An organization admin, or
manage_structure on the organization (KAIROS-T-0337).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
user_id |
path | yes | string |
User id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Removed |
403 |
ErrorEnvelope |
Not an org admin, and no manage_structure on the organization |
404 |
ErrorEnvelope |
Unknown team or not a member |
GET /api/teams/{id}/standup
Section titled “GET /api/teams/{id}/standup”The team of a stand-up and its people.
The people are the members of the team, by display name. Some people
are not members but claim a task of the team or own an initiative of
the team. They get a turn too, with member: false. A service account
is not in the list. The page shuffles the list.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
Standup |
The team and its people |
401 |
ErrorEnvelope |
Missing/invalid token |
404 |
ErrorEnvelope |
Unknown team |
GET /api/teams/{id}/standup/people/{user_id}
Section titled “GET /api/teams/{id}/standup/people/{user_id}”The work of one person in a team, in two lanes.
- Initiatives: the initiatives that the person owns and that have the team (from their tasks, or set by hand).
- Tasks: the tasks on the boards of the team that the person, or an agent key of the person, claims.
Any member of the organization can read the work of any person. The person does not have to be a member of the team.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
user_id |
path | yes | string |
The id (UUID) of the person |
| Response | Body | Meaning |
|---|---|---|
200 |
MyWork |
The two lanes of the work of the person in the team |
401 |
ErrorEnvelope |
Missing/invalid token |
404 |
ErrorEnvelope |
Unknown team or person |
GET /api/teams/{id}/standup/unclaimed
Section titled “GET /api/teams/{id}/standup/unclaimed”The last stop of a stand-up. It gives the tasks on the boards of the team that no one claims, in the state Todo or Blocked. A task in Backlog is not in it.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
UnclaimedWork |
The unclaimed tasks of the team |
401 |
ErrorEnvelope |
Missing/invalid token |
404 |
ErrorEnvelope |
Unknown team |
GET /api/teams/{id}/unlinked-refs
Section titled “GET /api/teams/{id}/unlinked-refs”The in-flight branches and pull requests with no linked item, in the
repositories of the team (KAIROS-T-0480). This is the other half of the
rollup of /api/teams/{id}/links. Open tenant-wide.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
state |
query | no | string |
Comma-separated states; defaults to open,draft — the panel’s question is “what is in flight”, not merged history. |
limit |
query | no | integer |
Result cap (default 100). |
| Response | Body | Meaning |
|---|---|---|
200 |
array of ForgeRef |
Branches and pull requests with no linked item, newest first |
404 |
ErrorEnvelope |
Unknown team |
team-pages
Section titled “team-pages”GET /api/teams/{id}/announcements
Section titled “GET /api/teams/{id}/announcements”One page of the team’s announcements, pinned first then newest (open tenant-wide; KAIROS-T-0629: limit and offset).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
limit |
query | no | integer |
Page size (default 50, max 200). |
offset |
query | no | integer |
Rows to skip (default 0). |
| Response | Body | Meaning |
|---|---|---|
200 |
ListEnvelope_TeamAnnouncement |
One page of the announcements |
404 |
ErrorEnvelope |
Unknown team |
POST /api/teams/{id}/announcements
Section titled “POST /api/teams/{id}/announcements”Post an announcement (team member or org admin; append-only — there is no edit route).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
Request body (required): application/json, CreateTeamAnnouncementRequest
| Response | Body | Meaning |
|---|---|---|
201 |
TeamAnnouncement |
Posted |
403 |
ErrorEnvelope |
Not a team member |
404 |
ErrorEnvelope |
Unknown team |
422 |
ErrorEnvelope |
Body too large |
DELETE /api/teams/{id}/announcements/{announcement_id}
Section titled “DELETE /api/teams/{id}/announcements/{announcement_id}”Delete an announcement (its author or an org admin).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
announcement_id |
path | yes | string |
Announcement id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Deleted |
403 |
ErrorEnvelope |
Not the author (and not org admin) |
404 |
ErrorEnvelope |
Unknown team or announcement |
GET /api/teams/{id}/archived-pages
Section titled “GET /api/teams/{id}/archived-pages”The archived nodes of a team, newest archive first (open tenant-wide, KAIROS-T-0439).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
array of ArchivedTeamPage |
The archived nodes |
404 |
ErrorEnvelope |
Unknown team |
GET /api/teams/{id}/pages
Section titled “GET /api/teams/{id}/pages”The team’s live page tree as a flat list, without content (open
tenant-wide). GET /api/teams/{id}/pages/{page_id} gives the content
of one page (KAIROS-T-0629).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
array of TeamPageSummary |
The page tree, flat, without content |
404 |
ErrorEnvelope |
Unknown team |
POST /api/teams/{id}/pages
Section titled “POST /api/teams/{id}/pages”Create a page or folder (team member or org admin).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
Idempotency-Key |
header | no | string, nullable |
Optional. A key that you choose for this write: 8 to 128 characters of letters, digits, ‘.’, ‘_’, ‘:’ and ‘-’ (a UUID is a good key). Send it when you may retry the request. For 24 hours, a request with the same key and the same arguments writes nothing and gives the first status and body again, with the header Idempotent-Replayed: true. The same key with other arguments is refused with REQUEST_KEY_REUSED (KAIROS-A-0065). |
Request body (required): application/json, CreateTeamPageRequest
| Response | Body | Meaning |
|---|---|---|
201 |
TeamPage |
Created |
403 |
ErrorEnvelope |
Not a team member |
404 |
ErrorEnvelope |
Unknown team |
409 |
ErrorEnvelope |
REQUEST_KEY_REUSED: the Idempotency-Key was used for a different request |
422 |
ErrorEnvelope |
Bad kind/parent, sibling slug conflict, or content too large |
GET /api/teams/{id}/pages/{page_id}
Section titled “GET /api/teams/{id}/pages/{page_id}”One live page (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
page_id |
path | yes | string |
Page id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
TeamPage |
The page |
404 |
ErrorEnvelope |
Unknown team or page |
DELETE /api/teams/{id}/pages/{page_id}
Section titled “DELETE /api/teams/{id}/pages/{page_id}”Archive a page, or a folder with everything in it (the Charter never).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
page_id |
path | yes | string |
Page id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Deleted |
403 |
ErrorEnvelope |
Not a team member |
404 |
ErrorEnvelope |
Unknown team or page |
422 |
ErrorEnvelope |
Protected page |
PATCH /api/teams/{id}/pages/{page_id}
Section titled “PATCH /api/teams/{id}/pages/{page_id}”Edit a page: EITHER a version-checked content save OR a rename/move — not both in one call.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
page_id |
path | yes | string |
Page id (UUID) |
Request body (required): application/json, UpdateTeamPageRequest
| Response | Body | Meaning |
|---|---|---|
200 |
TeamPage |
Updated |
403 |
ErrorEnvelope |
Not a team member |
404 |
ErrorEnvelope |
Unknown team or page |
409 |
ErrorEnvelope |
Stale version; details.current carries the current page |
422 |
ErrorEnvelope |
Mixed edit kinds, protected page, slug conflict, or bad parent |
GET /api/teams/{id}/pages/{page_id}/history
Section titled “GET /api/teams/{id}/pages/{page_id}/history”The saved versions of a page, newest first, without content, or one
version in full with ?version=N (open tenant-wide, KAIROS-T-0439,
KAIROS-T-0629).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
page_id |
path | yes | string |
Page id (UUID) |
version |
query | no | integer |
Return this version in full instead of the version list. |
limit |
query | no | integer |
Page size for the version list (default 50, max 200). |
offset |
query | no | integer |
Rows to skip (default 0). |
| Response | Body | Meaning |
|---|---|---|
200 |
ListEnvelope_TeamPageVersionSummary |
One page of the versions, newest first, without content (or a TeamPageVersion with ?version=N) |
404 |
ErrorEnvelope |
Unknown team, page, or version |
POST /api/teams/{id}/pages/{page_id}/restore
Section titled “POST /api/teams/{id}/pages/{page_id}/restore”Restore an archived node and what was archived with it (team member or organization admin, KAIROS-T-0439).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
page_id |
path | yes | string |
Page id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
TeamPage |
Restored |
403 |
ErrorEnvelope |
Not a team member |
404 |
ErrorEnvelope |
Unknown team or page |
422 |
ErrorEnvelope |
Not archived, or a live sibling has the slug |
GET /api/teams/{id}/tree-items
Section titled “GET /api/teams/{id}/tree-items”The documents and ADRs of a team with their places in its tree (open tenant-wide, KAIROS-T-0437).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
| Response | Body | Meaning |
|---|---|---|
200 |
array of TeamTreeItem |
The items of the team |
404 |
ErrorEnvelope |
Unknown team |
PUT /api/teams/{id}/tree-items/{item}
Section titled “PUT /api/teams/{id}/tree-items/{item}”Put a document or an ADR of the team in a folder of its tree
(KAIROS-T-0437). A team member or an organization admin can do this.
item is a short code or a UUID.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
The slug or the id (UUID) of the team |
item |
path | yes | string |
The short code or the id of a document or an ADR of the team |
Request body (required): application/json, PlaceTeamItemRequest
| Response | Body | Meaning |
|---|---|---|
200 |
TeamTreeItem |
Placed |
403 |
ErrorEnvelope |
Not a team member |
404 |
ErrorEnvelope |
Unknown team |
422 |
ErrorEnvelope |
Not an item of the team, or a parent that is not a live folder |
delivery-streams
Section titled “delivery-streams”GET /api/delivery-streams
Section titled “GET /api/delivery-streams”List delivery streams (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
limit |
query | no | integer |
Page size (default 50, max 200). |
offset |
query | no | integer |
Rows to skip (default 0). |
| Response | Body | Meaning |
|---|---|---|
200 |
ListEnvelope_DeliveryStream |
Page of streams |
401 |
ErrorEnvelope |
Missing/invalid token |
POST /api/delivery-streams
Section titled “POST /api/delivery-streams”Create a delivery stream. Org-admin-only.
The slug must match ^[a-z][a-z0-9_-]{1,62}$, and it cannot have the
form of a UUID (COLLIERY-T-0260). If not, the request is a 422
VALIDATION with details.field = slug.
Request body (required): application/json, CreateStreamRequest
| Response | Body | Meaning |
|---|---|---|
201 |
DeliveryStream |
Created |
403 |
ErrorEnvelope |
Not an org admin |
409 |
ErrorEnvelope |
Slug already in use |
422 |
ErrorEnvelope |
The slug does not have the form of a slug |
GET /api/delivery-streams/{id}
Section titled “GET /api/delivery-streams/{id}”Get one delivery stream (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Stream id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
DeliveryStream |
The stream |
404 |
ErrorEnvelope |
Unknown stream |
DELETE /api/delivery-streams/{id}
Section titled “DELETE /api/delivery-streams/{id}”Soft-delete a delivery stream (team links are left in place — the stream is recoverable). Org-admin-only.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Stream id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Soft-deleted |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Unknown stream |
PATCH /api/delivery-streams/{id}
Section titled “PATCH /api/delivery-streams/{id}”Update a delivery stream. Org-admin-only.
A new slug must match ^[a-z][a-z0-9_-]{1,62}$, and it cannot have the
form of a UUID (COLLIERY-T-0260). If not, the request is a 422
VALIDATION with details.field = slug. A delivery stream with a
slug from before the rule keeps that slug.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Stream id (UUID) |
Request body (required): application/json, UpdateStreamRequest
| Response | Body | Meaning |
|---|---|---|
200 |
DeliveryStream |
Updated |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Unknown stream |
409 |
ErrorEnvelope |
Slug already in use |
422 |
ErrorEnvelope |
Empty body, or the new slug does not have the form of a slug |
GET /api/delivery-streams/{id}/teams
Section titled “GET /api/delivery-streams/{id}/teams”Teams in this stream (open tenant-wide).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Stream id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
array of Team |
Teams in the stream |
404 |
ErrorEnvelope |
Unknown stream |
POST /api/delivery-streams/{id}/teams
Section titled “POST /api/delivery-streams/{id}/teams”Add a team to a stream. Org-admin-only.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Stream id (UUID) |
Request body (required): application/json, AddStreamTeamRequest
| Response | Body | Meaning |
|---|---|---|
201 |
OrgDeleteResponse |
Added |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Unknown stream |
409 |
ErrorEnvelope |
Team already in the stream |
422 |
ErrorEnvelope |
Unknown team |
DELETE /api/delivery-streams/{id}/teams/{team_id}
Section titled “DELETE /api/delivery-streams/{id}/teams/{team_id}”Remove a team from a stream. Org-admin-only.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string |
Stream id (UUID) |
team_id |
path | yes | string |
Team id (UUID) |
| Response | Body | Meaning |
|---|---|---|
200 |
OrgDeleteResponse |
Removed |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Unknown stream or team not in stream |
members
Section titled “members”GET /api/members
Section titled “GET /api/members”List the organization’s members (open tenant-wide, paginated, ordered by email).
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
limit |
query | no | integer |
Page size (default 50, max 200). |
offset |
query | no | integer |
Rows to skip (default 0). |
| Response | Body | Meaning |
|---|---|---|
200 |
ListEnvelope_OrgMember |
Page of members |
401 |
ErrorEnvelope |
Missing/invalid token |
POST /api/members
Section titled “POST /api/members”Add a member by email. The user must have logged in once already (JIT
provisioning creates public.users rows at first login) — unknown
email is 404 with that guidance. Org-admin-only.
Request body (required): application/json, AddOrgMemberRequest
| Response | Body | Meaning |
|---|---|---|
201 |
OrgMember |
Added |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
No user with this email has logged in yet |
409 |
ErrorEnvelope |
Already a member |
422 |
ErrorEnvelope |
Bad role |
DELETE /api/members/{user_id}
Section titled “DELETE /api/members/{user_id}”Remove a member. Removing the LAST admin is rejected (422 LAST_ADMIN).
Kairos revokes the agent keys of the member in the same transaction
(KAIROS-T-0388). Then the strategies and the initiatives of the member
have no owner (KAIROS-T-0411). The tasks that the member has the claim
on are free (KAIROS-T-0531). Org-admin-only.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
user_id |
path | yes | string |
The member: a user id (UUID), an email or a user name |
| Response | Body | Meaning |
|---|---|---|
200 |
RemoveOrgMemberResponse |
Removed |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Not a member |
422 |
ErrorEnvelope |
LAST_ADMIN |
PATCH /api/members/{user_id}
Section titled “PATCH /api/members/{user_id}”Change a member’s role. Demoting the LAST admin is rejected (422
LAST_ADMIN). Org-admin-only.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
user_id |
path | yes | string |
The member: a user id (UUID), an email or a user name |
Request body (required): application/json, UpdateOrgMemberRequest
| Response | Body | Meaning |
|---|---|---|
200 |
OrgMember |
Updated |
403 |
ErrorEnvelope |
Not an org admin |
404 |
ErrorEnvelope |
Not a member |
422 |
ErrorEnvelope |
LAST_ADMIN or bad role |