Create and manage schedules

Create and manage scheduled payments by returning scheduling actions from your collection module lifecycle hooks.


Create a schedule

A collection module creates a scheduled payment by returning a schedule_payment action from a lifecycle hook.

The examples use addMonths as a date helper. Replace it with your module's date utility if you use a different one.

export const afterPolicyIssued = async ({ policy }) => {
  const billingPeriodEnd = addMonths(policy.first_debit_date, 1);

  return [
    {
      name: 'schedule_payment',
      scheduled_for: policy.first_debit_date,
      expected_amount: policy.premium_amount + (policy.outstanding_balance ?? 0),
      currency: policy.currency,
      premium_type: 'recurring',
      billing_period_start: policy.first_debit_date,
      billing_period_end: billingPeriodEnd,
      // payment_method_id omitted, so the platform uses the policy's payment method.
    },
  ];
};

The hook returns an array of actions. Return [] to schedule nothing. Return more than one action to schedule several payments at once.

Action fields

FieldRequiredDescription
nameYesAlways "schedule_payment".
scheduled_forYesThe date the payment is due. A calendar date, not a time, for example "2026-08-01".
expected_amountYesThe amount to collect, in the smallest currency unit.
currencyYesThe ISO currency code, for example "ZAR".
premium_typeYesThe kind of payment. Most schedules use recurring. Other values: pro_rata, arrears, ad_hoc, cover_period, collection_request, manual_eft, premium_refund.
billing_period_startYesThe first day of the period this payment covers.
billing_period_endYesThe last day of the period this payment covers.
payment_method_idNoA specific payment method. Leave it out to use the policy's payment method.

The platform validates each action, records the schedule, and emits a collection_scheduled event.


Make payments recur

A schedule_payment action schedules one payment. To collect every period, return a new action from the lifecycle hook that runs after each payment. Recurrence comes from your hooks, not from configuration.

  • afterPolicyIssued schedules the first payment when the policy goes live.
  • afterPaymentSucceeded schedules the next payment after each payment succeeds.
export const afterPaymentSucceeded = async ({ policy, payment }) => {
  const next = addMonths(payment.billing_period_start, 1);
  const nextPeriodEnd = addMonths(next, 1);

  return [
    {
      name: 'schedule_payment',
      scheduled_for: next,
      expected_amount: policy.premium_amount,
      currency: policy.currency,
      premium_type: 'recurring',
      billing_period_start: next,
      billing_period_end: nextPeriodEnd,
    },
  ];
};

afterPaymentSucceeded is what keeps the chain going. Each successful payment runs the hook again, and the hook returns the next schedule_payment. Your hook decides the next due date and amount, so you control the cadence.

Recurrence depends entirely on your hooks. If your module does not implement afterPaymentSucceeded or another hook that returns the next schedule_payment, a policy is scheduled once and never billed again.


Change or cancel a schedule

To move a scheduled payment to a different date, return a reschedule_payment action. To cancel one before it is created, return an unschedule_payment action. Both take the id of the schedule you are changing.

// Return these from a lifecycle hook, the same way you return schedule_payment actions.
// `scheduledPayment` is the schedule you are changing; your module looks it up (for example,
// from the hook input or by querying your own records).

// Move a scheduled payment to a new date.
return [
  {
    name: 'reschedule_payment',
    scheduled_payment_id: scheduledPayment.id,
    new_scheduled_for: '2026-08-01',
    reason: 'policyholder requested a later date', // optional
  },
];

// Cancel a scheduled payment.
return [
  {
    name: 'unschedule_payment',
    scheduled_payment_id: scheduledPayment.id,
    reason: 'policy_cancelled',
  },
];

reschedule_payment fields

FieldRequiredDescription
nameYesAlways "reschedule_payment".
scheduled_payment_idYesThe id of the schedule to move.
new_scheduled_forYesThe new due date.
reasonNoA short note on why it moved.

unschedule_payment fields

FieldRequiredDescription
nameYesAlways "unschedule_payment".
scheduled_payment_idYesThe id of the schedule to cancel.
reasonYesOne of "manual_admin", "payment_method_revoked", or "policy_cancelled".

The unschedule_payment reason must be one of the fixed values above; the reschedule_payment reason is free text.

A reschedule emits collection_rescheduled; an unschedule emits collection_unscheduled.


Next step

Submit scheduled payments if your collection module uses an API provider.