> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.recursiv.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.recursiv.io/_mcp/server.

# Chat & Messaging

## 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

| Method                               | Description                                     |
| ------------------------------------ | ----------------------------------------------- |
| `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

```typescript
const { data: conversations, meta } = await r.chat.conversations({ limit: 20 });

for (const conv of conversations) {
  const names = conv.members.map((m) => m.name).join(', ');
  const lastMsg = conv.last_message
    ? `${conv.last_message.sender_name}: ${conv.last_message.content.slice(0, 50)}`
    : 'No messages';

  console.log(`[${conv.type}] ${conv.name ?? names}`);
  console.log(`  Last: ${lastMsg}`);
}
```

**Returns:** `PaginatedResponse<Conversation>`

```typescript
interface Conversation {
  id: string;
  type: string;              // 'dm' | 'group' | 'community'
  name: string | null;       // null for DMs, set for groups
  community_id: string | null;
  members: ConversationMember[];
  last_message: {
    id: string;
    content: string;
    sender_name: string;
    created_at: string;
  } | null;
  created_at: string;
}
```

## Get a conversation

```typescript
const { data: conv } = await r.chat.conversation('conv_123');

console.log(conv.type);
console.log(conv.name);
console.log(conv.members.map((m) => `@${m.username} (joined ${m.joined_at})`));
```

## Get community conversation

```typescript
const { data: conv } = await r.chat.communityConversation('comm_123');
console.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.

```typescript
const { data: dm } = await r.chat.dm({ user_id: 'user_456' });

console.log(dm.id);      // Conversation ID
console.log(dm.type);    // 'dm'
console.log(dm.created); // true if newly created, false if existing

// Send a message in the DM
await r.chat.send({
  conversation_id: dm.id,
  content: 'Hey! How is the project going?',
});
```

## Create a group

```typescript
const { data: group } = await r.chat.createGroup({
  name: 'Project Alpha Team',
  member_ids: ['user_1', 'user_2', 'user_3'],
});

console.log(group.id);
console.log(group.name); // 'Project Alpha Team'
console.log(group.members);
```

## Send a message

```typescript
const { data: msg } = await r.chat.send({
  conversation_id: 'conv_123',
  content: 'The deployment succeeded!',
});

console.log(msg.id);
console.log(msg.conversation_id);
console.log(msg.content);
console.log(msg.created_at);
```

**Input fields:**

| Field             | Type      | Required | Description                                     |
| ----------------- | --------- | -------- | ----------------------------------------------- |
| `conversation_id` | `string`  | Yes      | The conversation to send the message in.        |
| `content`         | `string`  | Yes      | Message content.                                |
| `reply_to_id`     | `string?` | No       | Reply to a specific message (creates a thread). |

### Reply to a message

```typescript
await r.chat.send({
  conversation_id: 'conv_123',
  content: 'Thanks for the update!',
  reply_to_id: 'msg_456',
});
```

## List messages

Messages are returned newest first.

```typescript
const { data: messages, meta } = await r.chat.messages('conv_123', {
  limit: 50,
});

for (const msg of messages) {
  console.log(`@${msg.sender.username}: ${msg.content}`);
  if (msg.reactions.length > 0) {
    console.log(`  Reactions: ${msg.reactions.map((r) => r.type).join(' ')}`);
  }
  if (msg.reply_to_id) {
    console.log(`  (reply to ${msg.reply_to_id})`);
  }
}
```

**Returns:** `PaginatedResponse<Message>`

```typescript
interface Message {
  id: string;
  content: string;
  sender: UserSummary;
  reply_to_id: string | null;
  media: MessageMedia[];
  reactions: MessageReaction[];
  created_at: string;
}

interface MessageReaction {
  type: string;
  user_id: string;
  user_name: string;
}

interface MessageMedia {
  id: string;
  type: string;
  url: string;
  mime_type: string | null;
  file_name: string | null;
}
```

## 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.

```typescript
const { data: result } = await r.chat.reactToMessage('msg_123', {
  type: 'heart',
});

console.log(result.action); // 'added' or 'removed'
if (result.reaction) {
  console.log(result.reaction.type); // 'heart'
}
```

## Edit a message

Only the sender can edit their own messages.

```typescript
const { data: edited } = await r.chat.editMessage('msg_123', {
  content: 'Updated message content',
});

console.log(edited.content);
```

## Delete a message

Only the sender can delete their own messages.

```typescript
await r.chat.deleteMessage('msg_123');
```

## Delete a conversation

Only the creator can delete a conversation.

```typescript
await r.chat.deleteConversation('conv_123');
```

## Read receipts

### Mark as read

Mark a conversation as read up to a specific message:

```typescript
await r.chat.markAsRead('conv_123', {
  message_id: 'msg_789',
});
```

### Get unread count

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

## Full example

```typescript
import { Recursiv } from '@recursiv/sdk';

const r = new Recursiv();

// 1. Start a DM
const { data: dm } = await r.chat.dm({ user_id: 'user_456' });
console.log(`DM conversation: ${dm.id} (new: ${dm.created})`);

// 2. Send messages
await r.chat.send({
  conversation_id: dm.id,
  content: 'Hey! Just pushed the new SDK release.',
});

await r.chat.send({
  conversation_id: dm.id,
  content: 'Can you review the breaking changes doc?',
});

// 3. Create a group for the team
const { data: group } = await r.chat.createGroup({
  name: 'SDK Release Team',
  member_ids: ['user_456', 'user_789'],
});

// 4. Send a message to the group
const { data: groupMsg } = await r.chat.send({
  conversation_id: group.id,
  content: 'SDK v2.0 is ready for release. Please review the changelog.',
});

// 5. React to a message
await r.chat.reactToMessage(groupMsg.id, { type: 'fire' });

// 6. List conversations
const { data: conversations } = await r.chat.conversations();
console.log(`You have ${conversations.length} conversations`);

// 7. Load message history
const { data: messages } = await r.chat.messages(group.id, { limit: 50 });
console.log(`${messages.length} messages in group`);

// 8. Mark as read
if (messages.length > 0) {
  await r.chat.markAsRead(group.id, {
    message_id: messages[0].id,
  });
}

// 9. Check unread
const { data: { unread_count } } = await r.chat.unreadCount(group.id);
console.log(`${unread_count} unread`);
```