SubTru logoSubTru
← Back to documentation

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.

  1. We receive the webhook at a project-scoped Stripe endpoint.
  2. We read the raw request body.
  3. We require the Stripe-Signature header.
  4. We verify the signature with the webhook endpoint secret from Stripe.
  5. We accept only the subscription event types we actually need.
  6. We deduplicate by Stripe event ID before processing.
  7. We map the Stripe subscription to your user with subscription metadata.
  8. 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:

Examples of 2xx cases in SubTru:

Examples of retryable non-2xx cases in SubTru:

This is SubTru's webhook handling policy. It is designed to avoid pointless retries while still recovering from short outages.

Common Stripe webhook mistakes

Why this matters for subscription apps

Bad Stripe webhook handling causes real business problems:

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.

Sources