Chat & Messaging

1:1 DMs, group chat, reactions, and message history

Overview

The Chat resource provides real-time messaging with support for 1:1 direct messages, group conversations, message reactions, editing, threading, and read receipts.

All chat methods are available on r.chat.

Methods

MethodDescription
conversations(params?)List the authenticated user’s conversations.
conversation(id)Get a conversation by ID with member details.
communityConversation(communityId)Get a community’s conversation.
messages(conversationId, params?)List messages in a conversation (newest first).
send(input)Send a message to a conversation.
dm(input)Get or create a DM conversation with a user.
createGroup(input)Create a group conversation.
deleteConversation(id)Delete a conversation.
reactToMessage(messageId, input)React to a message (toggles on/off).
editMessage(messageId, input)Edit a message.
deleteMessage(messageId)Delete a message.
markAsRead(conversationId, input)Mark a conversation as read up to a message.
unreadCount(conversationId)Get unread message count for a conversation.

List conversations

1const { data: conversations, meta } = await r.chat.conversations({ limit: 20 });
2
3for (const conv of conversations) {
4 const names = conv.members.map((m) => m.name).join(', ');
5 const lastMsg = conv.last_message
6 ? `${conv.last_message.sender_name}: ${conv.last_message.content.slice(0, 50)}`
7 : 'No messages';
8
9 console.log(`[${conv.type}] ${conv.name ?? names}`);
10 console.log(` Last: ${lastMsg}`);
11}

Returns: PaginatedResponse<Conversation>

1interface Conversation {
2 id: string;
3 type: string; // 'dm' | 'group' | 'community'
4 name: string | null; // null for DMs, set for groups
5 community_id: string | null;
6 members: ConversationMember[];
7 last_message: {
8 id: string;
9 content: string;
10 sender_name: string;
11 created_at: string;
12 } | null;
13 created_at: string;
14}

Get a conversation

1const { data: conv } = await r.chat.conversation('conv_123');
2
3console.log(conv.type);
4console.log(conv.name);
5console.log(conv.members.map((m) => `@${m.username} (joined ${m.joined_at})`));

Get community conversation

1const { data: conv } = await r.chat.communityConversation('comm_123');
2console.log(conv.id);

Start a DM

Get or create a direct message conversation with another user. If a DM already exists, it returns the existing conversation.

1const { data: dm } = await r.chat.dm({ user_id: 'user_456' });
2
3console.log(dm.id); // Conversation ID
4console.log(dm.type); // 'dm'
5console.log(dm.created); // true if newly created, false if existing
6
7// Send a message in the DM
8await r.chat.send({
9 conversation_id: dm.id,
10 content: 'Hey! How is the project going?',
11});

Create a group

1const { data: group } = await r.chat.createGroup({
2 name: 'Project Alpha Team',
3 member_ids: ['user_1', 'user_2', 'user_3'],
4});
5
6console.log(group.id);
7console.log(group.name); // 'Project Alpha Team'
8console.log(group.members);

Send a message

1const { data: msg } = await r.chat.send({
2 conversation_id: 'conv_123',
3 content: 'The deployment succeeded!',
4});
5
6console.log(msg.id);
7console.log(msg.conversation_id);
8console.log(msg.content);
9console.log(msg.created_at);

Input fields:

FieldTypeRequiredDescription
conversation_idstringYesThe conversation to send the message in.
contentstringYesMessage content.
reply_to_idstring?NoReply to a specific message (creates a thread).

Reply to a message

1await r.chat.send({
2 conversation_id: 'conv_123',
3 content: 'Thanks for the update!',
4 reply_to_id: 'msg_456',
5});

List messages

Messages are returned newest first.

1const { data: messages, meta } = await r.chat.messages('conv_123', {
2 limit: 50,
3});
4
5for (const msg of messages) {
6 console.log(`@${msg.sender.username}: ${msg.content}`);
7 if (msg.reactions.length > 0) {
8 console.log(` Reactions: ${msg.reactions.map((r) => r.type).join(' ')}`);
9 }
10 if (msg.reply_to_id) {
11 console.log(` (reply to ${msg.reply_to_id})`);
12 }
13}

Returns: PaginatedResponse<Message>

1interface Message {
2 id: string;
3 content: string;
4 sender: UserSummary;
5 reply_to_id: string | null;
6 media: MessageMedia[];
7 reactions: MessageReaction[];
8 created_at: string;
9}
10
11interface MessageReaction {
12 type: string;
13 user_id: string;
14 user_name: string;
15}
16
17interface MessageMedia {
18 id: string;
19 type: string;
20 url: string;
21 mime_type: string | null;
22 file_name: string | null;
23}

React to a message

Reactions toggle: if you already reacted with the same type, it is removed. If you reacted with a different type, it is replaced.

1const { data: result } = await r.chat.reactToMessage('msg_123', {
2 type: 'heart',
3});
4
5console.log(result.action); // 'added' or 'removed'
6if (result.reaction) {
7 console.log(result.reaction.type); // 'heart'
8}

Edit a message

Only the sender can edit their own messages.

1const { data: edited } = await r.chat.editMessage('msg_123', {
2 content: 'Updated message content',
3});
4
5console.log(edited.content);

Delete a message

Only the sender can delete their own messages.

1await r.chat.deleteMessage('msg_123');

Delete a conversation

Only the creator can delete a conversation.

1await r.chat.deleteConversation('conv_123');

Read receipts

Mark as read

Mark a conversation as read up to a specific message:

1await r.chat.markAsRead('conv_123', {
2 message_id: 'msg_789',
3});

Get unread count

1const { data: { unread_count } } = await r.chat.unreadCount('conv_123');
2console.log(`${unread_count} unread messages`);

Full example

1import { Recursiv } from '@recursiv/sdk';
2
3const r = new Recursiv();
4
5// 1. Start a DM
6const { data: dm } = await r.chat.dm({ user_id: 'user_456' });
7console.log(`DM conversation: ${dm.id} (new: ${dm.created})`);
8
9// 2. Send messages
10await r.chat.send({
11 conversation_id: dm.id,
12 content: 'Hey! Just pushed the new SDK release.',
13});
14
15await r.chat.send({
16 conversation_id: dm.id,
17 content: 'Can you review the breaking changes doc?',
18});
19
20// 3. Create a group for the team
21const { data: group } = await r.chat.createGroup({
22 name: 'SDK Release Team',
23 member_ids: ['user_456', 'user_789'],
24});
25
26// 4. Send a message to the group
27const { data: groupMsg } = await r.chat.send({
28 conversation_id: group.id,
29 content: 'SDK v2.0 is ready for release. Please review the changelog.',
30});
31
32// 5. React to a message
33await r.chat.reactToMessage(groupMsg.id, { type: 'fire' });
34
35// 6. List conversations
36const { data: conversations } = await r.chat.conversations();
37console.log(`You have ${conversations.length} conversations`);
38
39// 7. Load message history
40const { data: messages } = await r.chat.messages(group.id, { limit: 50 });
41console.log(`${messages.length} messages in group`);
42
43// 8. Mark as read
44if (messages.length > 0) {
45 await r.chat.markAsRead(group.id, {
46 message_id: messages[0].id,
47 });
48}
49
50// 9. Check unread
51const { data: { unread_count } } = await r.chat.unreadCount(group.id);
52console.log(`${unread_count} unread`);