Spin up a community + mint a Platform API Key.
Five minutes from zero to an authenticated `curl`. We'll provision Glow — a community we'll keep using through the rest of the guide — and a PAK with full social.* scope on it.
1
Enable Social on your workspace
Open the Social area in the console and pick a workspace. If Social isn't enabled, hit Enable Social for this workspace(workspace owners and admins). Until it is, every Social call returns 403 SERVICE_NOT_ENABLED.
2
Create your community
Picking a workspace lands you on its Communities list — click Create community. Give it a display name and a slug. For this guide we'll use Glow / glow as a small creator network. Leave Connect to a Auth app for end-user identity unchecked — standalone is the right default unless you already authenticate end-users via Auth. (Ticking it reveals an Auth app picker listing the workspace's Auth apps.)
The console call returns the new community's UUID. Keep it on your side — every call from here on takes it as:communityId.
{
"id": "4d5f5c9e-b4ee-4401-9275-283feb66c178",
"workspace_id": "<your-workspace-uuid>",
"app_id": null,
"slug": "glow",
"display_name": "Glow",
"description": "A tiny Instagram/LinkedIn-shaped community.",
"settings": {},
"status": "active",
"created_by": "<your-platform-user-id>",
"created_at": "2026-05-02T19:28:19.283Z",
"updated_at": "2026-05-02T19:28:19.283Z"
}3
Mint a Platform API Key (PAK)
Every customer-backend Social call authenticates with a Platform API Key — a workspace-scoped opaque token prefixed pcft_live_. Mint one from Workspace → API keys → New API key, or via the API. A PAK is bound to one or more managed policies, so it's two steps either way: create the policy (console: Workspace → Policies), then mint the key — the key wizard's Permissions step only binds policies that already exist. Both are cookie/JWT only — use your platform access token from POST /v1/auth/signin (a PAK can't mint other PAKs, and policy authoring is owner-only):
# 1) Create a managed policy granting full Social access.
curl -X POST https://api.platform-auth.productcraft.co/v1/workspaces/<ws-slug>/policies \
-H "content-type: application/json" \
-H "Authorization: Bearer <your-platform-access-token>" \
-d '{
"name": "glow-social",
"policy": [{
"effect": "allow",
"actions": ["social.*"],
"resources": ["pcft:agora:*"]
}]
}'
# → { "id": "<policy-uuid>", ... }
# 2) Mint the PAK bound to that policy.
curl -X POST https://api.platform-auth.productcraft.co/v1/workspaces/<ws-slug>/api-keys \
-H "content-type: application/json" \
-H "Authorization: Bearer <your-platform-access-token>" \
-d '{
"name": "Glow demo client",
"description": "Full social.* PAK for the build-a-social-app guide.",
"policy_ids": ["<policy-uuid>"]
}'
# response (the plaintext token is returned ONCE — store it now):
# {
# "token": "pcft_live_...",
# "record": { "id": "...", "token_prefix": "pcft_live_a1b2c3", "policies": [...] }
# }social.* on pcft:agora:* is the right grant here — it covers every Social call in this guide. Don't narrow resources to a single pcft:agora:community/<uuid>: write routes authorize against resource URNs like pcft:agora:actor/* and pcft:agora:object/*, so a community-only resource list 403s every actor and post write. If you front your API with multiple workers, mint one PAK per service so a leak blast-radius is bounded.
4
Make your first call
Sanity-check the PAK by listing the (currently empty) actors collection on the community:
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<community-uuid>/actors?limit=10"
# response:
# {
# "data": [],
# "pagination": { "next_cursor": null, "has_more": false }
# }If you get a 200 with an empty list, you're done. Wrong PAK → 401. An action or resource your policy doesn't allow → 403 (the body names the denied action). Wrong community UUID → 404 (opaque — the response doesn't reveal whether the community exists in another workspace).