Stripe Webhook Setup

Stripe Webhook Setup

Implemented - Stripe webhook handler is implemented at /api/billing/webhook with signature verification and event processing.

Learn how to configure Stripe webhooks for AllureLMS to receive real-time billing events and subscription updates.

Overview

This guide covers:

  • Understanding Stripe webhooks
  • Configuring webhook endpoints
  • Webhook event types
  • Signature verification
  • Testing webhooks

Prerequisites

  • Stripe account
  • Admin access to Stripe Dashboard
  • Understanding of webhooks
  • (Optional) Webhook testing tool (ngrok, etc.)

Understanding Stripe Webhooks

What are Webhooks?

Webhooks are HTTP callbacks that notify your application when events occur in Stripe:

  • Subscription created/updated
  • Payment succeeded/failed
  • Invoice created/paid
  • Customer updated

Why Use Webhooks?

  • Real-time Updates: Immediate notification of events
  • Reliability: Automatic retry on failure
  • Event History: Complete audit trail
  • Automation: Trigger actions based on events

Configuring Webhooks

Step 1: Get Webhook Endpoint URL

Your AllureLMS webhook endpoint:

https://your-domain.com/api/billing/webhook

Step 2: Configure in Stripe Dashboard

  1. Log in to Stripe Dashboard
  2. Navigate to DevelopersWebhooks
  3. Click Add Endpoint
  4. Enter endpoint URL: https://your-domain.com/api/billing/webhook
  5. Select events to listen to (see below)
  6. Click Add Endpoint
  7. Copy the Signing Secret

Step 3: Set Environment Variable

Implemented - The webhook handler uses STRIPE_WEBHOOK_SECRET environment variable for signature verification.

Set the webhook signing secret:

STRIPE_WEBHOOK_SECRET=whsec_...

Required Environment Variables:

  • STRIPE_SECRET_KEY: Stripe API secret key (for creating customers, subscriptions)
  • STRIPE_WEBHOOK_SECRET: Webhook signing secret from Stripe Dashboard
  • NEXT_PUBLIC_APP_URL: Base URL of your application (for redirect URLs)

Webhook Events

Required Events

Implemented - The webhook handler processes these events:

Subscribe to these events for full functionality:

Subscription Events:

  • customer.subscription.updated - Updates subscription status
  • customer.subscription.deleted - Marks subscription as canceled

Payment Events:

  • checkout.session.completed - Activates subscription after payment
  • invoice.payment_failed - Sets subscription status to past_due

Customer Events:

  • 🚧 customer.created - Planned for future implementation
  • 🚧 customer.updated - Planned for future implementation
  • 🚧 customer.deleted - Planned for future implementation

Event Handling

AllureLMS handles these events automatically:

  • ✅ Creates/updates subscription records in tenant_pricing table
  • ✅ Updates tenant pricing status (active, past_due, canceled)
  • ✅ Handles payment failures by setting status to past_due
  • ✅ Updates checkout session status in billing_checkout_sessions table

Signature Verification

Why Verify?

Webhook signature verification ensures:

  • Request is from Stripe
  • Request hasn't been tampered with
  • Request is authentic

How It Works

Stripe signs each webhook with HMAC-SHA256:

  1. Stripe creates signature from payload + secret
  2. Signature sent in Stripe-Signature header
  3. AllureLMS verifies signature matches
  4. Request processed if valid

Verification Code

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

function verifyWebhookSignature(payload, signature, secret) {
  const elements = signature.split(',');
  const signatureHash = elements.find(el => el.startsWith('v1='));
  
  if (!signatureHash) {
    return false;
  }
  
  const expectedSignature = signatureHash.split('=')[1];
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(payload);
  const computedSignature = hmac.digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature, 'hex'),
    Buffer.from(computedSignature, 'hex')
  );
}

Webhook Handler

AllureLMS Webhook Endpoint

The webhook endpoint at /api/billing/webhook handles:

  1. Signature Verification: Verifies request authenticity
  2. Event Parsing: Parses Stripe event
  3. Event Handling: Processes event based on type
  4. Database Updates: Updates subscription/pricing records
  5. Response: Returns 200 OK to Stripe

Event Processing

// Example event processing
switch (event.type) {
  case 'checkout.session.completed':
    await handleCheckoutCompleted(event.data.object);
    break;
  case 'customer.subscription.updated':
    await handleSubscriptionUpdated(event.data.object);
    break;
  case 'invoice.payment_succeeded':
    await handlePaymentSucceeded(event.data.object);
    break;
  // ... more event types
}

Testing Webhooks

Using Stripe CLI

1. Install Stripe CLI:

# macOS
brew install stripe/stripe-cli/stripe

# Linux/Windows
# Download from https://stripe.com/docs/stripe-cli

2. Login:

stripe login

3. Forward Webhooks:

stripe listen --forward-to http://localhost:3000/api/billing/webhook

4. Trigger Test Event:

stripe trigger checkout.session.completed

Using ngrok

1. Install ngrok:

# Download from https://ngrok.com

2. Start ngrok:

ngrok http 3000

3. Use ngrok URL in Stripe:

https://abc123.ngrok.io/api/billing/webhook

4. Test in Stripe Dashboard:

  • Go to Webhooks → Your Endpoint
  • Click "Send test webhook"
  • Select event type
  • Send test

Webhook Security

Best Practices

  1. HTTPS Only: Always use HTTPS for webhooks
  2. Verify Signatures: Always verify webhook signatures
  3. Idempotency: Handle duplicate webhook deliveries
  4. Timeout Handling: Implement proper timeouts
  5. Error Handling: Log errors and retry logic

Signature Verification

Always verify signatures:

// In webhook handler
const signature = request.headers.get('stripe-signature');
const isValid = verifyWebhookSignature(
  requestBody,
  signature,
  process.env.STRIPE_WEBHOOK_SECRET
);

if (!isValid) {
  return new Response('Invalid signature', { status: 401 });
}

Troubleshooting

Webhooks Not Received

Problem: Webhooks not arriving

  • Solution: Check webhook endpoint URL is correct
  • Check: Verify endpoint is accessible (HTTPS)
  • Try: Test with Stripe CLI or ngrok
  • Check: Review Stripe webhook logs

Signature Verification Fails

Problem: "Invalid signature" error

  • Solution: Verify STRIPE_WEBHOOK_SECRET matches Stripe
  • Check: Ensure using correct signing secret
  • Try: Regenerate webhook secret in Stripe
  • Check: Verify raw body is used for signature

Events Not Processing

Problem: Webhook received but not processed

  • Solution: Check webhook handler logs
  • Check: Verify event type is handled
  • Try: Review event processing logic
  • Check: Ensure database updates are working

Related Documentation


Next Steps


Next: Reporting Guides → Learn about reports