Skip to content
Finanly

Security & deployment

One door in. Nothing out.

Finanly runs on infrastructure you control, with one public API, a private network for everything else, isolation enforced in the database, and an audit log that cannot be edited. Here is exactly what is in place — and what is not yet.

Self-hostedRLS per companyNot SOC 2 certified — stated

Controls

Nine controls, each traceable to code.

The annotation under each card names the mechanism. Your security team can ask for the file.

Tenant isolation

Every tenant table carries a row-level security policy keyed on the request's tenant context; the application role cannot bypass it. The application also filters by tenant explicitly — two layers.

Postgres RLS · forced

Encrypted secrets

Connector credentials are encrypted with AES-GCM under a master key; associated data binds each ciphertext to its tenant and key id so it cannot be swapped between tenants.

AES-GCM · tenant-bound AAD

Append-only audit

A database trigger rejects UPDATE and DELETE on audit_events. Every irreversible action writes actor, event, reference and its idempotency key.

audit_events · trigger

Idempotent side effects

Side-effect endpoints require an Idempotency-Key. A replay returns the stored response; a changed payload under the same key is rejected; the ledger connector uses the same key so a posting is created once.

Idempotency-Key · 409 on conflict

Internal-only model gateway

The model gateway has no host port and is called by core-api with a short-lived token bound to one tenant and one audience. It never reaches a connector or the database.

internal JWT · no public AI API

Edge and rate limits

TLS and routing at the edge; public write routes are rate-limited per IP and per email; admin endpoints sit behind an extra IP allowlist.

rate_limit.py · admin allowlist

Roles and entitlements

Memberships carry a role per company (owner, admin, member). Every feature is a registered key checked at the endpoint and in the UI; plans assign keys.

memberships · plan_features

Reversibility

Categorizations and postings can be undone through the same idempotent path; the original action and the undo are separate audit events.

txn_undo_categorization

Parity gates

Balance sheet, P&L and trial balance are re-derived from the canonical store and compared with the ledger of record every hour. Drift is visible, not silent.

financial_statements · hourly

Multi-company

Many companies, one login, zero leakage.

Each company is a tenant. Switching sets the tenant context for every query; Postgres row-level security enforces it underneath the application, not just in it. Illustrative tenants below.

BusinessCompany A
  • Mercury · Plaid
  • ERPNext ledger
  • Cost centers
WHERE tenant_id = current_setting('app.tenant_id')
BusinessCompany B
  • Shopify · Flexport
  • Landed cost
  • COGS sync
WHERE tenant_id = current_setting('app.tenant_id')
BusinessCompany C
  • Plaid · EUR accounts
  • FX revaluation
  • Simple books
WHERE tenant_id = current_setting('app.tenant_id')
PersonalPersonal space
  • Safe-to-spend
  • Baskets
  • Subscriptions
WHERE tenant_id = current_setting('app.tenant_id')

Audit trail

Every action is on the record.

Illustrative rows with the real event names: categorize, export item created, replay returns the stored result, changed payload rejected, undo, hourly parity check.

audit_events · append-only · tenant 9f26…0021
timeactoreventreference
09:41:03luca@…txn.categorizeIdempotency-Key 7f3a…c1
09:41:03core-apiexport_batch.item_createderpnext JE-2026-00412
09:41:09luca@…txn.categorize (replay)same key → stored 200
09:42:17luca@…txn.categorize (changed payload)same key → 409 idempotency_conflict
09:44:52luca@…txn.undo_categorizationreversal JE-2026-00413
09:45:00jobs-beatfinancial_statements.parity_checkBS / P&L / TB · pass

Illustrative rows — the shapes are real event names from core-api; the values are sample data.

Deployment

Your host. One stack.

One Docker Compose stack: edge, UI, core-api, model gateway, connectors, jobs, Postgres, Redis and the semantic engine. Only the edge, the UI and core-api are reachable; everything else is on a private network with no host ports.

Browserfinanly.ai · app.finanly.ai
edgeTLS · routing · rate limits
core-apithe single enforcement point
private network · internal JWT · no host ports
ai-gatewayprivate model · internal only
jobs · beatCelery workers + schedule
compliancemass balance · trace-back
connector-*mercury · plaid · shopify · flexport · paypal · wise · ga4 · erpnext
Postgrescanonical store · RLS per tenant
Cubesemantic layer · 26 cubes
audit_eventsappend-only (DB trigger)
Redisqueues · idempotency locks

Where it runs

A single host or VPS you control — on-premises or in your cloud account. The model is served on the same host. We do not operate a shared multi-customer cloud.

Where data lives

Postgres and Redis on local volumes under a path you choose; scheduled backups to a separate disk; secrets in an environment file that is never committed.

How it is updated

Images are built from the repository and tagged; a deployment is a container recreate; rollback is the previous tag. Migrations are versioned and forward-only.

What is observable

Request and correlation IDs on every response; sync runs, webhook receipts and exports write audit events; a public status probe; admin-only sync controls.

What leaves the host

Connector calls to the sources you connect (your bank, store, freight forwarder, ledger) and self-hosted web search for vendor enrichment. No ledger rows go to any AI API.

What you can inspect

The OpenAPI surface of core-api, the connector contract, the migration history and the Compose file. Documentation is written as a requirement of each service.

Certification status

What is in place. What is not yet.

We would rather tell you than imply it.

In place and documented

  • Row-level security per tenant, forced for the application role
  • AES-GCM-encrypted secrets bound to their tenant
  • Append-only audit events enforced by a database trigger
  • Idempotency keys on every side-effect endpoint
  • Internal-only model gateway; no public AI API; no cloud fallback
  • Rate limits on public write routes; admin IP allowlist
  • Self-hosted deployment with versioned migrations and image-tag rollback
  • Scheduled backups of databases and secrets to a separate disk

Not yet

  • SOC 2 Type I or Type II report — controls documented, audit not commissioned
  • Third-party penetration test report
  • Formal SLA and uptime history (the status page is a live probe, not a track record)
  • Single sign-on (SAML / OIDC) for institution identity providers
  • Customer-managed encryption keys
  • Public bug bounty programme

FAQ

Straight answers

Can Finanly see our data?

Not unless you grant access. The stack runs on your host; there is no Finanly-operated cloud holding your data. Support is done with you, on your terms.

How is one company kept away from another?

Row-level security policies in Postgres filter every tenant table by the request's tenant context, and the application filters explicitly on top. Secrets are encrypted per tenant. The model sees one tenant per call.

What if a sync or export runs twice?

Every side-effect call carries an Idempotency-Key. A replay returns the stored response; the ledger connector uses the same key so a posting is created once; a changed payload under the same key is rejected.

Who can edit the audit log?

Nobody. A database trigger rejects updates and deletes on audit_events. Undo is a new event, not an edit.

Which ports are open?

The edge (TLS), the UI and core-api. Connectors, the model gateway, workers, Redis, Postgres and the semantic engine have no host ports and are reached only on the private Docker network.

Is there SSO?

Not yet. Authentication is email and password with short-lived access tokens and refresh sessions, plus one-time tokens for password reset. SSO for institutional identity providers is on the list.

Is the AI a security risk?

It is designed not to be: it cannot read rows, call connectors or post entries. It receives a question plus vocabulary and returns a plan the platform validates. It runs on your host.

Can we review the code and the controls?

Yes, under an agreement. The architecture, the OpenAPI surface, the migrations and the Compose file are the primary evidence; we walk your team through them.