Skip to content
DocsWebhooks

Webhooks

MantleWP receives webhooks from Stripe to handle subscription changes, payment failures, and billing events. This page explains how webhook processing works and which events are handled.

Stripe Webhooks

MantleWP receives Stripe webhooks at POST /api/webhooks/stripe. Stripe signs each webhook request with a secret, so MantleWP can verify that the request actually came from Stripe and wasn't tampered with.

Handled Events

MantleWP handles the following Stripe webhook events:

EventAction
checkout.session.completedActivate subscription, update organization plan tier
customer.subscription.updatedSync plan changes (upgrade, downgrade, billing cycle)
customer.subscription.deletedMark subscription as canceled, enforce free plan limits
invoice.payment_succeededRecord successful payment, update billing status
invoice.payment_failedMark organization as past due, send notification to owner

Webhook Security

Every incoming webhook is verified against the Stripe webhook signing secret (STRIPE_WEBHOOK_SECRET). Requests that fail signature verification return 400 Bad Request and are not processed.

The raw HTTP request body is used for verification — the body must never be parsed before verification completes.

// Verify webhook signature
const sig = request.headers.get('stripe-signature');
const event = stripe.webhooks.constructEvent(
  rawBody,
  sig,
  STRIPE_WEBHOOK_SECRET
);
// Process event only after successful verification

Retry Behavior

Stripe automatically retries failed webhook deliveries for up to 3 days. If your server returns an error status (5xx), Stripe will retry the webhook later.

Webhook events are idempotent — processing the same event twice (due to a retry) should have no side effect. MantleWP tracks processed event IDs to prevent duplicate processing.

Testing Webhooks Locally

Use the Stripe CLI to simulate webhook events during local development:

# Install Stripe CLI
brew install stripe/stripe-cli/stripe

# Forward Stripe events to your local server
stripe listen --forward-to localhost:3000/api/webhooks/stripe

# Trigger a test event in another terminal
stripe trigger customer.subscription.updated

The Stripe CLI displays all webhook events sent to your endpoint, making it easy to test billing flows locally.

Example Webhook Event

Here's what a checkout.session.completed webhook looks like:

{
  "id": "evt_1234567890",
  "object": "event",
  "api_version": "2023-10-16",
  "created": 1234567890,
  "type": "checkout.session.completed",
  "data": {
    "object": {
      "id": "cs_live_abc123xyz",
      "customer": "cus_abc123",
      "subscription": "sub_abc123",
      "client_reference_id": "org_12345"
    }
  }
}

Next steps: Back to API Reference, read about billing and plans, or check authentication.