Create a Direct-Debit Subscription
A direct-debit subscription lets the merchant pull recurring payments directly from the customer’s bank account. Instead of a card token, the payment source is a mandate issued by the customer’s bank via Nomba. Once active, each billing cycle triggers a debit against that mandate.In a nutshell
Prerequisites
- A plan with a recurring interval. Create one with
POST /v1/plan/. - The customer’s bank account details and phone number.
1. Initialize the mandate
NombaInitiation and calls Nomba to register the mandate. On success it returns a mandate ID:
Field notes
bankCode— 3-digit CBN code. Examples:058GTBank,011First Bank,044Access,057Zenith,033UBA.customerPhoneNumber— Nomba expects the international form234...(with or without a leading+).startDate/endDate— Nomba’s Jackson deserializer treats these asLocalDateTime. The engine already reformats them for you; if you’re calling Nomba directly, useYYYY-MM-DDTHH:MMwithout any timezone offset.frequency— acceptsMONTHLY,WEEKLY,QUARTERLY, and other cadences documented by Nomba. Must be consistent with the plan interval.
2. Customer authorizes the mandate
Out-of-band: the customer receives an approval prompt from their bank (SMS or bank app) and confirms. Nomba then flips the mandate to:mandateStatus = ActivemandateAdviceStatus = ADVICE_SENT
3. Engine activates the subscription
The moment Nomba reportsActive + ADVICE_SENT, the engine — inside a single database transaction — does the following:
- Creates a
PaymentSourceof typebankwith the mandate attached and statusactive. - Creates a
Subscription(active, ortrialingif the plan has a trial period). - Marks the
NombaInitiationascompleted. - Enqueues
mandate.activatedandsubscription.createdwebhooks. - Enqueues the “subscription started” email to the customer.
4. Recurring debits
On every billing cycle, the invoice-processing cron opens the invoice and calls Nomba’sdebit-mandate endpoint against the saved payment source. On success:
invoice.paidwebhook fires.mandate.debit_successwebhook fires.- A
Settlementrow is created for the merchant’s next payout.
PaymentIntentis marked failed with afailureReason.- If
allowRetrieswastrueon the subscription, the invoice is scheduled 24h later and the subscription moves topast_due. - After exhausted retries (or a non-transient failure), the invoice is marked
failed, the subscription ispaused, and the customer gets a “subscription paused” email.
5. Cancellation
To cancel a direct-debit subscription — for example when the merchant terminates it — callPUT /v1/subscription/:idOrCode/mandate:
SUSPENDED, DELETED. The engine updates the mandate at Nomba, marks the payment source inactive, and emits the corresponding mandate.* webhook. To cancel just the subscription (without touching the mandate), use POST /v1/subscription/:idOrCode/cancel.
Common failure modes
Invalid phone number— use the international form234....startDate must be a date in the present or in the future— Nomba compares against wall-clock time; the engine already bumps past-times tonow, but if you’re constructing the payload yourself, send a fresh timestamp.Failed to retrieve Mandate Statusduring polling — usually a stale sandbox mandate. The backoff scheduler stretches the retry interval automatically; nothing to do.- Mandate stays in
ADVICE_NOT_SENT— Nomba hasn’t dispatched the advice to the bank yet. Sandbox usually catches up within a few minutes; in production this can take longer depending on the bank.
Related
- Card-backed subscription — the sibling flow that uses a tokenized card instead of a mandate.
- Subscription states — the full lifecycle diagram including
past_due,paused, andattention. - Test billing flow — walking through webhooks and settlements end-to-end.
