Public Beta: Direct engineering support available. Join Discord →
Docs
Recipes
Stripe: Debug Webhooks

Debug Stripe Webhooks

Time: ~10 minutes | Difficulty: Beginner | Prerequisites: Stripe account with webhook access, Slashbin account

TL;DR: Put Slashbin in front of your Stripe endpoint. Every event is stored with its raw payload, transform result, delivery attempts, and response codes — so when something "doesn't work," you debug from evidence instead of re-firing test events.


The Problem

A Stripe event fired. Your system shows nothing happened. Now what?

Without stored evidence, you can't tell where it went wrong:

  • Was it never sent? Maybe Stripe didn't dispatch it, or your endpoint URL was misconfigured.
  • Was it rejected? A signature mismatch, an invalid payload, a timeout at the edge.
  • Was it transformed wrong? Your parser exploded on a field shape you weren't expecting.
  • Was it delivered and dropped? Your handler returned 200 but the business logic silently no-op'd.

Raw endpoints keep no history. Your only diagnostic is re-triggering a test event and hoping the failure reproduces — while the original event, the one that actually broke, is gone.


The Solution

Route Stripe through a Slashbin project. Every event is stored end-to-end:

  • The raw payload exactly as Stripe sent it — bytes and headers.
  • The transform result — what your Golden Model produced (or the error it threw).
  • Every delivery attempt to your endpoint — with response code, response body, and timing.
  • The final disposition — delivered, retrying, or in the DLQ.

When something goes wrong, you open the delivery log, find the event, and read the story. No re-firing. No guessing.

Outcome: You debug Stripe webhooks by reading stored evidence, not by trying to reproduce failures in a test environment that doesn't match production.


Step 1: Route Stripe Through a Slashbin Project

If you haven't already put Slashbin in front of Stripe, follow Retry Stripe Webhooks Reliably — the setup is the same. Debugging is a byproduct of the gateway pattern.

Once the project exists:

  1. Stripe posts to a Slashbin Ingestion URL (Dashboard → Developers → Webhooks).
  2. Slashbin verifies the Stripe signature at the gateway and stores the raw payload.
  3. Every downstream stage — transform, delivery attempts, retries — is recorded against that event.

Nothing about your endpoint changes; you gain a delivery log for free.


Step 2: Open the Delivery Log for the Failing Event

In the Slashbin Console, open the project and go to the Delivery Log.

Find the event you want to debug — by Stripe event id (evt_...), by timestamp, or by filtering to failed deliveries only.

Each entry shows a single stored delivery record. Its shape looks like this:

{
  "event_id": "evt_1MtwBwLkdIwHu7ixV1YrJ8vN",
  "received_at": "2026-07-21T14:03:22.104Z",
  "source": "stripe",
  "event_type": "invoice.paid",
  "signature_verified": true,
  "transform": {
    "status": "ok",
    "model_version": 7
  },
  "attempts": [
    {
      "attempt": 1,
      "at": "2026-07-21T14:03:22.482Z",
      "destination": "Billing Service",
      "url": "https://api.example.com/webhooks/stripe",
      "response_status": 502,
      "response_body": "Bad Gateway",
      "duration_ms": 4213
    },
    {
      "attempt": 2,
      "at": "2026-07-21T14:03:52.501Z",
      "destination": "Billing Service",
      "url": "https://api.example.com/webhooks/stripe",
      "response_status": 500,
      "response_body": "TypeError: Cannot read property 'customer' of undefined",
      "duration_ms": 118
    }
  ],
  "disposition": "in_dlq"
}

The record above tells you three things at a glance:

  1. Signature verification passed — this wasn't a bad-secret problem.
  2. The transform succeeded — the Golden Model produced valid output.
  3. Your handler returned a real error — TypeError: Cannot read property 'customer' of undefined — and after retries, the delivery landed in the DLQ.

That's the fix location: your handler, not Stripe, not the transform.


Step 3: Pinpoint the Failed Stage

The delivery record is stage-ordered on purpose. Walk it top-down:

  • signature_verified: false → Slashbin rejected the event at the gateway. Check the signing secret in the project settings against Stripe's current signing secret for that endpoint.
  • transform.status: "error" → The Golden Model threw. The record includes the error and the offending source field so you can fix the mapping and re-publish the model.
  • attempts[].response_status in the 4xx range → Your endpoint rejected the payload. The stored response_body is the exact response your handler returned.
  • attempts[].response_status in the 5xx range or timeout → Your endpoint errored transiently. Slashbin will retry with backoff; if all attempts exhaust, the disposition becomes in_dlq.
  • disposition: "delivered" but the downstream system shows nothing → Delivery succeeded end-to-end. The bug is downstream of your handler's 2xx response — dropped inside your own code, not in the pipeline.

You don't guess between these — you read the record.


Step 4: Replay After the Fix

Once you've deployed the fix, the same event is re-runnable from the gateway:

  1. Open the Dead Letter Queue.
  2. Find the event by id or filter.
  3. Click Replay. Slashbin re-delivers the stored payload to your endpoint.

Stripe is not involved in the replay — the payload comes from Slashbin's storage, not a re-trigger of Stripe's send. That matters when the original event was one-of-a-kind (a specific customer's failed subscription renewal) and can't be reproduced on demand.

If the fix worked, the replay attempt logs a 2xx and the disposition flips to delivered. If it didn't, you get a fresh attempt record to read.


Why Slashbin vs a Raw Handler

  • Debug from stored evidence, not re-triggered test events. The exact payload that broke is on disk, along with every attempt, response code, and timing.
  • Stage-by-stage attribution. Signature, transform, delivery — each stage's result is captured, so you don't have to guess where it failed.
  • Replay from storage, not from Stripe. Fixed the bug? Re-run the exact original event. Stripe never re-sends anything.
  • DLQ instead of silent drops. Failed deliveries surface. They don't disappear.

Next Steps