Data Policy

Last updated: September 12, 2026

Zedi is a personal-finance tool. You hand it bank statements and receipts, and it gives you back a real picture of where your money went. This page explains what we keep, where it sits, who can read it, and how to delete it. In plain English, grounded in the code.

Questions or requests: zedi@sneeks.ai.

1. What we store

  • Transactions, categories, accounts, and rules in our Postgres database. This is the data the dashboard runs on: dates, amounts, merchant names, descriptions, the categories you assign, and the auto-categorization rules you build by correcting us.
  • Receipt photos and PDF statements, transiently, in Cloudflare R2. A receipt image is deleted from R2 the moment OCR succeeds: the parsed line items become the record, not the photo. If OCR fails, the image is kept so you can hit Reprocess or delete the receipt yourself. PDF statements follow the same pattern: the file lives in R2 only while the import is in its preview state, and is deleted on commit, on discard, or on statement delete.
  • Your Anthropic API key, encrypted, if you choose to bring one in Settings. Stored as a ciphertext blob in user_settings.anthropic_api_key_encrypted. When unset, Zedi's shared key is used and the monthly OCR allowance applies.
  • Your SimpleFIN connection, encrypted, if you connect a bank. SimpleFIN issues Zedi a read-only access URL when you paste a setup token; it is not your bank password, which Zedi never receives. It is stored as a ciphertext blob in bank_connections.access_url_encrypted, encrypted with AES-256-GCM by the same cipher as the BYOK key, next to the last sync time, its status, any errors the bridge reported and a count of today's reads.
  • The bank account list SimpleFIN reports: institution, account name, currency, balances, balance date, and holdings where your institution provides them, plus the Zedi account you mapped each one to. Refreshed on every sync. Synced transactions are stored like imported ones, and each also keeps the bank's transaction id, payee, memo and merchant category code (MCC) in import_original.bank and external_txn_id.
  • A transaction audit log for the Memory page. Every edit, import, auto-categorizer touch, and delete on a transaction writes a row noting what changed, when, and which actor (you, an importer, the auto-categorizer) made the change. This is yours: it shows you your own history.
  • Better Auth session data. Your email, name, optional handle, and the session rows that keep you logged in. If you signed up with email and password, we also store a one-way hash of that password (we never see the plaintext). If you signed up with Google or Apple, no password is stored; your provider-issued user ID lives in the linked-account row instead.

2. Where it lives

SaaS at zedi.sneeks.ai. Postgres is a Railway managed instance in a US region. Receipt and PDF blobs live in a Cloudflare R2 bucket named zedi-saas, with object keys prefixed by your user ID ({user_id}/receipts/..., {user_id}/statements/...).

Personal deployment.The same code also runs as a single-tenant box (Nicolo's personal instance on a Proxmox VM). That deployment holds exactly one user's data. If you signed up at zedi.sneeks.ai, your data is on the SaaS side, not on the personal box.

3. How long we keep it

  • Receipt images: deleted from R2 the moment OCR succeeds, in the same database write that records the parsed line items. We do not retain user receipt images longer than the OCR call itself.
  • Failed-OCR receipt images: held in R2 until you act on them. Either retry the OCR, in which case a successful parse triggers the same delete, or delete the receipt entirely, in which case the image is removed too.
  • PDF statements: held in R2 only during the preview window between extract and commit. The blob is deleted on commit, on discard, and on statement delete.
  • Anthropic-side retention: Anthropic deletes API inputs within 30 days and contractually does not train on them (Anthropic Commercial Terms, Section B). That covers receipt photos and PDF statements during the seconds-long OCR call.
  • Bank connections:the encrypted access URL and the account list persist until you disconnect or close your account. Disconnecting deletes Zedi's copy of the credential and the account list, but it does not revoke access at SimpleFIN Bridge: remove the Zedi app in Bridge too. Transactions already synced stay in your ledger, like imported ones, until you delete them.
  • Everything else: kept until you delete it. Transactions, categories, accounts, audit log entries, your encrypted BYOK key, your account itself. No silent purges, no data lifecycles. If you want it gone, see section 6.

4. Who can read it

You. Postgres Row-Level Security isolates every user from every other user. The application runs as a Postgres role (app_user) that cannot bypass RLS, even on a bug. Every read and every write is scoped to the policy user_id = current_setting('app.user_id'), set at the start of each request from your verified session. A handler that forgets to filter by user gets blocked at the database layer.

R2 keys are user-prefixed. Every receipt image and PDF blob is stored under {user_id}/...in the bucket. The storage layer also verifies the prefix matches the requester on read and delete, so a forged database row would still not reach another user's bytes.

BYOK keys are encrypted at rest.If you store your own Anthropic API key in Settings, it is encrypted with AES-256-GCM before it touches the database. A fresh random nonce is used per encryption. The 32-byte master key lives outside the database, in the backend's environment. The SimpleFIN access URL for a bank connection is encrypted the same way.

The operator. Nicolo, who runs the service, has administrative access to the production database and the R2 bucket. That access exists for operations: migrations, incident response, support requests you initiate. It is not used to browse user data.

5. Third parties

A short list of services see specific slices of your data so Zedi can function. The full list:

Anthropic (Claude Vision)

Receipt photos and PDF statements are sent to Anthropic's Vision API for OCR. Per Anthropic's Commercial Terms, Section B, Anthropic may not train models on API inputs and deletes them within 30 days. CSV and QFX imports never go to Anthropic: they are parsed locally in our Rust backend.

Model disclosure. Both calls use the Claude model claude-sonnet-5. A receipt call sends the receipt image and a fixed extraction prompt. A PDF call sends the statement document and a fixed extraction prompt. Nothing else goes with them: no account identifier, no email address, no other transactions, no history from earlier calls. If you bring your own key, the same request goes out under your key instead of ours.

Cloudflare

Hosts the R2 bucket where receipt photos and PDF statements sit transiently during OCR. Also serves DNS for the sneeks.ai domain. Cloudflare sees the bytes of your uploads only while they are in R2; it does not see your transactions, your categories, or your account.

Railway

Hosts the SaaS application (backend and frontend) and the Postgres database for zedi.sneeks.ai. Your transactions, categories, accounts, rules, audit log, and account record live in a Railway-managed Postgres instance in a US region.

SimpleFIN Bridge (optional bank sync)

Only if you connect a bank. You subscribe to SimpleFIN Bridge yourself and SimpleFIN bills you directly, $1.50 a month; Zedi takes no cut and sees no payment details. You link your bank inside Bridge and paste a setup token into Zedi, which exchanges it once for a read-only access URL. On each sync Zedi sends SimpleFIN that access URL's credentials and the date range it wants, nothing else: no email, no name, no other data from your Zedi account. What comes back is your account list (institution, account name, currency, balances, holdings where available) and up to 90 days of transactions (date, amount, description, payee, memo, MCC). Zedi reads at most 24 times a day per connection. See SimpleFIN's privacy policy and security page.

MX (SimpleFIN's data aggregator)

SimpleFIN Bridge uses MX Technologies to connect to banks. When you link a bank in Bridge, the bank login goes to MX, not to SimpleFIN and never to Zedi; MX fetches your balances and transactions and hands them to SimpleFIN, which passes them to Zedi on a sync. Zedi has no account with MX and sends MX nothing directly. See the MX Privacy Statement.

Google Identity (optional sign-in)

If you choose “Continue with Google” on the login or signup page, Google handles the authentication handshake and returns your email, name, and a stable user ID to Zedi. Google does not see your transactions, receipts, categories, or anything else you do inside Zedi. You can skip this and use email + password instead, in which case nothing is sent to Google.

Apple Sign in with Apple (optional sign-in)

If you choose “Continue with Apple,” Apple handles the authentication handshake and returns either your email or a private-relay alias (your choice via Apple's “Hide my email”) plus a stable user ID. Apple does not see your transactions, receipts, categories, or anything else you do inside Zedi. You can skip this and use email + password instead, in which case nothing is sent to Apple.

Better Auth (library)

Open-source library that handles signup, login, and session management inside the Next.js frontend. Better Auth is not a third-party service: it runs as code inside our own backend, and its tables (users, sessions, accounts, verifications) live in our own Postgres database. No user data is sent to a Better Auth vendor, because there isn't one.

No data brokers. No advertisers. No behavior-analytics vendor on authenticated pages: no Google Analytics, no Mixpanel, no PostHog, no Amplitude, no session replay. If we ever add another sub-processor, this list updates first.

6. Deleting your data

Email zedi@sneeks.ai for either of two things, and you'll get a reply within a day:

  • Full JSON export of everything you have in Zedi: transactions, categories, accounts, rules, receipts, audit log.
  • Account closure that hard-deletes your user record, all transactions, all receipts, all categories, all rules, all audit log entries, every bank connection, and any remaining R2 blobs.

Bank syncyou can stop yourself: disconnect it under Settings > Connections & keys, which deletes the stored access URL and account list right away, then remove the Zedi app in SimpleFIN Bridge so the access URL stops working there too. Synced transactions stay until you delete them or close your account.

Self-serve buttons for both are tracked under ZEDI-71. Until that ships, email is the path, and it's a real path: it is in the marketing copy, the signup page, this policy, and the account page.

7. Changes to this policy

If we change something material (adding a sub-processor, changing how a class of data is handled, broadening retention), you see a banner inside Zedi before the change takes effect, with a pointer to the updated version of this page. Cosmetic edits (typos, clarifications) update the Last-updated date and don't get a banner.

Contact

Anything in this policy unclear, anything you want changed, anything you want a copy of, anything you want deleted: zedi@sneeks.ai. You'll hear back within a day.

See also: Terms of Service.