Posts are the unit of content in Community. A post belongs to a page (or to a user's personal feed) and can carry text, media attachments, a poll, or a share of another post. The feed endpoint aggregates posts across pages, authors, hashtags and content types into a paginated stream.
Endpoints
/client/community/feedNo auth/client/community/postsJWT/client/community/posts/:postIdNo auth/client/community/posts/:postIdJWT/client/community/posts/:postIdJWT/client/community/posts/:postId/shareJWT/client/community/posts/:postId/voteJWT/client/community/posts/:postId/commentsNo auth/client/community/posts/:postId/commentsJWT/client/community/comments/:commentIdJWT/client/community/reactJWT/client/community/reactionsNo auth/client/community/hashtags/trendingNo authPost shape
type Post = {
pk: string;
sk: string;
datatype: 'community_post';
data: {
author: string; // email of the poster
authorInfo: {
firstName: string;
lastName: string;
image?: string;
company?: string;
jobTitle?: string;
};
page?: string; // pageId, or omitted for personal feed
content: {
text?: string;
media?: Array<{ url: string; type: 'image' | 'video' | 'file' }>;
poll?: {
question: string;
options: Array<{ id: string; text: string; votes: number }>;
endsAt?: string;
};
sharedFrom?: string; // postId being shared
};
contentType: 'text' | 'media' | 'poll' | 'share';
hashtags?: string[];
visibility: 'public' | 'page' | 'connections';
reactionCounts?: Record<string, number>;
commentCount?: number;
shareCount?: number;
createdAt: string;
};
};
Creating a post
await fetch('/client/community/posts', {
method: 'POST',
headers: {
orgid: 'my-org',
Authorization: `Bearer ${customerJwt}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
page: 'page-id-optional',
content: {
text: 'First sketches from the new logo project #design #typography',
media: [{ url: 'https://cdn/.../sketch.png', type: 'image' }],
},
contentType: 'media',
visibility: 'public',
}),
});
The service derives author and authorInfo from the customer record on the JWT — you cannot post on behalf of another email through this endpoint.
Reading the feed
GET /client/community/feed accepts optional filters and is paginated by limit + pageNum (the route's own page number, distinct from the page-as-in-community-page param).
| Field | Type | Description |
|---|---|---|
| page | string | Filter to a specific community page id. |
| author | string | Filter to posts by this email. |
| type | string |
|
| hashtag | string | Filter by a single hashtag (without |
| sort | string |
|
| limit | number | Items per page. Default 20. |
| pageNum | number | 1-based page number. |
If a JWT is present, viewerEmail is forwarded into the query so the response can mark each post with viewer-relative state (already reacted, bookmarked, voted in poll, etc.).
const res = await fetch('/client/community/feed?sort=trending&limit=20&pageNum=1', {
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}` },
});
const { data, total } = await res.json();
Comments
Comments form a tree. parentComment on a comment points to another comment id; the GET accepts ?parentComment=<id> to drill into a thread. Pagination uses limit + page.
await fetch(`/client/community/posts/${postId}/comments`, {
method: 'POST',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
content: { text: 'Love the second one.' },
parentComment: undefined, // top-level
}),
});
Reactions
POST /react is unified across post, comment, story and message targets:
await fetch('/client/community/react', {
method: 'POST',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
target: postId,
targetType: 'post', // 'post' | 'comment' | 'story' | 'message'
type: 'like', // 'like' | 'love' | 'haha' | 'wow' | 'sad' | 'angry'
}),
});
GET /reactions?target=<id>&targetType=<t> returns the reactor list for a target.
Polls and shares
POST /posts/:postId/vote records a vote against a poll option. The body is { optionId: string }. A customer can vote once per poll; a second vote updates the existing record.
POST /posts/:postId/share reposts the target post with an optional comment. The new post has contentType: 'share' and content.sharedFrom set to the source post id.
Hashtags
GET /hashtags/trending?limit=10 returns the top hashtags by recent post volume. Hashtags are extracted from content.text at write time and stored in a denormalised community_hashtag collection that drives the trending query.
Posts are first-class records — you can also CRUD them through the generic /data/community_post endpoints and segment them with Dynamic Query, but the /community/posts routes carry the right author/feed wiring you almost always want.