Security
Last updated: October 17, 2026
This page describes what PaidCheck does with the credentials and data you give it, as the service is built today. If anything here is unclear or you think something is wrong, email support@paidcheck.app.
1. Restricted Stripe keys only
- PaidCheck asks for a Stripe restricted key (
rk_live_…orrk_test_…). You choose Read or None per resource when you create it in the Stripe Dashboard. - Live secret keys (
sk_live_…) are refused by the free report, by monitored apps and by the key checker. Publishable keys (pk_…) are refused too. - The key checker also refuses test-mode secret keys (
sk_test_…). The free report and monitored apps currently still acceptsk_test_…keys, which can only reach Stripe test-mode data. Use a restricted key there too. - For Supabase, PaidCheck refuses service-role and
sb_secret_keys and asks for the anon/publishable key plus a secret-protected function instead.
2. The exact permissions we ask for
Create the restricted key with these permissions and set everything else to None:
| Customers | Read | match a subscription to the customer's email, ID and metadata |
| Subscriptions (Billing) | Read | know who is active, trialing, past_due, unpaid or canceled, and seat quantities |
| Charges | Read | detect duplicate charges, refunds and one-time payments |
| Events | Read | find events whose webhook delivery failed (pending_webhooks > 0) |
| Webhook Endpoints | Read | detect disabled endpoints and endpoints missing key events |
| Checkout Sessions | Read (optional) | optional: one-time purchases (mode=payment) and telling separate checkouts apart |
| Invoices | Read (optional) | optional: link charges to subscription periods (fewer double-charge false positives) and invoice emails |
| Entitlements | Read (optional) | optional: count Stripe active entitlements as paid access |
| Everything else | None | PaidCheck never needs Write on anything. |
PaidCheck only makes read (list) requests to the Stripe API. It never creates, updates, refunds or deletes anything in Stripe. It can't check whether a key also has Write permissions, because it never makes write requests, so please make sure every other resource is set to None when you create the key.
3. How stored credentials are encrypted
- For monitored apps, the Stripe key, the access-feed bearer secret, the Supabase anon/publishable key and PaidCheck secret, and any uploaded CSV are encrypted before storage with AES-256-GCM, using a fresh random 12-byte IV for every value and GCM's authentication tag to detect tampering.
- The 256-bit encryption key is kept in a server-side environment variable on our hosting provider, separate from the stored data. It is never sent to the browser.
- Credentials are decrypted only on the server, when a check runs. The dashboard shows only a masked hint of your Stripe key (its prefix and last 4 characters).
- Not encrypted beyond the storage itself: the app name, the access-feed or Supabase project URL, the alert email, your allowlist and plan mapping, and the reports and history described below.
4. Where data is stored
PaidCheck runs on Vercel. It has no separate database: everything is stored as JSON documents in Vercel Blob with private access. All traffic to paidcheck.app uses HTTPS, and PaidCheck only connects to an access feed or Supabase project over an https:// URL.
5. What we store, and for how long
- Account: your email, plan, sign-up time and, if you subscribe, the Stripe customer and subscription IDs for your PaidCheck plan. Kept until you ask us to delete your account.
- Monitored app settings: the encrypted credentials above, the app name, alert email, allowlist, plan mapping, dismissed findings and a summary of the last check. Kept until you delete the app. There is no automatic time limit.
- Latest report for each monitored app, which can include end-user emails, Stripe object IDs and amounts. Overwritten on every check and kept until you delete the app.
- Daily history for each monitored app: IDs and types of undelivered webhook events, issue identifiers (which can include end-user emails) and daily totals. Daily snapshots older than 400 days are deleted automatically on the next check.
- Sign-in links are stored only as a SHA-256 hash, expire after 15 minutes and are deleted when used. Sessions use an HTTP-only cookie signed with HMAC-SHA256 that expires after 30 days.
- Rate-limit counters: a request count and time window, keyed by a one-way SHA-256 hash of your IP address (or of your email for sign-in and report emails). They are overwritten as you make requests and aren't automatically deleted.
6. The free report doesn't keep your keys or data
The free leak report uses your Stripe key, any access-feed credentials and any CSV you paste or upload for that one request, in memory. The results go back to your browser. We don't store the keys, the CSV, the Stripe data or the report. The only thing written to storage is the rate-limit counter keyed by a hash of your IP address (see above). If you dismiss a finding there, that choice is saved only in your browser.
The key checker works the same way: it makes one read-only list request (limit 1) per resource, never stores the key and never returns it in the response. It also keeps only the hashed-IP rate-limit counter.
If you choose to have the free report summary emailed to you, that goes in a separate request that never contains your keys.
7. Deleting data and revoking access
- Revoke the key in Stripe: in the Stripe Dashboard, go to Developers → API keys, find the restricted key you created for PaidCheck, and roll or delete it. PaidCheck can't read anything after that, and checks for that app will fail.
- Revoke app access: change or remove the PaidCheck secret your Supabase function or HTTPS endpoint checks.
- Delete the app in PaidCheck: each app page has a Delete app & keys button. It deletes the app's encrypted credentials and CSV, its latest report and its history right away.
- Delete your account: there's no in-app button for this yet. Email support@paidcheck.app and we'll delete it. See the Privacy Policy for details.
8. Analytics
We use Vercel Web Analytics, which is cookieless, for page views and anonymous product events. Before an event is sent, any value that looks like a key, secret or email address is replaced with "[redacted]".
9. Reporting a security issue
If you find a vulnerability or think a key may have been exposed, email support@paidcheck.app. Please include steps to reproduce, and give us a reasonable chance to fix the issue before you disclose it publicly. Our security.txt lists the same contact.