Skip to content

Reactions

Add emoji reactions to messages. Users and bots can react with standard Unicode emoji. Reactions are delivered in real time via the Reactions intent.

How Reactions Work #

Any user or bot with the AddReactions permission can react to a message with a Unicode emoji. Each message supports up to 20 unique emoji. Each user can react once per emoji — attempting to react twice returns already_reacted.

Performance note: Reactions are buffered in-memory on the server and flushed to the database periodically. Real-time events (ReactionAdd / ReactionRemove) fire instantly — there's zero latency for connected clients even under heavy load.

Reaction Schema #

When you query messages or receive them via events, each message includes a reactions array. Each entry represents one emoji with its count and a preview of who reacted.

Field Type Description
emoji string Unicode emoji (e.g. "👍", "🔥").
count number Total number of users who reacted with this emoji.
userIds string[] Preview of user IDs (up to 3). Use count for the real total.

Example — message with reactions

{
  "messageId": 42,
  "text": "Hello everyone!",
  "reactions": [
    {
      "emoji": "👍",
      "count": 128,
      "userIds": ["d3b07384-...", "a1b2c3d4-...", "e5f6a7b8-..."]
    },
    {
      "emoji": "🔥",
      "count": 3,
      "userIds": ["d3b07384-...", "a1b2c3d4-...", "e5f6a7b8-..."]
    }
  ]
}

userIds is capped at 3. For display purposes (avatars), use the IDs in the array. For the actual count, always use the count field — it reflects the real total even when hundreds of users react.

Adding Reactions #

Send a POST to /IReactions/v1/Add with the channel, message, and emoji.

Request

POST /IReactions/v1/Add
Authorization: Bot YOUR_TOKEN
Content-Type: application/json

{
  "channelId": "c0ffee00-...",
  "messageId": 42,
  "emoji": "👍"
}
Status Code Description
200 Reaction added successfully.
403 insufficient_permissions Bot lacks AddReactions permission.
404 message_not_found Message doesn't exist in this channel.
409 already_reacted Bot already reacted with this emoji.
422 reaction_limit_reached Message already has 20 unique emoji.

Removing Reactions #

Remove the bot's own reaction with DELETE /IReactions/v1/Remove. Bots can only remove their own reactions — not those of other users.

Request

DELETE /IReactions/v1/Remove
Authorization: Bot YOUR_TOKEN
Content-Type: application/json

{
  "channelId": "c0ffee00-...",
  "messageId": 42,
  "emoji": "👍"
}

Listing Reactions #

Query all reactions on a specific message with GET /IReactions/v1/List.

Request

GET /IReactions/v1/List?channelId=c0ffee00-...&messageId=42
Authorization: Bot YOUR_TOKEN

Response

{
  "reactions": [
    {
      "emoji": "👍",
      "count": 42,
      "userIds": ["d3b07384-...", "a1b2c3d4-...", "e5f6a7b8-..."]
    }
  ]
}

Batch Refresh #

After a reconnect or when a tab regains focus, the client may need to refresh reactions for all currently visible messages. Instead of calling /List per message, use POST /IReactions/v1/BatchGet to fetch reactions for up to 50 messages in a single request.

When to use BatchGet: All messages must belong to the same channel. The server resolves reactions from an in-memory LRU cache, so hot messages return instantly with no DB hit. Ideal for refreshing the 15–30 messages visible in the viewport.

Request

POST /IReactions/v1/BatchGet
Authorization: Bot YOUR_TOKEN
Content-Type: application/json

{
  "channelId": "c0ffee00-...",
  "messageIds": [42, 43, 44, 45, 46]
}

Response

{
  "messages": [
    {
      "messageId": 42,
      "reactions": [
        { "emoji": "👍", "count": 128, "userIds": ["...", "...", "..."] }
      ]
    },
    {
      "messageId": 43,
      "reactions": []
    }
  ]
}

Recommended client pattern (TypeScript)

// On reconnect or visibilitychange → "visible"
async function refreshVisibleReactions(channelId: string, visibleIds: number[]) {
  const res = await fetch("/IReactions/v1/BatchGet", {
    method: "POST",
    headers: { "Authorization": "Bot " + token, "Content-Type": "application/json" },
    body: JSON.stringify({ channelId, messageIds: visibleIds })
  });
  const { messages } = await res.json();
  // Replace local reaction state for each returned message
  for (const { messageId, reactions } of messages) {
    store.setReactions(messageId, reactions);
  }
}

Reactions in Messages #

Reactions are included automatically when fetching messages via GET /IMessages/v1/History and in MessageCreate events. No extra API call needed — reactions travel with the message.

Example — message history with reactions

GET /IMessages/v1/History?channelId=c0ffee00-...&limit=1

// Response includes reactions on each message
{
  "messages": [
    {
      "messageId": 42,
      "text": "Ship it!",
      "creatorId": "...",
      "reactions": [
        { "emoji": "🚀", "count": 15, "userIds": ["...", "...", "..."] }
      ]
    }
  ]
}

Real-time Events #

Subscribe to the Reactions intent (bit 3, value 8) to receive reaction events via SSE. Add it to your intents bitmask: intents = Messages | Reactions = 1 | 8 = 9.

Event Fields Description
ReactionAdd spaceId, channelId, messageId, userId, emoji Fired when any user adds a reaction.
ReactionRemove spaceId, channelId, messageId, userId, emoji Fired when any user removes a reaction.

SSE example

id: 128
event: reactionAdd
data: {
  "spaceId": "aaaabbbb-...",
  "channelId": "c0ffee00-...",
  "messageId": 42,
  "userId": "d3b07384-...",
  "emoji": "👍"
}

Handling reaction events (TypeScript)

// Update local reaction count from delta events
eventSource.addEventListener('reactionAdd', (e) => {
  const data = JSON.parse(e.data);
  // Increment local count for data.emoji on data.messageId
  // Add data.userId to the user preview list
});

eventSource.addEventListener('reactionRemove', (e) => {
  const data = JSON.parse(e.data);
  // Decrement local count for data.emoji on data.messageId
  // Remove data.userId from the user preview list
  // If count reaches 0, remove the reaction group entirely
});

Limits & Permissions #

Limit Value Description
Unique emoji per message 20 Maximum distinct emoji on a single message.
Reactions per user per emoji 1 Each user can react once with the same emoji. Duplicates return 409.
userIds preview 3 Max user IDs returned per reaction. Use count for the real total.
Rate limit 60/min Sliding window per bot.
BatchGet max messages 50 Maximum message IDs per /BatchGet request. Excess IDs are silently truncated.
Required permission AddReactions Checked on /Add. Removing own reaction has no permission requirement.
SSE intent Reactions (bit 3 = 8) Required to receive ReactionAdd / ReactionRemove events.