Theme
Presence + Comments API
Real-time collaboration on a Story: see who's editing right now, leave threaded comments on individual blocks, resolve discussions.
Presence
Heartbeat-based — clients ping every 15s with their cursor focus.
http
POST /v1/spaces/{slug}/stories/{uuid}/presence
GET /v1/spaces/{slug}/stories/{uuid}/presence
DELETE /v1/spaces/{slug}/stories/{uuid}/presence/{session_id}POST body:
json
{
"session_id": "client-uuid-v4",
"block_path": "blocks/2/headline",
"selection": { "anchor": 12, "head": 30 }
}GET returns active sessions (last heartbeat ≤ 30s ago):
json
{
"data": [
{
"session_id": "abc",
"user_id": 4,
"user_name": "Lisa",
"block_path": "blocks/2/headline",
"last_seen": "2026-05-27T19:00:00Z"
}
]
}Cleanup
DELETE is a courtesy — sessions older than 5 minutes are pruned by a background worker regardless.
Comments
Block-anchored threads.
http
GET /v1/spaces/{slug}/stories/{uuid}/comments
POST /v1/spaces/{slug}/stories/{uuid}/comments
PATCH /v1/spaces/{slug}/stories/{uuid}/comments/{id}
DELETE /v1/spaces/{slug}/stories/{uuid}/comments/{id}
POST /v1/spaces/{slug}/stories/{uuid}/comments/{id}/resolvePOST body:
json
{
"block_path": "blocks/2",
"body": "Headline reads more like a question than a statement?",
"parent_id": null
}Threads form a single-level tree (no nested nesting) — parent_id points at the root comment of the thread.
Resolved comments stay queryable but are hidden in the editor by default. Re-open with POST .../{id}/resolve again (toggles).
RBAC
| Role | Can do |
|---|---|
viewer | read presence + comments |
editor | + post comments, edit/delete own comments |
admin | + edit/delete any comment, resolve any thread |
See also
/api/workflow— formal approval flow/api/stories— Story CRUD