Skip to main content

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:

ObjectWhat it represents
Payment Plan TemplateA reusable billing definition: amount, currency, interval, trial period, end condition. One template can back many customer plans.
Payment PlanThe 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

FieldDescription
amountAmount charged on each renewal, in minor units (BigInt).
initialAmountAmount for the first charge. Defaults to amount if omitted.
currencyISO 4217 currency code.
renewalIntervalDaysInterval between charges in days.
renewalIntervalMonthsInterval between charges in months.
renewalIntervalYearsInterval between charges in years.
endsAfterDaysPlan duration in days. Omit for indefinite billing.
endsAfterMonthsPlan duration in months.
endsAfterYearsPlan duration in years.
trialPeriodDaysFree period in days before the first charge.
trialPeriodMonthsFree period in months.
trialPeriodYearsFree period in years.

Use one field per dimension — set renewalIntervalMonths: 1 for monthly, not a combination of days and months.

Template statuses

StatusMeaning
ENABLEDTemplate is active; new plans can be created from it.
DISABLEDTemplate 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).

note

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)
StatusMeaning
INITIALIZINGPlan created; provider is setting it up.
ACTIVEPlan is running; charges occur on schedule.
INACTIVEPlan is paused. No charges occur until reactivated.
CANCELEDPlan was explicitly canceled. Terminal state.
ENDEDPlan ran its full term (endsAfter* elapsed). Terminal state.
ERRORProvider 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 schedule
  • sdk.paymentPlanTemplates.updateOne() — modify a template's fields
  • sdk.paymentPlanTemplates.syncOne() — pull latest template state from provider
  • sdk.paymentPlans.createOne() — enroll a customer
  • sdk.paymentPlans.cancelOne() — cancel a running plan
  • sdk.paymentPlans.syncOne() — pull latest plan state from provider