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. This page covers the complete subscription lifecycle.
Subscription Lifecycle
┌─────────┐ ┌──────────┐ ┌────────┐
│ PENDING │────>│ TRIALING │────>│ ACTIVE │
└─────────┘ └──────────┘ └───┬────┘
│
┌────────────────┼────────────────┐
│ │ │
v v v
┌──────────┐ ┌──────────┐ ┌──────────┐
│ PAST_DUE │ │ PAUSED │ │ CANCELED │
└────┬─────┘ └──────────┘ └──────────┘
│
v
┌──────────┐
│ UNPAID │
└────┬─────┘
│
v
┌──────────┐
│ EXPIRED │
└──────────┘Subscription Statuses
| Status | Description | Billing |
|---|---|---|
pending | Subscription created, awaiting first payment | Not billing |
trialing | In free trial period | Not billing |
active | Active and billing normally | Billing |
past_due | Payment failed, retrying | Attempting |
paused | Temporarily paused by customer or merchant | Not billing |
canceled | Subscription ended | Not billing |
unpaid | All payment retries exhausted | Stopped |
expired | Subscription term ended without renewal | Stopped |
Creating Subscriptions
Via Checkout
The most common way to create subscriptions is through checkout links:
- Create a checkout link with a recurring price
- Customer completes checkout
- Subscription is automatically created
- First invoice is generated and charged
Via API
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'subscription = client.subscriptions.create(
customer_id="cus_xxxxxxxx",
product_id="prod_monthly",
trial_days=14,
discount_id="disc_xxxxxxxx",
billing_cycle_anchor=1
)
print(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. The billing interval (e.g., "Billed monthly") is automatically shown on all invoices, receipts, and the checkout success page.
Subscription Items
A subscription can contain multiple items, similar to Stripe's model. This allows you to bundle multiple products in a single subscription.
// Subscription with multiple items
const subscription = await client.subscriptions.create({
customerId: 'cus_xxxxxxxx',
items: [
{
priceId: 'price_pro_monthly', // Pro plan at $49/mo
quantity: 1,
},
{
priceId: 'price_extra_users', // Extra users at $10/mo each
quantity: 5,
},
],
});
// Each item generates its own line on invoicesTrial Periods
Trials allow customers to try your product before paying:
- Subscription status is
trialing - Customer has full access during the trial
- No payment is collected
- At trial end, first invoice is created and charged
- If payment fails, subscription enters
past_due
Trial periods can be set on the Price or overridden when creating the subscription.
Billing Cycle
Each subscription has a billing cycle that determines when invoices are generated:
| Field | Description |
|---|---|
interval | Billing frequency: day, week, month, quarter, half_year, year |
interval_count | Number of intervals between charges (e.g., 2 with month = every 2 months) |
current_period_start | Start of current billing period |
current_period_end | End of current billing period |
billing_cycle_anchor | Day of month/year for billing (e.g., 1st of each month) |
The billing interval is automatically shown on invoices, receipts, and the checkout success page so customers always know when their next charge will occur.
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 immediatelyProration Preview
Preview proration calculations before changing plans to show customers what they will be charged.
// Get proration preview (newPlanId must be a UUID)
const preview = await client.subscriptions.prorationPreview('sub_xxxxxxxx', {
newPlanId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
});
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,
});Cancelling 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,
});Warning: Immediate cancellation stops access right away. Use
cancelAtPeriodEnd: trueto let customers use their remaining time.
Pausing Subscriptions
// Pause immediately
await client.subscriptions.pause('sub_xxxxxxxx', {
pauseAt: 'now',
resumeAt: '2026-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 monthsSmart 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 |
Order Creation on Renewal
When a subscription renews and the invoice is paid, RevKeen checks whether the subscription contains products with a fulfillment_type of physical or digital. If so, an Order is automatically created to track fulfillment for that billing period.
This means a subscription for a monthly physical product (e.g., a supplement box) will create a new order every month when the renewal invoice is paid. Products with
fulfillment_type: none(e.g., SaaS access) do not create orders.
Dunning (Payment Recovery)
When a subscription payment fails, RevKeen automatically enters the dunning process:
- Subscription status changes to
past_due - Payment is retried according to your retry schedule
- Customer receives reminder emails
- If all retries fail, subscription becomes
unpaidorcanceled
Configure dunning behavior at Settings > Dunning including retry intervals, email templates, and end behavior. See the Dunning page for details.
Subscription Events
| Event | When Triggered |
|---|---|
subscription.created | Subscription is created |
subscription.activated | Trial ends or first payment succeeds |
subscription.renewed | Billing period renews successfully |
subscription.updated | Plan changed or details updated |
subscription.paused | Subscription is paused |
subscription.resumed | Paused subscription resumes |
subscription.cancelled | Subscription is cancelled |
subscription.expired | Subscription term ended without renewal |
subscription.past_due | Payment failed, entering retry period |
subscription.unpaid | All payment retries exhausted |
subscription.trial_will_end | Trial period ending soon (3 days before) |
Related
- Products and Pricing -- Define subscription products with pricing
- Invoices and Orders -- How subscriptions generate invoices
- Dunning -- Configure payment recovery settings