Skip to content

Notifications and watches

Notifications are personal: every call on this page reads or changes the rows of the person the key belongs to. Nobody, including admins, can read another person’s inbox. Marking items read, changing preferences and watching need write scope.

Method and path Purpose
GET /notifications Your inbox
GET /notifications/unread-count Unread badge count
POST /notifications/read Mark read
POST /notifications/seen Clear the badge without marking read
GET /notifications/prefs, PUT /notifications/prefs Mute or unmute reasons
GET /entries/{entry_id}/watch, PUT, DELETE Your watch state on one entry
GET /watches Everything you explicitly watch or muted
Reason You get it when
review.requested You were added as a reviewer on a review request.
review.responded A reviewer responded to your review request.
review.assigned A requested change was assigned to you.
review.mention Someone mentioned you in a review request or response note.
comment.mention Someone mentioned you in a comment.
comment.reply Someone replied in your thread.
comment.new Someone commented on an entry you watch.
comment.resolved Your thread was resolved.

You are never notified of your own actions, and one action produces at most one notification per person (the most specific reason wins, in the order above). The list may grow; ignore reasons you do not recognize.

Parameter Type Description
unread boolean Only unread items.
cursor integer Id cursor: pass the previous next_cursor to get older items.
limit integer 1 to 200, default 50.
{
"notifications": [
{
"id": 802,
"reason": "comment.mention",
"actor": { "id": 12, "name": "<user>", "display_name": "Lee Lead" },
"entry_id": 412,
"lineage_id": "guid:6F9619FF8B86D011B42D00C04FC964FF",
"object_id": 1880,
"comment_id": 91,
"request_id": null,
"payload": {},
"seen_at": null,
"read_at": null,
"created_at": "2026-07-25T12:00:00Z"
}
],
"next_cursor": null
}

{"unread": 3}. Cheap enough to poll.

Send exactly one of:

{ "ids": [802, 801] }
{ "all": true, "before_id": 802 }

ids takes up to 500 of your notification ids (others are ignored). all marks everything read; add before_id (the newest id you displayed) so an item that arrived meanwhile stays unread. Returns {"updated", "unread"}.

{"before_id"?}. Marks items as seen (clears a badge) without marking them read. Returns {"updated"}.

GET /notifications/prefs returns your overrides and the full list of reasons:

{
"prefs": [{ "reason": "comment.new", "enabled": false }],
"reasons": ["review.requested", "review.responded", "review.assigned", "review.mention", "comment.mention", "comment.reply", "comment.new", "comment.resolved"]
}

PUT /notifications/prefs replaces all your overrides with {"prefs": [{"reason", "enabled"}]} (up to 32). Reasons not listed are enabled. {"reason": "*", "enabled": false} mutes everything. Unknown reasons are 422. Returns the same shape as GET.

Watching an entry sends you comment.new notifications for it. The person who created an entry watches it automatically, and commenting on or reviewing an entry also starts watching it, unless you muted it.

Endpoint Body Response
GET /entries/{entry_id}/watch Watch state
PUT /entries/{entry_id}/watch {"state": "watching" or "muted"} (default watching) Watch state
DELETE /entries/{entry_id}/watch Watch state after returning to the default
GET /watches {"watches": [{entry_id, name, state, reason, created_at}]}, newest first

Watch state:

{ "entry_id": 412, "watching": true, "state": "watching", "reason": "manual", "implicit": false }

implicit: true means you watch it only because you created it (no explicit row). A muted state sticks: commenting or reviewing does not undo it.