Local Webhook Development
Radarboard’s inbound webhook endpoints live under:/api/webhooks/github/api/webhooks/vercel/api/webhooks/sentry/api/webhooks/betterstack/api/webhooks/linear
localhost directly, so local development requires a public HTTPS URL that tunnels traffic back to your machine.
Radarboard supports two practical workflows:
- Tailscale Funnel
- Cloudflare Tunnel
Before you start
Make sure the dashboard app is running locally. Radarboard’s local web app runs at:webhook_secret::githubwebhook_secret::vercelwebhook_secret::sentry
Option 1: Tailscale Funnel
Tailscale Funnel is the simplest setup if you already use Tailscale.Prerequisites
- Tailscale installed and logged in
- Funnel enabled on your device/account
Start Funnel
Expose the local app port:Verify locally
Open the public URL in the browser first:Notes
- good for one-person local development
- HTTPS is handled for you
- easiest path if you’re already on Tailscale
Option 2: Cloudflare Tunnel
Cloudflare Tunnel is a good choice if you want a stable development hostname.Prerequisites
cloudflaredinstalled- access to a Cloudflare account
- either a managed domain or a quick tunnel setup
Quick Tunnel
For a disposable public URL:Named Tunnel
For a stable hostname:Configuring providers
Each provider should point directly to the integration-specific route.GitHub
- URL:
https://<public-host>/api/webhooks/github - secret: the same value stored as
webhook_secret::github - content type:
application/json
Vercel
- URL:
https://<public-host>/api/webhooks/vercel - secret: the same value stored as
webhook_secret::vercel
Sentry
- URL:
https://<public-host>/api/webhooks/sentry - secret: the same value stored as
webhook_secret::sentry
BetterStack
- URL:
https://<public-host>/api/webhooks/betterstack - token/secret: the same value stored as
webhook_secret::betterstack
Linear
- URL:
https://<public-host>/api/webhooks/linear - secret: the same value stored as
webhook_secret::linear
Security model
No public webhook endpoint is ever “100% secure”, but Radarboard’s model is strong if you follow the intended setup.1. Per-integration signature verification
Each integration owns its own verifier in:2. Narrow routes
Every service gets its own endpoint:- GitHub cannot hit the Vercel verifier path
- Sentry cannot hit the Linear verifier path
3. Shared-secret matching
Radarboard compares provider signatures against the configured secret for that integration. If the signature fails, the route returns401.
4. Replay protection through dedup
Events are deduplicated where source event IDs are available, so repeated deliveries do not create repeated notifications.5. Defense in depth
Recommended operational practices:- rotate webhook secrets when you regenerate a tunnel URL or suspect exposure
- do not reuse the same secret across integrations
- prefer named tunnels for repeat development workflows
- avoid sharing tunnel URLs publicly
- shut the tunnel down when not in use
Recommended workflow
For quick local testing:- use Cloudflare quick tunnel or Tailscale Funnel
- use named Cloudflare Tunnel or stable Tailscale Funnel hostname
- point providers at your deployed Radarboard URL, not a local tunnel
Troubleshooting
Webhook returns 401
Check:
- provider secret matches
webhook_secret::<integration> - provider is sending to the correct integration route
- tunnel URL is still active
No notifications appear
Check:- the integration webhook route returns
200 - source/global notification preferences are enabled
- digest window is not delaying a non-critical event
- custom rules are not filtering the event out
Tunnel works in browser but webhook fails
Check:- provider requires HTTPS (both Funnel and Cloudflare Tunnel provide this)
- webhook path is correct
- body signature is configured correctly for that provider