Social guides
Guides

Notification preferences.

Per-actor, per-kind opt-out. The producer checks the preference before inserting a notification row, so muted kinds never land in the inbox or the unread-count — they're simply not written.

Six notification kinds today: follow, reaction, comment_on_post, reply_to_comment, mention, vote. The catalogue grows in lockstep with the schema; new kinds default to enabled for every actor.


1

Read the current settings

One row per known kind. Kinds the actor has not explicitly toggled report enabled: true with an epoch updated_at, so your UI always renders the full catalogue without a separate metadata call.

bash
curl -H "Authorization: Bearer pcft_live_..." \
  "https://social.productcraft.co/v1/communities/<communityId>/actors/<actorId>/notification-prefs"
json
{
  "data": [
    { "actor_id": "...", "kind": "follow",           "enabled": true,  "updated_at": "1970-01-01T00:00:00.000Z" },
    { "actor_id": "...", "kind": "reaction",         "enabled": true,  "updated_at": "1970-01-01T00:00:00.000Z" },
    { "actor_id": "...", "kind": "comment_on_post",  "enabled": true,  "updated_at": "1970-01-01T00:00:00.000Z" },
    { "actor_id": "...", "kind": "reply_to_comment", "enabled": true,  "updated_at": "1970-01-01T00:00:00.000Z" },
    { "actor_id": "...", "kind": "mention",          "enabled": true,  "updated_at": "1970-01-01T00:00:00.000Z" },
    { "actor_id": "...", "kind": "vote",             "enabled": true,  "updated_at": "1970-01-01T00:00:00.000Z" }
  ]
}

2

Mute a kind

Idempotent upsert keyed on (actor, kind). The cache (60s LRU) is invalidated on every write, so the next notification fired against this actor sees the new preference within milliseconds — no waiting for the cache to expire.

bash
curl -X PATCH \
  -H "Authorization: Bearer pcft_live_..." \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}' \
  "https://social.productcraft.co/v1/communities/<communityId>/actors/<actorId>/notification-prefs/follow"
json
{
  "actor_id": "aaaaaaaa-0000-0000-0000-000000000001",
  "kind": "follow",
  "enabled": false,
  "updated_at": "2026-05-11T19:42:00.000Z"
}

3

Re-enable

Same endpoint, { "enabled": true }. The row stays — only the boolean flips. You can also delete the row directly via SQL if you ever need to bulk reset, but the API only exposes the toggle.

bash
curl -X PATCH \
  -H "Authorization: Bearer pcft_live_..." \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}' \
  "https://social.productcraft.co/v1/communities/<communityId>/actors/<actorId>/notification-prefs/follow"

Behaviour

What changes downstream

  • Write-time suppression. When a kind is muted, the producer (`tryEmit`) silently skips the insert. The notification never appears in the inbox or the unread-count.
  • Stacks with existing suppressions. Self-actions and blocked-pair actions are still skipped first — preferences are an additional gate, not a replacement.
  • Fail-open on a DB hiccup. If the preference lookup itself errors out, the producer defaults to delivering — a transient outage must not silently mute the inbox.
  • Existing notifications are untouched. Muting a kind only stops new ones from being written. Rows already in the inbox stay where they are; clear them via the existing mark-read endpoints.

Permissions

PAK scopes

  • GET requires social.notify.read on pcft:agora:community/<communityId>.
  • PATCH requires social.notify.update on the same URN.

Both scopes are part of the default owner and admin system roles; member does not have social.notify.update by default. If your customer-backend signs in as an admin or an owner-scoped PAK, you're good.