Skip to main content

Payment Plans

A payment plan is a live subscription instance that ties a plan template to a specific customer and stored payment method. Once created, AccruPay charges the stored payment method on the renewal schedule defined by the template.


Prerequisites

Before creating a plan you need:

  1. A plan template — see Plan Templates
  2. A stored customer payment method — obtained by completing a checkout or save-a-card flow with storePaymentMethod: true

Create a plan

import AccruPay, { CURRENCY, PAYMENT_PLAN_STATUS } from '@accrupay/node';

const sdk = new AccruPay({
apiSecret: process.env.ACCRUPAY_API_SECRET!,
});

const plan = await sdk.paymentPlans.createOne({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
data: {
merchantInternalPaymentPlanCode: 'plan-customer-123',
templateId: template.id,
paymentMethodId: storedPaymentMethod.id,
amount: 2999n,
initialAmount: 2999n,
currency: CURRENCY.USD,
customer: {
merchantInternalCustomerCode: 'customer-123',
},
// All interval/duration/trial integers are required — send 0 for unused units
renewalIntervalDays: 0,
renewalIntervalMonths: 1,
renewalIntervalYears: 0,
endsAfterDays: 0,
endsAfterMonths: 12,
endsAfterYears: 0,
trialPeriodDays: 14,
trialPeriodMonths: 0,
trialPeriodYears: 0,
},
});

console.log(plan.id, plan.status);
note

templateId and paymentMethodId are both required. The plan will be rejected if either references an invalid or inactive record.


Plan lifecycle

INITIALIZING


ACTIVE ──────────────────────────────────────────────► ENDED
│ (endsAfterX reached)
│──────────────────────────────────────────────────► CANCELED
│ (cancelOne() called)
│──────────────────────────────────────────────────► INACTIVE
│ (provider paused)
└──────────────────────────────────────────────────► ERROR
(provider failure)
StatusDescription
INITIALIZINGPlan is being set up on the provider
ACTIVEPlan is running — renewals will be charged automatically
INACTIVEPlan is paused by the provider but not canceled
CANCELEDPlan was explicitly canceled via cancelOne()
ENDEDPlan reached its natural end date (endsAfterX condition met)
ERRORProvider encountered an unrecoverable error

Cancel a plan

await sdk.paymentPlans.cancelOne({
merchantPaymentPlanId: plan.id,
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
});

Cancellation stops future renewals. Any already-charged periods are not refunded automatically.


Query plans

List plans

getMany() supports rich filtering:

const plans = await sdk.paymentPlans.getMany({
// Filter options (all optional)
merchantInternalCustomerCode: 'customer-123',
templateId: template.id,
currency: CURRENCY.USD,
providerStatus: PAYMENT_PLAN_STATUS.ACTIVE,
take: 20,
skip: 0,
});

Fetch a single plan

const plan = await sdk.paymentPlans.getOne({
merchantPaymentPlanId: plan.id,
});

Sync a plan

Pull the latest plan state from the provider. Use this after a webhook or to confirm a cancellation took effect:

const synced = await sdk.paymentPlans.syncOne({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
providerCode: plan.providerCode,
});

Plan field reference

Key fields on the plan object returned by the API:

FieldTypeDescription
statusPAYMENT_PLAN_STATUSCurrent lifecycle status
currentPeriodStartDateStart of the current billing period
currentPeriodEndDateEnd of the current billing period
startedAtDate | nullWhen the plan became active
endsAtDateScheduled end of the plan
trialEndsAtDateWhen the trial period ends
canceledAtDate | nullWhen the plan was canceled
periodCountnumberNumber of completed billing cycles

Next steps