Integrations / Stripe

    S

    Stripe

    Capture, inspect, and replay Stripe webhook events. Never miss a payment_intent.succeeded again.

    Auto-detected:Paggio automatically detects Stripe events via the stripe-signature header. No extra config needed.

    Setup

    1

    Create a Paggio endpoint

    Go to Dashboard → Webhooks → New Endpoint.

    Set the destination URL to your app's Stripe webhook handler, e.g.:

    text
    https://your-app.com/api/stripe/webhook
    2

    Copy your Paggio webhook URL

    Copy the endpoint URL from your new endpoint card:

    text
    https://paggio.dev/api/webhook/your-endpoint-slug
    3

    Add to Stripe Dashboard

    Go to the Stripe Webhooks dashboard Add endpoint.

    Paste your Paggio URL and select the events you want to listen to.

    4

    Send a test event from Stripe

    In the Stripe Dashboard, click "Send test webhook". You should see it appear in Paggio instantly.

    Testing locally

    Instead of using the Stripe CLI, you can use Paggio to capture real Stripe events and replay them to localhost whenever you need:

    1

    Point Stripe at your Paggio URL

    Use the Paggio URL as your Stripe webhook endpoint (even in test mode).

    2

    Trigger a real Stripe event

    Make a test payment in Stripe — the event is captured in Paggio.

    3

    Replay to localhost

    Open the event in Paggio → Replay panel → select "Local" → click Replay.

    The event is forwarded to http://localhost:3000/api/stripe/webhook.

    Verifying Stripe signatures

    Paggio stores the original stripe-signature header. If you verify signatures in your handler, note that replayed events have the same signature as the original. Stripe signatures are time-based and will expire. Disable signature verification in your local dev handler, or use Stripe's tolerance setting.

    app/api/stripe/webhook/route.ts
    import Stripe from 'stripe';
    
    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
    
    export async function POST(req: Request) {
      const body = await req.text();
      const signature = req.headers.get('stripe-signature')!;
    
      let event: Stripe.Event;
      try {
        event = stripe.webhooks.constructEvent(
          body,
          signature,
          process.env.STRIPE_WEBHOOK_SECRET!,
          // Increase tolerance for replays (default: 300s)
          600
        );
      } catch (err) {
        return Response.json({ error: 'Invalid signature' }, { status: 400 });
      }
    
      switch (event.type) {
        case 'payment_intent.succeeded':
          // handle payment...
          break;
      }
    
      return Response.json({ received: true });
    }
    Signature expiry:Stripe signatures expire after 5 minutes by default. When replaying old events, either disable signature verification in dev or pass a high tolerance value to constructEvent().

    Common Stripe event types

    EventWhen it fires
    payment_intent.succeededCustomer completes a payment
    payment_intent.payment_failedPayment fails
    customer.subscription.createdNew subscription created
    customer.subscription.deletedSubscription cancelled
    invoice.payment_succeededInvoice paid successfully
    invoice.payment_failedInvoice payment fails
    checkout.session.completedCheckout session completed