Billing Webhooks

Webhooks

Handle Stripe webhook events for subscription lifecycle, payment failures, and more.

Auto-Handled

Core events handled by platform

Forwarding

Forward to your app for custom logic

Verified

Cryptographic signature validation

Auto-Retry

Exponential backoff on failures

Platform-Handled Events

These Stripe events are automatically handled by the platform - no setup required:

checkout.session.completed

Creates subscription record

customer.subscription.created

Activates subscription

customer.subscription.updated

Updates plan/status

customer.subscription.deleted

Marks subscription ended

invoice.payment_succeeded

Records successful payment

invoice.payment_failed

Updates status to past_due

No Setup Required

You don't need to configure a webhook endpoint for basic subscription management. The platform handles everything automatically.

App Webhook Forwarding

1

Configure in Dashboard

Go to App Settings → Billing → Webhooks and add your endpoint URL.

2

Select Events

Choose which events to forward to your app.

3

Copy Signing Secret

Copy the webhook signing secret to verify incoming webhooks.

app/api/webhooks/billing/route.ts
import { platform } from '@/lib/platform'
import { NextRequest } from 'next/server'

export async function POST(req: NextRequest) {
  const body = await req.text()
  const signature = req.headers.get('stripe-signature')!

  // Verify and parse the webhook
  const event = await platform.billing.verifyWebhook({
    body,
    signature,
    secret: process.env.SYLPHX_WEBHOOK_SECRET!,
  })

  switch (event.type) {
    case 'subscription.created':
      await sendWelcomeEmail(event.data.userId, event.data.plan)
      break

    case 'subscription.canceled':
      await sendCancellationSurvey(event.data.userId)
      break

    case 'payment.failed':
      await sendPaymentFailedEmail(event.data.userId)
      break

    case 'subscription.upgraded':
      await unlockFeatures(event.data.userId, event.data.newPlan)
      break
  }

  return new Response('OK', { status: 200 })
}

Webhook Events

Available webhook events for forwarding:

subscription.createdNew subscription started
subscription.upgradedUser upgraded to higher plan
subscription.downgradedUser downgraded to lower plan
subscription.canceledUser canceled subscription
subscription.renewedSubscription renewed for new period
subscription.expiredSubscription ended
trial.startedFree trial began
trial.endingTrial ends in 3 days
trial.endedTrial converted or expired
payment.succeededPayment processed successfully
payment.failedPayment failed

Event Payload

Webhook event structure:

PropertyTypeDescription
idstringUnique event ID
typestringEvent type (e.g., subscription.created)
createdAtDateWhen the event occurred
data.userIdstringUser ID
data.subscriptionIdstringSubscription ID
data.planobjectCurrent plan (id, slug, name)
data.previousPlanobject?Previous plan (for upgrades/downgrades)
data.statusstringSubscription status

Testing Webhooks

Test webhooks locally using the Stripe CLI:

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

# Login
stripe login

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

# Trigger test events
stripe trigger checkout.session.completed

Dashboard Testing

You can also send test webhook events from the Sylphx Dashboard under App Settings → Billing → Webhooks → Send Test Event.

Retry Policy

If your webhook endpoint returns a non-2xx status code, the platform retries with exponential backoff:

1st
1 min
2nd
5 min
3rd
30 min
4th
2 hours
5th
24 hours

After 5 failed attempts, the webhook is marked as failed. You can view failed webhooks and manually retry them in the dashboard.