Unread and unseen counts
`unread` drives list styling; `unseen` drives the bell badge (cleared by mark-all-seen when the inbox opens). Served from maintained counters (Redis cache, Postgres authoritative) — O(1), not O(rows).
unread drives list styling; unseen drives the bell badge (cleared
by mark-all-seen when the inbox opens). Served from maintained counters
(Redis cache, Postgres authoritative) — O(1), not O(rows).
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 GET "https://example.com/v1/inbox/counts"{
"unread": 0,
"unseen": 0
}{
"error": {
"code": "invalid_request",
"message": "string"
}
}Create direct notifications (1–100 recipients, fan-out on write) POST
Creates one notification per recipient in a single transaction together with counter bumps and the outbox job. The `idempotency_key` covers the **whole request**: a retry never partially re-runs the batch. `deliver_at` schedules delivery (max 13 months out): the notification is durable immediately but invisible to the subscriber until then; counters and real-time hints fire at `deliver_at`. Recipients that don't exist yet are lazily created as subscribers. Need more than 100 recipients? That's a broadcast.
Status timeline for one notification GET
The append-only delivery timeline — the "did it send?" answer. Statuses appear as they happen: `created` (accepted and durable), `delivered_hint` (a real-time hint announcing it was published), `seen` and `read` (subscriber actions; watermark moves apply them asynchronously, so a just-clicked "mark all read" may take a moment to appear here). Entries are ordered by `occurred_at`. Unknown future statuses must be ignored by clients. Broadcasts have no per-recipient timeline (they are never materialized per subscriber).