Add Social to your product.
From zero to a working community in five steps. You'll mint an API key, create a community, project an end-user as an actor, and post your first piece of content.
1
Enable Social on your workspace
Open the Social area in the console and pick a workspace. If that workspace doesn't have Social enabled yet, you land on a prompt with an Enable Social for this workspace button (workspace owners and admins). Until it is, the workspace-scoped routes — creating communities, the moderation and analytics lanes — reject with 403 SERVICE_NOT_ENABLED.
2
Mint a Platform API Key
Every Social customer-backend call authenticates with a workspace Platform API Key. A PAK carries no permissions of its own — it binds one or more managed policies, so it's two steps in the console. First author the policy under Workspace → Policies → New policy (owner-only): actions social.*, resources pcft:agora:*. Then open Workspace → API keys → New API key and tick that policy on the Permissions step of the wizard. Keys are pcft_live_* prefixed, shown once at the end, and travel as Authorization: Bearer.
3
Create a community (standalone or Auth-backed)
A community is the container everything else lives in. slug (lowercase letters, digits and hyphens, 3–64 chars) and display_name are the only required fields — that's a standalone community, where you manage actor external_ids however you like (your own user table, opaque IDs, etc.). The Create community button on the console's Communities list does the same thing.
If you already authenticate end-users via Auth, pass app_id (or tick Connect to a Auth app in the console modal). Social verifies the app belongs to the same workspace (cross-tenant gate, enforced server-side), and actors then map 1:1 to Auth end-users. The integration is purely about how you source actor identity.
# Standalone — no Auth app needed
curl -X POST -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-d '{
"slug": "my-community",
"display_name": "My Community"
}' \
https://social.productcraft.co/v1/workspaces/<workspaceId>/communities
# Auth-backed — social verifies the app is in your workspace
curl -X POST -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-d '{
"app_id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "my-community",
"display_name": "My Community"
}' \
https://social.productcraft.co/v1/workspaces/<workspaceId>/communities4
Project an end-user as an actor
Before any post, follow, or comment can be created, the actor has to exist. Upsert is idempotent on (community, external_id); the second call with the same id returns created: false. The response carries the social actor.id (a UUID) — keep it on your side, every downstream call below keys off it.
curl -X POST -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-d '{
"external_id": "user_42",
"display_name": "Alice",
"avatar_url": "https://cdn.example.com/avatars/alice.png"
}' \
https://social.productcraft.co/v1/communities/<communityId>/actors
# response: { "actor": { "id": "770a8600-...", ... }, "created": true }5
Create your first post
With the actor in place, you can post on their behalf. actor_id — the social actor.id from step 4 — is the only required field:
curl -X POST -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-d '{
"actor_id": "770a8600-0000-0000-0000-000000000001",
"body": "hello, world"
}' \
https://social.productcraft.co/v1/communities/<communityId>/postsEverything else rides the same primitive. kind is a free-form label — text (the default), link, image, story, repost, quote. visibility is one of public (default), followers, close_friends, private. Stories add an expires_at for the 24h-disappearing UX, and attributes is a free-form blob for whatever your client needs to render.
6
Retries & idempotency
Network timeouts happen. When your backend retries a write, you don't want a duplicate post, a second group chat, or a message delivered twice. Social handles retries two ways:
Naturally idempotent writes need nothing from you — the operation has a natural key, so repeating it converges on the same state. Follows, mutes, blocks and other edges, reactions, bookmarks, actor upserts (keyed by external_id), list-member adds, and direct (1-on-1) conversation opens all behave this way, and the response tells you it was already applied — created: false, or the same resource id coming back.
Everything else takes an Idempotency-Key header. Creating posts, comments, communities, lists, collections, assets, group conversations, messages and webhooks — plus webhook secret rotation and the moderation write endpoints — accept an opaque, client-generated key (1–256 chars, [A-Za-z0-9_-:]). Retrying with the same key and the same body within 24 hours replays the original response instead of re-running the write; replays carry an Idempotent-Replay: true response header. Reusing a key with a different body returns 409 IDEMPOTENCY_KEY_REUSE — mint a fresh key per logical operation (a UUID per user action works well):
curl -X POST -H "Authorization: Bearer pcft_live_..." \
-H "content-type: application/json" \
-H "Idempotency-Key: post-create-8b3f2c1d" \
-d '{ "actor_id": "770a8600-...", "body": "hello, world" }' \
https://social.productcraft.co/v1/communities/<communityId>/posts
# Safe to run the exact same command again on a timeout:
# the replay returns the SAME post with Idempotent-Replay: true.The key is scoped to your workspace and API key, so keys never collide across tenants. The API reference marks every endpoint that accepts the header.
Next
Where to go from here
- API reference — every endpoint with request and response schemas.
- Feeds —
GET /actors/:actorId/feedserves a ranked, algorithmic timeline by default. Passorder=chronologicalfor time-ordered. Tune ranking weights per-community viacommunity.settings.ranking. - Notifications —
GET /actors/:actorId/notificationsreturns the per-actor inbox; producers fire automatically when someone follows, reacts, comments, or votes. - Stories —
GET /actors/:actorId/story-traygives the Instagram-style author tray. View tracking, polls, highlights, close-friends visibility, and private replies are all in the API reference. - Moderation — flags fire from
POST /communities/:c/flags; the queue, enforcement actions and audit log live under/v1/workspaces/:ws/communities/:c/moderation/*and in the console. See the moderation guide. - Messaging — direct + group conversations with reactions, read markers, and unread badges. Walked end-to-end in tutorial stage 10.
- Guides — the full ten-stage tutorial plus focused guides for reposts, bookmarks, hashtags, search, actor lists, muted terms, and more.