DEV Community

Pirate Prentice
Pirate Prentice

Posted on

n8n Stripe Webhooks: Handle Payment Events, Subscriptions, and Refunds Automatically

n8n Stripe Webhooks: Handle Payment Events, Subscriptions, and Refunds Automatically

Stripe fires webhooks for every meaningful payment event: a charge succeeds, a subscription renews, a payment fails, a refund is issued. If your n8n workflow isn't listening to these, you're missing real-time signals you need to run your business.

This guide covers everything you need to build a production-ready Stripe webhook handler in n8n — from wiring up the endpoint to handling the five events that matter most.


What You'll Learn

  • How to create a Stripe webhook endpoint in n8n
  • How to verify the webhook signature (so only Stripe can trigger your workflow)
  • How to handle the five most important Stripe events
  • Three real workflow patterns: payment receipt, failed payment recovery, and subscription lifecycle

Prerequisites

  • n8n (self-hosted or cloud) with a publicly accessible URL
  • A Stripe account with API access
  • Stripe secret key and webhook signing secret (from Stripe Dashboard → Developers → Webhooks)

Step 1: Create the Webhook Trigger in n8n

  1. Open n8n and create a new workflow
  2. Add a Webhook node as the trigger
  3. Set HTTP Method to POST
  4. Copy the generated webhook URL — you'll add it to Stripe next
  5. Set Response Mode to Immediately (Stripe expects a 200 within 30 seconds)

Important: If you're running n8n locally, Stripe can't reach localhost. Use ngrok or deploy to a cloud instance for testing.


Step 2: Register the Endpoint in Stripe

  1. Go to Stripe Dashboard → Developers → Webhooks
  2. Click Add endpoint
  3. Paste your n8n webhook URL
  4. Select the events you want to handle (start with the five below)
  5. Save — Stripe will show you the Signing Secret (starts with whsec_)

Events to select:

  • payment_intent.succeeded
  • payment_intent.payment_failed
  • invoice.payment_succeeded
  • invoice.payment_failed
  • customer.subscription.deleted

Step 3: Verify the Webhook Signature

Stripe signs every webhook with an HMAC-SHA256 signature. Verifying it ensures your workflow only processes real Stripe events — not spoofed requests.

After the Webhook trigger node, add a Code node:

const stripe = require('crypto');
const payload = $input.first().json.body;
const sigHeader = $input.first().headers['stripe-signature'];
const secret = 'whsec_YOUR_SIGNING_SECRET';
const parts = sigHeader.split(',').reduce((acc, part) => {
  const [key, val] = part.split('=');
  acc[key] = val;
  return acc;
}, {});
const timestamp = parts['t'];
const sig = parts['v1'];
const signedPayload = `${timestamp}.${payload}`;
const expectedSig = stripe.createHmac('sha256', secret).update(signedPayload, 'utf8').digest('hex');
if (expectedSig !== sig) { throw new Error('Invalid Stripe signature'); }
const event = JSON.parse(payload);
return [{ json: event }];
Enter fullscreen mode Exit fullscreen mode

Gotcha: n8n's Webhook node parses the body by default. You need the raw body for signature verification. Set Raw Body to true in the Webhook node options.


Step 4: Route Events with a Switch Node

Add a Switch node to route different event types:

  • Output 1: {{ $json.type }} equals payment_intent.succeeded
  • Output 2: {{ $json.type }} equals payment_intent.payment_failed
  • Output 3: {{ $json.type }} equals invoice.payment_succeeded
  • Output 4: {{ $json.type }} equals invoice.payment_failed
  • Output 5: {{ $json.type }} equals customer.subscription.deleted
  • Fallback: log and ignore everything else

The Five Events That Matter

1. payment_intent.succeeded — One-Time Payment Confirmed

Fires when a customer completes a one-time charge. Use this to:

  • Trigger product delivery (email a download link, provision access)
  • Write the sale to Google Sheets or Airtable
  • Send a Slack notification to your team

Key fields:

$json.data.object.amount           // amount in cents
$json.data.object.currency         // e.g., \"usd\"
$json.data.object.receipt_email    // customer email
$json.data.object.metadata         // your custom fields
Enter fullscreen mode Exit fullscreen mode

2. payment_intent.payment_failed — Charge Failed

Fires when a card is declined or payment fails. Use this to:

  • Send a \"payment failed\" email with a retry link
  • Pause service access after N failures
  • Alert your team for high-value orders

Key fields:

$json.data.object.last_payment_error.message
$json.data.object.last_payment_error.code
Enter fullscreen mode Exit fullscreen mode

3. invoice.payment_succeeded — Subscription Renewal Paid

Fires every subscription invoice payment. Use this to:

  • Extend customer access
  • Send renewal receipts
  • Update MRR tracking

Key fields:

$json.data.object.customer_email
$json.data.object.amount_paid
$json.data.object.subscription
Enter fullscreen mode Exit fullscreen mode

4. invoice.payment_failed — Subscription Payment Failed

Critical for retention. Most involuntary churn is recoverable if you act fast.

Use this to:

  • Send \"please update your card\" email immediately
  • Trigger dunning (Day 1, Day 4, Day 7)
  • Flag customer for manual follow-up

5. customer.subscription.deleted — Subscription Cancelled

Fires when a subscription ends. Use this to:

  • Revoke access
  • Send cancellation confirmation
  • Trigger win-back sequence after 7 days

Three Complete Workflow Patterns

Pattern 1: Automated Payment Receipt + Delivery

Webhook → Verify Signature → Switch (event type)
  → payment_intent.succeeded
       → Extract: email, amount, metadata
       → Gmail: send receipt + download link
       → Google Sheets: log sale
Enter fullscreen mode Exit fullscreen mode

Result: Every successful payment triggers a receipt email and auto-logs within seconds.


Pattern 2: Failed Payment Recovery

Webhook → Verify Signature → Switch
  → invoice.payment_failed
       → IF attempt_count == 1: \"Card failed\" email
       → IF attempt_count == 2: \"Last chance\" email  
       → IF attempt_count >= 3: mark churned + pause access
Enter fullscreen mode Exit fullscreen mode

Result: Automated dunning recovers 20-40% of failed subscription payments without manual work.


Pattern 3: Subscription Lifecycle Tracker

Webhook → Verify Signature → Switch
  ├→ invoice.payment_succeeded → Sheets: upsert (status=active)
  ├→ invoice.payment_failed    → Sheets: update (status=past_due)
  └→ subscription.deleted      → Sheets: update (status=cancelled)
                                → Wait 7 days → Send win-back email
Enter fullscreen mode Exit fullscreen mode

Result: Real-time subscription dashboard in Google Sheets with zero manual updates.


Free Workflow JSON

I've built the complete workflow: Webhook trigger → Signature verification → Switch routing → all 5 event handlers with Gmail/Sheets stubs.

Download free n8n Stripe Webhook Workflow JSON →

Import in n8n: Settings → Import from file. Add your credentials and webhook signing secret, activate, and you're live.


6 Gotchas to Know

  1. Raw body requirement: Stripe signature verification needs the exact raw request body. Check your n8n Webhook node for \"Raw Body\" option.

  2. 30-second response window: Stripe fails webhooks if no 200 within 30s. Use Response Mode: Immediately and do heavy work after.

  3. Idempotency: Stripe retries failed webhooks for 3 days. Check event.id in Sheets to skip duplicates.

  4. livemode flag: Stripe sends both test and live events to the same endpoint. Check $json.livemode === true to filter.

  5. payment_intent.succeeded + subscriptions: First subscription charge fires both payment_intent.succeeded and invoice.payment_succeeded. Handle only one.

  6. Metadata is your friend: Add metadata fields to Stripe Payment Intents. They come through in webhooks and let you route without extra API calls.


Want This Built For You?

If you'd rather have a working Stripe webhook workflow built to your spec — event types, routing, email templates, Sheets schema — I build and test it within 48 hours.

$99 Done-For-You n8n Workflow →

Fill out a short intake form describing what you need (which events, what actions, integrations). I build and deliver the workflow JSON ready to import.


Publishing free n8n workflow guides and automation templates. Subscribe for the full library:

Gumroad Library →

Top comments (0)