Scheduled payments example

A simple monthly card module uses an addMonths date helper. It bills the premium only; see Create and manage schedules for adding arrears with outstanding_balance.


Configure billing settings

{
  "billingSettings": {
    "batching": {
      "enabled": true,
      "submitPaymentsFunction": "submitPayments",
      "submitBatchSize": 100,
      "scheduleTimeUtc": "05:00",
      "submissionLeadTime": 2,
      "latestSubmissionTimeUtc": "20:00"
    },
    "retry": { "maxAttempts": 3, "backoffDays": 1, "backoffMultiplier": 2 }
  }
}

Add lifecycle hooks

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,
      currency: policy.currency,
      premium_type: 'recurring',
      billing_period_start: policy.first_debit_date,
      billing_period_end: billingPeriodEnd,
    },
  ];
};

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,
    },
  ];
};

afterPolicyIssued schedules the first payment at issue. afterPaymentSucceeded schedules the next month after each success.


Add the submission hook

export const submitPayments = async ({ payments }) => {
  const results = await Promise.all(
    payments.map(async (p) => {
      try {
        // `provider` is your payment provider's client.
        const charge = await provider.charge({
          amount: p.amount,
          currency: p.currency,
          idempotencyKey: p.payment_id,
        });

        return {
          payment_id: p.payment_id,
          status: 'submitted',
          provider_reference: charge.id,
        };
      } catch (error) {
        return {
          payment_id: p.payment_id,
          status: 'failed',
          failure_reason: error instanceof Error ? error.message : 'provider_submission_failed',
        };
      }
    }),
  );

  return { results };
};

This module schedules the first payment at issue, charges it through its provider on the due date, and schedules the next month after each success.


Related guides



Did this page help you?