Ledgr/Documentation/Connecting Aura POS
Connecting Aura POS
Aura is the till. Ledgr is the books. This is how a day's takings get from one to the other without anyone retyping them.
Needs Reports (Business upwards) for the ledger, and an API key, which is on every plan. Aura is a separate product with its own subscription.
What Aura is
Aura POS is a hospitality point-of-sale system for South African restaurants — Kotlin Multiplatform on Android, iOS, desktop and web, with its own Ktor backend. Table-side QR ordering, a kitchen display, split bills, tips, Yoco/SnapScan/Zapper, WhatsApp receipts, and offline-first sync built for load shedding.
It is not a Ledgr module and it is not becoming one. A restaurant till has a different shape from an accounting ledger: it cares about covers, courses, prep stations and shift hand-overs, and it has to keep taking orders when the power and the network are both gone. Bolting that into an accounting package would compromise both. What the two share is the money.
Which way the data flows
One direction only: Aura → Ledgr. Aura owns the sale, the menu, the stock behind the menu and the payment. Ledgr owns the books, the VAT return and the financial statements. Ledgr never writes back into the till, because a POS that could have its takings edited from an accounting package is a POS whose cash-up means nothing.
Push a day, not a sale
Aura already computes double-entry journals for every checkout, in its own ledger. The integration sends those to Ledgr — summarised by day, per location, not one document per sale.
This matters more than it sounds. A restaurant doing 300 covers a night would create 300 Ledgr documents an evening, 9 000 a month, for a set of books whose owner wants one line saying what Tuesday took. The detail belongs in Aura, which is where anyone asking "what did table twelve order" is going to look anyway. Ledgr gets the total, the VAT, and a reference back to the day.
Push after the cash-up, not during service. A day that is still open can still change — a void, a late tip adjustment, a re-opened tab — and a journal posted mid-service has to be reversed rather than simply not yet written.
Authenticating
Aura holds a Ledgr API key and exchanges it for a short-lived token, exactly as any other integration does. It never needs a Ledgr password.
- In Ledgr: create the key
Settings → Roles & Users → API keys → Generate. Give it
reports:write— posting a journal needs create permission on the ledger — and nothing else. Name it "Aura POS" so it can be revoked without anyone wondering what it was for. - In Aura: store the key
As a server-side secret, not in a client build. The POS terminals never talk to Ledgr; only Aura's backend does.
- Exchange it for a token
POST /auth/tokenwith the key as a bearer credential returns a one-hour access token. Aura's nightly job asks for a fresh one each run rather than caching it — a job that runs once a day gains nothing from reusing an hour-old token.
Full details of the exchange, the scopes and the rate limits are in the developer documentation.
Mapping the accounts — read this part twice
Aura's journal generator uses its own account numbers, and they are not Ledgr's.
The two charts overlap in the ranges but disagree on the codes, and two of the collisions are
the dangerous kind: Aura's 2000 is VAT Output, while Ledgr's 2000 is
the Non-Current Liabilities header. Aura's 2100 is Tips Payable, while
Ledgr's 2100 is the Current Liabilities header.
The trial balance would still foot — debits would equal credits — and the balance sheet would be nonsense, with VAT owed to SARS sitting inside a heading. That is the worst class of accounting bug, because nothing looks broken. Map every line explicitly, and let an unmapped code fail loudly rather than defaulting to anything.
| Aura | What it is | Ledgr | Ledgr account |
|---|---|---|---|
1000 | Cash | 1360 | Petty Cash |
1010 | Yoco settlement due | 1330 | Other Receivables & Prepayments |
1100 | Inventory | 1310 | Inventory / Stock on Hand |
2000 | VAT Output ⚠ | 2130 | VAT Output (Control) |
2100 | Tips Payable ⚠ | 2120 | Other Payables & Accruals |
2200 | Processor fees payable | 2120 | Other Payables & Accruals |
4000/4010 | Revenue | 4010 | Sales — Goods |
5000 | Cost of goods sold | 5040 | Cost of Goods Sold |
6000 | Yoco fees | 6030 | Bank Charges |
Ledgr's ledger endpoint takes account ids, not codes, so resolve them once with
GET /api/ledger/accounts and cache the code→id map. Codes are stable;
the ids are per tenant.
The daily journal
One balanced journal per trading day per location. A Tuesday taking R18 400 including VAT, of which R12 000 on card and R6 400 cash, with R900 of tips and R240 of card fees:
{
"journalDate": "2026-08-04",
"memo": "Aura POS takings — Main floor — Tue 4 Aug",
"reference": "AURA-MAIN-20260804",
"post": true,
"lines": [
{ "accountId": "<1360 Petty Cash>", "debit": 6400.00, "description": "Cash takings" },
{ "accountId": "<1330 Yoco settlement>", "debit": 11760.00, "description": "Card takings net of fees" },
{ "accountId": "<6030 Bank Charges>", "debit": 240.00, "description": "Yoco processing fees" },
{ "accountId": "<4010 Sales — Goods>", "credit": 15217.39, "description": "Food & beverage revenue" },
{ "accountId": "<2130 VAT Output>", "credit": 2282.61, "description": "VAT at 15%" },
{ "accountId": "<2120 Tips Payable>", "credit": 900.00, "description": "Tips owed to staff" }
]
}
Note what the numbers do. Revenue is the VAT-exclusive figure — R17 500 of sales excluding tips, ÷ 1.15 = R15 217.39, with R2 282.61 of output VAT. Tips are a liability, not revenue: the restaurant is holding staff money, and booking it as income overstates both turnover and the VAT due on it. And the card line is net of fees, because that is what Yoco actually settles — with the fee shown as its own expense so the margin is honest.
Use reference as a natural key: one value per location per day. If a day is
pushed twice, Ledgr will create a second journal — the reference is what lets Aura detect that
and lets a human find it.
Not posting twice
Aura already tracks this on its own side: its journal generator skips any transaction that
already carries a POS_SALE entry, which is how it stays safe when offline sales
arrive late through /sync/push. Keep the same discipline for the Ledgr push —
record, per day and location, that it was sent and what Ledgr's journal id was.
Ledgr's own idempotency works per source document, and a manually posted journal has no source document, so it will not deduplicate this for you. That is deliberate: two identical journals on the same day are sometimes genuinely two journals.
Stock, and why to leave it alone at first
Aura decrements its own stock on checkout and knows its own recipes. Ledgr has inventory too, with its own costing engine. Running both against the same physical stock means reconciling two sets of numbers forever.
Pick one. For a restaurant, Aura is usually the right owner — it knows the recipes and it is where the stock actually moves — and Ledgr receives the cost of sales as part of the daily journal, which is all the income statement needs. Keep Ledgr's inventory module for anything the till does not sell: cleaning supplies, crockery, kitchen equipment.
VAT and the VAT201
Once the daily journals are landing, Ledgr's VAT analysis and VAT201 pick the output VAT up
automatically — it is a normal credit to 2130 like any other sale. Aura also has
its own VAT201 export; use one or the other, not both, and if the books are in Ledgr then
Ledgr is the one that will agree with the trial balance.
Before you go live
- Push one quiet day and compare Ledgr's income statement against Aura's dashboard for the same date. They should agree to the cent on revenue and on VAT.
- Check the balance sheet: tips should be a liability, and the Yoco settlement figure should match what actually lands in the bank two days later.
- Reconcile the Yoco payout against
1330once it clears. If the settlement account does not clear to nil over a week, the fee split is wrong. - Confirm no journal line landed on a header account — a header with a balance is the symptom of the mapping mistake above.
- Revoke and re-issue the API key once, to prove that path works before you need it.
Where this stands
Honestly: Aura computes the journals today, in its own ledger, and Ledgr accepts them today over the public API. What is described here is the wiring between the two, and it is a job of a day or so on the Aura side — a nightly task that reads its own journal entries, maps the account codes, and posts one document per location per day. Nothing in Ledgr needs to change for it.