Collaboration
Comments, page history, activity, notifications, attachments and the workspace symbol library.
26 operations. Every path is relative to the instance origin; every response body is JSON unless stated. See API for authentication, errors and pagination.
POST /api/v1/workspaces/{workspaceId}/attachments
Upload an image attachment (multipart/form-data, one file field; image/* only, 10 MiB max). Send a pageId field naming the page the image goes on: it requires edit there and decides who may read the bytes afterwards. Omit it only for an icon — that uploads workspace-scoped (member+), readable by every member. Returns the attachment DTO whose url is a relative same-origin serve path.
uploadAttachment · token scope: content:write
Path parameters
workspaceId· string (uuid) — required
Response 200 — application/json
id· string (uuid) — requiredurl· string — requiredfilename· string — requiredmime· string — requiredsizeBytes· integer — required, 0–9007199254740991
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/attachments/{attachmentId}
Stream an attachment's bytes with its stored Content-Type and a long immutable Cache-Control (ids are stable). Workspace-scoped; auth + membership guarded. Served as an image, not JSON — use as an <img src>.
getAttachment · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredattachmentId· string (uuid) — required
Response 200 — application/json
- string
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/symbols
The workspace's named symbols, newest first. Readable by every member — an entry only names bytes that are already workspace-scoped.
listSymbols · token scope: session only
Path parameters
workspaceId· string (uuid) — required
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredname· string — requiredattachmentId· string (uuid) — requiredurl· string — requiredmime· string — requiredcreatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/symbols
Name a workspace-scoped attachment so it appears in the symbol library. Upload the image first with uploadAttachment and omit its pageId; a page-scoped attachment is refused, because naming it would widen who may read the bytes. Requires member.
createSymbol · token scope: session only
Path parameters
workspaceId· string (uuid) — required
Request body — application/json, required
attachmentId· string (uuid) — requiredname· string — required, length 1–80
Response 200 — application/json
id· string (uuid) — requiredname· string — requiredattachmentId· string (uuid) — requiredurl· string — requiredmime· string — requiredcreatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
PATCH /api/v1/workspaces/{workspaceId}/symbols/{symbolId}
Rename a symbol. Requires member.
updateSymbol · token scope: session only
Path parameters
workspaceId· string (uuid) — requiredsymbolId· string (uuid) — required
Request body — application/json, required
name· string — required, length 1–80
Response 200 — application/json
id· string (uuid) — requiredname· string — requiredattachmentId· string (uuid) — requiredurl· string — requiredmime· string — requiredcreatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
DELETE /api/v1/workspaces/{workspaceId}/symbols/{symbolId}
Remove a symbol from the library. The underlying attachment and its bytes are kept on purpose: icons are stored by URL, so deleting them would break every page already wearing this one. Requires member.
deleteSymbol · token scope: session only
Path parameters
workspaceId· string (uuid) — requiredsymbolId· string (uuid) — required
Response 200 — application/json
ok·true— required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/pages/{pageId}/comments
Every comment thread on a page, with its replies, oldest thread first. Needs read on the page (ADR-0016 D4); a trashed page resolves to no capability and answers 404 (D9c). Each thread's anchor is resolved against the server's copy of the document, so state and currentText say whether it still points at text.
listPageComments · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — required
Query parameters
status·"open"|"resolved"|"all"
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredworkspaceId· string (uuid) — requiredpageId· string (uuid) — requiredpageTitle· string — requiredanchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — requiredstart· string (byte) | null — requiredend· string (byte) | null — requiredstate·"anchored"|"orphaned"|"unknown"— requiredcurrentText· string | null — required
resolved· boolean — requiredresolvedAt· string (date-time) | null — requiredresolvedBy· string (uuid) | null — requiredcreatedBy· string (uuid) — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requiredcomments· object[] — requiredid· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/pages/{pageId}/comments
Open a thread on a page — anchored to a block or to a text range — with its first comment. Needs comment on the page, the level D4 defines for exactly this.
createCommentThread · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — required
Request body — application/json, required
body· string — required, length 1–10000anchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — length 0–2000start· string (byte) — length 0–2048end· string (byte) — length 0–2048
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredpageId· string (uuid) — requiredpageTitle· string — requiredanchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — requiredstart· string (byte) | null — requiredend· string (byte) | null — requiredstate·"anchored"|"orphaned"|"unknown"— requiredcurrentText· string | null — required
resolved· boolean — requiredresolvedAt· string (date-time) | null — requiredresolvedBy· string (uuid) | null — requiredcreatedBy· string (uuid) — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requiredcomments· object[] — requiredid· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/comments
Comment threads across the workspace, most recent first — the review queue. Keyset-paginated and permission-filtered inside the SQL, before the LIMIT (D9): threads on pages the caller cannot read, and on trashed pages, are gone before the page is cut. Anchors are NOT resolved here (state is unknown) — this listing loads no documents.
listWorkspaceComments · token scope: content:read
Path parameters
workspaceId· string (uuid) — required
Query parameters
cursor· string — length 1–∞limit· integer — 1–100status·"open"|"resolved"|"all"
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredworkspaceId· string (uuid) — requiredpageId· string (uuid) — requiredpageTitle· string — requiredanchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — requiredstart· string (byte) | null — requiredend· string (byte) | null — requiredstate·"anchored"|"orphaned"|"unknown"— requiredcurrentText· string | null — required
resolved· boolean — requiredresolvedAt· string (date-time) | null — requiredresolvedBy· string (uuid) | null — requiredcreatedBy· string (uuid) — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requiredcomments· object[] — requiredid· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
nextCursor· string | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/comment-threads/{threadId}
One thread with its replies. Needs read on the page it is anchored to.
getCommentThread · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredthreadId· string (uuid) — required
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredpageId· string (uuid) — requiredpageTitle· string — requiredanchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — requiredstart· string (byte) | null — requiredend· string (byte) | null — requiredstate·"anchored"|"orphaned"|"unknown"— requiredcurrentText· string | null — required
resolved· boolean — requiredresolvedAt· string (date-time) | null — requiredresolvedBy· string (uuid) | null — requiredcreatedBy· string (uuid) — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requiredcomments· object[] — requiredid· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/comment-threads/{threadId}/comments
Append a reply to a thread. Needs comment on the page.
replyToCommentThread · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredthreadId· string (uuid) — required
Request body — application/json, required
body· string — required, length 1–10000
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredpageId· string (uuid) — requiredpageTitle· string — requiredanchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — requiredstart· string (byte) | null — requiredend· string (byte) | null — requiredstate·"anchored"|"orphaned"|"unknown"— requiredcurrentText· string | null — required
resolved· boolean — requiredresolvedAt· string (date-time) | null — requiredresolvedBy· string (uuid) | null — requiredcreatedBy· string (uuid) — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requiredcomments· object[] — requiredid· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/comment-threads/{threadId}/resolve
Resolve or un-resolve a thread. Needs comment on the page: settling a discussion is part of taking part in it, and a reviewer who may reply but never tidy up leaves every page permanently marked.
resolveCommentThread · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredthreadId· string (uuid) — required
Request body — application/json, required
resolved· boolean — required
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredpageId· string (uuid) — requiredpageTitle· string — requiredanchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — requiredstart· string (byte) | null — requiredend· string (byte) | null — requiredstate·"anchored"|"orphaned"|"unknown"— requiredcurrentText· string | null — required
resolved· boolean — requiredresolvedAt· string (date-time) | null — requiredresolvedBy· string (uuid) | null — requiredcreatedBy· string (uuid) — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requiredcomments· object[] — requiredid· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
PATCH /api/v1/workspaces/{workspaceId}/comment-threads/{threadId}/comments/{commentId}
Edit a comment's body. Authors only — edit on the page does not include putting words in someone else's mouth.
updateComment · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredthreadId· string (uuid) — requiredcommentId· string (uuid) — required
Request body — application/json, required
body· string — required, length 1–10000
Response 200 — application/json
id· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
DELETE /api/v1/workspaces/{workspaceId}/comment-threads/{threadId}/comments/{commentId}
Delete a comment. Its author may always delete it; so may anyone with edit on the page, since moderating a page is part of maintaining it. Deleting the last comment deletes the thread.
deleteComment · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredthreadId· string (uuid) — requiredcommentId· string (uuid) — required
Response 200 — application/json
commentId· string (uuid) — requiredthreadDeleted· boolean — requiredthread· object | null — requiredid· string (uuid) — requiredworkspaceId· string (uuid) — requiredpageId· string (uuid) — requiredpageTitle· string — requiredanchor· object — requiredkind·"block"|"text"— requiredblockId· string (uuid) — requiredquote· string — requiredstart· string (byte) | null — requiredend· string (byte) | null — requiredstate·"anchored"|"orphaned"|"unknown"— requiredcurrentText· string | null — required
resolved· boolean — requiredresolvedAt· string (date-time) | null — requiredresolvedBy· string (uuid) | null — requiredcreatedBy· string (uuid) — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requiredcomments· object[] — requiredid· string (uuid) — requiredthreadId· string (uuid) — requiredbody· string — requiredauthor· object — requiredid· string (uuid) — requiredemail· string (email) | null — requiredname· string | null — requiredimage· string | null — required
createdAt· string (date-time) — requirededitedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/pages/{pageId}/history
Browse a page's versions, newest first, keyset-paginated. History is content, so it is gated like content (ADR-0016 D4): read on the page. A trashed page resolves to no capability and answers 404 (D9c) — the same answer an unknown page id gets. Metadata only; use getPageVersion for a version's body.
listPageVersions · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — required
Query parameters
cursor· string — length 1–∞limit· integer — 1–100
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredpageId· string (uuid) — requiredkind·"auto"|"manual"|"pre_restore"|"restore"— requiredlabel· string | null — requiredtitle· string — requiredexcerpt· string — requiredblockCount· integer — required, 0–9007199254740991sizeBytes· integer — required, 0–9007199254740991createdBy· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredrestoredFrom· string (uuid) | null — required
nextCursor· string | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/pages/{pageId}/history
Capture the page's current body as a named version. Requires edit — a version is a write to the page's history. Unlike the automatic capture this is never deduplicated against the previous version and is never pruned by retention: it exists because a person asked for it.
savePageVersion · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — required
Request body — application/json, required
label· string — length 0–200
Response 200 — application/json
id· string (uuid) — requiredpageId· string (uuid) — requiredkind·"auto"|"manual"|"pre_restore"|"restore"— requiredlabel· string | null — requiredtitle· string — requiredexcerpt· string — requiredblockCount· integer — required, 0–9007199254740991sizeBytes· integer — required, 0–9007199254740991createdBy· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredrestoredFrom· string (uuid) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/pages/{pageId}/history/{versionId}
Read one version, including its body as canonical Markdown (ADR-0012). Requires read on the page.
getPageVersion · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — requiredversionId· string (uuid) — required
Response 200 — application/json
id· string (uuid) — requiredpageId· string (uuid) — requiredkind·"auto"|"manual"|"pre_restore"|"restore"— requiredlabel· string | null — requiredtitle· string — requiredexcerpt· string — requiredblockCount· integer — required, 0–9007199254740991sizeBytes· integer — required, 0–9007199254740991createdBy· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredrestoredFrom· string (uuid) | null — requiredmarkdown· string — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
DELETE /api/v1/workspaces/{workspaceId}/pages/{pageId}/history/{versionId}
Delete one version. Requires edit on the page. Exists because retention deliberately never prunes a version a person created or a restore recorded — removing one has to be a decision, not a background job. Returns the deleted row.
deletePageVersion · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — requiredversionId· string (uuid) — required
Response 200 — application/json
id· string (uuid) — requiredpageId· string (uuid) — requiredkind·"auto"|"manual"|"pre_restore"|"restore"— requiredlabel· string | null — requiredtitle· string — requiredexcerpt· string — requiredblockCount· integer — required, 0–9007199254740991sizeBytes· integer — required, 0–9007199254740991createdBy· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredrestoredFrom· string (uuid) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/pages/{pageId}/history/{versionId}/restore
Put a version's body back. Requires edit on the page (the matrix prices editing a body at edit — D4). The write goes through the doc mutator as one Yjs transaction, so the CRDT is never bypassed and connected editors see it live. Two versions are recorded: the state being overwritten (undo) and the restored state (restored) — nothing after the restored point is deleted, so a restore is itself undoable.
restorePageVersion · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — requiredversionId· string (uuid) — required
Response 200 — application/json
undo· object — requiredid· string (uuid) — requiredpageId· string (uuid) — requiredkind·"auto"|"manual"|"pre_restore"|"restore"— requiredlabel· string | null — requiredtitle· string — requiredexcerpt· string — requiredblockCount· integer — required, 0–9007199254740991sizeBytes· integer — required, 0–9007199254740991createdBy· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredrestoredFrom· string (uuid) | null — required
restored· object — requiredid· string (uuid) — requiredpageId· string (uuid) — requiredkind·"auto"|"manual"|"pre_restore"|"restore"— requiredlabel· string | null — requiredtitle· string — requiredexcerpt· string — requiredblockCount· integer — required, 0–9007199254740991sizeBytes· integer — required, 0–9007199254740991createdBy· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredrestoredFrom· string (uuid) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/pages/{pageId}/activity
One page's activity, most recent first. Requires read access to the page; entries are coalesced per actor, verb and time window.
listPageActivity · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredpageId· string (uuid) — required
Query parameters
cursor· string — length 1–∞limit· integer — 1–100
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredblockId· string (uuid) — requiredresourceType·"page"|"database"— requiredtitle· string — requiredverb·"created"|"edited"|"renamed"|"moved"|"trashed"|"restored"— requiredactorId· string (uuid) | null — requiredoccurredAt· string (date-time) — requiredcount· integer — required, −∞–9007199254740991movedUnderTitle· string | null — required
nextCursor· string | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/activity
Recent activity across the workspace, most recent first, filtered to the pages and databases the caller may read (filtered in SQL before the LIMIT).
listWorkspaceActivity · token scope: content:read
Path parameters
workspaceId· string (uuid) — required
Query parameters
cursor· string — length 1–∞limit· integer — 1–100
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredblockId· string (uuid) — requiredresourceType·"page"|"database"— requiredtitle· string — requiredverb·"created"|"edited"|"renamed"|"moved"|"trashed"|"restored"— requiredactorId· string (uuid) | null — requiredoccurredAt· string (date-time) — requiredcount· integer — required, −∞–9007199254740991movedUnderTitle· string | null — required
nextCursor· string | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/notifications
The caller's inbox for this workspace, newest first. Entries about content the caller can no longer read are omitted.
listNotifications · token scope: content:read
Path parameters
workspaceId· string (uuid) — required
Query parameters
cursor· string — length 1–∞limit· integer — 1–100status·"unread"|"all"
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredkind·"mention"— requiredblockId· string (uuid) — requiredtitle· string — requiredsourceType·"block"|"comment"— requiredsourceId· string (uuid) — requiredactorId· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredreadAt· string (date-time) | null — required
nextCursor· string | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/notifications/summary
How many unread notifications the caller has here — the shell's badge. Counted over the same permission filter as the listing.
getInboxSummary · token scope: content:read
Path parameters
workspaceId· string (uuid) — required
Response 200 — application/json
unread· integer — required, 0–9007199254740991
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/notifications/{notificationId}/read
Mark one of your own notifications read (or unread again).
markNotificationRead · token scope: content:write
Path parameters
workspaceId· string (uuid) — requirednotificationId· string (uuid) — required
Request body — application/json, required
read· boolean — required
Response 200 — application/json
id· string (uuid) — requiredkind·"mention"— requiredblockId· string (uuid) — requiredtitle· string — requiredsourceType·"block"|"comment"— requiredsourceId· string (uuid) — requiredactorId· string (uuid) | null — requiredcreatedAt· string (date-time) — requiredreadAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/notifications/read
Mark every notification the caller can currently see as read.
markAllNotificationsRead · token scope: content:write
Path parameters
workspaceId· string (uuid) — required
Response 200 — application/json
updated· integer — required, 0–9007199254740991
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
DELETE /api/v1/workspaces/{workspaceId}/notifications/{notificationId}
Clear one of your own notifications — it leaves the inbox for good.
clearNotification · token scope: content:write
Path parameters
workspaceId· string (uuid) — requirednotificationId· string (uuid) — required
Response 200 — application/json
updated· integer — required, 0–9007199254740991
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required