Social guides
Guides

Private accounts & follow requests.

Flip an actor to private and their effective post visibility is capped at followers — even their public posts become readable only by approved followers, on every surface (feed, search, hashtags, single reads). Following a private actor creates a request the actor approves or declines.


1

Make an actor private

PATCH the actor with is_private: true. From then on, non-followers can't read any of the actor's posts — a public post is effectively clamped to followers, and reads by a non-follower 404 rather than 403. Flipping back to public auto-approves every pending request.

bash
curl -X PATCH -H "Authorization: Bearer pcft_live_..." \
  -H "Content-Type: application/json" -d '{"is_private": true}' \
  "https://social.productcraft.co/v1/communities/<communityId>/actors/<actorId>"
# → { "id": "...", "is_private": true, ... }

2

Following a private actor

POST /follows against a private destination doesn't create a follow edge — it creates a pending request and the response is { "status": "pending", "edge": null, "created": true } (public destinations return { "status": "followed", "edge": {…}, "created": true } as before). The private actor gets a follow_request notification and a edge.follow.requested webhook. No follower/following counters move until approval.

bash
curl -X POST -H "Authorization: Bearer pcft_live_..." \
  -H "Content-Type: application/json" \
  -d '{"actor_id":"<follower>","dst_actor_id":"<private>"}' \
  "https://social.productcraft.co/v1/communities/<communityId>/follows"
# → { "status": "pending", "edge": null, "created": true }

3

Approve, decline, list

The private actor reviews incoming requests, then approves (creating the follow edge — counters bump, edge.follow.created fires, the requester gets a follow_request_approved notification) or declines (the request is dropped silently).

bash
# List incoming requests (newest-first, cursor-paginated)
curl -H "Authorization: Bearer pcft_live_..." \
  "https://social.productcraft.co/v1/communities/<communityId>/actors/<private>/follow-requests"
# → { "data": [ { "request_id": "...", "src_actor_id": "...", "src_external_id": "...",
#                 "src_display_name": "...", "src_avatar_url": null, "created_at": "..." } ],
#     "pagination": { "next_cursor": null, "has_more": false } }

# Approve → 201 { "edge": {…}, "created": true }
curl -X POST -H "Authorization: Bearer pcft_live_..." \
  "https://social.productcraft.co/v1/communities/<communityId>/follow-requests/<private>/<follower>/approve"

# Decline → 204
curl -X DELETE -H "Authorization: Bearer pcft_live_..." \
  "https://social.productcraft.co/v1/communities/<communityId>/follow-requests/<private>/<follower>"

4

Notes

  • GET /actors/{actorId}/relationships?with=<dst> returns a follow_pending flag alongside following / blocking / …, so you can render a “Requested” state.
  • Going public→private keeps existing followers — only new follows require approval. Going private→public auto-approves everything pending.
  • Blocking someone tears down any pending request between the pair, both directions.
  • To remove an existing follower, use the normal DELETE /follows/{src}/{dst} — there's no separate remove-follower route.