Recurring billing engine for Nigeria. Subscription state machine, dunning loop, proration math, Nomba payments, PDF invoicing. Next.js monolith.
# NomSubz
**A managed recurring-billing engine built on top of Nomba's payment primitives.**
NomSubz wraps Nomba's Checkout, Tokenised Cards, Charge API, and Transfers into a full subscription-management layer, so downstream product teams can offer recurring billing without building state machines, dunning logic, or proration math themselves.
---
## Features
- 🔁 **Subscription state machine** — `incomplete → active → past_due → paused/canceled`
- 💳 **Tokenized card billing** via Nomba's Charge API
- 📉 **Dunning loop** — automatic retries and email notifications on failed payments (Day 1 / Day 3 / Day 7)
- ⏸️ **Delayed pause** — users keep access until the end of their paid period
- 🧮 **Accurate proration** — `decimal.js`-based math with defensive clamping, no floating-point drift
- 🧾 **Invoices & PDFs** — generated on the fly
- 🔐 **Secure by design** — HMAC-verified webhooks, hashed server-to-server API keys
- 🔔 **Webhook registration** — downstream products can subscribe to engine events
---
## Tech Stack
| Layer | Choice |
| --------------- | ------------------------------------------------------------------- |
| Framework | Next.js (Node.js / TypeScript monolith) |
| Database | PostgreSQL |
| Background Jobs | `pg-boss` (SQL-backed queue, avoids Redis cache-eviction conflicts) |
| Scheduler | Lightweight DB-backed cron / event-driven trigger |
| Payments | Nomba (Checkout, Tokenised Cards, Charge API, Transfers) |
---
## Database Schema
The core of the engine is the `subscriptions` table:
```sql
CREATE TABLE subscriptions (
id SERIAL PRIMARY KEY,
customer_id VARCHAR(255) NOT NULL,
plan_id VARCHAR(255) NOT NULL,
status VARCHAR(50) NOT NULL, -- 'active', 'past_due', 'paused', 'canceled'
current_period_start TIMESTAMP WITH TIME ZONE NOT NULL,
cur …