Skip to main content

Authentication

Status: Current (Scale plan). /v1 does not accept the raw API key. You first exchange the wk_live_… key for a short-lived org session (a Supabase JWT), then call /v1 with Authorization: Bearer <access_token>. The SDK does this exchange, caches the token, and re-runs it automatically — so most callers never touch the exchange endpoint directly. The details below are for anyone building their own client.

Getting a key

Mint a wk_live_… key in the Developers tab of the Warmr app (or the web cockpit at app.warmr.so). Minting requires the Scale plan, and an org owner or operator can do it. You see the raw key once — store it in a secret manager. Key lifecycle (mint, revoke, choose scopes) is a dashboard-only action. An API session can call /v1, but it can never mint or revoke keys — so a leaked key can’t escalate itself into more keys. Pick the scopes the key needs at mint time; a key never gains a scope it wasn’t minted with.

The exchange

You exchange the key at the Supabase edge function, passing the Supabase publishable/anon key in the apikey header (the edge function rejects the request without it).

Response (200)

expires_at is a UNIX epoch in seconds. Cache the access_token and re-exchange as it nears expiry — or on any 401 from /v1.
The Cloud API is a Scale-plan feature. If the org behind your key is not on an active Scale plan, the exchange returns 403 scale_plan_required — this is the live, authoritative gate on every API session.

Exchange errors

Exchange errors use a flat body, distinct from the /v1 envelope:

Calling /v1

Carry the access token on every /v1 request:
A missing or invalid token returns 401 unauthorized — re-exchange and retry. See Scopes for the per-endpoint permission each call requires.

Token caching and auto-refresh (what the SDK does)

The SDK holds the session token in memory and reuses it until it nears expiry. It re-exchanges automatically:
  • Proactively, a configurable leeway (default 60 seconds) before expires_at.
  • Reactively, once on any 401 from /v1 — it clears the cached session, re-exchanges, and retries the request a single time.
Concurrent calls that both need a fresh token coalesce into one exchange, so a burst of requests triggers a single round-trip. Because the token is reused until it expires, normal usage exchanges infrequently.

Rate limits

Exchange

  • 30 requests / IP / hour — best-effort, keyed on x-forwarded-for.
  • 1000 requests / key / day — the binding limit, keyed on the key’s hash.
Over either limit returns 429 rate_limited on the exchange. Because a session token is reused until it expires, cache it (the SDK does) and you will rarely approach these.

Enqueue

Enqueue endpoints (POST /v1/runs, POST /v1/runs/batch) share a per-org limit of 120 runs / minute. Over the limit returns 429 with the /v1 error code rate_limited and a Retry-After header. Every enqueue response (including the 429) also carries RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset (seconds) so you can pace client-side before hitting the cap.

Next

  • Scopes — what each endpoint requires.
  • SDK quickstart — let the SDK handle the exchange for you.