Manage the joelclaw webhook gateway — add providers, debug delivery, register with external services.
Architecture
External Service → hooks.joelclaw.com → narrow Vercel raw-body proxy
→ Flagg Tailscale Funnel :10000 → Worker :3111 → /webhooks/:provider
→ verifySignature() → normalizePayload() → (queue pilot or direct Inngest event) → notify function → gateway
Stable provider URL target:
https://hooks.joelclaw.com/webhooks/<provider>
The ingress is intentionally narrow: it preserves raw bodies/signature headers and only proxies /webhooks/:provider. Provider registrations still using Panda are migration work; do not declare a provider migrated until a real signed delivery succeeds through the stable URL.
ADR-0048: Webhook Gateway for External Service Integration
Gateway skill: Use gateway push/gateway test patterns for delivery checks
Current Providers
Provider
Events
Signature
Legacy/current registration until verified migrated
Current ADR-0217 pilot note: when QUEUE_PILOTS=github, the webhook gateway enqueues normalized github/workflow_run.completed events into the shared Redis queue instead of posting them directly to Inngest. The Restate drainer then forwards the concrete event name github/workflow_run.completed. github/package.published still goes direct.
Secret: generate one, store as github_webhook_secret
Events: push, pull_request, deployment_status, or "Send me everything"
Todoist
Configured at https://hooks.joelclaw.com/webhooks/todoist via Todoist App Console → Webhooks tab.
Uses client_secret as HMAC key (not the "Verification token").
Front
Configured at https://hooks.joelclaw.com/webhooks/front as a Front application webhook.
Initial validation is a signed challenge. Application events use HMAC-SHA256 over timestamp:rawBody; legacy Rules events use HMAC-SHA1 over compact JSON. Keep their secrets separate.
Signature Algorithms by Provider
Provider
Algorithm
Encoding
Header
Secret Source
Todoist
HMAC-SHA256
base64
x-todoist-hmac-sha256
App Console → client_secret
Front application
HMAC-SHA256
base64 over timestamp:rawBody
x-front-signature, x-front-request-timestamp
joelclaw-front-app-secret
Front rules
HMAC-SHA1
base64 over compact JSON
x-front-signature
front_rules_webhook_secret
Vercel
HMAC-SHA1
hex
x-vercel-signature
Webhook creation response
GitHub
HMAC-SHA256
hex (prefixed sha256=)
x-hub-signature-256
Webhook config secret
Stripe
HMAC-SHA256
hex
stripe-signature (structured)
Endpoint signing secret
Gotchas
Caddy drops Funnel POST bodies — Point Tailscale Funnel directly at worker :3111, not through Caddy
joelclaw inngest restart-worker --register after deploy — ensures restart + registration in one step
Vercel webhooks are Pro/Enterprise only — free plans cannot create account-level webhooks
Front has TWO webhook types — application (SHA256, signed challenges) and Rules (SHA1, no challenges). The worker supports both; hooks.joelclaw.com is registered as the application webhook.
agent-secrets v0.5.0+ — raw output is default, don't pass --raw flag
Idempotency keys on all events — safe to receive duplicates from retry-happy providers