Last updated: March 13, 2026
How to process Stripe subscription webhooks safely and reliably
If you build a subscription app with Stripe, webhooks do a lot of the important work.
Stripe sends webhook events when a subscription changes, renews, or gets canceled. That sounds simple, but real Stripe webhook handling still has sharp edges. You need to verify the Stripe-Signature header, keep the raw request body unchanged, handle retries, ignore duplicates, and avoid depending on event order.
That is where SubTru helps. SubTru gives subscription apps a cleaner way to process Stripe subscription webhooks. We verify the webhook, narrow the event types we listen to, map the subscription to the right user, and turn Stripe's event data into one normalized subscription record your app can use.
Want the broader product docs too? Browse the SubTru documentation to see how Stripe webhook handling fits into the rest of your subscription backend.
What are Stripe subscription webhooks?
Stripe webhooks are HTTPS POST requests that Stripe sends to your server when something important happens in your Stripe account.
For subscriptions, that usually means events like customer.subscription.created, customer.subscription.updated, and customer.subscription.deleted. Stripe's subscription docs recommend using webhooks because a lot of subscription activity happens asynchronously.
What Stripe sends to your webhook endpoint
Stripe sends a JSON payload that includes an Event object. That Event has an event ID, an event type, a creation time, and a data.object value that holds the Stripe resource tied to the event.
Stripe also signs the request and includes a Stripe-Signature header. You should not trust the event just because it reached your endpoint. You should verify that signature first.
Do not trust a Stripe webhook until you verify the signature with the raw request body and your endpoint secret.
How SubTru verifies Stripe webhooks
SubTru verifies Stripe subscription webhooks before they can change subscription access.
- We receive the webhook at a project-scoped Stripe endpoint.
- We read the raw request body.
- We require the
Stripe-Signatureheader. - We verify the signature with the webhook endpoint secret from Stripe.
- We accept only the subscription event types we actually need.
- We deduplicate by Stripe event ID before processing.
- We map the Stripe subscription to your user with subscription metadata.
- We upsert one normalized subscription record for your app.
That matters because a fake event, a broken event, or the same event arriving twice should never create the wrong access decision.
Why the raw request body matters
Stripe is very clear on this point: signature verification needs the raw request body. If your framework changes the body before you verify it, the signature check can fail even when Stripe really sent the event.
That is why SubTru reads the raw body first and verifies the webhook before trusting the payload.
Why SubTru listens to only a small set of Stripe events
Stripe lets you configure webhook endpoints to receive only the event types your integration actually needs.
SubTru follows that pattern. For Stripe subscription state, we focus on customer.subscription.created, customer.subscription.updated, and customer.subscription.deleted. Other Stripe events can be useful for billing workflows, but they do not all need to drive access state in SubTru.
How Stripe webhook retries work
Stripe retries failed live-mode webhook deliveries for up to three days with exponential backoff. In sandbox, Stripe retries three times over a few hours.
That means your system should treat Stripe webhooks as at-least-once delivery. In real life, the same event can arrive more than once.
Why idempotency matters for Stripe webhooks
Stripe says webhook endpoints can sometimes receive the same event more than once. Their docs say to track the event IDs you have already processed and skip them if they show up again.
SubTru uses Stripe event IDs to make normal retry deliveries safe. We also upsert the subscription record itself, so repeated subscription state updates do not create duplicate subscription rows.
Why event order matters with Stripe
Stripe does not guarantee webhook event order. An updated event can arrive before a created event, and invoice events can arrive around the same time as subscription events.
That is why Stripe webhook code should not depend on a perfect event sequence. SubTru narrows the event set, normalizes each subscription event into one current subscription record, and avoids building access logic around webhook order alone.
How SubTru links Stripe subscriptions to your users
For Stripe subscriptions, SubTru uses subscription metadata named subtru_external_user_id.
When your app creates a Stripe subscription, it should include that metadata value. SubTru uses it to link the Stripe subscription to your customer record. If that metadata is missing, the event may be real, but SubTru cannot safely map it to the right user.
Stripe API versioning still matters for webhooks
Stripe webhook endpoints can have their own API version. Stripe also says that if you process webhook events with a statically typed SDK, the webhook endpoint API version should match the version used to generate that SDK.
That helps keep event deserialization stable. When teams connect Stripe to SubTru, this is part of safe Stripe webhook setup.
When SubTru returns 2xx and when it returns a non-2xx
Response codes matter because they affect whether Stripe retries the webhook.
SubTru follows a simple policy:
- If the event has a permanent problem and retrying will not help, we return a 2xx response.
- If the problem is temporary on our side, we return a non-2xx response so Stripe can try again.
Examples of 2xx cases in SubTru:
- missing required user metadata
- unsupported event type
- bad payload data that will not become valid later
- an already-processed duplicate event
Examples of retryable non-2xx cases in SubTru:
- temporary internal processing failure
- database or infrastructure problem that may succeed on retry
- temporary internal configuration issue blocking processing
This is SubTru's webhook handling policy. It is designed to avoid pointless retries while still recovering from short outages.
Common Stripe webhook mistakes
- Parsing the body too early. If you change the raw request body before signature verification, Stripe signature checks can fail.
- Listening to too many events. Webhook endpoints should only receive the event types your integration actually needs.
- Skipping idempotency. Duplicate deliveries are normal, so a Stripe webhook handler must safely ignore repeats.
- Depending on event order. Stripe says event order is not guaranteed.
- Forgetting user mapping metadata. If the event is real but you cannot tie it to a customer in your system, access logic gets messy fast.
Why this matters for subscription apps
Bad Stripe webhook handling causes real business problems:
- active users may lose access
- canceled users may keep access too long
- duplicate deliveries may create duplicate work
- billing state may drift away from access state
- support teams may not know what happened
Stripe webhooks are powerful, but they are easy to get wrong. SubTru gives subscription apps a project-scoped Stripe webhook pipeline with signature verification, idempotency, logging, and normalized subscription state built in.
Frequently asked questions
Does Stripe require the raw request body for webhooks?
Yes. Stripe says you should use the raw request body when you verify the Stripe-Signature header.
Does Stripe retry failed webhooks?
Yes. Stripe retries failed live-mode webhook deliveries for up to three days with exponential backoff. In sandbox, Stripe retries three times over a few hours.
Can Stripe send duplicate webhooks?
Yes. Stripe says webhook endpoints can receive the same event more than once, so handlers should be idempotent.
Does Stripe guarantee event order?
No. Stripe says event order is not guaranteed, so your code should not depend on receiving events in a specific sequence.
What metadata does SubTru use for Stripe subscriptions?
SubTru uses subtru_external_user_id in Stripe subscription metadata to link the subscription to your customer record.
Build on Stripe webhooks without rebuilding the hard parts
SubTru gives subscription apps a better way to handle Stripe subscription webhooks.
Instead of stitching together signature verification, retries, duplicate handling, event ordering concerns, and metadata mapping on your own, you can use SubTru to keep Stripe subscription events clean, accurate, and in sync with your access system.
Ready to build with SubTru?
Explore the docs or go back to the main site to learn how SubTru handles subscription access across providers.