Authentication
Last verified: 2026-06-20 (Task #388 — multi-feature portal restructure).
Platform endpoints authenticate with the same developer API keys used
across the Travelmode developer platform. A key identifies both the
developer account and the environment (test vs production)
that calls are billed against.
Sending the key
Use either header on every request:
| Header | Example |
|---|---|
Authorization: Bearer <key> | Authorization: Bearer tm_weather_abc123... |
X-API-Key: <key> | X-API-Key: tm_weather_abc123... |
If both are present, Authorization wins. If neither is present you get
api_key_missing (HTTP 401).
Scopes
| Endpoint | Required scope |
|---|---|
POST /v1/webhooks | weather:webhooks |
GET /v1/webhooks | weather:webhooks |
GET /v1/webhooks/{webhook_id} | weather:webhooks |
DELETE /v1/webhooks/{webhook_id} | weather:webhooks |
GET /v1/webhooks/{webhook_id}/attempts | weather:webhooks |
GET /v1/usage | none — any valid key can read its own usage |
A request whose key is missing the required scope gets scope_required
(HTTP 403) with a details.required field naming the missing scope. The
weather:admin wildcard scope, issued to internal tooling only,
satisfies any scope check.
Environments
Each developer account has an environment of test or production,
surfaced in meta.environment on every response. test accounts get
isolated quotas, isolated webhook endpoints, and a separate billing
ledger; there is no separate test base URL for the MVP.
Errors at a glance
| Code | HTTP | Cause |
|---|---|---|
api_key_missing | 401 | No Authorization and no X-API-Key header. |
api_key_invalid | 401 | Header present but the key doesn't resolve. |
api_key_revoked | 401 | Key was explicitly revoked by an admin. |
api_key_expired | 401 | Key has an expires_at in the past. |
scope_required | 403 | Key valid but missing the scope the endpoint requires. |
account_suspended | 403 | Developer account has been suspended. |