Subscriptions
Manage recurring SaaS plans, customer billing portals, and plan status.
Subscriptions belong to teams. Subscription.teamId is unique, and the current record includes provider/customer IDs, plan and variant IDs, status and an optional next payment date.
Supported status values are TRIALING, ACTIVE, PAUSED, CANCELED, PAST_DUE, UNPAID, INCOMPLETE and EXPIRED. Their access implications depend on the product and provider event handling; a PAST_DUE value alone does not implement a grace period, and CANCELED alone does not guarantee access until a future date.
Customer portal
Reuse billing.createCustomerPortalLink rather than creating an unguarded provider session. It accepts subscriptionId and optional redirectUrl, loads the subscription, requires ownership of its team, and returns a URL string from the selected adapter. The default return path is /app/settings/team/billing; cross-origin return URLs are rejected.
const portal = apiClient.billing.createCustomerPortalLink.useMutation();
const url = await portal.mutateAsync({ subscriptionId });
window.location.href = url;This excerpt belongs in a client component using apiClient from @shared/lib/api-client; the existing billing UI handles loading and errors.
Pause, resume, cancellation and seat updates depend on the adapter's optional methods. Unsupported operations throw clear errors, and one-time purchases are excluded from these operations. Verify the selected provider's capabilities before exposing controls.