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

Retry Stripe Webhooks Reliably

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

TL;DR: Put Slashbin in front of your Stripe webhook endpoint. Slashbin ACKs Stripe instantly, retries your endpoint automatically on failure, and keeps every failed delivery replayable — so a five-minute outage doesn't cost you an invoice.paid event.


What You'll Build

Stripe posts each event to a Slashbin ingestion URL. Slashbin verifies the Stripe signature, ACKs Stripe in milliseconds, and delivers the event to your API with automatic retries and per-destination circuit breaking. Your endpoint receives the same clean Stripe event structure:

{
  "id": "evt_1MtwBwLkdIwHu7ixV1YrJ8vN",
  "type": "invoice.paid",
  "created": 1680640200,
  "data": {
    "object": {
      "id": "in_1MtwBwLkdIwHu7ix4LGN3vfB",
      "object": "invoice",
      "customer": "cus_NcTh4G8kxKPeUM",
      "subscription": "sub_1MtwBqLkdIwHu7ixEo1YRZg8",
      "amount_paid": 4900,
      "currency": "usd",
      "status": "paid",
      "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1.../test_YWNjdF8x..."
    }
  }
}

If your endpoint returns a 5xx or times out, Slashbin retries with exponential backoff. If retries are exhausted, the event lands in the Dead Letter Queue — still fully replayable, never silently dropped.


The Problem

Your endpoint was down for five minutes during a deploy. Stripe posted invoice.paid three times, got 502s, gave up. That subscription renewal never arrived in your database.

Stripe's retry window is finite, and their docs push the reliability contract onto you: build idempotent handlers, add your own retry queue, keep an audit log of every event. That's a lot of infrastructure to run in your API just to survive a bad five minutes.

Without a gateway, your API is on the hook for:

Without SlashbinWith Slashbin
Endpoint down = Stripe events lost after Stripe gives upSlashbin ACKs Stripe, retries your endpoint on its own schedule
Idempotency keys, dedupe tables, retry queues in your appRetry + DLQ live at the gateway — your handler just does business logic
Silent failures when a deploy hiccup swallows a webhookEvery failure surfaces in the DLQ with the full payload
No way to re-run a specific event after fixing a bugOne-click Replay from the dashboard

The Solution

Point Stripe at a Slashbin ingestion URL instead of your API. Slashbin owns the reliability contract:

  1. Instant ACK to Stripe — Slashbin verifies the Stripe signature and returns 200 in milliseconds, so Stripe never gives up.
  2. Automatic retries to your endpoint — if your API returns a 5xx or times out, Slashbin retries with exponential backoff. Per-destination circuit breakers stop hammering a downed endpoint.
  3. DLQ + Replay — deliveries that exhaust retries land in the Dead Letter Queue with the full original payload. Replay any event from the dashboard once you've deployed the fix.

Outcome: Your handler stays simple. The gateway carries the "never miss a message" guarantee.


Step 1: Create a Stripe Project in Slashbin

Secure the connection before data ever flows.

  1. Project Setup: Click Create New Project and select Stripe.
  2. Type: Choose Transactional — Stripe events are stateful business events.
  3. Security: Paste your Stripe Webhook Signing Secret (the value that starts with whsec_, available in Stripe Dashboard → Developers → Webhooks → your endpoint → Signing secret).

Result: Slashbin auto-rejects any request that fails Stripe's HMAC signature check, so only verified Stripe events reach your retry pipeline.


Step 2: Add Your Endpoint as a Destination

On the Outbound tab, click + Add Destination and choose Custom Webhook.

  1. Enter a Name (e.g., "Billing Service").
  2. Enter your URL (e.g., https://api.example.com/webhooks/stripe).
  3. Add any custom headers your endpoint requires, then click Add Destination.

The Developer Guide tab on your destination shows the exact JSON your endpoint will receive plus sample receiver code with signature verification. See Destination Model for how Slashbin routes events to one or more destinations per project.

Your handler only needs to return a 2xx on success and anything else on failure. Slashbin does the rest:

// Express — minimal Stripe event handler behind Slashbin.
// Return 2xx on success, 5xx on transient failure to trigger a retry.
import express from 'express'
 
const app = express()
 
app.post('/webhooks/stripe', express.json(), async (req, res) => {
  const event = req.body
 
  try {
    if (event.type === 'invoice.paid') {
      await recordInvoicePayment(event.data.object)
    }
    res.status(200).end()
  } catch (err) {
    // Transient failure — return 5xx so Slashbin retries with backoff.
    console.error('handler failed', err)
    res.status(500).end()
  }
})

Verify the Slashbin signature header on production endpoints — copy the code sample from the destination's Developer Guide tab, which generates a signature-verified receiver in your language of choice.


Step 3: Point Stripe at the Slashbin Ingestion URL

  1. Copy the Ingestion URL from the Slashbin project dashboard.
  2. In Stripe Dashboard, go to Developers → Webhooks → Add endpoint.
  3. Paste the Slashbin Ingestion URL and select the events you want to forward (e.g., invoice.paid, checkout.session.completed, customer.subscription.updated).
  4. Save.

Done. Stripe now posts to Slashbin. Slashbin verifies, ACKs, and delivers to your endpoint with automatic retry and replay.


Verify Delivery and Replay Failures

Take your endpoint down (or block the destination URL) and fire a test event from the Stripe Dashboard. In Slashbin:

  • The event shows as delivered to gateway immediately (Stripe sees a 200).
  • The delivery to your endpoint shows retry attempts as Slashbin backs off.
  • After the retry budget is exhausted, the event lands in the Dead Letter Queue with the full original payload — see Replay & Retry for the DLQ walkthrough.

Bring your endpoint back up, click Replay on the DLQ entry, and the same event is re-delivered from the gateway. Stripe never re-sent anything; the recovery is entirely gateway-side.


Why Slashbin vs a Raw Handler

  • Never miss a message. Slashbin owns the retry contract end-to-end. Your endpoint being down doesn't cost you an invoice.paid.
  • Instant ACK to Stripe. Slashbin returns 200 in milliseconds regardless of your endpoint's latency, so Stripe never triggers its "delivery attempts exhausted" flow.
  • Visible failures, not silent drops. Every exhausted delivery surfaces in the DLQ with the exact payload Stripe sent, ready to inspect and replay.
  • One-click replay. Fix the bug, click Replay, done — no manual stripe events list + stripe events resend gymnastics.

Next Steps

  • Transform Stripe payloads into your internal schema — see Golden Model.
  • Send the same Stripe event to more than one service — see Fan-Out Routing.
  • Debug a specific failed delivery with Replay & Retry.
  • Browse every supported source and destination on Integrations.