Your API is live on Pro. Nobody's session broke.
Pro accounts can mint a key in Settings and start calling today. Cookie sessions kept working — keys ride the same middleware.
curl https://api.acme.dev/v1/usage -H "Authorization: Bearer sk_live_…"
How it works now
Request
Bearer sk_live_…
api_keys
hashed lookup
Rate limit
600 Pro · 60 Free
rate-limits.md
Your handler
unchanged
usage_log
one row per call
Worth flagging
Nothing expires a key yet
Hashed at rest, shown once — but nothing rotates them. Your policy call.
Your sales deck still promises 600 on Free
The run used decisions/rate-limits.md. The deck disagrees; I left it alone.
What changed
| Surface | Change |
|---|---|
| api_keys | new table · hash, prefix, last used |
| POST /v1/keys | new · issued once, shown once |
| auth middleware | cookie or key, one session object |
| docs/api | generated from the routes |
Acceptance
- Cookie sessions unaffected47 existing tests green
- Limits enforced before the handler429 at request 601
- Keys never stored rawhash + prefix only


