Subscriptions
Recurring billing — plans, stored payment methods, and the subscription lifecycle. Access via zenpays.subscriptions.
The Python SDK does not yet expose a subscriptions namespace. Call the REST endpoints directly from Python.
Plans
A plan defines what is charged and how often. Subscriptions attach a customer to a plan.
createPlan
const plan = await zenpays.subscriptions.createPlan({
name: 'Pro Monthly',
amount: 2999,
currency: 'USD',
interval: 'month',
description: 'Pro tier, billed monthly',
intervalCount: 1, // 3 + 'month' would be quarterly
trialDays: 14,
})
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Plan name shown to customers |
amount | number | Yes | Amount charged each interval, in the currency's minor unit |
currency | string | Yes | ISO 4217 currency code |
interval | 'day' | 'week' | 'month' | 'year' | Yes | Billing interval |
description | string | No | Longer plan description |
intervalCount | number | No | Intervals between charges. Defaults to 1 |
trialDays | number | No | Free trial length in days |
metadata | Record<string, unknown> | No | Arbitrary key/value data |
Returns a SubscriptionPlan.
listPlans
const plans = await zenpays.subscriptions.listPlans()
Returns SubscriptionPlan[] for the authenticated merchant.
archivePlan
Stops new subscriptions on the plan. Existing subscriptions continue to bill.
const plan = await zenpays.subscriptions.archivePlan('plan_xxx')
getPublicPlan
Unauthenticated plan details, safe to render on a hosted subscribe page.
const plan = await zenpays.subscriptions.getPublicPlan('plan_xxx')
Payment methods
To charge a subscription automatically you need a stored payment method. Collect one on the client with a setup token, then store the resulting provider token.
createSetupToken
const setupToken = await zenpays.subscriptions.createSetupToken({
customerId: 'cust_xxx',
customerEmail: 'customer@example.com',
currency: 'USD',
})
| Parameter | Type | Required | Description |
|---|---|---|---|
customerId | string | Yes | Customer the method will belong to |
customerEmail | string | Yes | Customer email |
currency | string | No | Currency the method will be charged in |
tspProvider | string | No | Force a specific payment provider |
storePaymentMethod
const method = await zenpays.subscriptions.storePaymentMethod({
customerId: 'cust_xxx',
customerEmail: 'customer@example.com',
tspToken: 'tok_from_provider',
tspProvider: 'stripe',
type: 'card',
last4: '4242',
brand: 'visa',
expiryMonth: 12,
expiryYear: 2028,
})
tspToken is the provider token representing the instrument the customer entered. Raw card details never reach ZenPays.
listPaymentMethods
const methods = await zenpays.subscriptions.listPaymentMethods('cust_xxx')
revokePaymentMethod
await zenpays.subscriptions.revokePaymentMethod('spm_xxx')
Subscription lifecycle
create
const subscription = await zenpays.subscriptions.create({
customerId: 'cust_xxx',
customerEmail: 'customer@example.com',
planId: 'plan_xxx',
storedPaymentMethodId: 'spm_xxx',
})
| Parameter | Type | Required | Description |
|---|---|---|---|
customerId | string | Yes | Customer to subscribe |
customerEmail | string | Yes | Customer email |
planId | string | Yes | Plan to subscribe them to |
storedPaymentMethodId | string | No | Method to charge. Omit to require setup first |
tspProvider | string | No | Force a specific payment provider |
metadata | Record<string, unknown> | No | Arbitrary key/value data |
list
const all = await zenpays.subscriptions.list()
const active = await zenpays.subscriptions.list('active')
Optionally filtered by SubscriptionStatus.
get
const subscription = await zenpays.subscriptions.get('sub_xxx')
cancel
Cancels at the end of the current billing period by default.
// At period end — the customer keeps access until currentPeriodEnd
await zenpays.subscriptions.cancel('sub_xxx')
// Immediately
await zenpays.subscriptions.cancel('sub_xxx', { immediately: true })
pause
const subscription = await zenpays.subscriptions.pause('sub_xxx')
resume
const subscription = await zenpays.subscriptions.resume('sub_xxx')
Types
SubscriptionStatus
'trialing' · 'active' · 'past_due' · 'paused' · 'cancelled'
SubscriptionPlan
| Field | Type | Description |
|---|---|---|
planId | string | Plan identifier |
merchantId | string | Owning merchant |
name | string | Plan name |
description | string? | Plan description |
amount | number | Amount per interval |
currency | string | ISO 4217 currency code |
interval | BillingInterval | 'day' | 'week' | 'month' | 'year' |
intervalCount | number | Intervals between charges |
trialDays | number | Free trial length in days |
status | 'active' | 'archived' | Plan status |
metadata | Record<string, unknown>? | Arbitrary data |
Subscription
| Field | Type | Description |
|---|---|---|
subscriptionId | string | Subscription identifier |
merchantId | string | Owning merchant |
customerId | string | Subscribed customer |
customerEmail | string | Customer email |
planId | string | Plan being billed |
status | SubscriptionStatus | Current status |
collectionMethod | 'auto_charge' | 'send_invoice' | How each period is collected |
storedPaymentMethodId | string? | Method charged automatically |
tspProvider | string? | Payment provider |
currentPeriodStart | string | ISO 8601 timestamp |
currentPeriodEnd | string | ISO 8601 timestamp |
nextBillingAt | string | ISO 8601 timestamp of the next charge |
trialEnd | string? | ISO 8601 timestamp the trial ends |
cancelAtPeriodEnd | boolean | Whether cancellation is pending |
cancelledAt | string? | ISO 8601 timestamp of cancellation |
pausedAt | string? | ISO 8601 timestamp of pause |
StoredPaymentMethod
| Field | Type | Description |
|---|---|---|
storedPaymentMethodId | string | Method identifier |
merchantId | string | Owning merchant |
customerId | string | Owning customer |
customerEmail | string | Customer email |
tspProvider | string | Payment provider |
type | string | Instrument type, e.g. card |
brand | string? | Card brand |
expiryMonth | number? | Card expiry month |
expiryYear | number? | Card expiry year |
isActive | boolean | Whether the method can still be charged |
metadata | Record<string, unknown>? | Arbitrary data |