Tutorial

How to Monitor Stripe Webhooks and Payment Flow Uptime

11 min read

TL;DR: The simplest way to monitor Stripe webhooks is a 3-step multi-step API monitor that triggers a synthetic event in Stripe test mode, verifies your endpoint received and signature-validated it, then reads back the resulting side effect. Velprove runs that chain free from 5 regions on every plan, with commercial use allowed and no credit card. Start for free.

You shipped Stripe months ago. Webhooks are working. Probably. The problem is that you have no idea, in this exact minute, whether your prod endpoint is still accepting a signed event, validating the signature, deduping it, and writing the right row to your database. Stripe will not tell you. Your dashboard will not tell you. The first signal that something broke is usually a customer in support asking why their subscription says canceled when they paid yesterday. This walks through how to prove the whole pipeline works, on a schedule, with a free 3-step monitor and zero real charges.

Webhook monitoring is not the same thing as Stripe API monitoring. An API monitor tests whether Stripe responds to you. A webhook monitor tests whether Stripe successfully reaches you and your handler does the right thing with what arrives. The 3-step chain covers both signature verification and the actual business-logic side effect, and the rest of this post is the how.

Why webhook monitoring is different from API health checks

It is tempting to think that if your Stripe API monitor is green, your Stripe integration is healthy. It is not. The two monitors catch opposite failures, and you need both.

A Stripe API monitor probes outbound. You call GET /v1/balance, you assert on the JSON response, and you know Stripe is responding to you. That is the pattern we cover in monitoring the Stripe API itself. It is necessary. It is not sufficient.

A webhook monitor probes inbound. Stripe calls your endpoint, your endpoint validates the signature, your handler dedupes by event id, and your application writes the side effect. None of that is visible from the outside. If Stripe is down, you receive zero webhooks, which from your end looks identical to a quiet Tuesday. If your handler is silently broken, Stripe is fine, the API monitor is fine, and subscriptions silently fail to provision. Two opposite blind spots, both expensive, neither caught by the other monitor.

The cleanest framing: API monitors prove the road exists. Webhook monitors prove the truck arrived, you signed for it, and you put the package on the right shelf.

CoverageStripe API monitorStripe webhook monitorWorkbench inspector
Direction probedOutbound (you to Stripe)Inbound (Stripe to you)Inbound, after the fact
Catches signature failuresNoYesIndirectly (4xx response)
Catches handler logic bugsNoYes (read-back step)No
Catches regional edge dropsNoYes (multi-region)Partially
Alerts proactivelyYesYesNo (manual review)

The five most common Stripe webhook failure modes

Stripe webhooks have five common failure modes in production: endpoint timeouts, signature verification breaks, idempotency bugs, URL drift after redeploys, and regional reachability gaps. Name them first, then build a monitor that catches all five. They are ordered roughly by how often they fire.

  • Endpoint timeout or slow handler. Stripe requires your endpoint to respond quickly enough to avoid a Timed out failure mode (Stripe support article on Timed out webhooks, verified 2026-04-26). When your handler does heavy work synchronously before responding, Stripe marks the delivery failed and enters the retry loop. The fix is to acknowledge with a 2xx immediately and queue the real work. Your monitor needs to catch the case where you forgot to do that.
  • Signature verification failure. Three sub-modes here, all from Stripe's webhook signing docs (verified 2026-04-26). First, the signing secret was rotated and your env var still has the old value. Stripe's rotation flow lets you keep both secrets active for up to 24 hours so you can deploy without dropping events, but if you miss the window you fail open. Second, your host clock has drifted more than 5 minutes off NTP, and Stripe's default tolerance rejects valid signatures. Third, a body parser somewhere in your stack mutates the raw request body before the verification step runs, and HMAC-SHA256 over a different byte sequence will never match.
  • Idempotency mishandling. Stripe explicitly delivers events at least once, so your handler will eventually receive the same checkout.session.completedtwice. If your code provisions a license, sends a welcome email, or credits an account without checking the event id, you double everything. Stripe's recommended fix is a uniqueness constraint on processed event ids (webhook best practices, verified 2026-04-26). Your monitor needs to assert that the side effect was applied exactly once.
  • Webhook URL drift after redeploys. Operational gotcha, not a Stripe-doc-named failure. You moved from api.example.com to payments.example.com last quarter. Most callers were updated. The Stripe dashboard endpoint URL was not. Now Stripe is dutifully retrying against a 404 for three days before giving up. The Workbench delivery inspector will show this clearly, but only if someone actually looks. Your monitor catches it because the verification step will never see the event arrive.
  • Regional reachability gap. Stripe's side works. Your endpoint works. But your CDN, WAF, or origin firewall drops Stripe traffic in one region only. A NA-only probe never sees this. We expand the multi-region angle in a later section.

Each of these has the same shape from your monitor's point of view. The synthetic event was triggered, but somewhere between Stripe and your database, the chain broke. The monitor needs to watch the whole chain, not just one link.

The 3-step multi-step API monitor that catches all of them

This is the wedge. Almost no monitoring tutorial in the search results actually shows a chained synthetic check across the full webhook pipeline. Here is the smallest version that catches every failure mode above. All three steps run on Velprove's free plan, which caps multi-step monitors at 3 steps, runs every 5 minutes, and is allowed for commercial use.

Pick Multi-Step in the Velprove monitor wizard to start a chained API check.
Velprove new-monitor wizard step 1, Choose Monitor Type, with four options visible: Browser Login, HTTP, API, and Multi-Step. Multi-Step is selected.

Setup safety note before the steps. All of this runs against Stripe test mode with a restricted test-mode key, signed with your test-mode signing secret, and routed to a dedicated monitoring webhook URL that only accepts test-mode payloads. Never wire this through real admin credentials. Never point the synthetic check at your live endpoint. Use a low-privilege test account on your side and assert livemode: false on the inbound event so a misconfigured monitor cannot silently push live-mode side effects through.

Step 1. Trigger a synthetic event in Stripe test mode

Step 1 sends a small POST to your own internal helper endpoint, for example POST /internal/stripe-monitor/trigger, which uses the Stripe test-mode SDK to create a tiny test object that fires a real test-mode webhook. A clean choice is creating a test customer, which fires customer.created, costs nothing, and produces a deterministic data.object.id you can pass downstream.

Why route through your own helper instead of calling Stripe directly? Because the helper holds the test-mode key in your server env, signs the request, returns a clean { event_id, customer_id }JSON shape your monitor can assert on, and never exposes a Stripe key to the monitoring path. Velprove's API monitor extracts both ids from the response body and passes them to step 2.

Assertion: response status equals 200, JSON path $.event_id is present and starts with evt_, JSON path $.customer_id is present and starts with cus_. If step 1 fails, you know the problem is your trigger helper, not Stripe and not your webhook handler.

Step 2. Verify your endpoint received and processed the event

Step 2 is a GET to a small read-only verification endpoint on your own server, for example GET /internal/stripe-monitor/receipts/{event_id}, with the event id captured in step 1. The endpoint looks up the event id in whatever table or log you write to from your real webhook handler, and returns 200 with a small payload describing what happened.

A useful response shape:

{
  "event_id": "evt_test_xxx",
  "received_at": "2026-04-26T13:37:00Z",
  "signature_valid": true,
  "deduped": false,
  "side_effect_applied": true
}

Your monitor asserts $.signature_valid equals true and $.side_effect_applied equals true. If signature validation failed, you catch a secret-rotation regression, a clock-skew regression, or a body-parser regression in one assertion. If deduped is true on the first delivery, your dedup logic is wrong. For the general pattern of validating REST responses with JSON path, see our guide on JSON path assertions for REST endpoint validation.

Important detail. The verification endpoint is read-only, takes no destructive action, and only reflects state your real webhook handler already wrote. Treat it like a status probe, not a control plane. Authentication is a single shared monitoring token in a header. If the token is leaked, the worst it does is reveal that a specific event id was processed.

Step 3. Read back the side effect

Step 3 is the one most monitors skip. A signed event landed and your handler ran. That does not prove the right database row got updated. Step 3 reads back the actual business-logic outcome.

For a SaaS subscription flow, that is something like GET /internal/users/{customer_id}/subscription which returns the current local subscription state for the test customer. Assert $.status equals active and $.stripe_customer_id equals the customer id from step 1. For a one-time purchase flow, read back the order record and assert it is marked paid. The point is that step 3 only passes when the webhook actually moved real state in your system, not just when it was acknowledged.

All three steps configured: POST to trigger a test-mode event, GET to verify receipt and signature, GET to read back the subscription side effect.
Velprove multi-step monitor configuration form with three steps: trigger synthetic Stripe event, verify webhook receipt, and read back subscription state

Three assertions, one chain, every link in the webhook pipeline covered. This is the same shape as the chained pattern in our full multi-step API monitoring guide, adapted to the inbound webhook direction instead of the outbound request direction.

Multi-region webhook reachability, the angle nobody covers

Webhooks fail in one region all the time, and the people running the integration almost never know. The reason is that webhooks arrive at your edge, not Stripe's edge. Your CDN, your WAF, your origin firewall, and your DNS resolver are all in the path, and any of them can drop traffic from one geography while letting it through everywhere else.

A real failure pattern we have seen in the wild: a Cloudflare WAF rule that deny-listed an entire IP range out of caution after a previous incident, scoped only to EU edge nodes. NA-region synthetic checks stayed green for months. EU customers silently stopped getting subscription provisioned. The team only caught it when a single user in Berlin emailed support.

Five regions and a five-minute interval on the free plan. Email alerts are locked-in; paid channels are grayed out.
Velprove schedule and alerts step on the free plan, showing five region options (North America selected, Europe, United Kingdom, Asia, Oceania), a 5-minute monitor interval, and Email locked-in as the alert channel with Slack, Discord, Teams, Webhook, and PagerDuty grayed out

A NA-only probe will never catch that class of failure. The fix is to run the same synthetic chain from multiple regions and watch which region's run fails. Velprove runs every monitor from 5 regions on every plan, free included. When step 2 returns signature_valid false in one region only while the other four pass, you know exactly where in the world your edge is dropping Stripe traffic before any human customer notices.

Setting up alerts for failed deliveries

Two-track alerting is the right shape here. Run both. They catch different things.

  • Track A. Velprove alert on the multi-step monitor. The free plan emails you when the chain fails. Starter unlocks Slack, Discord, Teams, and outbound webhooks. Pro adds PagerDuty. This is the proactive channel. It fires within minutes of any link breaking, even if Stripe never noticed anything was wrong on their side.
  • Track B. Stripe-native delivery health. In Stripe Workbench (previously Developers > Webhooks), open your endpoint and inspect the Event deliveries tab. Stripe shows per-event status, the HTTP code from each attempt, and when the next retry is scheduled (Stripe webhooks docs, verified 2026-04-26). This is the reactive channel. It tells you what Stripe saw when it tried to deliver, which is the authoritative view from the sender side.
Starter plan unlocks Slack, Discord, Teams, and Webhook. PagerDuty stays locked.
Velprove schedule and alerts step on the Starter plan, with Email always-on plus Slack, Discord, Teams, and Webhook unlocked as selectable alert channels and PagerDuty still locked
Pro plan adds PagerDuty alongside the Starter channels.
Velprove schedule and alerts step on the Pro plan, with all six alert channels selectable: Email, Slack, Discord, Teams, Webhook, and PagerDuty

The mental model: Track A catches the whole pipeline failing before Stripe even notices. Track B catches the case where Stripe knows your endpoint is rejecting deliveries and you need the per-event evidence to debug why. Either alone leaves a gap. Together they close it.

Test mode vs live mode, the safest setup pattern

Every synthetic check in this post runs against Stripe test mode with restricted test-mode keys. Three reasons.

First, the live and sandbox retry windows are different. Stripe retries live events for up to three days with exponential backoff (Stripe webhook best practices, verified 2026-04-26). Sandbox events retry three times over a few hours. You want your monitor running in the faster sandbox loop so failed test deliveries clear out quickly and do not pile up.

Second, the safest credential is the smallest one. Use a Stripe restricted key scoped to the minimum your trigger helper needs. For the customer-created flow above, that is Customers create permission on test-mode resources, nothing else. Same principle we walk through in our companion post on monitoring the Stripe API itself. Restricted keys with surgical scopes mean a leaked monitoring credential cannot mutate live state.

Third, isolate the monitoring path from the production webhook path. Use a dedicated URL like /webhooks/stripe-monitoring separate from your real /webhooks/stripe. The monitoring URL accepts only test-mode signatures and asserts livemode: false on every inbound event. If a misconfiguration ever sends live traffic to the monitoring URL, the assertion rejects it loudly instead of silently writing test logic over real customer state.

Wrap and next step

Webhook monitoring closes the blind spot the Stripe API health check leaves open. The 3-step chain in this post is the smallest monitor that proves the whole pipeline works: trigger a synthetic event, verify it arrived and was signature-validated, read back the side effect. Run it from 5 regions to catch the geography-only failures. Pair it with the Workbench delivery inspector for full coverage from both directions.

Review summary before scheduling: six total assertions across three chained steps.
Velprove review summary for the three-step Stripe webhook monitor, listing each step name with its assertion count

Set up a free Stripe webhook monitor with Velprove. Three steps, five regions, no credit card, commercial use allowed. If you have not already wired up the outbound side, our companion guide on Stripe API health monitoring covers the other half of the picture.

The saved Stripe webhook monitor reporting Up after its first run, scheduled to run every 5 minutes from NA.
Velprove monitors dashboard listing the saved Stripe webhook monitor with an Up status badge, the Multi-Step type badge, NA region, and a 5-minute interval.

Frequently asked questions

How do I monitor my Stripe webhook endpoint for free?

Sign up for a free Velprove account and create a multi-step API monitor with 3 steps. Step 1 triggers a synthetic event in Stripe test mode. Step 2 calls a small read-only endpoint on your own server that confirms the event was received and signature-verified. Step 3 reads back the resource the webhook was supposed to mutate to confirm the side effect happened. The free plan caps multi-step monitors at 3 steps, which is exactly the chain this post describes, and runs from 5 monitoring regions on every plan including free.

How long does Stripe retry a failed webhook delivery?

In live mode, Stripe attempts delivery for up to three days with exponential backoff. In sandbox mode, Stripe retries failed deliveries three times over the course of a few hours. After the live retry window closes, the event drops out of the active retry queue. You can still recover events created in the last 30 days through the List Events API by filtering on delivery_success=false.

What happens when a Stripe webhook times out?

Stripe expects your endpoint to respond quickly enough to avoid a Timed out failure mode. When your handler is too slow, Stripe marks the attempt as Timed out, which counts as a failed delivery and enters the standard retry loop. If every retry across the 3-day live-mode window also times out, the event is permanently dropped from the live retry queue. The fix is to acknowledge with a 2xx response immediately and process the event in a background job. A multi-step monitor like Velprove catches a regression here in minutes instead of days, because step 2 of the chain fails when your endpoint stops returning a timely 2xx.

How does Stripe sign webhook events and how do I verify the signature?

Stripe signs every event with an HMAC-SHA256 signature in a Stripe-Signature header that contains a t= timestamp and a v1= signature. The signature is computed over the timestamp, a literal period, and the raw request body, using your endpoint signing secret. Stripe libraries enforce a default tolerance of 5 minutes between the signed timestamp and the current time. The most common reasons verification fails in production are a hardcoded old secret after rotation, a clock that has drifted more than 5 minutes off NTP, and middleware that mutates the request body before the verification step runs.

Why are my Stripe webhooks failing in only one region?

Webhooks land at your endpoint, which means your CDN, WAF, and origin firewall all sit in the path. A Cloudflare WAF rule, a regional DDoS filter, or a misconfigured edge can drop Stripe traffic in one geography while letting it through everywhere else. Stripe sees this as your endpoint failing. You only catch it by running the same synthetic check from multiple regions and watching which region fails. Velprove runs every monitor from 5 regions on every plan including free.

Can I monitor Stripe webhooks without sending real test charges?

Yes. Run all synthetic monitoring against Stripe test mode using restricted test keys. Trigger test events through Stripe test mode endpoints, sign them with your test-mode signing secret, and route them to a dedicated monitoring webhook URL that only accepts test-mode payloads. Never run synthetic monitoring against live mode and never use a real admin key. Test mode produces a clean signal for your monitor and never charges a card.

What is the difference between monitoring the Stripe API and monitoring Stripe webhooks?

API monitoring tests the outbound direction. You call Stripe and confirm Stripe responded. Webhook monitoring tests the inbound direction. Stripe calls you and you confirm your handler validated the signature, deduped the event, and wrote the side effect. They cover opposite blind spots. If the Stripe API is down you get zero webhooks, which from your inbox looks like a quiet Tuesday. If your webhook handler is silently broken, the Stripe API monitor stays green while subscriptions go un-provisioned. You need both.

Start monitoring for free

Free browser login monitors. Multi-step API chains. No credit card required.

Start for free