Security and tenant isolation
What keeps one organisation’s invoices separate from the next, how access is controlled, and where your files and data actually go.
This page describes the controls that exist in the product today — no more, no less. If your security review needs something that isn’t here, write to hello@ledgersync.fyi and we’ll answer specifically.
One database per organisation
Each organisation (tenant) gets its own MongoDB database, named after its tenant ID. Documents, extractions, ERP records, reconciliation results, tickets, workflows and audit entries all live there. A separate, small global database holds only the tenant registry and user accounts.
Every API request is authenticated first, and the database handle it works with is resolved from the tenant ID inside the caller’s token — before any query runs. There is no code path that lists or joins across tenant databases, and provisioning a tenant never drops or touches another one’s data.
Roles and what they can do
| Role | Can |
|---|---|
| Viewer | Read documents, extractions, ERP records, reconciliation results, tickets and workflow runs. Cannot upload, import or review. |
| Member / User | Everything a viewer can, plus upload documents, import ERP records, run and review reconciliation, approve workflow steps, open and comment on tickets. |
| Tenant admin | Everything above, plus invite and deactivate users, manage workflows, integrations, branding and settings for their own organisation. |
| Platform admin | Creates organisations. This is the only cross-tenant role, and it is held by the LedgerSync team — there is no self-serve signup. |
Authentication
- Passwords are hashed with bcrypt (cost 12). They are never stored or logged in clear.
- Sessions use signed JWTs: a short-lived access token (15 minutes by default) and a longer-lived refresh token (90 days by default). The two carry different type claims and each endpoint rejects the other kind, so a refresh token can’t be replayed as an access token. Refreshing re-checks that the user and organisation are still active and that the role hasn’t changed.
- Two-factor authentication (time-based one-time codes, 30-second step, ±1 window) can be enabled per user. When it is on, login returns a short interim token (10 minutes) that is only good for submitting the code.
- Rate limits: login is limited to 10 attempts per minute per IP; token refresh and 2FA endpoints have their own per-IP limits; every tenant has an overall limit of 200 API requests per minute.
Files and documents
- Uploads are checked against the file’s real signature (PDF, JPEG, PNG, WebP, TIFF, BMP, GIF) — a declared type that doesn’t match the bytes is rejected. The default size limit is 50 MB per file.
- Files are stored under a key that starts with the tenant ID (
{tenant}/{document}/) in S3-compatible object storage, or on local disk in development. Downloads go through authenticated API routes only; there are no public file URLs. - Imports from a URL are protected against server-side request forgery: loopback, private, link-local and IPv6-local address ranges are refused.
- LedgerSync does not add its own encryption-at-rest layer for stored files or the database; it relies on the storage and database providers’ encryption at rest.
Third-party processing
Document extraction is performed by Google’s Gemini API: the content of each uploaded file is sent with a fixed response schema and the structured result is stored with the document. It is sent for that purpose only. The privacy policy describes what we collect and how long it is kept.
Integration credentials
SFTP and database connector secrets (passwords, private keys, connection details) are encrypted with AES-256-GCM under a key that exists only in the server environment, with a fresh random IV per secret. They are decrypted only at the moment a connection is made and are returned to the UI masked.
Audit log and change safety
- Audit log (on by default): logins, uploads, ERP imports and edits, reconciliation reviews and bulk reviews, ticket and workflow changes, user invitations and deactivations — each with the acting user, action, resource, outcome, IP and user agent, stored in the tenant’s own database.
- Idempotency keys on uploads, imports and ticket writes mean a retried request (after a network error, for example) can’t create duplicate records for 24 hours.
- Errors are normalised before they leave the server: clients receive a message and a code, never a stack trace or a raw database error.
- Browser hardening: cross-origin API access only for an explicit allowlist of origins (never a wildcard), HTTP Strict Transport Security, no MIME sniffing, no framing by other sites, and a strict referrer policy.
What we do not claim
Honest scope
Ready to see it on your own invoices?