@-mentions.
Write @alice in a post or comment. Social parses the body, resolves "alice" to an actor by external_id, persists the mention row, and fires a "mention" notification to her inbox. Unknown handles are silently ignored — no errors, no notifications.
1
Mentions in posts
Use the existing post-create endpoint. Any @handle in body is parsed at write time. Handles are matched against actor.external_id (case-insensitive), de-duplicated, and capped at 50 per post body.
curl -X POST \
-H "Authorization: Bearer pcft_live_..." \
-H "Content-Type: application/json" \
-d '{"actor_id":"<authorActorId>","body":"shipping today, cc @ada and @grace"}' \
"https://social.productcraft.co/v1/communities/<communityId>/posts"Each resolved mention triggers a kind: "mention" notification on the recipient's inbox with target_kind: "post" and target_id set to the post UUID. Self-mentions, blocked-pair mentions, and per-kind opt-outs (see notification preferences) are filtered at write time — no row written, no inbox noise.
2
Mentions in comments
Same parser, same resolution rules. Comment mentions carry both comment_id and the parent post_id in the notification payload so the client can deep-link straight into the threaded view.
curl -X POST \
-H "Authorization: Bearer pcft_live_..." \
-H "Content-Type: application/json" \
-d '{"actor_id":"<commenterActorId>","body":"agreed @ada"}' \
"https://social.productcraft.co/v1/communities/<communityId>/posts/<postId>/comments"3
Updating: re-indexing on body changes
Editing the body of a post or comment re-runs the parser. Mentions removed from the new body are deleted from the index; mentions newly added are persisted and re-fan-out notifications. Editing only visibility / pinned / status doesn't re-parse — mentions ride on body content.
4
"Show me everywhere I'm tagged"
Per-actor mentions feed. Cursor-paginated newest-first, interleaving posts + comments. Each entry carries source (post or comment), source_id, and the parent post_id so the client can deep-link either way.
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<communityId>/actors/<actorId>/mentions?limit=20"{
"data": [
{ "source": "post", "source_id": "p-1", "post_id": "p-1", "mentioned_id": "...", "created_at": "2026-05-11T12:00:00.000Z" },
{ "source": "comment", "source_id": "c-7", "post_id": "p-3", "mentioned_id": "...", "created_at": "2026-05-10T08:00:00.000Z" }
],
"pagination": { "next_cursor": null, "has_more": false }
}Parser rules
What counts as a mention
- Pattern:
@followed by 1..32 chars from[a-z0-9_], case-insensitive (but matched againstexternal_idin lowercase). - A handle longer than 32 chars never matches — the parser uses a negative lookahead so it doesn't silently truncate.
- Duplicates within the same body collapse to one notification.
- Cap: 50 mentions per body. Beyond that, additional
@handles are silently dropped. - Unknown handles (no actor with that
external_id) are silently ignored — no error, no notification.
Permissions
PAK scopes
- POST / PATCH on the post + comment endpoints uses their existing scopes (
social.create/social.update) — no extra grant needed for mentions. - GET
/actors/:actorId/mentionsrequiressocial.listonpcft:agora:community/<communityId>.