Lesson 43Operations and structureAdvanced

Reserve accounts

Your provider holds back a percentage of your earnings. Track it as an asset, not as cash.

By Solomon Ajayi · Free to read, no signup

Your payment provider (Stripe, Flutterwave, etc.) takes a 10% reserve on top of their normal fees. The reserve is YOUR money, they're just holding it as collateral against chargebacks. After 90 days with no disputes, they release it. The wrong way to book this: ignore it, see your bank balance be mysteriously smaller than expected. The right way: track the held reserve as a SEPARATE asset account. Your bank balance is what's settled; your reserve balance is what's held. Sum to know your real entitled cash. This pattern shows up at every fintech that takes card payments.

When a provider holds back a reserve, your instinct is to feel like they took your money. They did not. The reserve is still yours; they are holding it as collateral against chargebacks that might land in the next ninety days. That distinction is not semantic, it is an accounting one: the reserve is an asset you own, it just is not cash you can spend yet, so it cannot sit in the same account as your settled bank balance.

So you split the settlement. Of the ₦9,850 the provider owed you, ₦8,865 becomes real Bank Account cash and ₦985 moves into Provider Reserve Held, a separate asset account. The receivable clears in full because every kobo is accounted for; it just lands in two different buckets with two different liquidity profiles. Ninety days later, with no disputes, the reserve releases: a clean asset-to-asset move from Reserve Held back into the bank, no revenue and no expense, because you already earned this money at deposit time.

The reason this matters operationally is cash forecasting. If you fold the reserve into your bank balance, your spendable-cash number is overstated by exactly the reserve, and you will plan payroll against money you cannot touch. If you ignore the reserve entirely, your books are short and your bank balance looks mysteriously smaller than your revenue says it should be. Keeping the reserve as its own asset account makes both numbers honest at once.

Worked example, step by step

User deposits ₦10,000, gross receivable from provider

Same shape as Lesson 2. User pays ₦10,000 via card; provider keeps 1.5% (₦150); your platform fee is 1% (₦100); user gets ₦9,900 in their wallet. Gross receivable from provider: ₦9,850.

User deposits ₦10,000 via card
AccountDebitCredit
Provider Receivable (1100)₦9,850.00
Card Fee Expense (5000)₦150.00
User Wallet (2000)₦9,900.00
Platform Fee Revenue (4000)₦100.00

Provider Receivable UP ₦9,850 (the gross amount provider owes you, before reserve). Card Fee Expense UP ₦150. User Wallet UP ₦9,900. Platform Fee Revenue UP ₦100. Standard deposit shape from Lesson 2, at THIS moment, reserves haven't entered the picture yet.

Provider settles with 10% reserve held back

Of the ₦9,850 owed to you, the provider holds back 10% (₦985) as reserve. They wire ₦8,865 to your bank. Both pieces of the ₦9,850 receivable are accounted for, ₦8,865 became cash, ₦985 became a reserved asset.

Provider settlement: ₦8,865 + ₦985 reserve
AccountDebitCredit
Bank Account (1200)₦8,865.00
Provider Reserve Held (1500)₦985.00
Provider Receivable (1100)₦9,850.00

Bank Account UP ₦8,865 (actual cash arrived). Provider Reserve Held UP ₦985 (your money, held by provider, NOT spendable). Provider Receivable DOWN ₦9,850 (cleared). The reserve is on YOUR balance sheet as an asset, it's yours, you just can't touch it for 90 days. Crucially: it is NOT bank cash. Cash forecasts that ignore the reserve are wrong by exactly the reserve amount.

90 days later: reserve released to your bank

Provider's reserve hold period ends. No chargebacks occurred against this batch. They release the ₦985 to your bank account.

Reserve released ₦985 after 90 days
AccountDebitCredit
Bank Account (1200)₦985.00
Provider Reserve Held (1500)₦985.00

Bank UP ₦985 (cash freed). Provider Reserve Held DOWN ₦985 (no longer held). Notice: no revenue, no expense, this is just the asset moving from one bucket to another. The full ₦9,850 of original receivable is now in your spendable bank. Reserve released = working capital unlocked.

Takeaway

Reserves are YOUR cash, temporarily held by your provider as risk collateral. Track them as a SEPARATE asset account, not as bank cash, because they're not bank cash. Your cash-flow forecasts need both numbers: bank (spendable now) and reserve (entitled, returns in N days). Forgetting to track reserves means your spendable-cash forecast is wrong by exactly the reserve balance, which can be 5-15% of your top line. Fintechs that scale into 8-figure monthly volumes get genuinely surprised by how much working capital is locked up in provider reserves, knowing it's there means you can borrow against it or negotiate to reduce it.

The code behind it

Hold 10% of each payout in Provider Reserve Held, then release matured tranches after 90 days.

-- Amounts in kobo (integer minor units). Tranche table tracks each reserve hold.
CREATE TABLE reserve_tranche (
  id           bigserial PRIMARY KEY,
  held_kobo    bigint  NOT NULL,
  held_on      date    NOT NULL,
  hold_days    int     NOT NULL DEFAULT 90,
  released_on  date             -- NULL until released
);

-- HOLD: provider settles ₦9,850 gross, keeps 10% (₦985) as reserve, wires ₦8,865.
-- Debit Bank 1200, debit Reserve Held 1500, credit Provider Receivable 1100.
WITH settle AS (
  INSERT INTO reserve_tranche (held_kobo, held_on) VALUES (98500, DATE '2026-06-24')
  RETURNING id
)
INSERT INTO journal_line (account_code, debit, credit, memo)
VALUES ('1200', 886500,      0, 'Provider settlement: cash to bank'),
       ('1500',  98500,      0, 'Provider settlement: 10% reserve held'),
       ('1100',      0, 985000, 'Clear gross provider receivable');

-- RELEASE: asset-to-asset move for every tranche whose hold period has matured.
-- Debit Bank 1200, credit Reserve Held 1500. No revenue, no expense.
-- date + int stays a date (no implicit timestamp cast); matures on held_on + hold_days.
WITH matured AS (
  UPDATE reserve_tranche
     SET released_on = CURRENT_DATE
   WHERE released_on IS NULL
     AND held_on + hold_days <= CURRENT_DATE
  RETURNING id, held_kobo
)
INSERT INTO journal_line (account_code, debit, credit, memo)
SELECT '1200', held_kobo, 0, 'Reserve released to bank (tranche ' || id || ')' FROM matured
UNION ALL
SELECT '1500', 0, held_kobo, 'Reserve released from held (tranche ' || id || ')' FROM matured;

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.

More in this section

Search lessons

Type to find any of the 85 lessons. Press Enter to open.