Tell Me When Down
How it worksWhat we checkPricing
BlogFree toolsCompareDocs
Log inGet started
All posts
Stripe webhooks you can trust

How to test Stripe webhooks locally (and what it won't prove)

July 18, 2026·5 min read
A workbench under a single lamp in the dark — a webhook tested in isolation before it faces production.

You can't point Stripe at localhost — it's not reachable from the internet. Testing a webhook handler locally means bringing the events to your machine instead, and the Stripe CLI does exactly that. The part worth getting right is what a passing local test does and doesn't prove.

The Stripe CLI, in two commands

The official way needs no tunnels or ngrok. Two commands cover it:

  1. stripe listen --forward-to localhost:PORT/api/webhook logs the CLI into your account and forwards real events straight to your local route. On start, it prints a signing secret (a whsec_ value) — use that as your webhook secret while testing.
  2. stripe trigger checkout.session.completed (or any event name) fires a realistic test event on demand, so you can exercise the handler without making test purchases by hand.
That signing secret from stripe listen is specific to the CLI session— it is not the same secret as your dashboard endpoint. Wire your local env to the CLI secret, your deployed env to the dashboard secret, and never cross them. A mismatch here is the single most common "works locally, 400s in production" cause.

This prompt sets the whole thing up for your framework:

paste into Claude or ChatGPT
Set me up to test my Stripe webhook handler locally with the Stripe CLI. I'm using <FRAMEWORK> and my local server runs on port <PORT>.

Requirements:
- Show me the stripe listen command that forwards events to my local webhook route, and explain that it prints a CLI-specific signing secret (whsec_...) I must use as my webhook secret WHILE testing locally — it's different from my dashboard endpoint's secret.
- Show me how to fire specific test events with stripe trigger (e.g. checkout.session.completed, invoice.paid) so I don't have to make real test purchases.
- Remind me that my handler must still read the RAW body for signature verification even locally, and that local success does not prove production works, because production uses a different signing secret and my real body-parsing middleware.
- Give me a quick checklist to verify before I rely on it in production.

Give me the exact commands and the local env var setup.

Stripe's local testing docs cover the CLI commands and event list.

Why local success can still lie to you

Here's the trap the tutorials skip: a webhook that passes locally can still fail the moment it's deployed. The two environments differ in exactly the ways that break webhooks.

Production uses a different signing secret (your dashboard endpoint's, not the CLI's). It runs behind your real body-parsing middleware, which may mangle the raw body the CLI's forwarding didn't — the classic signature-verification failure. And it's subject to real deploys, timeouts, and cold starts a local run never sees.

So local testing proves your logic is right. It says almost nothing about whether the live endpoint actually works — which is a separate thing you have to confirm after every deploy.

Testing is a moment; production is forever

You test a webhook once and then trust it for months, during which a deploy renames a route, a dependency changes how the body is parsed, or an endpoint gets auto-disabled after three days of failures. None of that shows up in a local test you ran in March.

The counterpart to testing locally is watching the live endpoint continuously. Tell Me When Down does that — so the webhook you verified in development stays verified in production, and you hear about it the day it stops.

Test it once locally. Watch it forever in production.

Join Tell Me When Down free and we'll watch your live Stripe webhook endpoint around the clock. A deploy that breaks the route, a body parser that changed, an endpoint Stripe disabled — you get an email in minutes, not a customer complaint.

Watch my webhookfree · no card required
more on stripe webhooks you can trust
Stripe webhooks failing silently — and how to catch itThe payment succeeds even when the webhook fails, so nothing looks broken until a customer writes in. The real retry-and-disable timeline, the raw-body trap, and how to catch it inside the window.Stripe webhook signature verification failed: the raw-body fix"No signatures found matching the expected signature" almost always means a body parser changed the request bytes before verification ran. Here's what Stripe actually compares, and the raw-body fix for each framework.Stripe webhook duplicate events: stop the double chargeStripe's delivery is at-least-once, so the same event can arrive twice and charge a customer twice. Here's why it happens, and how to make your handler idempotent with the event id so running it twice is safe.Stripe subscription not activating after paymentPaid but still not upgraded? The subscription's status splits it in two: stuck in 'incomplete' means the payment never finalized; active-in-Stripe-but-not-your-app means a webhook never landed. Here's how to tell which.

spot something wrong or out of date? [email protected] — we'll fix it

Tell Me When Down

Uptime and security monitoring for people who'd rather ship than babysit servers. We watch so you can sleep.

product
How it worksWhat we checkPricingDocsBlogFAQ
free toolsWebsite security scanSupabase pause checkRender sleep checkMixed content checkerSecurity headers checkCookie security checkSSL expiry check
comparevs UptimeRobotvs Better Stackvs PingdomFor indie hackers
company
StatusAbout our botSupportPrivacyTerms
© 2026 TellMeWhenDown · tellmewhendown.com