Skip to content

Discord Sink

The Discord sink supports two distinct delivery styles: message events received through the Discord Gateway and interactions delivered to a hosted HTTP endpoint.

StyleReceivesRequired configuration
GatewayBot messages from guild channels and direct messagesBot token, enabled Gateway intents, and a running desktop app or sink worker
Gateway on a deviceThe same messages, answered by a service on a device you manageBot token entered when deploying; see On a device
Interactions webhookPING verification, slash commands, components, autocomplete, and modal submissionsPublic HTTPS URL and the application’s public key

Gateway mode is used by the desktop adapter and is also available to the Docker Compose sink service. The hosted API exposes the interactions webhook when Discord is enabled in the hub.

FieldApplies toMeaning
tokenGatewayDiscord bot token
webhook_secretWebhookDiscord application public key, despite the legacy field name
intentsGatewayRequested Gateway intents
channel_whitelistDesktop and device GatewayProcess only listed channel IDs when non-empty
channel_blacklistDesktop and device GatewayIgnore listed channel IDs
respond_to_mentionsDesktop and device GatewayIn a server channel, start a run for a message that mentions the bot or replies to one of its messages. When disabled, only the prefix counts, or every message when no prefix is set; see Gateway setup
respond_to_dmsGatewayAccept direct messages
command_prefixGatewayIn a server channel, start a run for a message that begins with the prefix. The Events editor writes ! for a new event; a config without the key, or with an empty value, has no prefix. The desktop app and a device combine it with respond_to_mentions; the Docker Compose sink service uses it on its own. Both are described under Gateway setup
bot_name, bot_descriptionUI metadataDisplay information for the event configuration

The default desktop intents are Guilds, GuildMessages, and MessageContent. MessageContent, GuildMembers, and GuildPresences are privileged intents and must also be enabled in the Discord Developer Portal if selected.

  1. Create an application and bot in the Discord Developer Portal.
  2. Copy the bot token into the event configuration.
  3. Enable only the Gateway intents the event needs.
  4. Add the bot to the relevant server and activate the event.

The desktop app and a device ignore messages authored by bots. Both then apply the same rules, in this order, before they start a run:

  1. The channel must pass the lists: channel_whitelist is empty or contains it, and channel_blacklist does not contain it. The lists apply to direct messages too.
  2. A direct message starts a run when respond_to_dms is enabled. It needs no prefix and no mention. The desktop app receives direct messages only when intents includes DirectMessages; a device adds that intent itself.
  3. A message in a server channel starts a run according to command_prefix and respond_to_mentions:
command_prefixrespond_to_mentionsMessages in a server channel that start a run
SetEnabledMessages that begin with the prefix, messages that mention the bot, and replies to one of the bot’s messages
SetDisabledMessages that begin with the prefix
Not setEnabledMessages that mention the bot and replies to one of the bot’s messages
Not setDisabledEvery message

No prefix is set when the key is missing, null or empty. A prefix is compared with the beginning of the message exactly as saved: case counts and nothing is trimmed, so a single space is a prefix. A mention counts when it names the bot itself, not @everyone, @here or a role.

The Docker Compose sink service applies its own rule instead. It ignores messages authored by bots, requires respond_to_dms for a direct message, and then starts a run for every message that begins with command_prefix, in a server channel and in a direct message alike; without a prefix, every message starts a run. respond_to_mentions and the channel lists have no effect there, so a mention does not replace the prefix. guild_id and channel_id limit an event to one server or one channel. Each holds one ID as a JSON number: the service ignores a string. A Discord ID is larger than a JavaScript number holds exactly, so once a JavaScript client, the Events editor included, has read and saved the config, the ID can be rounded and match nothing.

  1. Copy the application’s Public Key from Discord’s General Information page into the event’s application-public-key field.
  2. Activate the event.
  3. Copy the generated Interactions Endpoint URL from Flow-Like. Its route ends in /sink/trigger/discord/{event_id}; the deployment may add an API prefix at the proxy layer.
  4. Paste that URL into Discord’s Interactions Endpoint URL field.

Discord sends a PING while validating the URL. Flow-Like verifies the Ed25519 signature and returns PONG for a valid PING.

For other interaction types, Flow-Like creates a run asynchronously and returns a deferred interaction response (type: 5) so Discord receives an acknowledgement within its response window.

The webhook verifies:

  • X-Signature-Ed25519
  • X-Signature-Timestamp
  • the exact request body
  • the public key stored for the active event sink

The public key is safe to share with the endpoint configuration; the bot token and any workflow credentials are not.

The payload depends on the delivery style:

  • A Gateway adapter constructs message-oriented context, including the author, channel, content, and available conversation context.
  • The interactions endpoint forwards the Discord interaction JSON, including fields such as type, data, token, guild_id, and channel_id.

Model the event input for the selected style. If one event can be delivered through both styles, branch on the payload shape before accessing nested fields.

An interactions webhook only acknowledges receipt; it does not wait for the workflow to finish. A workflow that needs to answer a slash command must use the interaction token with Discord’s follow-up API.

Gateway message workflows can respond through the Discord context supplied by the desktop adapter. That context is not present on a webhook-triggered run.

A Gateway bot can be deployed to a device as part of a service. The service then holds the bot’s Gateway connection: it connects out to Discord and opens no port, so the device needs no public address. The interactions webhook stays on the hub; a device answers messages only.

Deploys strip the bot token from the event. The deploy wizard asks for it in its Settings step, or offers the token saved on the event, and keeps it as a secret of the service on the device. A run never receives the token: local_session.bot_token carries a handle of the form device-bot:<event id>, which the Discord nodes of the same service turn back into the token. Every flow of that service can therefore act as the bot; none can read the token.

A device applies these rules:

  • One place. For an online app, only someone who can edit the app’s events can move a bot to a device; the deploy does it for them. A second device or service is refused. While a device holds the bot, the hub’s interactions endpoint answers with a short notice and starts no run. A bot that this computer’s desktop app runs has to be stopped there before it can be deployed; the wizard does it in one click. Discord accepts several connections with one token and reports none of them: when the same token also runs elsewhere (on another computer, in another service or in another program), every message is answered twice.
  • Which messages start a run. A device considers fewer messages than the desktop app: only a new message of the kind Default or Reply, from an author that is neither a bot nor a webhook, with text or an image. A system message, such as a member joining, or a message without text or an image starts nothing on a device, while the desktop app considers it; neither considers an edit. Such a message must then pass the same rules as on the desktop, listed under Gateway setup. The allow list (channel_whitelist) must be empty or contain the channel, and the deny list (channel_blacklist) must not contain it. A direct message needs respond_to_dms, and the device adds the DirectMessages intent for it. In a server channel the table there applies: with a prefix the bot answers messages that begin with it, and with respond_to_mentions on also mentions and replies; with no prefix it answers every message, or only mentions and replies when respond_to_mentions is on. When two events of a service use the same bot, a message starts one run: of the first event in the service’s list whose rules it passes.
  • What the flow receives. The Chat payload of the desktop adapter. local_session holds the handle, bot_user_id, guild_id, channel_id, message_id and user. messages holds up to 10 earlier messages of the channel, read once per message, and then the message itself, each as {name}[id: {id}]: {text} with images as Discord CDN links. attachments holds links to the message’s other files.
  • Limits. One run per channel at a time with four messages waiting, eight runs at once per service, ten runs a minute per channel and sixty per bot. A message over a limit is not answered, and its channel gets one notice a minute. A run is stopped after 30 minutes. A run that asks a question is cancelled, because nobody can answer it there.
  • Answers. The answer streams into one reply that is edited as the flow writes, split into messages of at most 2,000 characters. Files of the answer are sent as links. An answer can mention people, but never pings @everyone, @here or a role.
  • Restarts and updates. Discord does not keep messages for a bot that is offline, so messages sent while the service stops, restarts or updates are not answered. A run that a stop cuts off is not started again, and messages still waiting behind it are not answered; their channels get one notice to send the message again.
  • Connection problems. A refused token or refused intents leave the service running and stop the bot until the service restarts, and the service’s status names the fix. Discord refuses the default intents until Message Content Intent is enabled for the bot in the Developer Portal. When the connection ends for another reason, the device starts it again after a pause that grows from 5 seconds to 5 minutes, at most 20 times an hour: Discord allows 1,000 session starts a day per token and resets the token of a bot that uses more.
  • Settings. The lists hold at most 256 channel IDs, the prefix at most 16 characters, and intents only the known intent names; a deploy refuses anything else. A missing, null or empty command_prefix means no prefix. The device runs the event version it was deployed with, so edits in Events take effect with the next update of the service.

Anyone who can message a bot with an empty allow list can start runs. Every run counts towards the service’s usage, and hosted models spend from its spending limit. Runs carry no personal access token and no signed-in provider tokens (an online service’s runs use its cloud access), so a flow that needs a signed-in provider works on the desktop and fails on a device. The token stays on the device when its cloud access ends: to cut a device off for certain, reset the token in the Developer Portal.

SymptomCheck
Discord rejects the endpoint URLEvent is active, URL is publicly reachable, public key is correct
Gateway connects but sees no contentMessageContent is selected and enabled in the Developer Portal
Guild messages are ignoredThe channel lists, then the row of the table under Gateway setup that matches command_prefix and respond_to_mentions. A prefix needs the MessageContent intent: without it Discord sends no text for messages that do not mention the bot
DMs are ignoredrespond_to_dms, and on the desktop the DirectMessages intent
Webhook returns 401Signature headers, request body integrity, and application public key
A device reports that Discord refused the bot’s permissionsEnable Message Content Intent (and any other privileged intent the event selects) in the Developer Portal, then restart the service
A device reports that Discord refused the tokenEnter a new token in the service’s configuration
Every message is answered twiceThe same token runs in a second place, such as another computer’s desktop app