Build a social app
08 · Notifications

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.

bash
curl -H "Authorization: Bearer pcft_live_..." \
  "https://agora.productcraft.co/v1/communities/<c>/actors/<carol>/notifications?limit=20"

# unread only
curl -H "Authorization: Bearer pcft_live_..." \
  "https://agora.productcraft.co/v1/communities/<c>/actors/<carol>/notifications?unread_only=true&limit=20"
response.json
{
  "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 }
}

Five kinds ship today: follow, reaction, comment_on_post, reply_to_comment, and vote. The mention kind is reserved for a future commit; no producer fires it yet.


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.

bash
curl -H "Authorization: Bearer pcft_live_..." \
  https://agora.productcraft.co/v1/communities/<c>/actors/<carol>/notifications/unread-count

# response: { "count": 10 }

3

Mark as read

bash
# One notification (PATCH; 204)
curl -X PATCH -H "Authorization: Bearer pcft_live_..." \
  -H "content-type: application/json" \
  -d '{ "read": true }' \
  https://agora.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://agora.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://agora.productcraft.co/v1/communities/<c>/actors/<carol>/notifications/read-all

Suppression

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.

Roadmap

Out of scope (today)

Real-time delivery (SSE / WebSocket), aggregation ("Bob and 3 others reacted"), per-kind preferences, and inbox-side mention parsing are not in v1. The shape leaves room for them — when they ship, existing clients keep working.