Knowledge Base

Webhook debugging guides

Honest command-line answers to the errors Stripe, GitHub, Shopify, Slack and Polar actually show you, and where WebhookMon makes it easier.

Stripe webhook signature verification failed

"No signatures found matching the expected signature for payload" usually means the wrong secret, a body a framework re-parsed before verifying, or a replay older than Stripe's 5-minute tolerance. Here's how to tell which.

Test Stripe webhooks locally without ngrok

stripe listen --forward-to forwards Stripe's test events to your machine over an outbound connection, no tunnel needed. It's Stripe-only, works only while the CLI runs on that machine, and signs with its own whsec_ secret.

GitHub: "We couldn't deliver this payload"

GitHub gives your server a few seconds to answer. Service Unavailable or a timeout means it didn't. Redeliver from the repo's webhook settings, or forward live events locally with gh webhook forward.

Validating Shopify webhook HMAC signatures

X-Shopify-Hmac-Sha256 is a base64 HMAC-SHA256 over the raw request body, keyed with your app's client secret, not its API key. Node and Python code that gets the raw-body part right.

Slack: "Your URL didn't respond with the value of the challenge parameter"

Slack's first request is a url_verification event; echo its challenge field back within 3 seconds, before you do anything else with the request.

Verifying Polar webhooks (Standard Webhooks)

Polar signs webhooks using the Standard Webhooks spec: webhook-id, webhook-timestamp and webhook-signature headers. Newer whsec_ secrets are used as-is; older ones need base64-encoding first.

Webhook timestamp expired when replaying a captured event

Stripe, Slack and Polar sign a timestamp along with the body and reject one more than 5 minutes old, even with the right secret. Replaying a saved event means re-signing it with a current timestamp.