Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Webhook Events

Webhook Events are the few gateway-style events Discord delivers over HTTP: an app being installed or removed, entitlements being created or changed, and lobby messages. Composure receives them on the same server as Interactions and hands them to an EventHandler.

use composure::{
    app,
    command::{EventCtx, EventHandler, HandlerError, Platform},
    types::{ApplicationAuthorized, ApplicationIntegrationType},
};

/// Welcomes users who install the app to their account
pub struct Events;

impl<S: Platform> EventHandler<S> for Events {
    async fn application_authorized(
        &self,
        ctx: EventCtx<'_, S>,
        event: ApplicationAuthorized,
    ) -> Result<(), HandlerError> {
        if event.integration_type != Some(ApplicationIntegrationType::UserInstall) {
            return Ok(());
        }
        let bot = ctx.bot()?;
        let dm = bot.create_dm(event.user.id).await?.model()?;
        bot.send_message(dm.id, "Thanks for installing! Try `/hello` anywhere.").await?;
        Ok(())
    }
}

/// Say hello
#[composure::command]
fn hello() -> &'static str {
    "Hello!"
}

#[app(handlers(hello), events = Events)]
pub struct Bot;
fn main() {}

Setting it up

  1. Implement EventHandler<S> on a unit struct, overriding the methods for the events you want; the rest ignore their event.
  2. Register it on an App with #[app(.., events = Events)]. At most one App in a tree sets events (a bot has one events URL); the root App forwards to it.
  3. In the Developer Portal, under Webhooks, set the Events URL to https://<your bot>/events and subscribe to the event types.

The Adapter verifies the request signature like an Interaction’s, answers Discord with 204 immediately, and only then runs the handler as Background Work. So handlers can take their time (within the platform’s Background Work limit), but their errors are only logged: Discord does not retry.

Events

MethodEventPayload
application_authorizedThe app was installed to a server or a userApplicationAuthorized
application_deauthorizedA user removed the appApplicationDeauthorized
entitlement_createA user or guild bought a SKUEntitlement
entitlement_updateA subscription renewed or endedEntitlement
entitlement_deleteAn entitlement was refunded or removedEntitlement
lobby_message_createA message was sent in a lobbyLobbyMessage
lobby_message_updateA lobby message was editedLobbyMessage
lobby_message_deleteA lobby message was deletedLobbyMessageDelete
unknownAny other type (game DMs, quests, types added later), or one whose data did not match its modelthe type name and raw JSON

Override handle instead to see every Event before it is routed to a method.

An unknown or malformed event never fails the request: it arrives in unknown, so a bot keeps working when Discord adds event types.

The context

EventCtx carries the Adapter’s state(), the application_id(), the event’s timestamp() (events can arrive late and out of order), and, with a Platform State, bot() for REST. There is no Interaction, so no Interaction client.

With the tracing feature, handlers run inside an event span carrying event_type.