Skip to main content
Security & data integrity

We let AI do the boring parts. We don't let it bypass the controls.

Most 'AI for accounting' tools either hand the model a service-role key and hope, or train on customer data without disclosing it. We do neither. The AI is bound by the same row-level security policies as a junior bookkeeper — not more. Your data is never used to train models. Posted entries are immutable at the database level, not just in application code.

A balanced double-entry journal: total debits equal total credits at 34,160.00, a balance the database trigger enforces at commit time before any row can post.

PROOF — the database enforces this, not the app

A posted entry the system cannot un-balance

DB-enforced
#AccountDebitCredit
1100Amazon clearing19,100.00—
5210Referral & selling fees3,200.00—
5220FBA fulfilment fees1,800.00—
4001Sales returns & refunds700.00—
4000Amazon sales — US—24,800.00
Cost relief
5000Cost of goods sold9,360.00—
1330Inventory — FBA—9,360.00
Totals0.000.00

The shape of the trust model

Three independent layers. Bypassing one bypasses none of the others.

The hard accounting invariants live in the database — in Postgres triggers and SECURITY DEFINER functions — not in application code an AI bug or a malicious actor could route around. Tenancy is enforced at the row, not the request. And the model never holds more privilege than the human it acts for.

Database-enforced

The invariants live in Postgres

Double-entry balance, posted-entry immutability and the append-only audit trail are database triggers and constraints — they hold even against a service-role write. There is no application-layer override path.

  • DR = CR checked at commit, within ±0.0001
  • Posted entries blocked from edit by a guard trigger
  • Audit log: SELECT only, no INSERT/UPDATE/DELETE path

Tenant-isolated

Isolation at the row, not the request

Row-level security is enabled on every business table — zero exceptions in production. A user from one seller account cannot read, write or delete another account’s rows, enforced by Postgres rather than by a session check the web app could forget.

  • RLS on every ledger + audit table
  • Two levels: account (org) and books (client)
  • Cross-tenant references rejected at the foreign-key layer

AI-bound

The model holds no extra keys

When the AI extracts a document or drafts an entry, it acts through the same SECURITY DEFINER RPCs a human would call — with strict tool-use schemas. There is no AI path that writes data it could not touch directly.

  • Extracted text treated as untrusted input, never instructions
  • Per-call + per-batch cost ceilings — no surprise bills
  • Low-confidence output flagged for human review
  • RLS on every business table
  • DR = CR enforced by trigger
  • Posted entries immutable
  • Append-only audit log
  • Cross-tenant FK guards
  • Signed-URL document access
  • Encrypted at rest + TLS 1.2+
  • EU-hosted (Stockholm)
  • 11-year audit retention
  • Model output treated as untrusted

Connect → books, end to end

One platform, six hops — and a control on every one.

A seller connects Amazon once. From there, settlements become balanced journal entries, cost of goods posts automatically with its settlement, the trial balance ties, and the period closes — all inside one ledger. Here is the whole path, and the guard that holds at each step so nothing — not a bug, not the AI, not another tenant — can route around it.

01

Connect

Read-only Amazon link

The Selling Partner API connection is read-only and carries no buyer personal data — it never holds write access to your store. OAuth tokens live in server-side secrets, never in a browser bundle or a committed workflow file.

OAuth tokens server-side only
02

Settlement

Each payout, decomposed

A settlement is parsed into its revenue, referral and FBA fees, refunds and reserves. The raw report is stored in private storage, reachable only through a tenant-scoped signed URL with a 10-minute time-to-live.

Signed-URL access · 10-min TTL
03

Journal entry

Drafted, then approved by a person

The decomposed settlement becomes a double-entry draft. SUM(debits) must equal SUM(credits) within ±0.0001 — checked by a constraint trigger at commit. An unbalanced entry cannot exist in the database.

DR = CR enforced by trigger
04

Cost of goods

Posted with its settlement

Cost of goods is units sold × the unit cost you set per SKU. It posts automatically when its settlement is approved and posted — on by default for a new book, and you can switch it off. It never touches the bank.

Auto-posts with its settlement
05

Trial balance

A TB that reconciles

Every posted entry rolls into a per-client trial balance computed live from the ledger, never a cached snapshot. Because each JE balances and tenancy is enforced at the row, the TB ties by construction — and drills back to the source settlement and the extraction job that produced it.

Full drill-down to the source pixel
06

Close

Period sealed, audit-logged

A period closes only when the trial balance is within ±0.01. A closed period refuses new entries unless an admin flags an explicit adjustment. The close, and every state change before it, writes an append-only audit-log row.

Close gate ±0.01 · append-only log

The control register

What the database guarantees, stated so your auditor can verify it.

These are not aspirations. Each one is a trigger, a constraint, or an RLS policy you can point a database introspection query at. The balance below is the same entry from the proof above — debits tie to credits, and the trigger is what makes that non-negotiable.

FIG — Trial balance that ties
AccountDebitCredit
1100Amazon clearing19,100.00—
5210Referral & selling fees3,200.00—
5220FBA fulfilment fees1,800.00—
4001Sales returns & refunds700.00—
4000Amazon sales — US—24,800.00
5000Cost of goods sold9,360.00—
1330Inventory — FBA—9,360.00
Totals34,160.0034,160.00
Balanced · enforced by trigger0.00
FIG — Database-enforced guarantees
  • DR = CR tolerance, every posted entry±0.0001
  • Posted-entry edit attempts permitted0
  • Same-day fat-finger un-post window24h
  • Audit-log mutation paths from a session0
  • Signed-URL time-to-live for source docs10min
  • Accounting-record retention design11yr
Default-deny posture0 overrides
FIG — Manual entries: prepare → check → approve, with dual control at two or more users · a solo owner posts as sole approver, with a permanent attestation in the audit log · settlements and bank matches take one click
  • JE-018291Prepared

    Preparer drafts the manual entry

    34,160.00
  • JE-018291Checked

    Checker reviews the entry

    34,160.00
  • JE-018291Posted

    Approver approves — then it posts

    34,160.00

Why one platform is the safer platform

The stitched stack has seams. Seams are where data leaks and numbers drift.

The typical setup runs a settlement connector, a general cloud ledger, and spreadsheets for inventory and costing. Each handoff is a CSV export, a re-keyed figure, a fourth place your data lives. Nexus does all three jobs in one audited ledger — so there is one access model to govern and one trail end to end.

  • Data copies to secure

    Connector + ledger + spreadsheets

    Settlement data lands in the connector, is exported, re-imported into the ledger, then copied again into spreadsheets — four resting places, four access models.

    Nexus — one platform

    One ledger holds the settlement, the JE, inventory and cost of goods. One RLS-enforced access model governs all of it; no CSV hop between systems.

  • Audit trail

    Connector + ledger + spreadsheets

    Each tool logs its own slice. Reconstructing who changed what across the connector, the ledger and a spreadsheet is manual — and a spreadsheet logs nothing.

    Nexus — one platform

    One append-only audit log spans connect → settlement → JE → close, with actor, timestamp and payload-diff on every transition. Nothing edits it from a session.

  • Balance integrity

    Connector + ledger + spreadsheets

    The ledger enforces double-entry; the spreadsheet does not. Inventory and cost of goods worked in a sheet can silently drift from the books.

    Nexus — one platform

    DR = CR is a database trigger, and cost of goods posts automatically when its settlement is approved — the figures cannot drift apart, because they live in the same ledger.

  • AI privilege

    Connector + ledger + spreadsheets

    Bolting an AI assistant onto a stitched stack usually means handing it broad API keys across several systems.

    Nexus — one platform

    The AI acts only through the same tenant-scoped RPCs a human calls, with strict tool-use schemas and per-batch cost caps. It holds no key a person would not.

Every control, in depth

Six domains. One frame.

The same specific commitments a security questionnaire asks for — pick a domain and the panel reconciles in place.

The accounting invariants are enforced in Postgres, not in application code that an AI bug or a malicious actor could bypass.

DR = CR

Double-entry enforced by trigger

Every journal entry must satisfy SUM(debits) = SUM(credits) within ±0.0001. The check runs as a CONSTRAINT TRIGGER on the journal-entry-lines table — even a service-role write that violates the rule is rejected at COMMIT time. There is no application-layer override.

Immutable

Posted entries are immutable

Once an entry is posted, a guard trigger blocks any UPDATE to its accounts, amounts or narratives, and the RLS delete policy refuses to delete it. Corrections happen via reversal entries, not edits. One narrow, audit-logged exception: the same user who posted an entry can un-post it within 24 hours, and only while nothing downstream has consumed the posting.

Audit

Append-only audit log

Every workflow transition writes a row with actor, timestamp, from-state, to-state and a payload-diff. Application roles hold SELECT only; the table has no INSERT, UPDATE or DELETE path from any client session. Once written, a log row cannot be altered through the application.

Before you send the questionnaire

The questions procurement asks — answered up front.

  • Do you train AI models on our data?

    No. We do not opt customer extractions or chat history into any model-training pipeline. Anonymised, aggregated counts (pages, entries, document-type mix) may inform product improvement; the underlying content never does. This is contractual in the agreement and operational in the subprocessor configuration.

  • Can one of your customers see another customer’s data?

    No. Row-level security is enabled on every business table, with no production exceptions, and keys on both the account (org) and the books (client). Dedicated foreign-key triggers reject any cross-tenant reference before it commits. The bypass key never reaches the browser.

  • Can a posted journal entry be edited or deleted?

    No. A guard trigger blocks any edit to a posted entry and the delete policy refuses it; corrections are made via reversal entries. The one narrow exception is a same-user, 24-hour un-post for a fat-finger, only while nothing downstream has consumed the posting — and it is itself audit-logged.

  • Where is our data hosted?

    Data is hosted in the EU (Stockholm) on every tier, under a Data Processing Addendum. There is one production region. Customer data is never used to train any model.

  • Can your engineers see our books?

    Not routinely. There is no “log in as the customer” path. Read-only access to a single tenant requires a written authorisation, a time-bounded grant that auto-revokes after 24 hours, and a matching audit-log entry. Break-glass access is alerted.

  • Do you hold SOC 2 or ISO 27001?

    Not yet — both are targeted in the hardening phase. The current posture is built to be compliant: the controls (RLS, the DR=CR trigger, the append-only audit log, least-privilege access) already exist, so certification formalises them rather than building them. We respond to security questionnaires within two business days.

Want our DPA, a security-questionnaire response, or a walkthrough of the controls?

We respond to security questionnaires within two business days. The DPA is signed before any pilot uploads its first document.