How we handle health data
Specific claims you can check, not reassurance. Where we're weaker than self-hosting, we say so.
What we actually store
This is the shortest list we could make it:
| Data | Stored? | Notes |
|---|---|---|
| Your email address | Yes | Used for sign-in and billing notices. |
| WHOOP access + refresh tokens | Yes, encrypted | AES-256-GCM under a key held in the environment, not in the database. |
| WHOOP account name, email, user id | Yes | So the dashboard can show which account is connected. |
| Your recovery, sleep, workout records | No | Fetched from WHOOP on demand and passed straight through. We keep no copy. |
| API keys | Hash only | SHA-256. The plaintext exists in one HTTP response and is never recoverable. |
| Which tools were called and when | Yes | Tool name, duration, success — never the returned data. |
| Card details | No | Handled entirely by Mollie. We never see a card number. |
| Your WHOOP password | Never | You authorise through WHOOP's own consent screen. |
The most important row is the fourth. FitnessPeak is a pipe, not a warehouse. Your health records live at WHOOP and pass through us to your assistant. There is no historical archive here to breach.
Token encryption
WHOOP tokens are sealed with AES-256-GCM before they touch the database, under a key supplied through the environment. The stored form is v1.<iv>.<tag>.<ciphertext> — versioned so keys can be rotated later without guessing at the old layout. A database file on its own does not grant API access.
If the encryption key is unavailable, the server refuses to store tokens rather than falling back to plaintext.
API keys
- 32 bytes of CSPRNG entropy — 256 bits — base64url encoded behind an
fp_live_prefix - Only
SHA-256(key)is stored; we cannot show you a key twice because we don't have it - Lookup is a unique-indexed hash match, so there's no per-row comparison and no timing oracle
- Revocation is immediate and permanent
- Access logs redact anything matching
fp_live_…
A leaked key could read your fitness data and nothing else. It cannot change your WHOOP account, cannot reach your card details, and cannot sign in to your dashboard.
Read-only, enforced upstream
FitnessPeak requests only WHOOP's read scopes: read:recovery, read:sleep, read:workout, read:cycles, read:profile, read:body_measurement, plus offline for refresh. Even a total compromise of our code could not write to your WHOOP account, because the token was never granted that power.
Transport and headers
- HTTPS everywhere, HSTS with a one-year max-age, includeSubDomains and preload
- Content-Security-Policy with
script-src 'self'— no third-party scripts on any page frame-ancestors 'none',object-src 'none', restrictive Permissions-Policy- No analytics or advertising trackers anywhere on the site
Rate limiting
120 MCP calls per minute per key. Sign-in links are capped per IP and per email address. Both return 429 with Retry-After.
Where self-hosting is stronger
Running your own WHOOP MCP server keeps your tokens on hardware you control. We cannot match that, and if it's your requirement you should self-host — we wrote the comparison ourselves.
Deleting everything
The delete button in your dashboard removes your user row, and every related table cascades from it: WHOOP connection, API keys, usage history, payment records. It is a real delete, not a flag. You can also revoke FitnessPeak's access from within WHOOP at any time, independently of us.
Reporting a vulnerability
Email security@fitnesspeak.app. We'll acknowledge within 72 hours. Please don't test against other people's accounts — if you need a second account to demonstrate something, ask and we'll set one up.
Machine-readable contact details: /.well-known/security.txt.
What we haven't done
FitnessPeak is a small independent product. We have no SOC 2 report, no penetration-test certificate, and no security team. If your threat model needs those, it needs a different vendor — or self-hosting.
Last updated 14 August 2026.