Concepts
Nine nouns. Learn these and the API reads itself — every endpoint is one of them, and every event is something happening to one of them.
The nouns
| Field | Type | Meaning |
|---|---|---|
| product | prd_… | You. Your vocabulary, your fee rule, your endpoints, your data. One product never sees another. |
| group | grp_… | A level of your hierarchy. A product names its own levels, however many it has. Your product names them. |
| holder | hld_… | Whoever the money is for. Each product chooses the word — a resident, a client, a membion product. |
| account | acc_… | A virtual account number at the bank. Permanent, and the thing money actually arrives on. |
| credit | crd_… | Money that arrived, priced. Immutable: a correction is a new entry, never an edit. |
| wallet | WALLET:… | A derived balance, not a stored one. The sum of its postings, computed when you ask. |
| journal | jrn_… | A balanced set of postings. Debits equal credits or it is not written at all. |
| settlement | stl_… | A bank cycle paying your collections account, linked to the credits it covers. |
| payout | pay_… | Money leaving, on request and approval. Recorded here, executed at the bank. |
Your words, not ours
Nineveh does not make your users learn its vocabulary. A product declares what its levels and holders are called, and every screen, export and report uses those words.
{
"levels": [
{ "singular": "Site", "plural": "Sites" },
{ "singular": "Meter", "plural": "Meters" }
],
"holder": { "singular": "Resident", "plural": "Residents" },
"walletLabel": "Available balance",
"payoutLabel": "Withdrawal"
}The structure is fixed; the labels are yours. A litigation product using the same code says Matter, Case, Client, Case balance and Disbursement, and nothing underneath changes.
Three statuses, never collapsed
A credit carries three independent statuses, and flattening them into one is how support tickets get born. They answer different questions and can disagree without anything being wrong.
| Field | Type | Meaning |
|---|---|---|
| creditStatus | RECEIVED | POSTED | Is it in the ledger? Answers: did the money land and get recorded. |
| deliveryStatus | PENDING | DELIVERED | RETRYING | DEAD_LETTERED | PAUSED | Does your product know? Answers: did the event reach you. |
| settlementStatus | UNSETTLED | LINKED | SETTLED | OVERDUE | Has the bank paid for it? Answers: is the cash actually ours yet. |
POSTED, DEAD_LETTERED and SETTLED at once: the money is real and in the bank, and your endpoint was down for two days. The tenant’s balance was right the whole time. That is exactly why these are three fields.Why a ledger at all
Because “what is this person’s balance?” must have one answer, and the only way to guarantee that is to derive it from entries rather than maintain it as a number. Every credit writes balanced journals; a balance is the sum of the postings against an account. Nothing increments a stored total, so nothing can drift.
a ₦10,150 top-up, priced at ₦100 institution + ₦50 product: DR POOL_RECEIVABLE:<bank> 10,150.00 CR WALLET:HOLDER:hld_01J9F2 10,000.00 ← the tenant's balance CR WALLET:PRODUCT_FEE 50.00 CR PASS_THROUGH:INSTITUTION_FEE 100.00
Nineveh’s own charge is a separate journal against the product, so it never touches what the tenant received. Every night an identity check asserts that assets equal liabilities; a difference is a break, and a break is a record.