A real inbox, produced for free.
Every follow, reaction, comment, reply, and vote produces a notification on the recipient's inbox automatically. Self-actions and blocked-pair actions are filtered out at write time, so every row in the read endpoints is already worth showing.
1
Read the inbox
Cursor-paginated, newest first. Pass ?unread_only=true to filter to read_at IS NULL. A second filter, ?status=inbox|requests|all, drives the Instagram-style requests split: inbox (default) hides rows from actors the recipient has restricted, requests shows only those, and all merges both. Restricted-actor rows carry suppressed: true so you can badge them differently.
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<c>/actors/<carol>/notifications?limit=20"
# unread only
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<c>/actors/<carol>/notifications?unread_only=true&limit=20"{
"data": [
{
"id": "2069ce7e-...",
"kind": "vote",
"actor_id": "<bob>", // who triggered
"recipient_actor_id": "<carol>",
"target_kind": "post",
"target_id": "<carol-poll-post>",
"payload": { "option_index": 2 },
"read_at": null,
"created_at": "2026-05-02T19:35:24.010Z"
},
{ "kind": "follow", "payload": {}, ... },
{ "kind": "reaction", "payload": { "type": "love" }, ... },
{ "kind": "comment_on_post", "payload": { "comment_id": "<comment-uuid>" }, ... },
{ "kind": "reply_to_comment","payload": { "comment_id": "<reply-uuid>" }, ... }
],
"pagination": { "next_cursor": null, "has_more": false }
}Twelve kinds ship today. Content kinds: follow, reaction, comment_on_post, reply_to_comment, mention, vote, repost, and quote_post. Messaging kinds: dm_new_message, dm_added_to_group, dm_role_changed, and dm_reaction (see stage 10). End-users can opt out of any kind individually — see the notification preferences guide; muted kinds are never written, so the inbox and the unread count stay consistent for free.
2
Unread badge
For the "3" pip on a navbar bell icon, hit the dedicated count endpoint — it's a single SELECT and doesn't pull rows.
curl -H "Authorization: Bearer pcft_live_..." \
https://social.productcraft.co/v1/communities/<c>/actors/<carol>/notifications/unread-count
# response: { "count": 10 }3
Mark as read
# One notification (PATCH; 204)
curl -X PATCH -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-d '{ "read": true }' \
https://social.productcraft.co/v1/communities/<c>/actors/<carol>/notifications/<notif-uuid>
# All at once — useful for "mark all as read" controls
curl -X POST -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-d '{}' \
https://social.productcraft.co/v1/communities/<c>/actors/<carol>/notifications/read-all
# response: { "updated": 9 }
# Pass an optional ?before= timestamp to mark only older ones:
curl -X POST -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-d '{ "before": "2026-05-02T12:00:00Z" }' \
https://social.productcraft.co/v1/communities/<c>/actors/<carol>/notifications/read-allSuppression
What you don't see
Three classes of notification are never written:
- Self actions — an actor reacting to their own post doesn't notify them.
- Blocked pairs — if Alice blocks Bob, no follow / reaction / comment from Bob shows up on Alice's inbox.
- Story views — views are tracked for the author's viewer list, but they don't spam the inbox. Votes do.
Server-side
Push events to your backend
The inbox above is per-actor product UX. If your backend needs the event stream — mirroring content, sending digest emails, driving mobile push — subscribe a webhook instead of polling. Deliveries are signed, retried on a backoff schedule, and cover posts, comments, follows, moderation, profile changes and DMs. See the Webhooks guide for registration, signature verification, and the full event catalog.
Roadmap
Out of scope (today)
Real-time push delivery (SSE / WebSocket) and aggregation ("Bob and 3 others reacted") are not shipped — poll the unread count for badges. The shape leaves room for both; when they ship, existing clients keep working.