Tutorials

Set Up Stripe Webhooks: Payment Automation with n8n and Make.com

How to set up Stripe webhooks for automatic payment processing.

12 min read

Stripe webhooks are the key to fully automated payment processes. Instead of manually checking whether a payment came through, your system reacts automatically to every event: payment successful, subscription cancelled, chargeback - all in real-time. In this guide, we show you the complete setup.

What Are Stripe Webhooks?

Webhooks are HTTP callbacks: Stripe sends a message to your URL as soon as something happens.

Without webhooks:
Customer pays -> You check manually -> Hours later: Access granted
With webhooks:
Customer pays -> Stripe sends event -> Immediately: Access granted

Important Stripe Events

EventWhen TriggeredTypical Action
checkout.session.completedCheckout completedGrant access
payment_intent.succeededPayment successfulSend invoice
payment_intent.failedPayment failedNotify customer
invoice.paidInvoice paidExtend subscription
invoice.payment_failedSubscription payment failedSend reminder
customer.subscription.deletedSubscription cancelledRevoke access
customer.subscription.updatedSubscription changedAdjust plan
charge.refundedRefund issuedRevoke access
charge.dispute.createdChargebackAlert team

Step 1: Create Webhook Endpoint

Option A: n8n Webhook

  • Create new workflow
  • Add node: Webhook
  • Configuration:
  • - HTTP Method: POST

    - Path: stripe-webhook

  • Copy URL: https://your-n8n-instance.com/webhook/stripe-webhook
  • Option B: Make.com Webhook

  • Create new scenario
  • Trigger: Webhooks > Custom webhook
  • Copy URL and enter in Stripe
  • Step 2: Register Webhook with Stripe

    In Stripe Dashboard

  • Dashboard -> Developers -> Webhooks
  • Click "Add endpoint"
  • Enter endpoint URL
  • Select events (e.g., checkout.session.completed)
  • Confirm "Add endpoint"
  • Copy Webhook Secret

    After creation, Stripe shows a Signing Secret:

    whsec_1234567890abcdefghijklmnop
    Important: Store this key securely - for signature verification!

    Via Stripe CLI (for Development)

    # Install Stripe CLI
    

    brew install stripe/stripe-cli/stripe

    # Login

    stripe login

    # Forward webhooks to localhost

    stripe listen --forward-to localhost:5678/webhook/stripe-webhook

    # Shows temporary signing secret

    Step 3: Verify Signature (Security!)

    Why important? Without verification, anyone could send fake events to your endpoint.

    n8n: Check Signature

    // Node: Code (before all other nodes)
    

    const crypto = require('crypto');

    const payload = $json.body; // Raw body

    const signature = $headers['stripe-signature'];

    const webhookSecret = 'whsec_1234567890abcdefghijklmnop';

    // Stripe signature format: t=timestamp,v1=signature

    const elements = signature.split(',');

    const timestamp = elements.find(e => e.startsWith('t=')).split('=')[1];

    const expectedSig = elements.find(e => e.startsWith('v1=')).split('=')[1];

    // Calculate signature

    const signedPayload = ${timestamp}.${JSON.stringify(payload)};

    const computedSig = crypto

    .createHmac('sha256', webhookSecret)

    .update(signedPayload)

    .digest('hex');

    if (computedSig !== expectedSig) {

    throw new Error('Invalid signature');

    }

    // Check timestamp (max 5 minutes old)

    const now = Math.floor(Date.now() / 1000);

    if (now - parseInt(timestamp) > 300) {

    throw new Error('Timestamp too old');

    }

    return $json;

    Make.com: HTTP Module with Verification

    In Make.com, you can add an HTTP module that verifies the signature.

    Step 4: Process Events

    Workflow: Checkout Completed

    Stripe Webhook
    

    (checkout.session.completed)

    |

    Verify signature

    |

    Extract customer data

    |

    Parallel:

    +- Database: Create/activate user

    +- Email: Send welcome email

    +- CRM: Mark deal as won

    +- Slack: Notify team

    n8n Implementation

    Node 1: Webhook Trigger
    // Webhook receives event
    

    {

    "type": "checkout.session.completed",

    "data": {

    "object": {

    "id": "cs_1234",

    "customer": "cus_1234",

    "customer_email": "customer@example.com",

    "amount_total": 9900,

    "currency": "eur",

    "metadata": {

    "plan": "pro",

    "user_id": "123"

    }

    }

    }

    }

    Node 2: Switch by Event Type
    // Node: Switch
    

    const eventType = $json.type;

    switch(eventType) {

    case 'checkout.session.completed':

    return { route: 'checkout_completed' };

    case 'invoice.paid':

    return { route: 'invoice_paid' };

    case 'customer.subscription.deleted':

    return { route: 'subscription_cancelled' };

    default:

    return { route: 'unknown' };

    }

    Node 3: Extract Data
    // Node: Set
    

    {

    "customerId": "{{ $json.data.object.customer }}",

    "email": "{{ $json.data.object.customer_email }}",

    "amount": "{{ $json.data.object.amount_total / 100 }}",

    "plan": "{{ $json.data.object.metadata.plan }}",

    "userId": "{{ $json.data.object.metadata.user_id }}"

    }

    Node 4: Activate User (Your Database)
    // Node: HTTP Request (to your API)
    

    {

    "method": "POST",

    "url": "https://api.your-app.com/users/activate",

    "body": {

    "userId": "{{ $json.userId }}",

    "plan": "{{ $json.plan }}",

    "stripeCustomerId": "{{ $json.customerId }}"

    }

    }

    Workflow: Subscription Payment Failed

    Stripe Webhook
    

    (invoice.payment_failed)

    |

    Check attempt number

    |

    Switch:

    +- Attempt 1: Friendly email

    +- Attempt 2: Urgent email

    +- Attempt 3: Final warning

    +- Attempt 4: Suspend access

    Implementation

    // Node: Code
    

    const invoice = $json.data.object;

    const attemptCount = invoice.attempt_count;

    let action, emailTemplate;

    switch(attemptCount) {

    case 1:

    action = 'soft_reminder';

    emailTemplate = 'payment_failed_soft';

    break;

    case 2:

    action = 'urgent_reminder';

    emailTemplate = 'payment_failed_urgent';

    break;

    case 3:

    action = 'final_warning';

    emailTemplate = 'payment_failed_final';

    break;

    default:

    action = 'suspend_account';

    emailTemplate = 'account_suspended';

    }

    return { action, emailTemplate, attemptCount };

    Workflow: Refund

    Stripe Webhook
    

    (charge.refunded)

    |

    Full or partial?

    |

    Full:

    +- Revoke access

    +- Create internal note

    +- Notify team

    |

    Partial:

    +- Just log

    Workflow: Chargeback (Dispute)

    Stripe Webhook
    

    (charge.dispute.created)

    |

    IMMEDIATE alert to team!

    |

    Slack: @channel Alert

    |

    Zendesk: High-priority ticket

    |

    Gather all customer data

    (for Stripe dispute response)

    Important: Chargebacks cost $15 in fees and can lead to account suspension!

    Make.com Scenario: Stripe Checkout

    Module Setup

  • Webhooks -> Custom Webhook
  • JSON -> Parse JSON
  • Router -> By event type
  • HTTP -> Call your API
  • Email -> Send confirmation
  • Slack -> Notify team
  • Filter Example

    // Only for certain products
    

    Condition: {{data.object.metadata.product_type}} = "subscription"

    Advanced Patterns

    Ensure Idempotency

    Stripe can send events multiple times. Prevent duplicate processing:

    // Node: Code
    

    const eventId = $json.id; // e.g., "evt_1234"

    // Check if already processed

    const existing = await getFromDatabase('stripe_events', eventId);

    if (existing) {

    return { skip: true, reason: 'already_processed' };

    }

    // Mark as processed

    await saveToDatabase('stripe_events', {

    id: eventId,

    type: $json.type,

    processedAt: new Date().toISOString()

    });

    return { skip: false };

    Retry Logic

    If your endpoint fails, Stripe retries:

    AttemptWait Time
    1Immediately
    21 hour
    36 hours
    424 hours
    548 hours
    Tip: Always respond with status 200, even on errors - and process asynchronously.

    Webhook Queue for Reliability

    Stripe Webhook
    

    |

    Save to queue (Redis/SQS)

    |

    Immediately respond 200 OK

    |

    [Asynchronously]

    Worker processes queue

    Testing

    Stripe Test Events

    In Stripe Dashboard:

  • Developers -> Webhooks -> Select endpoint
  • Click "Send test webhook"
  • Select event type
  • "Send test webhook"
  • Stripe CLI

    # Send test event
    

    stripe trigger checkout.session.completed

    # With custom data

    stripe trigger payment_intent.succeeded \

    --add payment_intent:metadata.user_id=123

    n8n Test Mode

  • Open workflow
  • Activate "Test Workflow"
  • Send Stripe test event
  • Inspect data
  • Debugging

    Event Logs in Stripe

    Dashboard -> Developers -> Webhooks -> Events

    Shows:

    • All sent events
    • HTTP response from your server
    • Retry attempts

    Common Errors

    ErrorCauseSolution
    401 UnauthorizedWrong API keyCheck key
    400 Bad RequestInvalid dataCheck payload
    500 Internal ErrorYour code has bugsCheck logs
    TimeoutProcessing too slowProcess async
    Signature mismatchWrong signing secretCheck secret

    Production Checklist

    Signature verification implemented
    Idempotency check built in
    All relevant events subscribed
    Error handling implemented
    Monitoring/alerting set up
    Test mode tested
    Live mode tested
    Backup processing for failures

    Costs

    ComponentCost
    Stripe WebhooksFree
    n8n (1000 executions)~20 EUR/month
    Make.com (10,000 ops)~30 EUR/month
    ROI: Automatic processing saves 5-10h/week with 100+ transactions.

    Conclusion

    Stripe webhooks are essential for any SaaS/e-commerce business:

    • Real-time response to payments
    • Fully automatic subscription management
    • Proactive churn management
    • Compliance (invoices, etc.)

    Next Steps

  • Create webhook endpoint (n8n/Make.com)
  • Register with Stripe
  • Implement signature verification
  • Process first event (checkout.session.completed)
  • Add more events
  • We support you with Stripe integration - from setup to complex subscription logic.

    Questions About Automation?

    Our experts will help you make the right decisions for your business.