Authorization
Authenticate API requests with the api-key header
Every request needs an api-key header. Some user-scoped endpoints also accept a bearer token.
Get a key
- Sign up or log in at app.tokenkithq.io.
- Open Settings -> API Keys in the dashboard.
- Click Generate Key and copy it. You see the value once. The dashboard only stores a hash.
If you'd rather mint keys from code, see API Keys.
Headers
| Header | Required | What it does |
|---|---|---|
api-key | yes | Identifies your project. Rate limits and billing are tied to this. |
Authorization: Bearer <token> | sometimes | A user-scoped session token. Needed for endpoints that mutate user-owned data. Read-only endpoints are fine with just api-key. |
origin | optional | For browser CORS. The API echoes Access-Control-Allow-Origin for whitelisted hosts. |
Example
Storing keys safely
Errors
| Status | When you see it |
|---|---|
401 Unauthorized | Missing api-key, malformed key, unknown key, or origin / IP not in the key's allow list. Response carries WWW-Authenticate: api-key realm="tokenkit". |
403 Forbidden | Valid api-key, but the endpoint also wants a bearer token. |
429 Too Many Requests | Either the per-key hourly rate limit is exhausted, or your IP is temporarily blocked after too many failed api-key attempts in a short window. Both return 429 — read the body's detail field to tell them apart. |
Why 429 covers both rate limits and IP blocks. When the backend rejects you because of the key's hourly cap or because too many bad-key attempts came from your IP in the last 5 minutes, it's a throttling event — your auth is fine, you've just used up your budget. The honest status code is 429, not 401. The 401 path is reserved for "your credentials don't work."
Missing api-key doesn't penalise your IP. Earlier versions counted a missing-header request as a failed authentication attempt against your IP's brute-force counter. One buggy client path that forgot the header could rack up failures fast and lock the IP for everyone behind the same NAT. That's fixed — missing-header now returns 401 quietly without incrementing anything.