CentraPoint

Guides

Recurring billing

Two ways to bill customers repeatedly: gateway-managed card subscriptions, or an invoice per billing cycle.

On this page

Choosing an approach#

Recurring billing approaches
Card subscriptionInvoice per cycle
How the customer paysCard charged automatically each cycle by the gatewayCustomer pays each invoice via its pay link (or EFT)
Who schedulesThe gatewayYour system (or a scheduled job)
Amount per cycleFixedCan change every cycle (usage, pro-rata, add-ons)
GatewaysPayFast, Netcash Pay Now (ZAR)Any gateway that accepts the currency, plus offline payments
PlanRecurring card billing feature (Growth and above)Invoicing feature
APIPayment links + SubscriptionsCustomers + Invoices

Option 1: card subscriptions#

The customer pays once through a recurring payment link; the gateway stores the card and charges it on each cycle. Gateways with recurring support are PayFast and Netcash Pay Now. Only gateways that support recurring payments are offered to the payer on a recurring link.

Start a subscription#

curl -X POST "https://app.centrapoint.co.za/api/v1/payment-links" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 0f2e4d6c-8b1a-4c3e-9f5d-7a2b4c6e8d10" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Pro plan",
    "amount": 499,
    "currency": "ZAR",
    "externalReference": "SUB-ACME-PRO",
    "customerId": "cmg2c0s7t0003cust0001abcd",
    "recurring": {
      "frequency": "monthly"
    },
    "metadata": {
      "plan": "pro"
    },
    "returnUrl": "https://app.example.co.za/billing/done"
  }'
  • recurring.frequency: monthly, quarterly, biannually or annually.
  • recurring.amount (optional) is charged on each later cycle; it defaults to the link amount. Use it for a different first payment, e.g. a setup fee.
  • The request fails with 400 if your plan lacks recurring billing or none of your enabled gateways can bill the currency automatically.

When the first payment completes you receive subscription.activated (and payment.complete); the subscription then appears in GET /api/v1/subscriptions?externalReference=SUB-ACME-PRO, and the payment carries its subscriptionId.

Renewals#

Each later collection is a new transaction with its own reference, renewal: true, parentReference (the first payment) and subscriptionId. You get payment.complete or payment.failed for each one, plus a subscription event.

Subscription webhooks#

Subscription webhooks
EventWhenTypical action
subscription.activatedFirst payment completedGrant access until periodEnd
subscription.chargedRenewal collectedExtend access to the new periodEnd
subscription.payment_failedRenewal failedWarn the customer; suspend if it stays unpaid
subscription.cancelledCancelled via API, dashboard or gatewayStop access at the end of the paid period
subscription.pausedPaused via API or dashboardKeep access until the paid period ends; stop renewing it
subscription.resumedResumed via API or dashboardRenew access again from the next collection

data is the subscription object plus subscriptionId; the first three events add payment (reference, amount, currency, status, paidAt) and periodStart/periodEnd for the period paid. See Subscription events.

Pausing, resuming and cancelling#

Pause a PayFast subscription with POST /api/v1/subscriptions/{id}/pause and resume it with /resume; Netcash Pay Now subscriptions can only be cancelled. See the rules. To cancel:

curl -X POST "https://app.centrapoint.co.za/api/v1/subscriptions/cmg2s5b8k0007sub0001abcd/cancel" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Returns the subscription with status: "cancelled" and sends subscription.cancelled. See Subscriptions errors for gateway failures.

Option 2: an invoice per cycle#

Your system decides what to bill each cycle and creates an invoice; CentraPoint emails it with a pay link and tells you when it is paid. CentraPoint does not schedule these invoices for you: run your own job (for example on the 1st of each month).

Each cycle#

  1. Make sure the customer exists (upsert once with POST /api/v1/customers and your customer ID as externalReference).
  2. Create the invoice with an externalReference unique to the customer and cycle, and send: true. Because creation is idempotent on externalReference, re-running the job for the same cycle never bills twice.
curl -X POST "https://app.centrapoint.co.za/api/v1/invoices" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "externalReference": "CRM-1001"
    },
    "externalReference": "CRM-1001-2026-10",
    "lines": [
      {
        "description": "Pro plan - October 2026",
        "quantity": 1,
        "unitPrice": 434.78
      },
      {
        "description": "Extra users (3)",
        "quantity": 3,
        "unitPrice": 43.48
      }
    ],
    "metadata": {
      "period": "2026-10"
    },
    "send": true
  }'

Tracking payment#

  • Listen for invoice.paid, invoice.partially_paid and invoice.cancelled webhooks; data is the invoice.
  • If the customer pays by EFT, record it with POST /api/v1/invoices/{id}/payments.
  • Chase unpaid invoices with GET /api/v1/invoices?status=overdue and send them again.

Bank debit orders#

For collecting directly from South African bank accounts, CentraPoint also supports Netcash debit orders from the dashboard. See Debit orders & reconciliation.