Security
Your books, locked to your business.
Papertools holds financial records, so this page skips the marketing and states what is actually built. Everything below is shipped behaviour, not aspiration.
Workspace isolation
Every record belongs to exactly one workspace, and that boundary is enforced in the database itself (Postgres row-level security) — not just in application code. A signed-in user’s queries can only ever reach rows of workspaces they are a member of.
This isn’t taken on faith: an automated integration suite boots a real database and attacks the boundary — cross-workspace reads, writes and injections — on every code change, and the change cannot ship if any of it gets through.
Sign-in and two-factor
A new account is confirmed with a 6-digit email code before it can sign in; sign-in itself uses a password, stored only as a salted hash by our authentication provider, and two-factor authentication (authenticator app) is available to every account. Closing an account is confirmed by an emailed code and a grace period — never a single click.
For Papertools’ own staff, 2FA is mandatory, not optional — an operator account without it is locked out of the admin console until enrolled.
Our staff and your data
Operator accounts and customer accounts are strictly separated: staff accounts cannot join, create or browse customer workspaces — the guards fail closed, in both the application and the database. Every administrative action an operator performs is written to an audit log.
The same rule applies upstream: every provider account we run the service from — hosting, database, source control, payments, email, DNS and each bank-data aggregator — has multi-factor authentication turned on, and production keys live only in the hosting platform’s protected environment, never in source control or a browser.
Payments and card data
Card details never touch Papertools servers — subscription payments are processed by Stripe (PCI DSS Level 1). When your customers pay your invoices online, that money flows through your own connected Stripe account; we are not in that money flow.
In transit and at rest
All traffic is TLS-encrypted (TLS 1.2 or later; older versions are refused), with strict transport security pinned for two years across subdomains, plus content-type, framing and referrer protections on every response. Data is stored on managed, encrypted infrastructure (Supabase for the database and files, in the Singapore region; Vercel for the application).
Outbound email is authenticated end to end — SPF, DKIM and DMARC are live on our sending domains.
Backups — the honest version
The database is backed up daily, with a 7-day retention window. We deliberately do not claim point-in-time recovery yet; when that changes, this page changes. You are never locked in either way: your data exports as CSV and PDF at any time, and owners can export a whole workspace as a ZIP of CSVs.
Integrity checks, every night
Your books are re-verified by automated jobs every night: that every journal entry balances, that every document has the ledger entry it should have, and that the tax summary agrees with the ledger. Each run is recorded, and a failed run is reviewed the same day. The ledger itself is append-only with continuous entry numbers — a correction is a reversal, never an edit.
On the code side, every push runs a dependency audit that fails the build on any high or critical advisory in the libraries we ship, alongside the isolation tests above. What we do not yet have is real-time alerting: today a problem is found by the next day’s review, not the same minute, and closing that gap is a dated item in our written policy.
Bank connections
When you connect a bank account for live feeds, you sign in with the bank-data provider’s own hosted flow — your online-banking credentials never reach us. What we hold is the provider’s access token for that one account, encrypted at the application layer with AES-256-GCM before it is stored, in a table no application role can read. Every call to the provider is made server-side; nothing about the connection runs in your browser.
Transactions arrive read-only. We never initiate payments or move money through a bank connection. Disconnecting removes the connection at the provider and deletes the stored token.
Public links
Documents you share by link (view, pay, sign) use long random tokens, are excluded from search engines, can be rotated or revoked at any time, and expose only the one document they were minted for.
Sub-processors
The canonical list of the services that process data on our behalf — and exactly what each one does — is maintained in the Privacy Policy. AI features only send data to their providers when you actively use them.
Reporting a vulnerability
We publish a security.txt (RFC 9116). Found something? Write to security@papertools.app — reports are read by the people who can fix them, and we won’t take legal action against good-faith research. A report is acknowledged within three business days, and the reporter is told when the fix has shipped.
If something goes wrong
An incident is contained first — credentials rotated, the affected route disabled, logs preserved — then assessed from the audit log and platform logs. If your data is affected, we tell you what happened, what was involved, what we have done and what you should do, no later than 72 hours after the breach is confirmed, and we notify the regulator where the law requires it. Partners whose data or credentials were involved, including bank-data providers, are notified under our agreements with them.
Our written policy
Everything on this page is also set down in a written Information Security Policy — scope, roles, data classification, access control, encryption and key handling, secure development, monitoring, vulnerability handling, incident response, backups, sub-processors, requests about personal data and a yearly risk assessment — with the procedures that go with it. It is reviewed at least yearly and whenever the product’s architecture or providers change. Business customers and partners can request a copy from security@papertools.app.