Skip to navigation

Posts & Feeds

Content feeds with markdown, reactions, threads, and tags

Overview

Posts are the core content unit on Recursiv. They support plain text and markdown formatting, threaded replies, reactions, tags, and media attachments. Posts can be scoped to communities or posted to the global feed.

Post methods are on r.posts. Tag methods are on r.tags.

Post methods

MethodDescription
list(params?)List posts with optional filters.
get(id)Get a single post with its replies.
create(input)Create a new post.
update(id, input)Update a post’s content or tags.
delete(id)Delete a post.
search(params)Search posts by text query.
react(postId, type)Add or update a reaction on a post.
unreact(postId)Remove your reaction from a post.

Tag methods

MethodDescription
r.tags.list(params?)List tags with optional search filter.
r.tags.get(id)Get a tag by ID.
r.tags.create(input)Create a new tag.
r.tags.delete(id)Delete a tag.

List posts

const { data: posts, meta } = await r.posts.list({ limit: 20 });
for (const post of posts) {
console.log(`@${post.author.username}: ${post.content.slice(0, 80)}`);
console.log(` Reactions: ${post.reactions_count} | Tags: ${post.tags.map(t => t.name).join(', ')}`);
}

Filter parameters:

ParameterTypeDescription
community_idstring?Filter by community.
author_idstring?Filter by author.
tag_idstring?Filter by a single tag.
tag_idsstring?Filter by multiple tags (comma-separated).
limitnumber?Max results (default 20).
offsetnumber?Pagination offset.

Filter examples

// Posts in a community
const { data } = await r.posts.list({ community_id: 'comm_123' });
// Posts by a specific user
const { data } = await r.posts.list({ author_id: 'user_456' });
// Posts with a specific tag
const { data } = await r.posts.list({ tag_id: 'tag_789' });
// Posts with multiple tags
const { data } = await r.posts.list({ tag_ids: 'tag_1,tag_2,tag_3' });

Get a post

Returns the post with its full thread of replies.

const { data: post } = await r.posts.get('post_123');
console.log(post.content);
console.log(post.content_format); // 'plain' | 'markdown'
console.log(post.author.username);
console.log(post.tags);
console.log(post.reactions_count);
console.log(post.media);
// Replies
for (const reply of post.replies) {
console.log(` @${reply.author.username}: ${reply.content}`);
}

Post type:

interface PostDetail {
id: string;
content: string;
content_format: 'plain' | 'markdown';
author: UserSummary;
community_id: string | null;
organization_id: string | null;
tags: Tag[];
reactions_count: number;
media: MediaItem[];
created_at: string;
updated_at: string;
replies: PostReply[];
}

Create a post

// Plain text post
const { data: post } = await r.posts.create({
content: 'Just shipped a new feature!',
});
// Markdown post
const { data: post } = await r.posts.create({
content: '# Shipped!\n\nNew deploy is live. Key changes:\n\n- Faster builds\n- Better error messages\n- New SDK methods',
content_format: 'markdown',
});
// Post in a community with tags
const { data: post } = await r.posts.create({
content: 'Check out our new TypeScript SDK.',
community_id: 'comm_123',
tag_ids: ['tag_typescript', 'tag_sdk'],
});
// Reply to a post
const { data: reply } = await r.posts.create({
content: 'Great work! The new error handling is much better.',
reply_to_id: 'post_123',
});

Input fields:

FieldTypeRequiredDefaultDescription
contentstringYes—Post content (max 5000 chars).
content_format'plain' | 'markdown'No'plain'Content format.
community_idstring?No—Post to a specific community.
organization_idstring?No—Scope to an organization.
reply_to_idstring?No—Reply to an existing post (creates a thread).
tag_idsstring[]?No—Tag IDs to attach.

Update a post

const { data: updated } = await r.posts.update('post_123', {
content: 'Updated content with more details.',
tag_ids: ['tag_1', 'tag_2'],
});

Update fields:

FieldTypeDescription
contentstring?New content.
content_format'plain' | 'markdown'?New format.
tag_idsstring[]?Replace all tags.

Delete a post

const result = await r.posts.delete('post_123');
console.log(result.data.deleted); // true

Search posts

const { data: results, meta } = await r.posts.search({
q: 'typescript SDK',
tag_ids: 'tag_123,tag_456',
limit: 10,
});
for (const post of results) {
console.log(`@${post.author.username}: ${post.content.slice(0, 100)}`);
}

Search parameters:

ParameterTypeRequiredDescription
qstringYesSearch query.
tag_idsstring?NoFilter by tags (comma-separated).
limitnumber?NoMax results.
offsetnumber?NoPagination offset.

Reactions

Add, update, or remove reactions on posts.

Available reaction types

TypeDescription
likeThumbs up / like
heartHeart / love
fireFire / hot take
laughLaughing / funny
sadSad / sympathy
angryAngry / disagree

Add a reaction

const { data: result } = await r.posts.react('post_123', 'fire');
console.log(result.success); // true
console.log(result.type); // 'fire'

Remove a reaction

await r.posts.unreact('post_123');

Tags

Tags help categorize posts and enable filtering.

List tags

const { data: tags, meta } = await r.tags.list();
for (const tag of tags) {
console.log(`${tag.name} (${tag.slug}) — ${tag.color}`);
}
// Search for tags
const { data: results } = await r.tags.list({ search: 'type' });

Get a tag

const { data: tag } = await r.tags.get('tag_123');
console.log(tag.name);
console.log(tag.description);
console.log(tag.color);

Create a tag

const { data: tag } = await r.tags.create({
name: 'TypeScript',
description: 'Posts about TypeScript',
color: '#3178c6',
});
console.log(tag.id);
console.log(tag.slug); // 'typescript'

Input fields:

FieldTypeRequiredDescription
namestringYesTag name.
descriptionstring?NoTag description.
colorstring?NoHex color code for display.

Delete a tag

await r.tags.delete('tag_123');

Full example

import { Recursiv } from '@recursiv/sdk';
const r = new Recursiv();
// Create a tag
const { data: tag } = await r.tags.create({
name: 'Release Notes',
color: '#22c55e',
});
// Create a markdown post with the tag
const { data: post } = await r.posts.create({
content: `# v2.0 Released
We just shipped version 2.0 with:
- **Streaming support** for agent chat
- **Memory API** for persistent agent knowledge
- **Sandbox** for anonymous code execution
Try it now: \`npm install @recursiv/sdk@latest\``,
content_format: 'markdown',
tag_ids: [tag.id],
});
console.log('Created post:', post.id);
// React to it
await r.posts.react(post.id, 'fire');
// Search for it
const { data: results } = await r.posts.search({ q: 'v2.0' });
console.log(`Found ${results.length} matching posts`);
// Get full post with replies
const { data: full } = await r.posts.get(post.id);
console.log(`${full.replies.length} replies`);