What it is
A drop-in module that handles both sides of webhook communication inside a SpacetimeDB module: verifying and deduplicating signed requests arriving from external services (GitHub, Twitch, Stripe, Discord, and others), and sending your own signed, retried webhook calls to external endpoints from a transactional outbox.
Where it fits
- Live stream tooling: A Twitch EventSub integration where follower, subscription, or channel-point events need to land directly in your module's tables without a separate relay service.
- Payment processing: A Stripe-connected game economy where purchase confirmations must be verified, deduplicated, and applied atomically alongside the in-game state change they trigger.
- CI/CD triggers: A game server or content pipeline that reacts to GitHub push events to update configuration or asset metadata stored in SpacetimeDB.
- Outbound notifications: Any module that needs to notify billing systems, analytics pipelines, or partner services whenever a reducer commits a significant state change, with retries and dead-letter handling built in.
- Multi-platform bots: A Discord-integrated application where slash commands and message interactions must be verified and answered within the same transaction that updates your module's state.
How it works
Incoming webhook requests arrive at a dedicated HTTP route inside your module. Before anything is written to your tables, the module checks the request's signature against the secret for that source, verifies the timestamp falls within an acceptable window to block replays, and handles any handshake challenges (such as those required by Twitch or Discord). Only if all of those checks pass does the module open a transaction.
Inside that transaction, the module records a delivery identifier so the same event can never be applied twice, then calls your handler with the parsed event. If your handler signals an error, the entire transaction rolls back, nothing is recorded, and the sender receives a failure response so it will retry. This means your business logic and the deduplication record either both succeed or both disappear together.
For outbound calls, events are queued inside the same transaction as the change that produced them, so an event can only exist if its originating change actually committed. Delivery happens shortly after the transaction closes, with automatic retries on a backoff schedule, per-endpoint event filters, and a dead-letter store for events that exhaust all retries. Outbound messages are signed in a way that any compatible receiver library can verify, and the stable message identifier lets downstream services deduplicate retries on their end.


