Back to BlogIndustry Guides

An Invoice-Financing Platform: Data Model and the Limits

Rupak Amin

Founder & Lead Engineer, RAITHub

10 min read

RAITHub ships and tests production software. See QA as a Service or talk to us.

An invoice-financing platform tracks invoices advanced against and the money owed back. The engineering is a ledger plus a status workflow: an invoice is verified, an advance is paid out, the debtor later pays, and the balance settles to zero. Build the invoice-to-repayment model, record every movement as a balanced ledger entry in integer minor units, and test that the balance is always exact.

This is engineering guidance only. Whether invoice financing, factoring or any advance your product offers is regulated lending that needs a licence, and on what terms, is a legal question that differs by jurisdiction; this is general information and not lending, licensing or financial advice, so confirm it with your adviser before you build or launch. Pair a regulated build with a licensed partner. If you would rather have the engineering built for you, see how RAITHub would build this below.

What is the platform actually tracking?

Three linked things: the invoice (who owes whom, how much, when due), the advance (what you paid the client against it, and your fee), and the repayment (what the debtor pays, and how the balance settles). Each has a state, and the money moves must balance. The engineering is unforgiving in the same way any financial system is: amounts cannot drift, payouts cannot happen twice, and you must be able to prove the balance of any advance at any moment.

EntityHoldsThe risk if wrong
InvoiceDebtor, amount, due date, verification statusAdvancing against an invoice that is disputed or already paid
AdvanceAmount paid to the client, fee, advance ratePaying out twice, or more than the agreed rate
RepaymentWhat the debtor pays, applied to the advanceA balance that does not settle to the right figure
LedgerEvery movement as double entryBooks that do not balance, so no advance can be proven

What does the data model look like?

An invoice has a verification status before any advance; the advance and repayments reference it; the ledger records the money. Keep money in integer minor units and currency explicit.

CREATE TABLE invoices (
  id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  client_id   bigint NOT NULL REFERENCES clients(id),
  debtor_id   bigint NOT NULL REFERENCES debtors(id),
  amount_minor bigint NOT NULL,
  currency    char(3) NOT NULL,
  due_on      date NOT NULL,
  status      text NOT NULL DEFAULT 'submitted',
              -- submitted | verified | advanced | repaid | overdue | written_off | rejected
  created_at  timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE advances (
  id            uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  invoice_id    uuid NOT NULL REFERENCES invoices(id),
  advance_minor bigint NOT NULL,                 -- paid to the client
  fee_minor     bigint NOT NULL,                 -- your charge
  idempotency_key text UNIQUE,                   -- one payout per key
  created_at    timestamptz NOT NULL DEFAULT now()
);

-- Repayments and all money movements post to a double-entry ledger (integer minor units).
-- An advance's outstanding balance = advanced + fees - repayments, always from the ledger.

An invoice must be verified before it can be advanced: you do not pay out against an invoice you have not checked is real, unpaid and undisputed. The ledger is the same double-entry design as any money system, covered in double-entry ledger database design.

How does the money flow, and why must it be a ledger?

Because you need to prove the outstanding balance of every advance at any time, and a ledger is the only structure that does so without drift. The advance posts entries when paid out; fees post entries when charged; each repayment posts entries that reduce the outstanding balance; the whole ledger sums to zero. Store money as integers in the smallest unit, never floats, so fees and partial repayments cannot round the balance off a cent. Reconciling what you recorded against what the bank actually moved is its own job, covered in payment reconciliation software.

How do you stop a double payout?

Make the payout idempotent. Give each advance a stable idempotency key, record the payout result before marking the invoice advanced, and on a retry return the recorded result instead of paying again. The reasoning for any money-moving request is in idempotency in API design. Paying a client twice against one invoice is the most expensive bug this kind of platform can have, so it is the first thing to test.

What are the limits you must build around?

The hard limits here are legal, not technical, and the software must respect them rather than paper over them:

  • Is it lending? Advancing money against invoices may be a regulated activity needing a licence. That determination is for your adviser; the platform must not assume it is unregulated.
  • Who verifies the debtor and the invoice? The checks (that the invoice is real, unpaid, assignable) are a business and sometimes legal process; the software records and routes them, it does not pronounce them valid.
  • Know-your-customer and anti-money-laundering. What a KYC/AML programme must contain is for a compliance professional; the software engineers the integration (verification states, review queues, retention, audit), covered in the engineering view in building a FinTech SaaS.

Build the engineering so these decisions sit with people and partners who are qualified to make them, and so every decision is recorded. This is general information, not legal advice; confirm with your adviser.

How do you test it?

The invariants: an advance's balance settles exactly, and no payout happens twice.

import { describe, it, expect } from 'vitest'
import { advance, repay, balanceOf, ledgerSum } from './financing'

describe('invoice financing ledger', () => {
  it('an advance settles to zero when fully repaid', async () => {
    const inv = await verifyInvoice({ amountMinor: 100000, currency: 'USD' })
    const a = await advance(inv.id, { advanceMinor: 90000, feeMinor: 3000, idempotencyKey: inv.id + ':1' })
    await repay(a.id, 93000)                         // advance + fee repaid
    expect(await balanceOf(a.id)).toBe(0)
    expect(await ledgerSum()).toBe(0)
  })

  it('does not pay out twice for one advance', async () => {
    const inv = await verifyInvoice({ amountMinor: 50000, currency: 'USD' })
    const key = inv.id + ':1'
    await advance(inv.id, { advanceMinor: 45000, feeMinor: 1500, idempotencyKey: key })
    await advance(inv.id, { advanceMinor: 45000, feeMinor: 1500, idempotencyKey: key })  // retry
    expect(await payoutCount(inv.id)).toBe(1)
  })
})

Add a test that an invoice cannot be advanced before it is verified, one for a partial repayment, and one for an overdue invoice moving to the right state.

Buy, build or hire?

OptionChoose this whenThe catch
A lending-platform or BaaS providerYour product fits their rails and you want licensing cover from a partnerYou fit their model and fees; the licence and attestation are theirs, not yours by default
Spreadsheets and manual transfersValidating the idea with a tiny bookNo ledger, no idempotency, no audit; unsuitable for real money at scale
Custom build with a licensed partnerYou need product-specific financing logic built and tested, with the regulated parts handled by a partnerYou own the engineering; the licence and compliance come from the partner, not the studio

How long does it take to build yourself, and what is the risk?

For an experienced team building the invoice-to-repayment model, a double-entry ledger, idempotent payouts and the status workflow, our estimate is 6 to 12 weeks, because this is ledger- and integration-heavy backend work. The main risk is not the code: it is building a regulated lending product without establishing whether you need a licence. That determination comes first, from your adviser, and the engineering must respect the answer. This is general information, not lending or licensing advice.

Why RAITHub for this

  • Ledgers in production. Sundor Skin runs credit limits and adjustments as append-only entries with a hash-chained audit log across 146 PostgreSQL tables and 530+ tests. See the Sundor Skin case study.
  • Money handled correctly. TheSkinProof, the founder's own venture built and run by RAITHub, uses integer minor units across four payment rails (750+ tests), and RAITHub has built a fintech dashboard for a client.
  • Honest limits. RAITHub has not shipped a regulated or licensed fintech product and gives no lending or licensing advice. For a regulated build, pair its engineering with a licensed partner.

When you don't need us

  • A lending platform or BaaS fits. If a provider's rails and licensing cover your product end to end, use them.
  • You are still validating. A small manual process may answer the demand question first.
  • You need a licence or attestation. Those come from a licensed partner and a certified assessor, not from an engineering studio.

How RAITHub would build this

  • Invoice-to-repayment model: verification before advance, advances and repayments linked to invoices, states that reflect the real lifecycle.
  • Double-entry ledger: every movement balanced, in integer minor units, with an advance's balance always derivable and provable.
  • Idempotent payouts: stable keys, recorded results, safe retries, and reconciliation against the bank feed.
  • Decision boundaries: verification, KYC/AML and licensing handled by qualified people and partners, with every decision recorded.

Timeline: this is 6 to 12 week backend work; a narrow first version can fit a 4 to 6 week fixed scope if the regulated parts sit with a partner from day one. See SaaS development, QA as a Service and the FinTech industry page. A related build is an expense-management SaaS.

You receive: the product on accounts you own, tests and CI covering the money logic, handover runbooks, and full IP under NDA. Licensing and compliance are handled with your partner and adviser, not claimed by RAITHub.

Frequently asked questions

What does an invoice-financing platform track?

Three linked things: the invoice (debtor, amount, due date, verification), the advance (what you paid the client and your fee), and repayments (what the debtor pays, applied to the advance). Each has a state, and the money moves are recorded in a ledger so the balance is always exact.

Why does it need a double-entry ledger?

Because you must prove the outstanding balance of every advance at any moment, and a ledger is the only structure that does so without drift. Every movement posts balanced entries in integer minor units, and the whole ledger sums to zero, so partial repayments and fees cannot round the balance off.

How do I stop paying out twice against one invoice?

Make the payout idempotent: give each advance a stable key, record the result before marking the invoice advanced, and return the recorded result on a retry instead of paying again. Paying a client twice against one invoice is the most expensive bug this kind of platform can have.

Does an invoice-financing platform need a licence?

That is a legal question, not an engineering one. Advancing money against invoices may be regulated lending that needs a licence, and the answer differs by jurisdiction. This is general information, not lending or licensing advice; confirm it with your adviser, and build the platform to respect the answer.

Who verifies the invoices and the debtors?

People and partners qualified to do so, not the software. The platform records and routes verification (that the invoice is real, unpaid and assignable) and the KYC/AML checks, and keeps an audit trail; it does not pronounce them valid or replace a compliance programme.

Can RAITHub build the regulated parts?

RAITHub builds the engineering: the model, the ledger, idempotent payouts and the KYC provider integration. It has not shipped a regulated or licensed fintech product and gives no lending or licensing advice, so the licence, the compliance programme and any attestation come from a licensed partner and your adviser.

invoice financingfintech platformledger designdata modelworkflowsaas

Ready to discuss your project?

Book a free 15-minute technical audit with our engineering team.