HookDeploy
Stripe Beginner

Testing Stripe Webhooks with HookDeploy

Complete guide to capturing, inspecting, and debugging Stripe webhook events using HookDeploy, the Stripe CLI, and signature verification.

HookDeploy Team · May 22, 2026

Stripe sends webhooks for almost every important event — payments, subscriptions, invoices, disputes. This guide walks through setting up HookDeploy as your Stripe endpoint, testing locally, and handling the details that trip up most integrations.

Stripe webhook events overview

Stripe organizes events by resource type. Common ones during development:

EventWhen it fires
payment_intent.succeededA PaymentIntent completes successfully
payment_intent.payment_failedA payment attempt fails
customer.subscription.createdA new subscription starts
customer.subscription.updatedPlan change, renewal, or status change
invoice.payment_succeededAn invoice is paid
checkout.session.completedA Checkout Session finishes

Each event is a JSON POST with an id, type, data.object, and created timestamp. Stripe signs every payload with your webhook signing secret.

Set up HookDeploy as your Stripe endpoint

  1. Sign up at app.hookdeploy.dev
  2. Create an endpoint named Stripe dev
  3. Copy your URL: https://hookdeploy.dev/h/{slug}

In the Stripe Dashboard:

  1. Go to Developers → Webhooks
  2. Click Add endpoint
  3. Paste your HookDeploy URL
  4. Select events — start with payment_intent.succeeded and checkout.session.completed
  5. Click Add endpoint
  6. Copy the Signing secret (whsec_...) — you need this for verification

Trigger a test event from Stripe

Send a test event from the Stripe Dashboard:

  1. Open your webhook endpoint in Stripe
  2. Click Send test webhook
  3. Choose payment_intent.succeeded
  4. Click Send test webhook

Within a second, the event appears in HookDeploy. Open the inspector to see the full payload, headers, and Stripe’s signature header.

Use the Stripe CLI alongside HookDeploy

The Stripe CLI is useful for triggering events without the Dashboard:

# Install Stripe CLI, then login
stripe login

# Forward Stripe events to your HookDeploy URL
stripe listen --forward-to https://hookdeploy.dev/h/YOUR_SLUG

The CLI prints a webhook signing secret (whsec_...) for local verification. Use this secret in your application when testing against CLI-forwarded events.

Trigger specific events:

stripe trigger payment_intent.succeeded
stripe trigger checkout.session.completed
stripe trigger customer.subscription.created

Events flow: Stripe → Stripe CLI → HookDeploy. You inspect in HookDeploy, then replay to your local handler when ready.

Verify Stripe signatures

Never process a webhook without verifying the signature. Stripe sends Stripe-Signature with timestamp and signature:

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

// In your Express handler:
const sig = request.headers['stripe-signature'];
let event;

try {
  event = stripe.webhooks.constructEvent(
    request.rawBody,  // must be raw bytes, not parsed JSON
    sig,
    process.env.STRIPE_WEBHOOK_SECRET
  );
} catch (err) {
  return response.status(400).send(`Webhook Error: ${err.message}`);
}

// event is verified — safe to process
console.log(event.type, event.data.object.id);

Handle Stripe retries

Stripe retries failed deliveries for up to 3 days with exponential backoff. If your handler returns non-2xx, Stripe retries.

HookDeploy always returns 200 to Stripe when capturing — your handler is not involved yet. When you forward or replay to your server:

  • Return 200 quickly after enqueueing work
  • Process asynchronously for slow operations
  • Make handlers idempotent — Stripe may deliver the same event more than once

Check event.id against a processed-events table before acting.

Common Stripe webhook issues

Event not appearing in HookDeploy

  • Verify the endpoint URL in Stripe matches your HookDeploy slug exactly
  • Check HookDeploy endpoint is not paused
  • Confirm you have not hit your plan’s monthly request limit

Signature verification fails

  • Using the wrong whsec_ secret (Dashboard secret vs CLI secret)
  • Body was parsed as JSON before verification — use raw body middleware
  • Clock skew — Stripe rejects timestamps older than 5 minutes

Missing fields in payload

  • You are looking at a test event — test payloads are simplified
  • Use stripe trigger or real test mode transactions for full objects

Duplicate events

  • Normal Stripe behavior on retries. Use idempotency on event.id

Test with curl

Simulate a minimal Stripe-like POST to your HookDeploy URL:

curl -X POST "https://hookdeploy.dev/h/YOUR_SLUG" \
  -H "Content-Type: application/json" \
  -H "Stripe-Signature: t=1234567890,v1=test" \
  -d '{
    "id": "evt_test_webhook",
    "type": "payment_intent.succeeded",
    "data": {
      "object": {
        "id": "pi_test_123",
        "amount": 2000,
        "currency": "usd",
        "status": "succeeded"
      }
    }
  }'

This won’t pass signature verification in your handler, but it validates your HookDeploy capture pipeline.

Replay to your local handler

Once you have a captured event in HookDeploy:

  1. Start your local server (via ngrok or Cloudflare Tunnel)
  2. Open the request in HookDeploy
  3. Click Replay and enter your local URL: https://your-tunnel.ngrok.io/webhooks/stripe

HookDeploy re-sends the original payload. Your handler processes it as if Stripe sent it directly.

Next steps

Related guides