Read-only by construction
Paylytics reads your payment accounts and never writes to them. Your keys are encrypted before they reach the database, and so are your customers’ names and email addresses. Here is exactly what that does and does not protect you from.
The path a key takes
From your provider to your figures, in five steps
- Step 1You create the keyRead permissions only, at your provider. How much that proves differs by provider, and the matrix below is exact about which.
- Step 2It is sealed on arrivalEncrypted with AES-256-GCM under a random initialisation vector before it reaches the database.
- Step 3The database holds ciphertextA dump of it gives up which account it belongs to and the last four characters of the key, and nothing that could be used against it.
- Step 4It opens only inside a syncDecrypted in memory, used to issue GET requests, and never returned to a page or written to a log.
- Step 5You read your own figuresEverything on screen is a query against our copy, so reading six accounts costs no more requests to you than reading one.
What is actually stored
The figures stay readable. The people do not.
Encrypting everything sounds stronger and would be worse. The database computes every total, bucket and filter over the amounts and dates, and it cannot sum what it cannot read — encrypting those would mean pulling your whole book into memory to draw a single chart.
So the split is deliberate: money and time stay in the clear, and identity does not. Two orders from the same buyer are not even the same ciphertext, because every value gets its own initialisation vector.
- total_amount
- 2400Minor units. Summed, bucketed and filtered by the database.
- currency
- usd
- placed_at
- 2026-08-14T09:12:44Z
- status
- paid
- customer_email
- NULLCleared on the account's next refresh.
- customer_email_enc
- k3Nq8s1r…7Vd2AES-256-GCM, with an initialisation vector of its own.
- customer_email_hash
- 9f1c4a02…be77A keyed HMAC, so one buyer can be matched across accounts without the address itself being readable.
- customer_name_enc
- Pd7Yb0m4…Qa9L
- raw
- { "id": "…", "name": "[redacted]" }The provider's original payload, kept for tracing a bug back to what they actually sent. Every identity field in it is stripped before it is stored.
Read-only, per provider
How strong the guarantee is depends on who issued the key
All 4 are read-scoped. Only one of them can be proved from the outside, and a single sentence covering every one of them would have to be written to the weakest to stay true.
PolarEnforced by the providerOnly an organization access token is accepted, scoped to the four read permissions you grant it. Polar publishes an introspection endpoint, but it authenticates with credentials we do not hold, so the scopes cannot be read back.
StripeEnforced by the providerA secret key is refused on sight, because it could move money. That refusal is real and Stripe enforces the boundary — but a restricted key carries its own write toggles, so leaving those alone is yours to get right.
Dodo PaymentsNot verifiableRead-only is a checkbox set when the key is created, and a key made that way is indistinguishable from one that was not. We can prove it is a Dodo key and nothing further. That part is genuinely yours.
PaddleProvableRead and write are separate grants, per entity. A key holding only the four read permissions has not been given the ability to write anything, and you can read that back off the key in Paddle.
Four things it will not do
Some of this is what the product refuses to build
It never writes to your provider
Not a refund, not a cancellation, not a metadata field. Every request Paylytics makes to a connected account is a GET. That is the one promise the whole product is built on, and everything below is downstream of it.
It never sends a write to test a permission
There is a well-known trick for proving a key cannot write: send a deliberately invalid write and read the status back. It works. It also means issuing write requests against your payment provider, which contradicts the sentence above, so it is not done — and the pages here say "we cannot verify this" instead.
It never shows a badge it cannot back
No "verified read-only" anywhere on this site. Only one provider here lets a key's permissions be read back at all; for the rest a badge would be decoration standing in for a guarantee.
It never sends a key back to the browser
Once stored, a credential is decrypted in one place — inside a sync, on the server. Nothing derived from it beyond a short hint for you to recognise it by is ever returned to a page.
The worst case
Stated as a ceiling on the damage, not as a reassurance
What a leaked database gives up
Amounts, dates, statuses, currencies and product names, account by account. That is a picture of how your business is doing, and it is not nothing. What it does not include is who your customers are: those columns are ciphertext, and the fingerprint that matches one buyer to another is a keyed HMAC rather than a plain hash, so it cannot be reversed by hashing a dictionary of addresses.
What it does not give up
Paylytics itself never issues a write, and refuses any credential it can recognise as write-capable, so the ceiling on a breach is disclosure rather than theft. How much that is worth depends on the provider, which is what the matrix above is for — the strength of the boundary is theirs to enforce, not a promise this page can make on their behalf.
This is not end-to-end encryption, and calling it that would be a lie. The key belongs to the application, because the server has to read your data to compute anything from it. The honest claim is narrower: the database on its own gives up nothing about who your customers are, while somebody holding both the database and the running server’s secrets could decrypt it. Real end-to-end would mean no server-side totals at all, which is the entire product.
Connect one and disconnect it whenever
Disconnecting deletes our copy of that account’s rows. Nothing about the account at your provider changes, because nothing about it ever could.