Skip to main content

Discord Interactions

Base path: /discord

POST /discord/interactions

Receive and process Discord interaction webhooks (slash commands, ping challenges).

Auth: Ed25519 signature verification via the DISCORD_INTERACTIONS_PUBLIC_KEY environment variable. If no public key is configured, signature verification is skipped. Tenant: Resolved automatically from the interaction's guild_id or the Discord user's registered tenant.

Headers

HeaderTypeRequiredDescription
x-signature-ed25519stringYes*Discord request signature (*required when public key is configured)
x-signature-timestampstringYes*Discord request timestamp (*required when public key is configured)

Request Body

Discord interaction payload (JSON). The endpoint validates the body against the following schema:

FieldTypeRequiredDescription
idstringNoInteraction ID
typenumberYesInteraction type (1 = Ping, 2 = Application Command, 3 = Message Component, 5 = Modal Submit)
guild_idstringNoDiscord guild/server ID
channel_idstringNoChannel where the command was invoked (required for /notify channel target)
memberobjectNoGuild member object containing user.id and roles
userobjectNoDM user object containing id
dataobjectNoCommand data: name and options (type 2), custom_id and values (type 3), custom_id and components (type 5)

Behavior

Ping Challenge (type 1)

Returns a ping acknowledgement so Discord can verify the endpoint.

{ "type": 1 }

Application Command (type 2)

  1. Deduplication: Acquires a cache lock on discord:interaction:lock:{id} (60 s TTL). If the lock is already held, responds with an ephemeral "already being processed" message.
  2. Tenant resolution: Resolves the tenant from the guild or the Discord user's registration. If unresolved, responds with an ephemeral message prompting the user to run /register in a server.
  3. User registration: Registers the Discord user for the resolved tenant if a guild_id is present.
  4. Webhook event logging: Persists the interaction to the WebhookEvent collection. Duplicate eventId values are silently ignored with an ephemeral acknowledgement.
  5. Command routing: Dispatches to the unified command router. Type 2 (slash commands) uses execute; type 3 (buttons/selects) uses executeComponent; type 5 (modal submit) uses executeModal. Results may be ephemeral messages (content, embeds, components) or a modal (type 9). The /notify command requires DISCORD_BOT_TOKEN for DM/channel delivery.

Response (200)

Responses use Discord's interaction response format. Type 4 = channel message (content, embeds, components); type 9 = modal.

Message response (type 4):

{
"type": 4,
"data": {
"content": "Command result message",
"embeds": [],
"components": [],
"flags": 64
}
}

flags: 64 means ephemeral (visible only to the invoking user).

BTC_NOWPAYMENTS order submit response (embed):

When a customer submits an order with BTC_NOWPAYMENTS as the payment method and the NOWPAYMENTS_API_KEY is configured, the bot posts an ephemeral embed (type 4, flags 64) containing a NOWPayments invoice. The embed includes:

  • BTC deposit address (code-block formatted)
  • Expected BTC amount
  • Invoice expiry time in minutes
  • A LINK button (Discord style 5) pointing to the hosted NOWPayments invoice page

Errors

StatusCondition
400Validation error or command execution failure
401Invalid Discord signature