Documentation

Posts and feed

Create posts, read the activity feed, and wire comments, reactions, polls, and shares.

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

GET/client/community/feedNo auth
POST/client/community/postsJWT
GET/client/community/posts/:postIdNo auth
PUT/client/community/posts/:postIdJWT
DELETE/client/community/posts/:postIdJWT
POST/client/community/posts/:postId/shareJWT
POST/client/community/posts/:postId/voteJWT
GET/client/community/posts/:postId/commentsNo auth
POST/client/community/posts/:postId/commentsJWT
DELETE/client/community/comments/:commentIdJWT
POST/client/community/reactJWT
GET/client/community/reactionsNo auth
GET/client/community/hashtags/trendingNo auth

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

FieldTypeDescription
pagestring

Filter to a specific community page id.

authorstring

Filter to posts by this email.

typestring

text, media, poll, share.

hashtagstring

Filter by a single hashtag (without #).

sortstring

latest (default), popular, trending.

limitnumber

Items per page. Default 20.

pageNumnumber

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.