Nordlet

Blog

What Defines an Immutable Double-Entry Ledger API

A practical breakdown of the features that separate a real accounting ledger for EU marketplaces from a mutable balance table with good marketing.

Nordlet Team · · 10 min read

A marketplace ledger is not defined by whether it stores money movements. Most systems do that. It is defined by what happens when a payment provider sends the same webhook twice, when a refund lands after a seller has already been paid out, or when an auditor asks how a seller balance reached its current number. Those moments expose whether you have an immutable double-entry ledger or a mutable field with a hopeful name.

For a marketplace platform, the short answer is this: an immutable double-entry ledger API records every financially consequential event as a balanced journal transaction, posts it atomically, never overwrites it, and lets you derive balances, reconcile against external systems, and export the history programmatically. Everything else is detail hanging off that core.

Balanced journal entries, not a running balance field

The single clearest test is how the API represents a seller's balance. If the balance is a number your application increments directly, it is not a double-entry ledger. If the balance is a derived view of posted journal lines, it might be.

Every transaction should carry equal debits and credits. When a buyer pays €100 for an order where the marketplace takes €15 commission, the ledger records the clearing account debited €100 against a seller payable credited €85 and commission revenue credited €15. The two sides always sum to the same figure. That structural rule catches a large class of bugs before they reach a report.

A journal transaction should expose, at minimum:

  • A unique, immutable transaction ID
  • Debit and credit lines, each with an account, amount, and currency
  • An effective date and a posting timestamp
  • A business-event type (sale, refund, payout, chargeback)
  • An idempotency key
  • A source reference to the order, payment, or provider event
  • A status (pending, posted, reversed)
  • The service or credential that created it

A seller's available funds then become a query against those lines, not a value someone updated in application code. This matters because a directly mutated balance loses the reason for every movement. Nordlet's model treats the double-entry ledger as the authoritative write path: every document posts balanced journal entries, and the database itself refuses unbalanced ones. That is the correct default for anyone embedding accounting into a marketplace.

Append-only posting with compensating corrections

"Immutable" should mean a posted journal cannot be edited in place. Mistakes are fixed forward, not erased. A wrong commission entry gets a reversal that negates the original, then a corrected entry that records the intended result. Both link back to the original, and the audit history shows who initiated the change and when.

The API should reject plain UPDATE and DELETE against posted accounting records. It may allow you to attach non-financial metadata, like a support case reference, as long as the amounts, accounts, and timestamps stay untouched.

It helps to separate three things people conflate:

  • Operational immutability: application users cannot alter or delete posted rows.
  • Audit immutability: the system can demonstrate the history has not changed.
  • Legal retention: records are kept for the period the applicable law requires.

An append-only relational database with strict permissions, backups, and disciplined reversal workflows delivers a genuinely immutable ledger. Blockchain is not a requirement here, and for EU accounting data it usually introduces privacy and correction problems that outweigh the tamper-evidence it adds.

Atomicity and idempotency

A marketplace event must post atomically. Either all journal lines commit or none do. Recording the €100 receipt but failing to record the €15 commission produces an unbalanced, misleading result that someone has to untangle later. Nordlet enforces this below the application layer: a deferred database trigger checks that every posting balances at commit time, so an unbalanced transaction cannot be committed at all.

Idempotency is where most integrations quietly break. Payment systems retry on network failures, and settlement files get replayed. Without an idempotency key scoped to the tenant or account, a single retried request creates duplicate accounting. A repeated request with the same key should return the original transaction, not a second one.

The key should tie to the originating event, the event type, the provider's event ID, the legal entity, and a hash of the request payload. If the same key arrives with a different amount or currency, the API should treat that as a collision and reject it rather than silently accept the new payload. Silent acceptance is how audit trails rot. Nordlet's Idempotency-Key header works this way: a retry with the same key and payload replays the stored response, and the same key with a different payload is rejected with idempotency_key_reuse. It is a small feature with an outsized effect on reconciliation.

Multi-party split accounting

A marketplace order is not one movement. A single sale can touch buyer funds, seller proceeds, marketplace commission, payment-processing fees, VAT on the commission, shipping, and reserves. The ledger needs account structures that keep these separate rather than collapsing them into one net figure.

There is a common assumption worth pushing back on: a payment provider's "split payout" feature is not the same as marketplace accounting. Splitting money across recipients routes cash. It does not give you a complete, immutable record of commission earned, VAT collected, refunds owed, or reserves held. You still need your own ledger, and you still need to reconcile it against the provider.

A marketplace ledger should also distinguish more than one seller balance:

Balance state What it represents
Pending Funds tied to an event but not yet eligible for withdrawal
Available Funds that pass release, reserve, refund, and dispute rules
Held / reserved Amounts withheld for chargebacks, returns, or fraud controls
Paid out Amounts transferred to the seller
Negative / recoverable Amounts the seller owes after refunds or fees exceed available funds

Moving money from pending to available should itself be a balanced journal transaction, not a relabeled field.

Reversals, refunds, and negative balances

Marketplace money flows both directions, often out of order. The hard cases are refunds after payout and chargebacks that arrive weeks later. A serious ledger defines what happens when a seller's available balance cannot cover a refund: create a negative balance, move the amount to seller receivables, draw on a reserve, or restrict further payouts.

Each of these events should reference the original transaction and preserve it. The ledger records the accounting consequence of a refund. It does not decide the marketplace's refund policy or legal liability. Keeping that boundary clear prevents a lot of confused design conversations.

Currencies and precision

Cross-border marketplaces need explicit money handling. Amounts should use ISO 4217 currency codes and an exact representation, either integer minor units or fixed-precision decimal strings, never floats. No silent rounding. When conversion happens, the ledger should preserve the original amount, the FX rate, the rate source, the timestamp, and the resulting amount, with rounding differences posted to a defined account.

A single balanced transaction should not mix currencies without an explicit FX mechanism. If it does, your reports will disagree with reality in ways that are painful to trace at month-end.

Reconciliation against external systems

An internally balanced ledger is not authoritative on its own. It has to agree with the outside world: payment-provider transactions, provider fees, settlement reports, bank statements, payout files, and chargeback reports.

A mature API supports imported external events and matching states such as matched, partially matched, unmatched, duplicate, amount mismatch, and needs review. Reconciliation differences should create explicit exception records or accounting entries. They should never quietly rewrite ledger history. Nordlet's approach to bank reconciliation and payment matching sits on this principle: imported statements and Stripe exports skip anything already imported, payment suggestions are scored by amount, reference, counterparty and IBAN, one-click matching handles the routine cases, and exceptions are surfaced rather than absorbed.

EU boundaries the API should respect, and the ones it cannot

This is where marketing claims tend to outrun reality. A ledger helps with EU obligations, but it does not satisfy them by itself.

VAT. The ledger should preserve tax-relevant dimensions: jurisdiction, rate, tax category, and how the rate was determined. It should distinguish the seller's sale to the buyer from the marketplace's commission, and separate VAT on fees from amounts merely passing through. Nordlet handles per-country VAT calculations, VIES validation, and i.SAF register generation, along with the OSS and IOSS scenarios that EU marketplaces run into. Treat the ledger as evidence and a tax engine, not as tax advice.

DAC7. Platform reporting rules require reliable links between seller identity, jurisdiction, transaction totals, fees, refunds, and payouts. A balanced ledger produces the transaction evidence. It does not determine whether a seller is reportable, and it does not replace KYC, onboarding, or the reporting workflow. Keep transaction accounting and regulatory reporting as separate concerns.

PSD2 and fund custody. Recording money movements is not the same as being a licensed payment service or safeguarding funds. The ledger should make the flow of funds and the parties explicit. It cannot, on its own, provide payment-services authorization or prove that cash is held in a particular account. That remains a question of your regulatory role and your PSP.

GDPR. Immutability creates real tension with data-protection principles. The safest architecture keeps monetary facts in the immutable core and personal data outside it. Use stable pseudonymous seller and customer references in journal lines. Store mutable personal details in a separate, access-controlled system with its own retention and deletion workflow. "Immutable" is not a licence to keep every payment payload forever.

A checklist for evaluating a ledger API

Feature labels are cheap. Test the behavior in a sandbox instead. Run these scenarios and check the evidence:

  • Post a €100 order split between seller and marketplace, and confirm a balanced journal with explicit accounts.
  • Send the same request twice, and confirm one transaction, no duplicate.
  • Try to edit a posted entry, and confirm it is rejected or limited to non-financial metadata.
  • Correct a wrong commission, and confirm a linked reversal plus corrected entry.
  • Issue a partial refund after payout, and confirm a traceable refund with a seller receivable or negative balance where needed.
  • Replay a provider webhook, and confirm duplicate detection.
  • Process a multi-currency settlement, and confirm FX details and conversion accounting.
  • Query a seller balance at period end, and confirm a reproducible result with a documented cut-off.
  • Import a provider settlement, and confirm matching with an exception status that leaves history intact.
  • Export a month of activity, and confirm a complete, paginated, repeatable extract.

The strongest evidence is documentation plus a reproducible test. Words like "real-time," "audit-ready," and "immutable" mean nothing without the data model, error semantics, and retention behavior behind them.

What we would check first

If we were evaluating a ledger API tomorrow for a marketplace, we would start with two things before looking at anything else. First, prove that a seller balance is derived from journal lines and not a mutable field, because everything downstream depends on it. Second, replay the same webhook and confirm exactly one accounting result. Those two tests tell you more about the quality of the underlying design than any feature list.

After that, the API-first considerations matter for how fast your team ships: typed SDKs, webhooks for events like sale_invoice.paid, a working sandbox, and period locking to protect closed months. Nordlet was built around this model, with the same feature set exposed through the API as through the app, which is what lets a platform run audit-ready books inside its own product instead of bolting on a third-party checkout. For the wider picture of how such a ledger fits into a marketplace stack, see our guide to double-entry ledger APIs for marketplace accounting.

FAQ

Does double-entry guarantee my accounting is correct?

No. A ledger can be perfectly balanced while posting to the wrong accounts, applying the wrong VAT treatment, or attributing funds to the wrong seller. Balance is a structural control that catches arithmetic errors and missing sides of a transaction. It says nothing about whether your business logic mapped the event correctly. That is why sandbox testing against real scenarios matters more than the balance check alone.

Is a payment provider's ledger enough for a marketplace?

Usually not. A PSP tracks funds inside its own system, which is useful for movement and payout. Your marketplace still needs its own records for commission revenue, seller liabilities, VAT on fees, refunds, reserves, disputes, and management reporting. The two systems have to be reconciled, and treating the provider's view as your accounting leaves gaps that surface at audit time.

Do I need blockchain to make a ledger immutable?

No. An append-only relational store with strict write permissions, controlled correction workflows, audit logging, and reliable backups gives you operational and audit immutability. Blockchain adds distributed tamper-evidence but brings privacy, performance, and correction difficulties that work against EU accounting and GDPR requirements. For most marketplaces it solves a problem they do not have.

Can an immutable ledger keep data forever under GDPR?

Retaining accounting records for a legally required period is fine. Retaining full personal data or payment payloads indefinitely because the ledger is immutable is not. Keep monetary facts and pseudonymous references in the immutable core, and hold personal details in a separate system with proper retention and deletion. Immutability applies to the financial event, not to every piece of data attached to it.