Payment Plans
Payment plans are recurring billing schedules. AccruPay charges a customer's stored payment method on a defined interval — weekly, monthly, annually, or any custom cadence — without any session or frontend interaction after the plan is created.
Two-object model
AccruPay separates the billing schedule from the customer enrollment:
| Object | What it represents |
|---|---|
| Payment Plan Template | A reusable billing definition: amount, currency, interval, trial period, end condition. One template can back many customer plans. |
| Payment Plan | The live instance: a specific customer's stored payment method enrolled in a template. This is what AccruPay charges on schedule. |
This separation lets you define your pricing catalog once and create plans for individual customers by reference.
Payment Plan Templates
A template is the blueprint. Create it once per billing product.
import AccruPay, { CURRENCY, PAYMENT_PLAN_TEMPLATE_STATUS } from '@accrupay/node';
const sdk = new AccruPay({ apiSecret: process.env.ACCRUPAY_API_SECRET });
const template = await sdk.paymentPlanTemplates.createOne({
merchantTransactionProviderId: 'provider-id',
data: {
name: 'Pro Monthly',
amount: 4900n, // $49.00 in cents
initialAmount: 4900n, // first charge; omit to use amount
currency: CURRENCY.USD,
providerStatus: PAYMENT_PLAN_TEMPLATE_STATUS.ENABLED,
renewalIntervalMonths: 1, // charge every month
endsAfterMonths: 12, // plan ends after 12 charges
trialPeriodDays: 14, // 14-day free trial before billing starts
},
});
Template schedule fields
| Field | Description |
|---|---|
amount | Amount charged on each renewal, in minor units (BigInt). |
initialAmount | Amount for the first charge. Defaults to amount if omitted. |
currency | ISO 4217 currency code. |
renewalIntervalDays | Interval between charges in days. |
renewalIntervalMonths | Interval between charges in months. |
renewalIntervalYears | Interval between charges in years. |
endsAfterDays | Plan duration in days. Omit for indefinite billing. |
endsAfterMonths | Plan duration in months. |
endsAfterYears | Plan duration in years. |
trialPeriodDays | Free period in days before the first charge. |
trialPeriodMonths | Free period in months. |
trialPeriodYears | Free period in years. |
Use one field per dimension — set renewalIntervalMonths: 1 for monthly, not a combination of days and months.
Template statuses
| Status | Meaning |
|---|---|
ENABLED | Template is active; new plans can be created from it. |
DISABLED | Template is inactive; existing plans are not affected, but new enrollments should use a different template. |
Creating a Payment Plan
Once you have a template and a stored payment method, create the plan. AccruPay begins scheduling charges immediately (after any trial period).
Payment plans require the customer to have a stored payment method first. See Stored Payment Methods for how to save one.
const plan = await sdk.paymentPlans.createOne({
merchantTransactionProviderId: 'provider-id',
data: {
merchantInternalPaymentPlanCode: 'plan-customer-123', // your own idempotency key
templateId: template.id,
paymentMethodId: 'payment-method-id', // stored payment method
amount: 4900n,
initialAmount: 4900n,
currency: CURRENCY.USD,
renewalIntervalMonths: 1,
endsAfterMonths: 12,
trialPeriodDays: 14,
customer: {
merchantInternalCustomerCode: 'customer-123',
},
},
});
Plan lifecycle
INITIALIZING → ACTIVE → ENDED (plan ran its full term)
↘ CANCELED (explicitly canceled)
↘ INACTIVE (temporarily paused)
↘ ERROR (provider-reported failure)
| Status | Meaning |
|---|---|
INITIALIZING | Plan created; provider is setting it up. |
ACTIVE | Plan is running; charges occur on schedule. |
INACTIVE | Plan is paused. No charges occur until reactivated. |
CANCELED | Plan was explicitly canceled. Terminal state. |
ENDED | Plan ran its full term (endsAfter* elapsed). Terminal state. |
ERROR | Provider reported an unrecoverable failure. |
Canceling a plan
await sdk.paymentPlans.cancelOne({
id: plan.id,
});
Cancellation is immediate and terminal. The stored payment method is not affected.
Syncing plan state
A plan's status can change outside your system — the provider may pause or error a plan following a failed charge. Call syncOne() to pull the latest state.
const updated = await sdk.paymentPlans.syncOne({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
providerCode: plan.providerCode,
});
Templates can also be synced if you suspect their provider-side configuration has drifted:
const updatedTemplate = await sdk.paymentPlanTemplates.syncOne({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
providerCode: template.providerCode,
});
Key SDK methods
sdk.paymentPlanTemplates.createOne()— define a billing schedulesdk.paymentPlanTemplates.updateOne()— modify a template's fieldssdk.paymentPlanTemplates.syncOne()— pull latest template state from providersdk.paymentPlans.createOne()— enroll a customersdk.paymentPlans.cancelOne()— cancel a running plansdk.paymentPlans.syncOne()— pull latest plan state from provider