Community supports two distinct relationship models. Follows are one-way subscriptions to a person or page — like Twitter follows or Facebook page likes. Connections are two-way handshakes — like LinkedIn connections — where both sides must confirm. Pick whichever matches your social model; you can use both at once if you need to.
Follows
A follow is a one-way edge from the current customer to a target email or pageId. No approval needed.
/client/community/followJWT/client/community/follow/:followingIdJWT/client/community/followersJWT/client/community/followingJWT// Follow a person
await fetch('/client/community/follow', {
method: 'POST',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
following: '[email protected]',
followingType: 'person', // 'person' | 'page'
}),
});
// Follow a page
await fetch('/client/community/follow', {
method: 'POST',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
following: 'page-id-here',
followingType: 'page',
}),
});
GET /followers returns who follows you. GET /following?followingType=person returns who/what you follow. Both are paginated by limit + page.
Connections
A connection is a request → response handshake. Either side can cancel; once accepted both sides see the connection in their list. This lives on the staff-facing controller because connections are typically used for B2B-style member networks where status (pending, accepted, rejected) matters operationally.
/community/connections/requestJWT/community/connections/:id/respondJWT/community/connectionsJWT/community/connections/pendingJWT/community/connections/sentJWT/community/connections/statsJWT/community/connections/accept-allJWT/community/connections/:idJWTThe same set is mirrored at /client/community/connections/* for customer-token usage.
// Send a request
await fetch('/community/connections/request', {
method: 'POST',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
targetId: '[email protected]',
message: 'Hi Bob — saw your design talk.',
context: { event: 'figma-conf-2026' },
}),
});
// Respond
await fetch(`/community/connections/${connectionId}/respond`, {
method: 'PUT',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'accept' }), // 'accept' | 'reject'
});
Connection states and stats
A connection record carries status (pending, accepted, rejected), requesterEmail, targetEmail, optional message, optional context, and timestamps for request/response. GET /connections/stats returns counts by status — useful for a dashboard widget.
{
"total": 124,
"accepted": 98,
"pending": 12,
"sent": 14
}
Mutual connections
There is no first-class mutual endpoint. To find mutuals between yourself and another person, fetch both /connections?status=accepted lists and intersect them client-side, or run a Dynamic Query over community_connection joining on email. For high-traffic UIs, denormalise — write a mutuals array to the customer record on each accept event.
Side effects
- Accepting a connection emits an event used by Sync to send a notification template (in-app + optional email).
- A new follow from a customer to a community page increments the page's
followerCountdenormalised counter. - Both follows and connections are checked when computing feed visibility for
visibility: 'connections'posts — only accepted connections see those posts.