Build a social app
01 · Set up

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.

response.json
{
  "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):

bash
# 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:

bash
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).