Mark everything read (watermark move)
Moves the per-subscriber read watermark to now — a one-row update, not a bulk UPDATE. Covers both sources; individually-read exception rows below the new watermark are garbage-collected.
Moves the per-subscriber read watermark to now — a one-row update, not a bulk UPDATE. Covers both sources; individually-read exception rows below the new watermark are garbage-collected.
Authorization
SubscriberEnv SubscriberHash SubscriberId In: header
Optional when the environment has require_subscriber_hash = false.
In: header
In: header
Response Body
application/json
application/json
curl -X POST "https://example.com/v1/inbox/read-all"{
"unread": 0,
"unseen": 0
}{
"error": {
"code": "invalid_request",
"message": "string"
}
}Merged inbox list (direct + broadcast), keyset-paginated GET
Newest first, ordered by `(occurred_at, id)` descending across both sources. `cursor` is the opaque keyset token from the previous page's `next_cursor`. Category mutes are applied server-side. Supports `ETag` / `If-None-Match`, so post-reconnect refetches (deploy thundering herd) are mostly 304s. The validator is a strong hash over: the request cursor, `subscriber_counters.updated_at` (bumped by EVERY read-state mutation — see the counter invariants in schema.sql), the subscriber's latest direct item `(visible_at, id)`, the environment's latest broadcast `(created_at, id)`, and `max(preferences.updated_at)` for the subscriber. Each input is one index-only lookup; anything that can change a page moves at least one of them. Responses are `Cache-Control: private, max-age=0` — inbox pages are per-user data and must never be cached by shared proxies.
Mark everything seen (badge clear; watermark move) POST
Called by the SDK when the inbox opens. Moves the seen watermark; read state is untouched.