Skip to main content
Use Shoppex as the billing engine behind your SaaS. Your app handles signup, dashboard, and feature flags. Shoppex handles the checkout, card/PayPal/crypto, trials, renewals, failed-payment retries, and plan changes.

Why this works well

No Stripe integration to build

Shoppex already orchestrates PSPs. You get card, PayPal, and crypto without wiring each one.

Real subscription lifecycle events

Trial started, trial ended, renewed, cancelled, upcoming renewal โ€” Shoppex emits them all as webhooks.

Flow

  1. The user signs up in your app.
  2. Your backend creates a payment for the subscription product.
  3. The user completes payment in hosted checkout.
  4. Shoppex emits subscription lifecycle webhooks.
  5. Your app updates entitlements from those events.

Shape

PieceResponsibility
Your SaaS appSignup, user record, feature flags, cancellation UI
Webhook handlerToggle feature flags based on subscription lifecycle events
ShoppexPlan pricing, trial logic, renewal billing, dunning, crypto support

Feature-flag pattern

Link your user record to the Shoppex customer on signup, then toggle entitlements on subscription events:
// On signup
const { data: customer } = await shoppex.customers.create({ email: user.email });
await db.users.update({ where: { id: user.id }, data: { shoppexCustomerId: customer.id } });

// Webhook handler (abbreviated)
switch (event.event) {
  case 'subscription:trial:started':
  case 'subscription:created':
  case 'subscription:renewed':
    await db.users.update({
      where: { shoppexCustomerId: event.data.customer_id },
      data: {
        billingStatus: 'active',
        planActiveUntil: event.data.current_period_end,
      },
    });
    break;

  case 'subscription:cancelled':
  case 'subscription:trial:ended':
    await db.users.update({
      where: { shoppexCustomerId: event.data.customer_id },
      data: {
        billingStatus: 'canceled',
        planActiveUntil: event.data.current_period_end,
      },
    });
    break;
}
Treat planActiveUntil as the source of truth in your feature-flag middleware. subscription:cancelled means โ€œwill not renewโ€ โ€” the user still has access until current_period_end.

Subscription management

Expose plan changes inside your own UI by calling the Dev API from your backend:
  • POST /dev/v1/subscriptions/{id}/change-plan โ€” upgrade / downgrade
  • POST /dev/v1/subscriptions/{id}/pause / /resume
  • POST /dev/v1/subscriptions/{id}/cancel
  • GET /dev/v1/subscriptions/{id}/billing-history
You can build a full billing page without ever linking the user to a Shoppex-branded UI.

Pitfalls

  • Idempotency on signups โ€” if your signup and checkout are two clicks apart, send the same Idempotency-Key on retry or you will create duplicate subscriptions.
  • subscription:upcoming is your churn signal โ€” sent before the next renewal, good trigger for โ€œupgrade your planโ€ emails or feature-usage reminders.
  • Dunning is automatic โ€” Shoppex retries failed payments on its own schedule. Do not build your own retry loop on top.

Architecture Reference

Setup B (Next.js SSR) is the typical SaaS shape.

Dev API Subscriptions

Full subscription endpoint surface.