Social
Base URL: /v1
All authenticated endpoints require a valid Bearer token in the Authorization header.
Get Feed
Section titled “Get Feed”GET /v1/feedReturns published posts from followed users and the authenticated user’s own posts, ordered by created_at descending. Each post includes the author object, media attachments, poll data, a reactions summary grouped by type, and a total comments count.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | — | Opaque cursor for pagination (optional) |
limit | int | 20 | Number of posts to return. Max 50. |
Response 200 OK
{ "posts": [ { "id": "post_abc123", "user_id": "user_xyz", "title": "Hello world", "content": "My first post on the platform!", "status": "published", "is_sensitive": false, "is_ai_generated": false, "created_at": "2026-03-28T14:30:00Z", "updated_at": "2026-03-28T14:30:00Z", "author": { "id": "user_xyz", "username": "janedoe", "first_name": "Jane", "last_name": "Doe", "avatar_url": "https://cdn.example.com/avatars/janedoe.jpg", "verified": true }, "media": [ { "id": "media_001", "url": "https://cdn.example.com/uploads/photo.jpg", "type": "image" } ], "poll": [], "reactions_summary": { "like": 12, "love": 3, "fire": 1 }, "comments_count": 5 } ], "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wMy0yOCJ9"}Create Post
Section titled “Create Post”POST /v1/postsCreates a new post. If a poll object is provided, an associated poll record is created and linked to the post.
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
title | string | No | null | Post title. |
content | string | No | null | Post text content. |
status | string | No | "published" | One of: draft, published. |
is_sensitive | boolean | No | false | Flag content as sensitive / NSFW. |
is_ai_generated | boolean | No | false | Flag content as AI-generated. |
poll | object | No | null | Poll object. See shape below. |
Poll Object
| Field | Type | Required | Description |
|---|---|---|---|
question | string | Yes | The poll question. |
options | string[] | Yes | Array of answer option strings. |
Example Request
{ "title": "Weekend plans?", "content": "What is everyone doing this weekend?", "status": "published", "is_sensitive": false, "is_ai_generated": false, "poll": { "question": "What are you up to?", "options": ["Hiking", "Reading", "Coding", "Sleeping"] }}Response 201 Created
{ "post": { "id": "post_def456", "user_id": "user_xyz", "title": "Weekend plans?", "content": "What is everyone doing this weekend?", "status": "published", "is_sensitive": false, "is_ai_generated": false, "created_at": "2026-03-29T10:00:00Z", "updated_at": "2026-03-29T10:00:00Z", "author": { "id": "user_xyz", "username": "janedoe", "first_name": "Jane", "last_name": "Doe", "avatar_url": "https://cdn.example.com/avatars/janedoe.jpg", "verified": true }, "media": [], "poll": [ { "id": "poll_001", "post_id": "post_def456", "question": "What are you up to?", "options": ["Hiking", "Reading", "Coding", "Sleeping"], "votes": {} } ] }}Get Post
Section titled “Get Post”GET /v1/posts/{id}Public endpoint. Returns a single post with its author, media attachments, poll data, the full reactions array, and the first 50 comments with their authors.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The post ID. |
Response 200 OK
{ "post": { "id": "post_abc123", "user_id": "user_xyz", "title": "Hello world", "content": "My first post on the platform!", "status": "published", "is_sensitive": false, "is_ai_generated": false, "created_at": "2026-03-28T14:30:00Z", "updated_at": "2026-03-28T14:30:00Z", "author": { "id": "user_xyz", "username": "janedoe", "first_name": "Jane", "last_name": "Doe", "avatar_url": "https://cdn.example.com/avatars/janedoe.jpg", "verified": true }, "media": [], "poll": [], "reactions": [ { "post_id": "post_abc123", "user_id": "user_aaa", "type": "like" }, { "post_id": "post_abc123", "user_id": "user_bbb", "type": "love" } ], "comments": [ { "id": "comment_001", "post_id": "post_abc123", "user_id": "user_aaa", "content": "Great post!", "parent_id": null, "created_at": "2026-03-28T15:00:00Z", "author": { "id": "user_aaa", "username": "alice", "first_name": "Alice", "last_name": "Smith", "avatar_url": "https://cdn.example.com/avatars/alice.jpg" } } ] }}Response 404 Not Found
{ "error": "Post not found"}Update Post
Section titled “Update Post”PATCH /v1/posts/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The post ID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | Updated post title. |
content | string | No | Updated post text content. |
status | string | No | One of: draft, published. |
is_sensitive | boolean | No | Updated sensitive flag. |
Example Request
{ "content": "Updated post content.", "is_sensitive": true}Response 200 OK
Returns the updated post object (same shape as Create Post response).
Delete Post
Section titled “Delete Post”DELETE /v1/posts/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The post ID. |
Response 200 OK
{ "message": "Post deleted"}Get Drafts
Section titled “Get Drafts”GET /v1/draftsReturns the authenticated user’s draft posts, ordered by created_at descending.
Response 200 OK
{ "posts": [ { "id": "post_draft001", "user_id": "user_xyz", "title": "Work in progress", "content": "Still writing this...", "status": "draft", "is_sensitive": false, "is_ai_generated": false, "created_at": "2026-03-27T08:00:00Z", "updated_at": "2026-03-27T09:15:00Z", "author": { "id": "user_xyz", "username": "janedoe", "first_name": "Jane", "last_name": "Doe", "avatar_url": "https://cdn.example.com/avatars/janedoe.jpg", "verified": true }, "media": [], "poll": [] } ]}Follows
Section titled “Follows”Follow User
Section titled “Follow User”POST /v1/followSends a follow request or immediately follows the target user. The server checks the target user’s privacy settings (follower_approval). If approval is required, the follow status is set to "requested"; otherwise it is set to "following". Self-follows are rejected.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | The ID of the user to follow. |
Example Request
{ "user_id": "user_target123"}Response 201 Created (immediate follow)
{ "follow": { "follower_id": "user_xyz", "following_id": "user_target123", "status": "following" }}Response 201 Created (approval required)
{ "follow": { "follower_id": "user_xyz", "following_id": "user_target123", "status": "requested" }}Accept Follow Request
Section titled “Accept Follow Request”POST /v1/follow/acceptAccepts a pending follow request. Updates the follow record status from "requested" to "following".
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
follower_id | string | Yes | The ID of the user whose request to accept. |
Example Request
{ "follower_id": "user_requester456"}Response 200 OK
{ "follow": { "follower_id": "user_requester456", "following_id": "user_xyz", "status": "following" }}Decline Follow Request
Section titled “Decline Follow Request”POST /v1/follow/declineDeclines and deletes a pending follow request.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
follower_id | string | Yes | The ID of the user whose request to decline. |
Example Request
{ "follower_id": "user_requester456"}Response 200 OK
{ "message": "Follow request declined"}Unfollow User
Section titled “Unfollow User”DELETE /v1/follow/{userId}Unfollows the specified user.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
userId | string | The ID of the user to unfollow. |
Response 200 OK
{ "message": "Unfollowed"}Reactions
Section titled “Reactions”Add Reaction
Section titled “Add Reaction”POST /v1/posts/{id}/reactionsAdds or updates a reaction on a post. Upserts on the composite key (post_id, user_id) — if the user already reacted, the type is updated.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The post ID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Reaction type (e.g. like, love, fire). |
Example Request
{ "type": "like"}Response 201 Created
{ "reaction": { "post_id": "post_abc123", "user_id": "user_xyz", "type": "like" }}Remove Reaction
Section titled “Remove Reaction”DELETE /v1/posts/{id}/reactionsRemoves the authenticated user’s reaction from the specified post.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The post ID. |
Response 200 OK
{ "message": "Reaction removed"}Comments
Section titled “Comments”List Comments
Section titled “List Comments”GET /v1/posts/{id}/commentsPublic endpoint. Returns comments for a post in ascending created_at order. Supports cursor-based pagination.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The post ID. |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | — | Cursor value (created_at timestamp) for pagination. |
limit | int | 30 | Number of comments to return. Max 100. |
Response 200 OK
{ "comments": [ { "id": "comment_001", "post_id": "post_abc123", "user_id": "user_aaa", "content": "Great post!", "parent_id": null, "created_at": "2026-03-28T15:00:00Z", "author": { "id": "user_aaa", "username": "alice", "first_name": "Alice", "last_name": "Smith", "avatar_url": "https://cdn.example.com/avatars/alice.jpg" } }, { "id": "comment_002", "post_id": "post_abc123", "user_id": "user_bbb", "content": "Thanks, Alice!", "parent_id": "comment_001", "created_at": "2026-03-28T15:05:00Z", "author": { "id": "user_bbb", "username": "bob", "first_name": "Bob", "last_name": "Jones", "avatar_url": "https://cdn.example.com/avatars/bob.jpg" } } ], "next_cursor": "2026-03-28T15:05:00Z"}Create Comment
Section titled “Create Comment”POST /v1/posts/{id}/commentsAdds a comment to a post. Supply parent_id to create a threaded reply.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The post ID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | The comment text. |
parent_id | string | No | Parent comment ID for threaded replies. |
Example Request
{ "content": "This is a reply!", "parent_id": "comment_001"}Response 201 Created
{ "comment": { "id": "comment_003", "post_id": "post_abc123", "user_id": "user_xyz", "content": "This is a reply!", "parent_id": "comment_001", "created_at": "2026-03-28T16:00:00Z", "author": { "id": "user_xyz", "username": "janedoe", "first_name": "Jane", "last_name": "Doe", "avatar_url": "https://cdn.example.com/avatars/janedoe.jpg" } }}Delete Comment
Section titled “Delete Comment”DELETE /v1/comments/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The comment ID. |
Response 200 OK
{ "message": "Comment deleted"}Bookmarks
Section titled “Bookmarks”List Bookmarks
Section titled “List Bookmarks”GET /v1/bookmarksReturns the authenticated user’s bookmarks in descending order. Supports filtering by bookmarkable type and cursor-based pagination.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
type | string | — | Filter by type. One of: post, course, product, event. |
cursor | string | — | Opaque cursor for pagination. |
limit | int | 20 | Number of bookmarks to return. Max 50. |
Response 200 OK
{ "bookmarks": [ { "id": "bookmark_001", "user_id": "user_xyz", "bookmarkable_id": "post_abc123", "bookmarkable_type": "post", "created_at": "2026-03-29T12:00:00Z" }, { "id": "bookmark_002", "user_id": "user_xyz", "bookmarkable_id": "course_456", "bookmarkable_type": "course", "created_at": "2026-03-28T08:00:00Z" } ], "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wMy0yOCJ9"}Create Bookmark
Section titled “Create Bookmark”POST /v1/bookmarksBookmarks an item. Upserts — if the bookmark already exists, it is returned as-is.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
bookmarkable_id | string | Yes | The ID of the item to bookmark. |
bookmarkable_type | string | Yes | One of: post, course, product, event. |
Example Request
{ "bookmarkable_id": "post_abc123", "bookmarkable_type": "post"}Response 201 Created
{ "bookmark": { "id": "bookmark_003", "user_id": "user_xyz", "bookmarkable_id": "post_abc123", "bookmarkable_type": "post", "created_at": "2026-03-30T09:00:00Z" }}Delete Bookmark
Section titled “Delete Bookmark”DELETE /v1/bookmarks/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The bookmark ID. |
Response 200 OK
{ "message": "Bookmark deleted"}Vote on Poll
Section titled “Vote on Poll”POST /v1/polls/{id}/voteCasts a vote on a poll. If the user has previously voted, the old vote is removed before recording the new one. Votes are stored as a JSON object where each key is the option index and the value is an array of user IDs who selected that option.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The poll ID. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
option_index | int | Yes | Zero-based index of the selected option. |
Example Request
{ "option_index": 2}Response 200 OK
{ "poll": { "id": "poll_001", "post_id": "post_def456", "question": "What are you up to?", "options": ["Hiking", "Reading", "Coding", "Sleeping"], "votes": { "0": ["user_aaa"], "1": ["user_bbb", "user_ccc"], "2": ["user_xyz"], "3": [] } }}Stories
Section titled “Stories”List Stories
Section titled “List Stories”GET /v1/storiesReturns active stories from followed users and the authenticated user’s own stories. Stories expire after 24 hours and are automatically filtered out.
Response 200 OK
{ "stories": [ { "id": "story_001", "user_id": "user_aaa", "created_at": "2026-03-30T06:00:00Z", "expires_at": "2026-03-31T06:00:00Z", "author": { "id": "user_aaa", "username": "alice", "first_name": "Alice", "last_name": "Smith", "avatar_url": "https://cdn.example.com/avatars/alice.jpg" }, "story_frames": [ { "id": "frame_001", "media_url": "https://cdn.example.com/stories/frame1.jpg", "media_type": "image", "duration": 5 } ] } ]}Create Story
Section titled “Create Story”POST /v1/storiesCreates a new story with optional frames. Each frame represents a single slide in the story.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
frames | array | No | Array of frame objects. |
Frame Object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
media_url | string | Yes | — | URL of the media asset. |
media_type | string | Yes | — | Type of media (e.g. image, video). |
duration | int | No | 5 | Display duration in seconds. |
Example Request
{ "frames": [ { "media_url": "https://cdn.example.com/stories/morning.jpg", "media_type": "image", "duration": 5 }, { "media_url": "https://cdn.example.com/stories/clip.mp4", "media_type": "video", "duration": 15 } ]}Response 201 Created
{ "story": { "id": "story_002", "user_id": "user_xyz", "created_at": "2026-03-30T10:00:00Z", "expires_at": "2026-03-31T10:00:00Z", "story_frames": [ { "id": "frame_010", "media_url": "https://cdn.example.com/stories/morning.jpg", "media_type": "image", "duration": 5 }, { "id": "frame_011", "media_url": "https://cdn.example.com/stories/clip.mp4", "media_type": "video", "duration": 15 } ] }}Get Story
Section titled “Get Story”GET /v1/stories/{id}Returns a single story with all its frames.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The story ID. |
Response 200 OK
{ "story": { "id": "story_001", "user_id": "user_aaa", "created_at": "2026-03-30T06:00:00Z", "expires_at": "2026-03-31T06:00:00Z", "story_frames": [ { "id": "frame_001", "media_url": "https://cdn.example.com/stories/frame1.jpg", "media_type": "image", "duration": 5 } ] }}Response 404 Not Found
{ "error": "Story not found"}Delete Story
Section titled “Delete Story”DELETE /v1/stories/{id}Deletes a story. All associated frames are deleted first, then the story record itself is removed.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The story ID. |
Response 200 OK
{ "message": "Story deleted"}Record Story View
Section titled “Record Story View”POST /v1/stories/{id}/viewRecords that the authenticated user has viewed the story. Upserts — duplicate views by the same user are silently ignored.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The story ID. |
Response 200 OK
{ "message": "View recorded"}