Webhook Debugging Guide

Test Stripe webhooks locally without ngrok

Short answer

Use the Stripe CLI. It's built for exactly this and doesn't need a tunnel:

stripe login
stripe listen --forward-to localhost:3000/webhook

This authenticates the CLI to your Stripe account, opens a connection to Stripe's API, and forwards any event your account generates (or one you trigger with stripe trigger) to your local server. There is no public URL involved: the CLI's connection is outbound. It prints its own signing secret starting with whsec_, which is different from the secret of any endpoint in your Stripe dashboard — put the CLI's one in your local environment variables while you test this way.

Trigger a test event

With stripe listen running in one terminal, fire a specific event type from another:

stripe trigger payment_intent.succeeded

The CLI logs each forwarded event and your server's response code, which is often enough to confirm your handler runs at all before checking the signature logic.

Where it stops being enough

The easier way: WebhookMon

WebhookMon gives each endpoint a URL that doesn't change between runs, queues events for up to 24 hours while your Mac is asleep or your server is down, and works the same way for Stripe, Polar, GitHub, Shopify and Slack. Every event gets a plain-English signature verdict, and replay can re-sign with the current timestamp using the secret you configured.

An endpoint's settings in WebhookMon: the local target http://localhost:3000/webhooks with Forward live events on, and signing secrets for each provider
Download WebhookMon free trial Learn more

Related guides