Connect your bot
In the Discord Developer Portal:- Create an application and choose its name in Discord. Copy the Application ID and Public Key from General Information.
- Under Bot, copy the bot token, or use Reset Token to create one.
- Enable Bot → Privileged Gateway Intents → Message Content Intent before connecting. This is required to read replies that do not mention the bot.
- Under Installation, enable Guild Install.
Dashboard
Choose Discord bot on your project’s Integrations page. Keep the suggested Omnara namediscord-bot or enter your own, such as support. Enter the Application
ID, public key and bot token, then choose Create and connect. Omnara saves the
credential for you and retrieves the bot User ID and display name from the token.
After connecting, save the displayed Interactions Endpoint URL under
General Information in Discord. Add bot to server opens Discord with the
permissions above already selected. Choose a server you manage, then select
Profiles for mentions in Omnara and select Save changes.
The dashboard requires the public key. It verifies interaction callbacks for
profile menus, questions and approvals; it is different from the bot token used
to read and send messages.
Discord controls who can install the bot and access its conversations. Public bots
are supported: people in accessible conversations can launch the offered profiles
and answer agent questions and approvals without Omnara project membership, subject
to the agent’s configured permissions. For internal use, turn off Public Bot
under Bot in the Developer Portal when available, and restrict server/channel
access in Discord. This setting limits new installations; review existing servers
separately. See Discord’s bot authorization guidance.
API
Create the integration withPOST /orgs/{orgID}/projects/{projectID}/integrations:
material: {"kind":"generic","value":"your-bot-token"}. Configure the
saved integration through POST /orgs/{orgID}/projects/{projectID}/integrations/{integrationID}/setup:
setup_revision. provider_tenant_id is the Application
ID; neither it nor the bot User ID is the guild ID. Setup discovers and saves the
bot User ID as provider_account_ref. If supplied explicitly, it must match the
token. Reconnecting cannot change the saved application or bot. Omnara manages one Gateway connection
per integration. This supports bots in fewer than
2,500 servers; larger bots
require sharding, which is not currently supported. Omit provider_config during
token rotation to keep the current settings. Supplying it replaces the settings, so include every field you intend to retain.
The API permits omitting the public key for messaging with a single launch profile.
Profile menus and Discord questions or approvals require it and a verified
Interactions Endpoint URL. Install the
bot through Discord with the permissions listed above.
Each saved integration has an independent runtime. Integrations can use the same bot credentials,
including in different projects, but duplicated sessions consume provider capacity.
Overlapping launch behavior can create duplicate responses. Omnara does not merge
these independently configured integrations.
Unrelated messages without role mentions or a mention of this bot use inbox capacity but make no
Discord REST requests. Omnara checks exact thread subscriptions and pending launches
before looking up the channel. Role mentions require a guild-role lookup unless the
bot user is also mentioned. Bot mentions require a channel lookup and share
the bot’s REST quota with replies.
Identity checks and attachment downloads happen only after routing finds a recipient.
Launch from mentions
Choose Profiles for mentions in the integration’s settings. Mentions work in every server where this bot is installed and permitted; manage server and channel access in Discord. All of those servers use this Omnara project’s profile choices. Mention either the bot user or its own Discord-managed role. Omnara verifies role ownership with Discord; matching names, other assigned roles and@everyone do not
trigger a launch. Mentioning both the user and its role is one request.
When starting an agent inside an existing thread or forum post, wait for the bot’s
response before sending follow-ups. Messages sent while Omnara is identifying that
thread can be missed, including while Discord lookups are retrying. Once the agent
has been attached to the thread, this limitation no longer applies.
For the API, put launcher inside settings and send it to
PUT /orgs/{orgID}/projects/{projectID}/integrations/{integrationID}:
settings; send {"settings":{}} to remove
the mention launcher.
A mention in a parent channel creates or reuses the public thread attached to that message. A
mention already inside a thread uses that thread. One offered profile starts
immediately; several profiles produce a menu and start only the selected profile.
Anyone in the conversation can choose. The menu expires after an hour; send
follow-ups after selecting, because earlier replies may be missed.
The launcher derives the agent’s tools and interaction handler for the thread,
preserving existing explicit entries in the profile config, and attaches a thread
subscription. Human messages
steer the agent and cancel open interactions. Bot and webhook messages are ignored.
The bot adds an eyes reaction after a message is accepted for an agent. Enable
Add Reactions on the bot’s role if you installed it before this permission was
included in setup. A failed reaction does not prevent the agent from receiving the message.
Change Profiles for mentions directly on the integration page and select Save changes
to update future launches; existing agents keep their configs.
Selecting profiles enables mention launches without a separate enable switch.
An empty selection leaves schedules and existing conversations available. With
no matching subscription or launcher, messages receive no response.
Scheduled threads
Choose a server text or announcement channel. The opening-message template is limited to 2,000 characters. Use Add schedule on the integration page to post a template opening message and launch one profile in its new thread. Each schedule selects its own profile and destination channel, independently of mention settings. The tools, reply subscription and interaction handler are ready when the agent starts. Schedules can coexist with mention launches. See scheduled integration launches for setup, template variables and recovery behavior.Thread tools and subscriptions
A mention or scheduled launch suppliesread and post_message for its assigned
thread. read supports before and limit; post_message takes content and an
optional paths array of up to 10 files. Use exact /artifacts/<artifact_id> or
/memory/<store>/<file> paths; directories and globs are not supported. For example,
{"content":"Update","paths":["/memory/reports/weekly.pdf"]} posts the message and
file directly to that thread. Omit paths for a text-only message. The model supplies
neither channel nor thread IDs. Adding these tools to an agent without an assigned
conversation is insufficient; calls fail before contacting Discord.
post_message returns the message’s actual channel_id (the thread ID when
posting in a thread), along with message_id and thread_id.
The launcher subscribes the agent to replies. Posting does not change that
subscription. To independently forward messages to an existing agent, send this
body to the integration subscriptions API.
This does not assign or change the conversation used by the integration’s tools.
thread_id; guild_id and the parent channel_id
are optional. Supplied IDs are checked for valid format, but subscription creation
does not verify them against Discord or retain them as routing restrictions.
Create/list responses return only thread_id for a thread. For a channel
subscription, supply channel_id and omit thread_id.
Channel subscriptions receive mentioned thread starters, not ordinary replies in
their threads. Removing the sending tool or changing
config does not remove subscriptions. Use Stop forwarding on the integration page or
DELETE the subscription to remove it, including while the integration is disconnected.
Questions, approvals and profile menus
Configure the integration’s public key, then set the Discord registration’s Interactions Endpoint URL to:itg_… ID. One public
endpoint can verify callbacks for independently configured integrations. Each menu or
agent interaction captures its owning integration, so its answer is routed only there.
Require successful signed PING verification
before offering profile menus or external approvals.
For an agent assigned to the support integration’s thread, select
interaction_handlers: {support: {}} in its config to expose the handler.
For manual configs, also select list_interaction_handlers and
set_interaction_handler under tools to let the model choose a destination.
The Discord launcher adds the handler and both tools automatically, preserving explicit settings.
The handler uses the thread assigned when the integration launches the agent.
Select it with {"handler":"support","args":{}}; the model does not supply
channel, thread or server IDs. The list tool shows the assigned destination. Adding
a handler to a manual config does not create an assignment. With automatic selection
enabled, the last eligible content input admitted into a new turn selects its handler.
Inputs from the dashboard, API, or an integration without an eligible handler select
dashboard-only delivery. Ordinary scheduled instructions and internal agent
messages/reports without an integration origin preserve the selection. An explicit
integration origin takes precedence, including a scheduled launch in a new thread.
Waiting inputs do not change the current turn. Set auto_select: false with
set_interaction_handler to pin a choice, or true to resume automatic selection;
omission preserves the mode. The list tool reports the mode. Questions remain
answerable in the dashboard if Discord
presentation fails. There is no Gateway fallback for interaction answers or
automatic slash-command registration.
Discord interaction notifications run independently of the waiting agent. Delivery is
best effort: overload can delay or drop notifications, and restarts can interrupt sending.
Omnara retries only safe failures, with a bounded retry budget. If delivery may
have succeeded, it does not automatically post another copy; a crash during
sending can leave a prompt missing or unconfirmed. The interaction remains
answerable in the dashboard and API regardless of delivery.
Restarts and deployments
An integration can retain its verified credentials while its Gateway connection is failing. The integration detail page shows the latest connection error and earliest retry time for the current setup and credential version. Refresh status rereads the recorded failure; it does not start a retry. The failure remains until a new attempt starts. After correcting the Discord settings, use Reconnect account to make the integration eligible for a new attempt without waiting for the old retry time. A missing error does not prove the Gateway is connected. The list and setup responses do not include this runtime status; API clients read the optionalruntime_failure from Get integration.
A worker saves its Discord session and last committed event sequence in Postgres.
The event receipt and sequence are saved together. When another worker takes over,
it resumes that session and Discord can replay missed events; repeated message
receipts are deduplicated. A database lease prevents two workers from committing
for the same saved integration. Normal shutdown releases that lease; after a
crash, a replacement waits for it to expire, normally within 30 seconds.
Keep replacement workers healthy during routine deployments, and allow the old
workers to shut down gracefully. Postgres and Redis must remain available. Discord
retains replay history for a limited time: a long outage or an invalidated session
can still leave a gap. The worker records that it must start a fresh session;
restarting is not a guarantee that Discord retains every missed message.
HTTP interactions use the API service separately. Keep a healthy API instance
receiving requests while another drains.
Before a production rollout, use a dedicated test guild to check a mention,
a plain reply in the resulting thread, and another reply after restarting the
test worker. Confirm that they reach the same agent without duplicate inputs.
Also verify a signed interaction callback if using approvals or profile menus.
The automated suite uses local provider fixtures; it does not replace this live
check of the bot’s intents and guild permissions.