Subscriptions
Manage customer subscriptions, handle lifecycle events, and check subscription status.
Subscription Lifecycle
Subscriptions flow through these states:
trialing— Free trial period (payment method may or may not be required)active— Subscription is paid and activepast_due— Payment failed, in grace periodpaused— Temporarily paused by customer or admincanceled— Subscription ended
Get Current Subscription
Retrieve the active subscription for a customer. Use the expand parameter to include plan details.
Using the SDK
import { StackBE } from '@stackbe/sdk';
const stackbe = new StackBE({
apiKey: process.env.STACKBE_API_KEY!,
appId: process.env.STACKBE_APP_ID!,
});
// Get subscription with plan details
const subscription = await stackbe.subscriptions.get(customerId, {
expand: ['plan'],
});
console.log(subscription);
// {
// id: 'sub_xyz789',
// status: 'active',
// planId: 'plan_pro',
// plan: {
// id: 'plan_pro',
// name: 'Pro Plan',
// priceCents: 2900,
// interval: 'month',
// entitlements: { api_calls: 10000, premium_support: true }
// },
// currentPeriodStart: '2025-01-15T00:00:00Z',
// currentPeriodEnd: '2025-02-15T00:00:00Z',
// cancelAtPeriodEnd: false
// }Via API
curl "https://api.stackbe.io/v1/subscriptions/current?customerId=cust_abc123&expand=plan" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "x-stackbe-tenant-id: your_tenant_id"Check Access (Recommended)
Use checkAccess() to determine if a customer should have access. This respects grace periods for failed payments.
// Returns true if subscription is active OR in grace period
const hasAccess = await stackbe.subscriptions.checkAccess(customerId);
if (!hasAccess) {
// Redirect to pricing page or show upgrade prompt
return redirect('/pricing');
}
// Customer has access, continue with your app logicWhy use checkAccess? When a payment fails, you typically want to give customers a grace period (configured in your app settings) rather than immediately cutting off access. checkAccess() handles this automatically.
Cancel Subscription
Cancel a subscription. By default, access continues until the end of the billing period.
// Cancel at end of billing period (recommended)
await stackbe.subscriptions.cancel(subscriptionId);
// Cancel immediately (rare - use for refunds, fraud, etc.)
await stackbe.subscriptions.cancel(subscriptionId, {
immediate: true,
});Via API
# Cancel at period end
curl -X POST "https://api.stackbe.io/v1/subscriptions/sub_xyz789/cancel" \
-H "Authorization: Bearer sk_live_your_api_key"
# Cancel immediately
curl -X POST "https://api.stackbe.io/v1/subscriptions/sub_xyz789/cancel" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"immediate": true}'Pause & Resume
Allow customers to temporarily pause their subscription. Billing stops during the pause.
// Pause subscription
await stackbe.subscriptions.pause(subscriptionId);
// Resume subscription
await stackbe.subscriptions.resume(subscriptionId);Note: Paused subscriptions don't have access to paid features. Use checkAccess() to handle this correctly.
Change Plan (Upgrade/Downgrade)
To change a customer's plan, create a new checkout session. Stripe handles proration automatically.
// Create checkout for plan change
const { url } = await stackbe.checkout.createSession({
customerId: customerId,
planId: 'plan_enterprise', // New plan
successUrl: 'https://yourapp.com/settings?upgraded=true',
cancelUrl: 'https://yourapp.com/settings',
});
// Redirect customer to checkout
redirect(url);When upgrading, the customer pays the prorated difference immediately. When downgrading, they receive credit toward future invoices.
Dunning & Payment Recovery
When a payment fails, StackBE automatically enters dunning mode. Check the dunning status to show appropriate UI.
const dunning = await stackbe.subscriptions.getDunningStatus(subscriptionId);
console.log(dunning);
// {
// inDunning: true,
// daysPastDue: 3,
// gracePeriodDays: 7,
// gracePeriodEndsAt: '2025-01-22T00:00:00Z',
// hasAccess: true, // Still in grace period
// nextRetryAt: '2025-01-18T00:00:00Z'
// }
if (dunning.inDunning) {
// Show payment update prompt
showPaymentUpdateBanner({
daysRemaining: dunning.gracePeriodDays - dunning.daysPastDue,
});
}List Past Subscriptions
Retrieve subscription history for a customer.
// Get all subscriptions (including canceled)
const history = await stackbe.customers.getSubscriptionHistory(customerId);
// Returns array of subscriptions with status, dates, and plan infoSubscription Object
interface Subscription {
id: string;
customerId: string;
organizationId?: string; // For B2B/team subscriptions
planId: string;
plan?: Plan; // Included with expand=plan
status: 'trialing' | 'active' | 'past_due' | 'paused' | 'canceled';
currentPeriodStart: string;
currentPeriodEnd: string;
cancelAtPeriodEnd: boolean;
canceledAt?: string;
trialEndsAt?: string;
createdAt: string;
}