Authentication
How API keys work and how to scope them.
Every API request authenticates via a Bearer token:
Authorization: Bearer zk_live_2bV4dXyZ8AfQpkw7Lp4mGr8wD3kCnXfRsT6vBpA9LxA missing or invalid token returns 401 unauthorized.
Key format
zk_<environment>_<random>zk_— issuer prefix (Zerokit). Identifies a key on sight in logs /git grepaudits.<environment>—liveortest. Live keys hit production AWS SES and deliver real mail. Test keys only deliver to addresses pre-verified on your AWS SES account, so accidentally blasting a test key in production CI doesn't email customers.<random>— 32 random characters. We store only a hash; the plaintext is shown once at creation.
Scopes
Every key carries one of three preset scopes:
| Preset | Send mail | Read mail / logs | Manage account |
|---|---|---|---|
send-only | ✓ | — | — |
read-only | — | ✓ | — |
full-access | ✓ | ✓ | — |
There's no "admin" scope on purpose — workspace management (billing, members, domains) is dashboard-only. The worst-case blast radius of a leaked key is bounded by its preset.
Treat plaintext keys like passwords. Don't commit them. Use environment variables or a secrets manager (Wrangler secrets, GitHub Actions secrets, Vercel env vars).
Issue + revoke
Both happen in the dashboard — see API Keys in your workspace. Issuance via REST is intentionally disabled so the plaintext value never lands in CI logs or shell history.
REST surface is read + delete:
- GET /api-keys — list every key on the workspace, with last-used timestamp.
- DELETE /api-keys/:id — immediate revocation.
Rotation
There's no built-in "rotate" verb because rotation = "create new
- deploy + revoke old" — and that flow benefits from confirmation between each step:
- Create a new key with the same scope (dashboard).
- Deploy your service with the new key.
- Confirm traffic on the new key — the dashboard shows last-used timestamps per key.
- Revoke the old key.
Skip step 3 and you risk revoking a key that's still in flight on a worker mid-deploy.
Best practices
- One key per service. Don't share a key between worker A and worker B — when you revoke for one, you revoke for both.
- Use
read-onlyfor analytics / observability. No reason for your dashboards to be able to send mail. - Test keys in dev / CI. Even if you have your prod DKIM ID
added to SES sandbox, prefer
zk_test_*for any non-prod environment so a stray send doesn't cost reputation.