Post search.
Same Postgres FTS shape as user search, this time over post.title (weight A) + post.body (B). Pick relevance ranking or recency ordering with one query param. Drafts, removed, hidden, and expired posts are stripped at the SQL layer.
1
Search by relevance
Default mode. Returns up to limit hits (default 20, max 50) ordered by ts_rank. Title matches are weighted higher than body matches.
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<communityId>/search/posts?q=phase+8&limit=10"2
Or by recency
Same FTS filter, but ordered by created_at desc among matching rows. Useful when the user is asking “what's the newest mention of X” rather than “the best mention”. Any other value is a 400 INVALID_ORDER.
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<communityId>/search/posts?q=phase+8&order=recent"3
Paginate past the first page
Every response carries pagination: { next_cursor, has_more }; pass next_cursor back as ?cursor= to fetch the next page. Relevance pages by (rank, id), recent by (created_at, id). A cursor is bound to the exact (q, order) that produced it — reusing it against a different query simply restarts from page one.
# page 1
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<c>/search/posts?q=phase+8&limit=25"
# → { data: [...], pagination: { next_cursor: "eyJ...", has_more: true } }
# page 2 — feed next_cursor back
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<c>/search/posts?q=phase+8&limit=25&cursor=eyJ..."4
Filter to the requester's view
Without actor_id the caller is treated as anonymous: only visibility="public" posts from non-private authors surface. Pass an actor uuid to search as that actor — the same read rules a feed applies:
- The requester's own posts always surface, whatever their visibility.
followersposts surface only with a follow edge to the author;close_friendsonly when the requester is on the author's close-friends list;privatenever surfaces to anyone else.- Posts authored by anyone the requester has muted / blocked — or who has blocked the requester — drop out.
Drafts, removed, hidden, and expired posts are stripped in SQL for every caller.
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<communityId>/search/posts?q=phase+8&actor_id=<actorId>"5
Response shape
{
"data": [
{
"post": {
"id": "...",
"title": "Shipping Phase 8",
"body": "stories live today",
"kind": "text",
"visibility": "public",
"status": "published",
"...": "..."
},
"rank": 0.6079
}
],
"pagination": { "next_cursor": "eyJ...", "has_more": true }
}Out of scope
Follow-ups
- Trigram fuzzy matching. Same trade- off as user search; deferred.
- Cross-community search. Per-community only.
Permissions
PAK scopes
- GET requires
social.listonpcft:agora:community/<communityId>.