Lifecycle
State reference
| State | What’s happening | Customer access | What’s next |
|---|---|---|---|
incomplete | Strict activation — awaiting first payment | No access | Activates when the checkout payment settles |
trialing | Free trial running, no charge yet | Full access | Converts to active when trial ends |
active | All good, payments collecting | Full access | Renews at next_bill_at |
past_due | First renewal attempt failed | Full access | Retry schedule starts |
grace | All retries exhausted, grace window open | Full access | Grace expires → delinquent |
delinquent | Grace expired, no payment | No access | Customer needs to pay to restore |
paused | Manually paused | No access | Resume when ready |
canceled | Ended | No access | Final state |
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
true when the subscription is set to cancel at period end (still active until then). Toggle with
cancel / reactivate.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.
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
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.