Subscriptions
Manage recurring billing with trials, discounts, and lifecycle events
Subscriptions automate recurring billing by charging customers at regular intervals. RevKeen handles billing dates, invoicing, payment collection, and dunning automatically.
Subscription Lifecycle
| Status | Description | Billable |
|---|---|---|
trialing | In trial period | No |
active | Actively billing | Yes |
past_due | Payment failed, retrying | Yes (retry) |
paused | Temporarily paused | No |
cancelled | Cancelled, ending at period end | Until period end |
expired | Ended | No |
Creating Subscriptions
const subscription = await client.subscriptions.create({
customerId: 'cus_xxxxxxxx',
productId: 'prod_monthly',
// Optional: Start with a trial
trialDays: 14,
// Optional: Apply a discount
discountId: 'disc_xxxxxxxx',
// Optional: Custom billing anchor (day of month)
billingCycleAnchor: 1, // Bill on the 1st
});
console.log(subscription.data.status); // 'trialing' or 'active'If the product has a trial period defined, it will be applied automatically unless you explicitly set
trialDays: 0.Changing Plans
// Upgrade or downgrade immediately
const subscription = await client.subscriptions.update('sub_xxxxxxxx', {
productId: 'prod_enterprise',
proration: 'create_prorations', // Prorate the difference
});
// Proration options:
// - 'create_prorations': Credit for unused time, charge for new plan
// - 'none': No proration, new price starts next billing cycle
// - 'always_invoice': Create and finalize proration invoice immediatelyCancelling Subscriptions
// Cancel at end of billing period (recommended)
await client.subscriptions.cancel('sub_xxxxxxxx', {
cancelAtPeriodEnd: true,
});
// Cancel immediately (stop access now)
await client.subscriptions.cancel('sub_xxxxxxxx', {
cancelAtPeriodEnd: false,
});Immediate cancellation stops access right away. Use
cancelAtPeriodEnd: true to let customers use their remaining time.Pausing Subscriptions
// Pause immediately
await client.subscriptions.pause('sub_xxxxxxxx', {
pauseAt: 'now',
resumeAt: '2025-03-01T00:00:00Z', // Optional: Auto-resume date
});
// Pause at end of current billing period (recommended)
await client.subscriptions.pause('sub_xxxxxxxx', {
pauseAt: 'period_end',
});
// Resume manually
await client.subscriptions.resume('sub_xxxxxxxx');Using
pauseAt: 'period_end' lets customers use their remaining paid time before pausing.Billing Anchor Day
Set a specific day of the month for billing. The first invoice will be prorated to align with the anchor.
// Set billing anchor to the 15th of each month
await client.subscriptions.setBillingAnchor('sub_xxxxxxxx', {
day: 15, // 1-31
});
// For days 29-31, falls back to last day of short monthsProration Preview
Preview proration calculations before changing plans to show customers what they'll be charged.
// Get proration preview (newPlanId must be a UUID)
const preview = await client.subscriptions.prorationPreview('sub_xxxxxxxx', {
newPlanId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', // UUID of the new plan/price
});
console.log({
credit: preview.data.creditAmountMinor / 100, // Credit for unused time
debit: preview.data.debitAmountMinor / 100, // Charge for new plan
net: preview.data.netAmountMinor / 100, // Net charge/credit
daysRemaining: preview.data.daysRemaining,
});Smart Payment Retry
RevKeen automatically retries failed payments using smart logic that distinguishes between temporary and permanent failures.
| Failure Type | Examples | Retry Behavior |
|---|---|---|
Soft Decline | Insufficient funds, expired card | Retry on days 1, 3, 7 |
Hard Decline | Lost/stolen card, fraud | No retry, request new card |
Subscription Webhook Events
| Event | Description |
|---|---|
subscription.created | New subscription started |
subscription.updated | Plan changed or details updated |
subscription.cancelled | Subscription cancelled |
subscription.paused | Subscription paused |
subscription.resumed | Subscription resumed |
subscription.trial_ending | Trial ends in 3 days |
subscription.past_due | Payment failed |
subscription.expired | Subscription ended |