✈
    TravelmodeDevelopers

    Weather Intelligence API · v1

    🔎/
    📖Overview🧪API Reference (Try It)
    Guides
    🚀Getting Started🔐Authentication⏱️Rate Limits📡Endpoints⚠️Errors💳Billing🧊Cache & Freshness🪝Webhooks📝Attribution
    ⬇️Download openapi.yaml🔑Manage API Keys
    Developers / Authentication

    Authentication

    Last verified: 2026-05-03 (Task #334 — docs accuracy pass).

    All Weather Intelligence endpoints require an API key. Keys identify both the developer account and the environment (test vs production) that calls are billed against.

    Sending the key

    Use either header on every request:

    HeaderExample
    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).

    Key format

    tm_weather_<32+ hex chars>
    
    • The tm_weather_ prefix is fixed and always plaintext.
    • The tm_weather_<prefix>... is logged in plaintext for debugging. Only the hash of the full key is persisted in developer_api_keys.key_hash.
    • The plaintext key is shown to you exactly once on creation. If you lose it, you have to mint a new key.

    Scopes

    Every endpoint requires at least one scope. The scope set is fixed — unknown scope values are ignored at provision time.

    ScopeRequired by
    weather:read/v1/weather/current, /v1/weather/forecast, /v1/weather/health
    weather:timeline/v1/weather/timeline
    weather:route/v1/weather/route
    weather:watch/v1/weather/watch (POST/GET/DELETE)
    weather:webhooks/v1/webhooks (POST/GET/DELETE) and /v1/webhooks/{id}/attempts
    weather:adminWildcard — satisfies any scope check. Issued to internal tooling only.

    /v1/usage is special: any valid key can read its own usage. No extra scope is required.

    A request whose key is missing the required scope gets scope_required (HTTP 403) with a details.required field naming the scope that was missing.

    Environments

    Each developer account has an environment field of test or production. The environment a request hit is surfaced in meta.environment on every response, so a misconfigured client can notice it's calling the wrong account.

    For the MVP there's no separate test base URL — calls hit the same endpoints, but test accounts get isolated quotas, isolated webhook endpoints, and a separate billing ledger.

    Internal keys

    Travelmode itself calls the public API for service-to-service weather lookups. Those calls are signed by an internal key (developer_accounts.is_internal = true), provisioned via scripts/provision-internal-weather-key.ts.

    Internal keys:

    • Bypass scope enforcement. Every endpoint is callable.
    • Bypass rate-limit enforcement. All requests are still logged via the standard api_usage_events pipeline.
    • Are still subject to webhook signing rules. Internal keys do not get to skip HMAC verification on the receiving end.

    Internal keys are not minted for external developers.

    Key rotation

    Mint a fresh key with the same scopes and revoke the old one once your client has rolled over. The hashed-only storage means there's no "reveal" path for an existing key — rotate and re-deploy.

    Errors at a glance

    CodeHTTPCause
    api_key_missing401No Authorization and no X-API-Key header.
    api_key_invalid401Header present but the key prefix doesn't resolve, or the hash doesn't match.
    api_key_revoked401Key was explicitly revoked by an admin.
    api_key_expired401Key has an expires_at and it's in the past.
    scope_required403Key valid but missing the scope this endpoint requires.
    account_suspended403Developer account has been suspended.

    See errors.md for the full table and example envelopes.

    Previous
    ← Getting Started
    Next
    Rate Limits →