Skip to content

Commit 765a481

Browse files
authored
fix(trigger): handle Slack reaction_added/reaction_removed event payloads (#3280)
* fix(trigger): handle Slack reaction_added/reaction_removed event payloads * fix(trigger): use oldest param for conversations.history consistency * fix oldest param * fix(trigger): use reactions.get API to fetch message text for thread replies
1 parent a1400ca commit 765a481

File tree

2 files changed

+84
-6
lines changed

2 files changed

+84
-6
lines changed

apps/sim/lib/webhooks/utils.server.ts

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,55 @@ async function downloadSlackFiles(
679679
return downloaded
680680
}
681681

682+
const SLACK_REACTION_EVENTS = new Set(['reaction_added', 'reaction_removed'])
683+
684+
/**
685+
* Fetches the text of a reacted-to message from Slack using the reactions.get API.
686+
* Unlike conversations.history, reactions.get works for both top-level messages and
687+
* thread replies, since it looks up the item directly by channel + timestamp.
688+
* Requires the bot token to have the reactions:read scope.
689+
*/
690+
async function fetchSlackMessageText(
691+
channel: string,
692+
messageTs: string,
693+
botToken: string
694+
): Promise<string> {
695+
try {
696+
const params = new URLSearchParams({
697+
channel,
698+
timestamp: messageTs,
699+
})
700+
const response = await fetch(`https://slack.com/api/reactions.get?${params}`, {
701+
headers: { Authorization: `Bearer ${botToken}` },
702+
})
703+
704+
const data = (await response.json()) as {
705+
ok: boolean
706+
error?: string
707+
type?: string
708+
message?: { text?: string }
709+
}
710+
711+
if (!data.ok) {
712+
logger.warn('Slack reactions.get failed — message text unavailable', {
713+
channel,
714+
messageTs,
715+
error: data.error,
716+
})
717+
return ''
718+
}
719+
720+
return data.message?.text ?? ''
721+
} catch (error) {
722+
logger.warn('Error fetching Slack message text', {
723+
channel,
724+
messageTs,
725+
error: error instanceof Error ? error.message : String(error),
726+
})
727+
return ''
728+
}
729+
}
730+
682731
/**
683732
* Format webhook input based on provider
684733
*/
@@ -953,6 +1002,23 @@ export async function formatWebhookInput(
9531002
})
9541003
}
9551004

1005+
const eventType: string = rawEvent?.type || body?.type || 'unknown'
1006+
const isReactionEvent = SLACK_REACTION_EVENTS.has(eventType)
1007+
1008+
// Reaction events nest channel/ts inside event.item
1009+
const channel: string = isReactionEvent
1010+
? rawEvent?.item?.channel || ''
1011+
: rawEvent?.channel || ''
1012+
const messageTs: string = isReactionEvent
1013+
? rawEvent?.item?.ts || ''
1014+
: rawEvent?.ts || rawEvent?.event_ts || ''
1015+
1016+
// For reaction events, attempt to fetch the original message text
1017+
let text: string = rawEvent?.text || ''
1018+
if (isReactionEvent && channel && messageTs && botToken) {
1019+
text = await fetchSlackMessageText(channel, messageTs, botToken)
1020+
}
1021+
9561022
const rawFiles: any[] = rawEvent?.files ?? []
9571023
const hasFiles = rawFiles.length > 0
9581024

@@ -965,16 +1031,18 @@ export async function formatWebhookInput(
9651031

9661032
return {
9671033
event: {
968-
event_type: rawEvent?.type || body?.type || 'unknown',
969-
channel: rawEvent?.channel || '',
1034+
event_type: eventType,
1035+
channel,
9701036
channel_name: '',
9711037
user: rawEvent?.user || '',
9721038
user_name: '',
973-
text: rawEvent?.text || '',
974-
timestamp: rawEvent?.ts || rawEvent?.event_ts || '',
1039+
text,
1040+
timestamp: messageTs,
9751041
thread_ts: rawEvent?.thread_ts || '',
9761042
team_id: body?.team_id || rawEvent?.team || '',
9771043
event_id: body?.event_id || '',
1044+
reaction: rawEvent?.reaction || '',
1045+
item_user: rawEvent?.item_user || '',
9781046
hasFiles,
9791047
files,
9801048
},

apps/sim/triggers/slack/webhook.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ export const slackWebhookTrigger: TriggerConfig = {
6767
'Go to <a href="https://api.slack.com/apps" target="_blank" rel="noopener noreferrer" class="text-muted-foreground underline transition-colors hover:text-muted-foreground/80">Slack Apps page</a>',
6868
'If you don\'t have an app:<br><ul class="mt-1 ml-5 list-disc"><li>Create an app from scratch</li><li>Give it a name and select your workspace</li></ul>',
6969
'Go to "Basic Information", find the "Signing Secret", and paste it in the field above.',
70-
'Go to "OAuth & Permissions" and add bot token scopes:<br><ul class="mt-1 ml-5 list-disc"><li><code>app_mentions:read</code> - For viewing messages that tag your bot with an @</li><li><code>chat:write</code> - To send messages to channels your bot is a part of</li><li><code>files:read</code> - To access files and images shared in messages</li></ul>',
71-
'Go to "Event Subscriptions":<br><ul class="mt-1 ml-5 list-disc"><li>Enable events</li><li>Under "Subscribe to Bot Events", add <code>app_mention</code> to listen to messages that mention your bot</li><li>Paste the Webhook URL above into the "Request URL" field</li></ul>',
70+
'Go to "OAuth & Permissions" and add bot token scopes:<br><ul class="mt-1 ml-5 list-disc"><li><code>app_mentions:read</code> - For viewing messages that tag your bot with an @</li><li><code>chat:write</code> - To send messages to channels your bot is a part of</li><li><code>files:read</code> - To access files and images shared in messages</li><li><code>reactions:read</code> - For listening to emoji reactions and fetching reacted-to message text</li></ul>',
71+
'Go to "Event Subscriptions":<br><ul class="mt-1 ml-5 list-disc"><li>Enable events</li><li>Under "Subscribe to Bot Events", add <code>app_mention</code> to listen to messages that mention your bot</li><li>For reaction events, also add <code>reaction_added</code> and/or <code>reaction_removed</code></li><li>Paste the Webhook URL above into the "Request URL" field</li></ul>',
7272
'Go to "Install App" in the left sidebar and install the app into your desired Slack workspace and channel.',
7373
'Copy the "Bot User OAuth Token" (starts with <code>xoxb-</code>) and paste it in the Bot Token field above to enable file downloads.',
7474
'Save changes in both Slack and here.',
@@ -128,6 +128,16 @@ export const slackWebhookTrigger: TriggerConfig = {
128128
type: 'string',
129129
description: 'Unique event identifier',
130130
},
131+
reaction: {
132+
type: 'string',
133+
description:
134+
'Emoji reaction name (e.g., thumbsup). Present for reaction_added/reaction_removed events',
135+
},
136+
item_user: {
137+
type: 'string',
138+
description:
139+
'User ID of the original message author. Present for reaction_added/reaction_removed events',
140+
},
131141
hasFiles: {
132142
type: 'boolean',
133143
description: 'Whether the message has file attachments',

0 commit comments

Comments
 (0)