The API uses Bearer token authentication. Every endpoint requires a key except GET /compliance/review_flags, which is deliberately public (see its page).
Issuing a key
Self-serve, free, no card: request one at /developers. Enter an email address and the plaintext token is shown once on the next screen. Copy and store it immediately — only a SHA256 hash is persisted, so we cannot recover it later. Lost a key? Request another; the old one keeps working until revoked.
Admins can also mint keys by hand from /admin/api_keys, which is how internal
and higher-limit keys are issued:
- Go to Admin → API keys → New API key
- Provide a label (e.g. "Internal Rails app", "Acme HS Tracker"), an owner email, the plan tier, and a per-minute rate limit (default 60).
- The plaintext token is shown once on the next screen. Copy and store it immediately — only a SHA256 hash is persisted; we cannot recover it later.
Token shape:
hsf_live_<8-hex-prefix>_<48-hex-secret>
The prefix is stored in the clear (for logging and lookup); the secret half is compared against the stored hash in constant time.
Sending the token
GET /api/v1/compliance/meta HTTP/1.1
Authorization: Bearer hsf_live_abc12345_dead...beef
Failure modes
- Missing or malformed header → 401 unauthorized
- Unknown prefix → 401 unauthorized (we never reveal whether a prefix exists)
- Wrong secret → 401 unauthorized
- Revoked key → 401 unauthorized (revocation is immediate)
Response body for all auth failures:
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key",
"request_id": "uuid-..."
}
}
Revocation
From the admin UI, hit "Revoke" on any active key. The key's revoked_at is set immediately and ApiKey.authenticate returns nil for that key on the very next request. Revoked keys remain visible in the admin index for audit purposes.
Rotation
There's no built-in rotation flow in v1. To rotate: mint a new key, hand it off, then revoke the old key.