Build a social app
02 · Profiles

Project your end-users as actors.

Every social interaction in Agora keys off an `actor` — your end-user's projection into a community. Create one with the id you already use on your side; Agora returns its own UUID and you key off that from then on.


1

Upsert an actor

POST /v1/communities/:c/actors is idempotent on (community, external_id). The first call creates; the second with the same external_idreturns the same row with created: false.

bash
curl -X POST -H "Authorization: Bearer pcft_live_..." \
  -H "content-type: application/json" \
  -d '{
    "external_id": "user_alice",
    "display_name": "Alice Lin",
    "avatar_url": "https://i.pravatar.cc/300?img=47",
    "metadata": {
      "bio": "Brand & product designer based in Lisbon ✦",
      "location": "Lisbon, Portugal"
    }
  }' \
  https://agora.productcraft.co/v1/communities/<community-uuid>/actors
response.json
{
  "actor": {
    "id": "d6ee4836-1645-41b0-a1c3-c7e22ad01934",
    "community_id": "4d5f5c9e-b4ee-4401-9275-283feb66c178",
    "external_id": "user_alice",
    "display_name": "Alice Lin",
    "avatar_url": "https://i.pravatar.cc/300?img=47",
    "metadata": {
      "bio": "Brand & product designer based in Lisbon ✦",
      "location": "Lisbon, Portugal"
    },
    "status": "active",
    "created_at": "2026-05-02T19:28:58.294Z",
    "updated_at": "2026-05-02T19:28:58.294Z"
  },
  "created": true
}

2

Idempotency in practice

Repeating the call returns created: false with the same actor.id. The shape is replace-style — fields you omit will be overwritten by the new body, including metadata. Always include every field you want to keep on each upsert call.


3

List actors

Cursor-paginated, newest first. Default page size 50 (max 200). Pass ?cursor=<next_cursor> while has_more is true:

bash
curl -H "Authorization: Bearer pcft_live_..." \
  "https://agora.productcraft.co/v1/communities/<community-uuid>/actors?limit=10"
response.json
{
  "data": [
    { "id": "76054baa-...", "external_id": "user_carol", "display_name": "Carol Diaz", ... },
    { "id": "a54d4499-...", "external_id": "user_bob",   "display_name": "Bob Park",   ... },
    { "id": "d6ee4836-...", "external_id": "user_alice", "display_name": "Alice Lin",  ... }
  ],
  "pagination": { "next_cursor": null, "has_more": false }
}

4

Resolve an external id → actor

On the wire, every Agora call below this stage takes an agora actor.id (a UUID). When you only have your customer-side external_id and need to resolve it, use the lookup helper:

bash
curl -H "Authorization: Bearer pcft_live_..." \
  https://agora.productcraft.co/v1/communities/<community-uuid>/actors/by-external/user_carol

# returns the actor row, or 404

5

Edit profile fields

PATCH /actors/:actorId takes a partial body and updates only the fields present:

bash
curl -X PATCH -H "Authorization: Bearer pcft_live_..." \
  -H "content-type: application/json" \
  -d '{
    "metadata": {
      "bio": "Travel photographer. Currently: Oaxaca.",
      "location": "Oaxaca, MX"
    }
  }' \
  https://agora.productcraft.co/v1/communities/<community-uuid>/actors/<actor-uuid>

Mental model: in your app, an end-user has a row in your users table. Mirror that into Agora once at signup time — just call POST /actorswith the user's id as external_id. From then on, your backend keeps user.id actor.id mapped however you like (a column on your users table works fine).