Accounting sync
Read your general ledger and keep an accounting system in sync.
Smooth POS keeps a full general ledger. Transactions that affect your books, like supplier bills and store credit adjustments, post journals to it, so your accounting system can take its numbers straight from Smooth POS. This guide covers how the ledger is laid out and the two ways to get it out: a CSV export, or an incremental sync through the API or a Glue job.
How the ledger works
- Accounts. Your chart of accounts is under Accounts → Chart Of Accounts, or List accounts. Each account has an
idand anumber(like100). Map them to your accounting system bynumber. - Journals and entries. A journal is one balanced posting, with a
name(likeAP InvoiceorStore Credit Adjustment), adate,tagsand two or more entries. Each entry posts anamountto one account, optionally with acost_centre_idand atax_rate_id. - Signs. Positive amounts are debits and negative amounts are credits. A journal's entries always add up to zero.
- Locked periods. Entries dated outside your general ledger dates are locked. See Get general ledger dates.
Option 1: Export a CSV
Export journal entries (GET /journals/entries/export.json) returns a CSV of up to 10,000 entries. It takes the same filters as List journal entries, so a date range is usually all you need:
curl "https://api.smoothpos.net/journals/entries/export.json?date_min=2026-10-01&date_max=2026-10-31" \
-H "X-Smoothpos-Auth: YOUR_TOKEN" -o october.csvThe columns are id, number, name, account_name, account_number, date, cost_centre, tax_rate, tax_rate_percent, amount, tags, reversed, created and created_by.
For a bigger range, split it into smaller ones. Count journal entries tells you how many entries match, plus their total debit and credit, which is a handy check that your import is complete.
Option 2: Sync incrementally
For a regular sync, read entries in ID order and remember the last one you sent.
- Call List journal entries with
since_idandlimit=250. - Send the entries to your accounting system.
- Remember the highest
idyou sent. - Next time, carry on from there.
since_idis inclusive hereOn journals and journal entries,
since_idreturns the entry with that ID as well as the ones after it. Ask forsince_id= last ID + 1, or skip the first entry, so you don't send it twice.
Follow the X-Next-Page header for each next page. Don't build cursors yourself. See Filtering, sorting and search.
Poll rather than wait for a hook
journal_createonly fires for journals created through Create a journal, not for every journal in the ledger. Supplier bills and store credit adjustments, for example, post journals without it. A scheduled sync is the reliable way to catch everything.
Reversals
Smooth POS doesn't edit posted journals. A correction is a reversal: a new journal with the opposite entries. Both the original and the reversal are then marked reversed, and a journal can only be reversed once. Your sync picks the reversal up like any other journal, so your accounting system stays in step.
Example: A nightly Glue job
Trigger: Scheduled, once a night.
-
Cache: Get the bookmark, Operation Get, Key
accounting:next_entry_id, Default value1, Response variablenext_id. -
API Request: List journal entries, Additional URL parameters
since_id={{ next_id }}&limit=250, Fetch all pages on, Response variableentries. -
Script: Build the posting
var rows = $.entries.items; $.has_entries = rows.length > 0; var maxId = 0; rows.forEach(function (e) { if (e.id > maxId) maxId = e.id; }); $.new_next_id = maxId + 1; $.posting_body = JSON.stringify(rows.map(function (e) { return { ref: e.id, journal: e.journal_id, date: e.date, account: e.account_number, amount: e.amount, description: e.name }; })); -
If Condition: If there's anything new, Condition
$.has_entries === true. Under THEN:- REST Request: Post to the accounting system, with Fail on bad response code on, and Body
{{ posting_body }}. - Cache: Save the bookmark, Operation Set, Key
accounting:next_entry_id, Value{{ new_next_id }}, Value type Number, Time to live2592000(30 days).
- REST Request: Post to the accounting system, with Fail on bad response code on, and Body
Because the bookmark is only saved after the post succeeds, a failed run simply tries the same entries again. Send each entry's id as its reference so your accounting system can ignore anything it's already seen.
Cache entries expireA cache entry lasts up to 30 days, and every nightly run refreshes it. If the job is paused for longer, the bookmark goes back to the default, so make sure your accounting system ignores entries it already has.
Post journals into Smooth POS
Need to bring adjustments the other way? Create a journal with balanced entries:
{
"name": "Month-end accrual",
"date": "2026-10-31T00:00:00Z",
"tags": ["accrual"],
"entries": [
{"account_id": 512, "amount": 1200},
{"account_id": 208, "amount": -1200}
]
}Unbalanced entries fail with unbalanced journal, and unknown accounts or tax rates fail with account doesent exist or tax rate doesent exist. To undo a journal, reverse it.
Supplier bills, invoices and bank feeds
- Supplier bills (AP invoices) link to purchase orders. See Purchasing and receiving.
- Customer invoices (AR invoices): Create an AR invoice.
- Bank feeds: Import bank transactions, then match and reconcile them in Accounts → Bank Accounts.
Updated about 22 hours ago
