What we store and when it leaves
A short answer first, with the technical detail below.
What we keep
| Your email | Until you delete your account. |
| Your searches | 35 days, then deleted. |
| IP address | Not saved to account records; hosting providers may retain request metadata. |
| How to delete | Request erasure in Account, or email paul@bmiapi.com |
Technical detail
Raw IPs may exist briefly in provider request metadata and operational logs, but are never written to account records or public responses.
The bmi_anon cookie holds a random browser id. We store only a keyed hash of it, to count signed-out live lookups per browser, and it expires after two days.
| session and verification | Deleted after Better Auth expiry. |
| result_cache and Workers KV | Fresh for 7 days, retained at most 30 days. Explicit no-results answers expire after 24 hours. |
| internal callback receipts | Kept through the signed callback replay window, then the next daily purge. |
| terminal jobs | 48 hours. Active jobs remain until recovery makes them terminal. |
| anonymous admission | 48 hours. |
| quota reservations and daily usage | A 24-hour idempotency window plus one day of terminal recovery evidence; daily usage 400 days. |
| billing checkout holds | Kept through their 24-hour expiry, then the next daily purge. |
| sent email and failed outbox attempts | 30 days. Pending delivery remains until delivery or operator recovery. |
| Stripe webhook events | 90 days, event metadata and a payload hash only; never the raw Stripe body. |
| query misses | 30 days, including the search type, stable input, offered suggestion rules, cache keys, and creation time. |
| search outcomes | 35 days. Linkage to a previous outcome and a followed suggestion is null for anonymous callers. |
| prewarm_seed (observed) and prewarm_seed_asker | At most 35 days from the oldest copied search. Every contributing account copied by a loader is linked atomically; erasing any linked account removes the shared input. Anonymous searches have no account link. Later searches are separate unless a later loader copies them. |
| prewarm_seed (forensics) and prewarm_seed_song | Kept while an eligible in-scope source song remains. The privacy sweep removes orphans after set deletion, rescope or owner erasure, even when warming is off. |
| prewarm_seed_day and prewarm_seed_usage_day | 400 days by UTC day, without search text or account IDs. |
| daily usage, canary runs, incidents, completed erasure records, audit events, distinct-work milestone ledger | 400 days. |
| work records and public work pointers | 30 days after fetch. Shared Songview data has no user association. |
| encrypted nightly backups | 30 days outside Cloudflare. Live sessions and one-time tokens are excluded. |
| Workers Logs and Fly log search | 7 days. |
| Analytics Engine | 90 days. |
| failure HTML artifacts | 14 days in object storage. |
| account, key, subscription, Terms acceptance, and email preference records | Account lifetime, then foreign-key erasure. Expired and revoked key metadata remains visible to its owner until erasure. |
| workspace evidence and forensics history | Kept with the result set/workspace until deletion; not subject to search-cache expiry. Shared owners transfer before account erasure. Transferred evidence and accounting survive, with known erased actor IDs cleared. |
| workspace memberships and invites | Removed memberships: 30 days. Invite tokens expire after 7 days; terminal invites are deleted after 30 days. Erasure removes personal recipient/accepted invite rows. |
| backup snapshot spool | Reads expire after one hour. Indexed cleanup runs within a time budget and may finish on a later sweep. |
| saved lists | Kept while your account is active, then deleted with the account. Lists store your rows and their outcome, not full answer records. |
External systems
- Inngest receives canonical inputs and safe structured results only. HTML, browser artifacts, causes, and IP-bearing context cannot enter event or run history.
- Cloudflare and Fly logs contain request and job identifiers and typed outcomes, never authorization values, callback signatures, emails, or raw search responses. Provider log-drain retention is an operations setting.
- Fly’s persistent volume contains the returning visitor Chrome profile. Failure HTML and screenshots live on ephemeral temp storage and disappear with machine replacement.
- D1 Time Travel keeps provider-managed recovery history for its configured window.
How deletion works
An erasure request first deletes the mapped Stripe customer. If that call fails, the local account stays intact and the request can be retried. After it succeeds, the Better Auth user and user-owned rows are deleted through foreign-key cascades. Shared-workspace owners must transfer ownership before erasure; sole-owner workspaces are deleted with the account. Evidence in a transferred workspace survives with nullable actor IDs cleared, and accepted jobs drain before an affected run pauses. A later explicit resume uses its current actor’s allowance. Shared Songview answers and public work pointers have their own expiry; deleting an account does not remove them. Encrypted nightly backups expire after 30 days, and D1 Time Travel keeps recovery history for its configured window. The completed erasure record keeps only an HMAC-pseudonymized identifier and audit event.
Stripe may retain financial records it is legally required to keep. bmiapi does not claim otherwise.