Skip to main content
When you subscribe a customer to a plan, you’re telling us: charge this customer this amount on this schedule, automatically, until further notice. That’s a subscription. It handles renewals, state transitions, and collection — you just listen to webhooks and gate access accordingly.

Lifecycle

State reference

During past_due and grace, the customer still has access — cutting them off immediately for one failed payment loses customers unnecessarily. Once delinquent, access is cut until they pay.

Two billing rails

Card billing — You tokenise the customer’s card once via Nomba, pass the token when creating the subscription. On each renewal, we charge the card automatically. Transfer billing — The customer has a dedicated virtual account number (bank name + account number). On renewal, instead of charging a card, we open an invoice and wait for the customer to send a bank transfer. When it arrives, we match it automatically and close the invoice. Set the rail on subscription creation:

Create a subscription

Response
boolean
true when the subscription is set to cancel at period end (still active until then). Toggle with cancel / reactivate.
boolean
Whether a card token is on file. Transfer-funded subscriptions have none, so renewals need manual payment — a cue to nudge the customer to add a card.
object | null
A pending period-end plan change (e.g. a scheduled downgrade): { id, new_plan_id, new_quantity, scheduled_for }. The current plan runs until scheduled_for, then switches.

One subscription per customer

By default a customer can have one live subscription per plan-group. Creating a second while one is still live (any non-canceled state) returns 409 customer_already_subscribed with the existing subscription’s id — reuse it (change its plan, or cancel it) rather than creating a duplicate:
409
Integrators that genuinely need concurrent subscriptions can set allow_multiple_subscriptions: true in their policy.
Use idempotency keys on subscription creation. If your request times out and you retry, the same key returns the original response instead of creating a duplicate subscription.