Skip to main content

The header

Every authenticated request carries your key in the X-API-Key header.
No cookies, no OAuth, no signed requests. Keys are secrets — treat them like passwords.
Never commit a key to git, embed it in a public SPA bundle, or email it in plaintext. If a key is exposed, rotate it immediately (see below) — rotation is atomic and the old key dies the same instant the new one is born.

Key tiers and prefixes

Each key carries a prefix that hints at its tier. The prefix is cosmetic — the real tier is stored server-side and returned by GET /v1/keys/current. Test-mode keys (exd_test_*) bypass the database and serve fixture data for deterministic plumbing tests. Production data requires a real key. See Test mode below.

Minting a trial key

Public endpoint, IP-rate-limited, idempotent per email within the key’s active window. Call it twice with the same email and you get the same key back.
curl
Python
A successful response (HTTP 201 first time, HTTP 200 if replayed):
If you call this endpoint again with the same email while a valid key still exists, you get the same key back with reused: true and HTTP 200. No duplicate keys, no silent reissuance. If the previous key for that email has expired or been revoked, a fresh key is minted (HTTP 201, reused: false).

Inspecting the current key

Use this at runtime to discover what your key can do — tier, topics, expiry, rate limit, webhook quota.
Same shape as the trial response, without reused. Build tier-aware UIs from this — read once at app start, refresh on 401/403.

Rotating a key

Rotation issues a new key with the same tier, topics, limits, and expiry. The old key is deactivated atomically — switch your clients to the new key immediately.
Expiry is not extended by rotation. Rotation is for credential hygiene, not lifetime extension. Replay protection: every subsequent call with the old key returns 401 invalid_api_key.

Revoking a key

Permanent. Idempotent. Once revoked, the key cannot be reactivated — a future POST to /v1/keys/trial with the same email will mint a brand-new key.
A second call with the same key returns already_inactive: true and HTTP 200 (idempotent, not an error).

Who am I

GET /v1/me returns the caller’s identity and full entitlements — tier, topics, rate limit, webhook + watchlist quotas, monthly usage. Ideal for building a tier-aware dashboard header or settings page.

The typed error envelope

Every non-2xx response follows the same shape. Match on the error enum, show message to users, log trace_id for support.
The four authentication-specific errors: Full list across all routers: Errors.
Trace IDs are 16-hex strings present on every response (success or error) in the X-Exorde-Trace-Id header and inside the JSON envelope on errors. Quote the trace_id when you email support — we resolve in one round trip.

Test mode

Keys with the exd_test_ prefix bypass the database, return a synthetic know-tier shape, and serve fixture data on every analytics endpoint. Use them to wire integrations (HTTP layer, JSON parsing, error handling) without burning real quota or polluting analytics.
How to tell apart a fixture alert from a live alert: Test keys are not issued to customers. They exist for our internal QA suite and for integrator partners who request a deterministic fixture path during onboarding.

Operational guidance

  • Store keys server-side only. Never in a public SPA bundle, git history, or a client-side env var shipped to users.
  • Rotate on suspicion of leak. Rotation is free, atomic, and preserves all tier/topic/limit settings.
  • Use /v1/me at startup to detect tier changes (upgrades, downgrades, expiries) without polling the billing system.
  • Handle 401 as “get a new key” and 403 as “ask the user to upgrade or change topic” — the codes are distinct for a reason.
  • Always log trace_id alongside any user-facing error message. It is the single most useful piece of evidence in a support ticket.
  • Set a watchdog on expires_at. Trial keys expire silently after 7 days; surface a “renew/upgrade” prompt when within 24h of expiry.

Lifecycle example: full mint → rotate → revoke

Every step in this lifecycle is exercised by our QA suite (205 scenarios, currently 100% PASS). See Changelog for release-by-release detail.
Last reviewed: 2026-05-19. API version 1.2.8.