Dispatch runs every webhook through one pipeline: ingest, verify, filter, format, deliver. No special cases, no silent drops. This page walks the path.
at-least-once delivery · up to 7 attempts over 6h backoff · every attempt logged
Every event starts as a plain HTTP POST to your endpoint. No SDK, no agent: if a service can send a webhook, Dispatch can receive it.
The payload and headers are captured exactly as the provider sent them. The event type is read from the provider's header, like X-GitHub-Event or X-Event-Key, or from a path you configure on the endpoint.
X-GitHub-Event: push
X-Hub-Signature-256: sha256=4f1a9c…
Content-Type: application/json
{
"ref": "refs/heads/main",
"commits": [{ "message": "fix: rate limiting" }],
"sender": { "login": "alice" }
}
Before an event is trusted, its signature is checked against the provider's own scheme. GitHub signs with HMAC-SHA256, Slack adds a timestamp to defeat replays, Stripe uses signing secrets, Jira sends a signed JWT.
Events that fail verification are rejected before they enter the pipeline. Forged or tampered payloads never reach a destination.
Not every event deserves a delivery. Before fan-out, each event is checked against your filter conditions: match on any header, any field in the body, or the event type.
Conditions combine with AND or OR, and groups of conditions handle the more complex cases. Events that don't match aren't dropped; they're stored as filtered, searchable and replayable like everything else.
header.X-GitHub-Event eq "push"
body.ref contains "main"
body.deleted neq true
Raw provider JSON is unreadable in a chat channel. Templates turn the payload into the right shape per platform: Discord embeds, Slack Block Kit, Telegram HTML.
Templates use Go text/template syntax with the full payload in scope. Before formatting, an optional JSONata transform can reshape the payload; if a transform errors, the original payload is used. No template at all? The event ships as a clean JSON embed.
Template
{{ .sender.login }} pushed {{ len .commits }} commit(s) to {{ .repository.name }}
alice pushed 1 commit(s) to acme-api
fix: rate limiting
Delivery is where webhooks usually get flaky: rate limits, timeouts, transient 5xx. Dispatch retries with exponential backoff, up to 7 attempts over 6 hours, independently per destination.
Every attempt is logged with its status code and latency. Discord and Slack rate limits are respected automatically, and any event can be replayed with one click. At-least-once delivery, not best-effort.
Create an endpoint, point a provider at it, and watch the deliveries land. Free plan, no credit card required.