Fulfilling data-subject requests.
Every actor's data is either enumerable through a per-actor endpoint (for access + portability) or erased by the actor hard-delete cascade (for erasure). This guide shows how to assemble a complete export and how to erase — and stays a living checklist as new datasets ship.
1
Access & portability — walk the per-actor endpoints
There is no single “download my data” blob. An export is assembled by walking every per-actor read endpoint and concatenating the pages. Almost all of them return the standard { data, pagination } envelope — follow next_cursor until has_more is false. The two exceptions are unpaginated: notification-prefs returns a bare { data } and counters returns a single object.
Two of these — comments authored and reactions given — are on the admin (workspace) lane and require social.audit.read, because they return all statuses (including hidden / removed content) for a complete record. The rest are on the customer lane under the actor.
1a
Content the actor created
BASE=https://social.productcraft.co/v1
C=<communityId>; A=<actorId>; WS=<workspaceId>
get() { curl -s -H "Authorization: Bearer pcft_live_..." "$@"; }
# Posts (published) — filter by author
get "$BASE/communities/$C/posts?author_id=$A"
# Drafts, scheduled, archived posts
get "$BASE/communities/$C/actors/$A/drafts"
get "$BASE/communities/$C/actors/$A/scheduled-posts"
get "$BASE/communities/$C/actors/$A/archived"
# Comments (ALL statuses) — admin lane, needs social.audit.read
get "$BASE/workspaces/$WS/communities/$C/actors/$A/comments"
# Reactions given (post + comment, unified by target_type) — admin lane
get "$BASE/workspaces/$WS/communities/$C/actors/$A/reactions"1b
Graph, preferences & activity
# Social graph
get "$BASE/communities/$C/actors/$A/following"
get "$BASE/communities/$C/actors/$A/followers"
get "$BASE/communities/$C/actors/$A/follow-requests"
get "$BASE/communities/$C/actors/$A/blocks"
get "$BASE/communities/$C/actors/$A/mutes"
get "$BASE/communities/$C/actors/$A/restricts"
get "$BASE/communities/$C/actors/$A/hides"
get "$BASE/communities/$C/actors/$A/dismissed-suggestions"
get "$BASE/communities/$C/actors/$A/close-friends"
# Saves, tags, mentions, hashtag follows
get "$BASE/communities/$C/actors/$A/bookmarks"
get "$BASE/communities/$C/actors/$A/tagged"
get "$BASE/communities/$C/actors/$A/mentions"
get "$BASE/communities/$C/actors/$A/hashtag-follows"
# Uploaded media assets
get "$BASE/communities/$C/actors/$A/assets"
# Named collections (bookmark folders + highlight reels)
get "$BASE/communities/$C/collections?owner_actor_id=$A&actor_id=$A"
# Preferences & counters (both unpaginated)
get "$BASE/communities/$C/actors/$A/notification-prefs"
get "$BASE/communities/$C/actors/$A/counters"
get "$BASE/communities/$C/actors/$A/muted-terms"
get "$BASE/communities/$C/actors/$A/notifications"
# Flags the actor filed
get "$BASE/communities/$C/flags?reporter_actor_id=$A"
# Direct messages — conversations first (actor_id is required),
# then the messages of each conversation
get "$BASE/communities/$C/conversations?actor_id=$A"
get "$BASE/communities/$C/conversations/<conversationId>/messages?actor_id=$A"Direct messages are keyed by conversation rather than by a single per-actor endpoint, which is why the last two calls are a two-step: both take actor_id as a required query parameter (it is the reading participant, and non-participants get a 404). Messages and DM reactions are erased by the hard delete below.
2
Erasure — one hard delete cascades everything
The right to erasure is a single call. Deleting the actor is a hard delete whose foreign keys cascade to every row the actor owns — posts, comments, all reactions (post + comment + DM), follows / blocks / mutes / hides, bookmarks, tags, mentions, poll votes, notifications, DMs sent, preferences, and list memberships.
Rows that reference the actor only incidentally are de-identified rather than deleted: a conversation's created_by and a moderation-audit row's target are set to null, severing the personal link while preserving the conversation for its other participants and the audit trail for its legal-basis retention.
# Right to erasure — irreversible, cascades everything the actor owns
get -X DELETE "$BASE/communities/$C/actors/$A" # 204 No Content3
Takedown vs. erasure
Removing a single piece of content (a takedown) is distinct from erasing the person. Apply the remove action through the moderation lane (see the moderation guide) — the post/comment drops from feeds immediately, and the daily purge hard-deletes rows that have been removed for 30 days, without touching the rest of the actor's data.
4
Coverage checklist
Every actor-owned dataset is accounted for one of two ways. This table is the audit surface — when a new dataset ships it gets a row here.
| Dataset | Export path | Erased on actor delete |
|---|---|---|
| Posts (all states) | ?author_id + drafts / scheduled / archived | cascade |
| Comments | .../actors/{id}/comments (admin) | cascade |
| Reactions (post + comment) | .../actors/{id}/reactions (admin) | cascade |
| Follows / blocks / mutes / restricts / hides / dismissals | per-edge listing | cascade |
| Bookmarks / tags / mentions / hashtag-follows | per-actor listing | cascade |
| Uploaded media assets (images + videos) | .../actors/{id}/assets | cascade (row + every stored object: renditions, video original/MP4/poster — including unfinalized uploads) |
| Collections + their items | collections?owner_actor_id | cascade |
| Impression reach rows (insights) | — (aggregate only, no raw export) | cascade on viewer delete |
| Preferences / muted-terms / notifications / counters | per-actor listing | cascade |
| Flags filed | flags?reporter_actor_id | cascade |
| Direct messages + DM reactions | walk conversations | cascade |
| Poll votes / list memberships | — | cascade |
| Conversation creator / moderation-audit target | — | de-identified (null) |