Subscriptions

Subscriptions connect organizations to plans through the active payment gateway. The billing system handles checkout, cancellation, resumption, invoices, and webhook events.

API Routes

POST   /api/billing/subscribe             # Create checkout session
GET    /api/billing/subscription           # Current subscription details
DELETE /api/billing/subscription           # Cancel at period end
POST   /api/billing/subscription/resume    # Resume cancelled subscription
GET    /api/billing/invoices               # List invoices
POST   /api/billing/portal                 # Get billing portal URL

Checkout Flow

When a user subscribes to a plan:

  • The client sends POST /api/billing/subscribe with the plan slug and billing interval
  • The server resolves the active gateway driver and calls checkoutUrl()
  • The gateway returns a hosted checkout URL (Stripe Checkout, Paddle overlay, etc.)
  • The user is redirected to complete payment on the gateway's hosted page
  • On success, the gateway sends a webhook to confirm the subscription
{
    "plan": "pro",
    "interval": "monthly"
}

The response contains the checkout URL for the client to redirect to:

{
    "checkout_url": "https://checkout.stripe.com/c/cs_live_..."
}

Cancellation

Cancelling a subscription does not take effect immediately. The subscription remains active until the end of the current billing period:

DELETE /api/billing/subscription
  • The subscription is marked as cancelling (ends at period end)
  • The user retains full access until the period expires
  • A SubscriptionCancelledNotification is sent to the organization owner

Resumption

A cancelled subscription can be resumed before the current period ends:

POST /api/billing/subscription/resume
  • Only works if the subscription has not yet expired
  • Removes the cancellation flag and continues billing normally

Webhook Handling

The BillingWebhookController processes events from the active gateway. Each gateway sends different event names, but the controller normalizes them into common actions:

  • payment_succeeded — Activates or renews the subscription
  • subscription_cancelled — Marks the subscription as cancelled
  • payment_failed — Flags the subscription and notifies the owner
  • subscription_updated — Syncs plan changes made outside the app
POST /api/billing/webhook    # Gateway webhook endpoint

Webhook signatures are verified using the gateway's webhook secret to prevent spoofed events.

Notifications

Billing events trigger notifications to the organization owner:

  • SubscriptionActivatedNotification — Sent when a subscription is successfully created or renewed
  • SubscriptionCancelledNotification — Sent when a subscription is cancelled
  • PaymentFailedNotification — Sent when a payment attempt fails, prompting the user to update their payment method