Authentication

API key shape

ck_live_[32 alphanumeric characters]
ck_test_[32 alphanumeric characters]

Prefix declares environment:

  • ck_live_* — production keys. Hit live data + bill against your tier quota.
  • ck_test_* — sandbox keys. Same endpoints; flagged on the server side for "this is a test integration"; useful for early integration before you flip a live key into production.

The 32-character body is base62 — ~190 bits of entropy, more than enough collision resistance even at billions of keys.

How to use the key

Set the X-API-Key header on every authenticated request:

curl 'https://crate.0xhoneyjar.xyz/api/v1/masters/12345' \
  -H 'X-API-Key: ck_live_AbCdEfGhIjKlMnOpQrStUvWxYz012345'

That's it. No OAuth dance, no token refresh, no signed-request gymnastics.

Where keys come from

Self-serve (cards via Stripe Checkout):

  1. Sign up at crate.0xhoneyjar.xyz/api/signup
  2. Stripe Checkout flow at your chosen tier
  3. Key is issued + emailed when the webhook fires (typically under 2s after Stripe payment confirmation)
  4. The key plaintext is shown EXACTLY ONCE — in the email + the dashboard at first load. After that, the dashboard only shows the prefix (e.g. ck_live_AbCdEfGh). Lost the key? Rotate it.

Sync tier (manual contract):

  1. Email jani@hosaka.fm with your use case + expected volume
  2. Contract conversation; key issued via the admin route
  3. Personal Slack channel for ongoing support

Key lifecycle

| Action | Endpoint | Effect | |---|---|---| | Create | Stripe Checkout webhook OR /api/v1/admin/keys (Sync) | New active key issued | | Rotate | POST /api/dashboard/keys/<id> | New key issued; old key → rotated status (returns 401) | | Revoke | DELETE /api/dashboard/keys/<id> | Key → revoked status (returns 401 immediately) | | Suspend | Automatic on 7d-grace after invoice.payment_failed | Key → suspended (returns 402 payment_required) | | Reactivate | invoice.payment_succeeded webhook | suspendedactive |

Authentication failures (errors)

| Code | Body | Meaning | |---|---|---| | 401 | {"error": "missing_api_key"} | No X-API-Key header on an authenticated endpoint | | 401 | {"error": "invalid_api_key"} | Key doesn't match any active row | | 401 | {"error": "revoked_api_key"} | Key was explicitly revoked or rotated | | 402 | {"error": "payment_required"} | Customer is past_due or key is suspended |

See error codes for the full list.

Storing keys securely

  • Use a secret manager (1Password, AWS Secrets Manager, GitHub Actions secrets, Vault, etc.)
  • Never commit the plaintext key to a public repo
  • Never log the plaintext key
  • The prefix (first 12 chars) is safe to share for support — never share the full key
  • Rotate immediately if the key may have been exposed (commit, log dump, screenshot)

What's public (no key)

Two surfaces are unauthenticated so you can discover the API before you have a key: GET /api/v1 (the self-describing root index) and GET /api/v1/openapi.json (the spec). Every data endpoint — search, the dossiers, bandcamp, breakouts, tastemakers, resolve, masters, facets — requires an X-API-Key.

(Earlier builds left /api/v1/search open at a per-IP limit; as of the cycle-078 wall it requires a key like every other data endpoint.)