How ERP Systems Work: Modules, Data Flow, and the Ledger Underneath
One transaction followed through every module of an ERP, with the actual journal entries, and why the general ledger is the record everything else reads.
An ERP system works by storing every business event once, in one database, and letting each module read and write that shared record. A shipped order is the same record whether the warehouse, the sales team or the accountant looks at it. The module that keeps the whole system honest is the general ledger: every event that has a money value ends as a balanced journal entry there, and every report is derived from those entries.
This article follows one sale through the modules, shows the journal entries it produces, and explains why integration with an ERP is about events and the ledger rather than about screens.
The shared database
Before ERP, each department ran its own program. Stock lived in a warehouse system, invoices in a billing system, and the books in an accounting package. Month end was spent reconciling the three. What ERP software is explains the category; the mechanism that makes it work is a single data model in which:
- a partner record is used by sales, purchasing and the ledger alike,
- an item record carries the stock quantity, the FIFO cost layers, the sales price and the revenue account,
- a document (order, invoice, credit note, purchase, production order) references partners and items and produces exactly one set of journal entries,
- a journal entry references the document that produced it, so every figure in a report can be traced back.
When the records are shared, there is nothing to reconcile between modules. What remains to reconcile is the outside world: bank statements and tax returns.
The module map
| Module | Writes | Reads |
|---|---|---|
| Sales | Orders, invoices, credit notes | Partners, items, prices, VAT rules |
| Purchasing | Purchase orders, supplier invoices | Partners, items, expense accounts |
| Inventory | Stock movements, FIFO cost layers, stock-takes | Items, warehouses |
| Production | Production orders, component consumption, finished goods | Bills of materials, stock |
| Bank | Imported transactions, payment matches | Open invoices, bank accounts |
| Payroll | Payroll runs, contributions, filings | Employees, contracts, tax tables |
| Assets | Asset register, depreciation runs | Asset groups, useful lives |
| Tax | VAT returns, EU sales lists, Intrastat, e-invoices | Issued and registered documents |
| General ledger | Journal entries, period locks | Everything above |
| Reporting | Nothing | The general ledger and the subledgers |
Every row except the last two ends with a write to the general ledger. That is the design rule that distinguishes an ERP from a set of connected tools.
A worked data flow
The example below uses Nordlet's endpoints and the default accounts of the Lithuanian chart it ships with. Any ERP performs the same steps; the account codes and endpoint names differ.
1. Order
A storefront places an order through POST /v1/ecommerce/orders/create: a partner, lines with items and quantities, a ship-to country. Nothing posts to the ledger yet. An order is a commitment, not a transaction.
2. Stock reservation
orders/reserve sets the quantities aside so a second order cannot sell the same units. Still no journal entry: reserved stock is still owned.
3. Fulfilment
orders/fulfill records the goods leaving the warehouse. Two things happen in one database transaction:
- Stock is consumed at FIFO cost: the oldest cost layers for each item are used first, which is the method described in the FIFO inventory valuation glossary entry.
- The cost of those units posts as a journal entry, debit cost of goods sold, credit stock.
| Account | Debit | Credit |
|---|---|---|
| 6000 Cost of goods sold | 600.00 | |
| 2040 Stock | 600.00 |
Fulfilment also creates a draft invoice for the order, and resolves the VAT treatment from the ship-to country using the EU VAT engine.
4. Invoice issue
Issuing the invoice is the moment revenue is recognised for a point-in-time sale. The document receives its gapless number, and one balanced entry posts: the gross to receivables, the VAT to the output VAT account, and the net to revenue.
For a €1,000 net sale at 21% Lithuanian VAT:
| Account | Debit | Credit |
|---|---|---|
| 2410 Accounts receivable | 1,210.00 | |
| 5000 Revenue from goods | 1,000.00 | |
| 4492 Output VAT payable | 210.00 |
If a line carries a recognition method other than point in time, the net goes to deferred income instead, and the revenue recognition engine releases it on schedule. The posting of receivables and VAT does not change.
The invoice can now leave as a PDF, as a Peppol BIS 3.0 e-invoice, or in the national e-invoicing format the company's country requires.
5. Bank match
Two weeks later €1,210 arrives. The movement comes in through a PSD2 bank feed or a camt.053 statement import. The bank module scores candidate invoices by amount, payment reference, counterparty name and IBAN, and bank/transactions/match posts the settlement:
| Account | Debit | Credit |
|---|---|---|
| 2710 Bank | 1,210.00 | |
| 2410 Accounts receivable | 1,210.00 |
The invoice status changes to paid, and a sale_invoice.paid webhook is emitted. The payment reconciliation entry explains the matching logic in more detail. A payment in another currency books the realised exchange difference to the gain or loss account in the same step.
6. VAT return
At month end nothing is re-keyed. The VAT return is computed from the issued and registered documents: declarations/eu/vat-return/compute for the national return (FR0600 in Lithuania), declarations/eu/oss/compute for cross-border consumer sales under the Union scheme. The sale above lands in the standard-rate box of the domestic return because its VAT scheme is domestic.
7. Period lock
Once the return is filed, ledger/periods/lock closes the month. From then on any posting dated into it, including a late bank match or a retried API call, is rejected with HTTP 409. Locking also triggers the recognition of any deferred revenue due through the period end, so a month cannot close with earned revenue left in the liability account.
Why the ledger is the system of record
Each module above keeps a subledger: receivables by customer, payables by supplier, stock by item, assets by asset. The general ledger holds the totals those subledgers must agree with. Subledger vs general ledger covers the relationship; the practical point is that a report built from the ledger and a report built from a subledger must give the same number, and an ERP guarantees that by producing both from the same journal entries.
Three properties make the ledger trustworthy as a record:
- Balance is enforced. In Nordlet the database refuses an entry whose debits do not equal its credits. A bug in a module cannot create a lopsided posting.
- History is append-only. A posted entry is never edited. A mistake is corrected with a reversal and a new entry, both linked to the original. The immutable ledger entry explains why auditors insist on this.
- Periods close. A locked month cannot change, so the figures you filed are the figures that stay in the system.
Integration: events and idempotency, not nightly batches
Older ERP integrations ran on files exchanged at night: export orders, import them, check the error log in the morning. Modern ERPs expose an API, and integration becomes a matter of two disciplines.
Events out. When something changes, the ERP tells you. Nordlet writes each webhook event to an outbox in the same database transaction as the change, so a document that was rolled back never emits an event and no event is lost. Deliveries are signed with HMAC-SHA256 and retried with exponential backoff. Your system reacts to sale_invoice.paid rather than asking every five minutes whether anything is paid.
Safe retries in. Networks fail, and a retried request must not create a second invoice. Nordlet accepts an Idempotency-Key header on every mutating call: the same key with the same payload returns the stored response, the same key with a different payload is rejected, and keys expire after 24 hours. The idempotency glossary entry and the API conventions describe the exact behaviour.
Because every operation is a POST /v1/{module}/{resource}/{action} call and the application uses the same endpoints, an integration can run the whole flow above with no one opening a screen. How to integrate a cloud accounting API into a SaaS platform walks through such a build.
What reporting reads
Reports do not store figures. They are queries over the ledger and subledgers at a point in time:
- Trial balance, balance sheet, profit and loss, cash flow read journal entries by account and period.
- Debt aging reads open receivables and payables by due date.
- Stock balance and movement read the inventory subledger and its FIFO layers.
- VAT summary reads the VAT lines of issued and registered documents.
- Cost-center reports read the cost-center dimension on each journal line.
In Nordlet a report is generated in the background as XLSX, PDF or JSON, and a webhook fires when the file is ready. Group figures come from consolidation, which combines several companies' ledgers with ownership weighting and currency translation.
Where this breaks in practice
Most ERP problems are failures of the shared-record principle rather than of software. Common cases:
- A parallel spreadsheet for something the ERP "cannot do", which then disagrees with the books.
- Manual journal entries used to fix module output instead of fixing the document, which breaks the trace from report to source.
- Integrations that write balances instead of documents, so the ledger holds totals nobody can explain.
- Open periods left unlocked for months, so last quarter's filed figures drift.
Why ERP implementations fail covers how these habits form during a rollout, and realistic ERP implementation timelines shows where in the project they usually appear.
FAQ
What is the core of an ERP system?
The general ledger and the shared data model around it. Every module writes documents that produce balanced journal entries, and every report is derived from those entries.
How does data flow through an ERP?
An event is recorded once as a document (order, invoice, movement, payroll run). The document produces journal entries in the ledger and movements in the relevant subledger. Reports and tax returns are computed from those records. Nothing is copied between modules.
What is the difference between a module and an integration?
A module writes to the same database and the same ledger as the rest of the system. An integration is an external program that calls the ERP's API. With an API-first ERP the distinction is small, because the integration uses the same endpoints the modules use.
Does an ERP post accounting entries automatically?
Yes. Issuing an invoice, fulfilling an order, matching a payment, running payroll or depreciating an asset each produces its journal entry without a person constructing debits and credits. The accounts used come from posting rules that can be changed per company.
Why do ERPs lock accounting periods?
So the figures reported or filed for a period cannot change afterwards. A locked period rejects new postings, which protects the audit trail and forces corrections into the current period where they are visible.