Docs

Webhooks

Inbound channel webhooks (Telegram, Discord, Slack) and billing webhooks (Stripe, LemonSqueezy, Polar). HMAC verification.

Webhooks

Hangar receives webhooks for inbound channel events and billing provider events. Every webhook is HMAC-verified at the edge before reaching the handler.

Channel webhooks

Channel URL Verification
Telegram /api/webhooks/telegram Telegram X-Telegram-Bot-Api-Secret-Token matches TELEGRAM_WEBHOOK_SECRET_TOKEN.
Discord /api/webhooks/discord Ed25519 signature using DISCORD_PUBLIC_KEY (per Discord interaction spec).
Slack /api/webhooks/slack Slack v0 signature using SLACK_SIGNING_SECRET.

If verification fails, we return 401 and emit an audit-log entry. Replays older than 5 minutes are rejected even with a valid signature.

Billing webhooks

Provider URL
Stripe /api/webhooks/stripe
LemonSqueezy /api/webhooks/lemonsqueezy
Polar /api/webhooks/polar

Each provider uses its native signing scheme. Secrets come from STRIPE_WEBHOOK_SECRET, LEMONSQUEEZY_WEBHOOK_SECRET, and POLAR_WEBHOOK_SECRET respectively.

Outbound webhooks

Hangar does not currently send outbound webhooks to your origin. State is exposed via:

  • The MCP server (/api/mcp) for read + control.
  • The realtime SSE stream (/api/realtime) for live activity.
  • The audit log table for retroactive queries.

If you need outbound delivery (e.g. an SQS-shaped fan-out), open a discussion and describe the use case.

Inbound rules

  • Inbound webhooks return 200 even when the message is dropped (e.g. filtered by persona); we use the JSON body to encode the action so the channel does not retry.
  • We accept Content-Type: application/json and the channel-native form encodings (Slack URL-encoded, etc.).
  • Bodies are size-limited to 1 MB; larger payloads return 413.
Webhooks — Hangar