Interest accrual
Earning interest daily, paying it monthly. The gap matters.
By Solomon Ajayi · Free to read, no signup
A user has ₦100,000 in a savings wallet. Your platform pays 6% annual interest. You do NOT credit ₦6,000 once a year, you accrue interest as an expense + payable every period, then capitalize it to the user's wallet on a schedule. The gap between accruing and capitalizing is when interest is 'earned' but not yet 'spendable.'
Interest builds up continuously, but it lands in the user's wallet only on a schedule. If you wait until the schedule to record anything, your books understate what you owe every single day in between. Accrual accounting closes that gap: at the end of each period you recognize the interest that has been earned even though no money has moved into the wallet yet.
An accrual touches two accounts that have nothing to do with the user's spendable balance. Interest Expense goes up, because paying interest is a real cost to your platform. Interest Payable goes up, because you now owe the user that amount even though it is not in their wallet. The savings wallet itself does not move on accrual; it only moves later, at capitalization, when Interest Payable is drawn down and the wallet is credited.
Splitting the two also makes the cost visible at the right cadence. You see the interest expense hit your P&L every period as it accrues, not in one lump when you capitalize, so your margins are honest month to month. And once capitalized interest joins the wallet balance, the next period accrues on the larger number, which is exactly how compounding falls out of the schedule for free.
Worked example, step by step
Set the stage: user has ₦100,000 in savings
User deposited ₦100,000 into their savings wallet at some point. We seed that state.
| Account | Debit | Credit |
|---|---|---|
| Bank Account (1200) | ₦100,000.00 | |
| User Savings Wallet (2000) | ₦100,000.00 |
Bank UP ₦100,000, User Savings Wallet UP ₦100,000. Same pattern as any deposit.
End of month: accrue ₦500 of interest
Monthly interest = 100,000 × 6% / 12 = ₦500. You do NOT credit the user yet. You ACCRUE: book it as an expense (your cost) and a payable (what you owe the user but have not paid).
| Account | Debit | Credit |
|---|---|---|
| Interest Expense (5300) | ₦500.00 | |
| Interest Payable (2500) | ₦500.00 |
Interest Expense UP ₦500 (your cost of paying interest). Interest Payable UP ₦500 (you OWE the user this, but it has not landed in their wallet). The User Savings Wallet does NOT move. The user has earned ₦500 of interest, but cannot yet withdraw it. This entry repeats every month.
End of quarter: capitalize ₦1,500 of accrued interest
Three months of accruals (₦500 × 3 = ₦1,500) have built up. Your policy: capitalize quarterly. Move it from Interest Payable into the user's wallet. Now they can spend it.
| Account | Debit | Credit |
|---|---|---|
| Interest Payable (2500) | ₦1,500.00 | |
| User Savings Wallet (2000) | ₦1,500.00 |
Interest Payable DOWN ₦1,500 (we no longer owe it, it is in their wallet). User Savings Wallet UP ₦1,500. The user's available balance is now ₦101,500. Future accruals start from there (compounding).
Takeaway
Interest is accrued continuously (as expense + payable) and capitalized periodically (payable → wallet). The user 'earns' it on accrual, 'gets' it on capitalization. Confusing these two timestamps is the bug behind every 'why did my interest only show up at month-end' support ticket, the answer is your accrual schedule, not a bug.
The code behind it
Daily interest accrual posted as a balanced two-line journal entry (kobo minor units).
-- Daily accrual on a ₦100,000 savings wallet at 6% annual.
-- Amounts are stored in kobo (integer minor units): ₦100,000 = 10_000_000.
-- daily interest = principal * annual_rate / 365
-- = 10000000 * 0.06 / 365 = 1643.83.. kobo, ROUND -> 1644 kobo (₦16.44).
-- One entry header carries the description; lines reference it via entry_id.
INSERT INTO journal_entry (description) VALUES ('Daily interest accrual 2026-06-24');
-- Compute the accrual once, then post the two balanced lines from it.
WITH accrual AS (
SELECT ROUND(10000000 * 0.06 / 365)::bigint AS amount_kobo
)
INSERT INTO journal_line (entry_id, account_code, debit, credit)
-- Debit Interest Expense (5300): the platform's cost of paying interest goes up.
SELECT currval('journal_entry_id_seq'), '5300', amount_kobo, 0 FROM accrual
UNION ALL
-- Credit Interest Payable (2500): we now owe the user this, not yet in their wallet.
SELECT currval('journal_entry_id_seq'), '2500', 0, amount_kobo FROM accrual;
-- Debits = credits = 1644 kobo, so the entry is balanced. Wallet (2000) does not move.Practice this on a real ledger
Reading is half of it. Open this lesson in the lab to post the entries yourself against a real Postgres-backed double-entry ledger, with the validation on. Free, your sandbox is yours.