API & MCP/Authentication
Auth

Authenticate your API calls

Two schemes: Bearer for web/mobile (Supabase session), X-API-Key for scripts/partners/Zapier. Pick by context, never both at once.

Available schemes

Authorization: BearerWeb, mobile

The client grabs the JWT from the Supabase session (supabase.auth.getSession()) and sends it as Authorization: Bearer <jwt>. Offline HS256 validation, no Supabase round-trip. The workspace is resolved via X-Workspace-Id or app_metadata.active_workspace_id.

curl https://api.freelance-os.fr/v1/me \
  -H "Authorization: Bearer $JWT"
X-API-KeyPartners, scripts, Zapier

Generate a key from /settings/api-keys in Kernel. Format fos_sk_live_<token>, scoped to a single workspace (no X-Workspace-Id needed). The plaintext shows once, store it immediately.

curl https://api.freelance-os.fr/v1/me \
  -H "X-API-Key: fos_sk_live_..."

Scopes

Keys carry a list of scopes. For public API calls the scope check is currently minimal (read:* implied). We tighten route-level enforcement as the write surface grows.

Scope
Covers
read:*
All GET endpoints
write:*
POST / PATCH / DELETE on top of GET
*
Full access including admin surfaces
read:bookings (granular)
Reserved for future segmented keys

Limits & best practices

  • Rate limit: 120 req/min sliding window per key or IP. 429 when exceeded, headers X-RateLimit-Limit / Remaining / Reset.
  • Management gate: the /v1/api-keys endpoints require a JWT. A key cannot create or revoke another key, by design.
  • Expiration: optional. Bot keys can live forever; human / Zapier keys get a recommended 30/90/365-day window.
  • Revocation: immediate on DELETE /v1/api-keys/<id>. No cache, no delay.
  • Storage: token_hash = sha256(plaintext) at rest, plaintext never persisted. On leak, revoke + regenerate.
  • Mobile: native Supabase login, store the JWT in the secure keychain, refresh like web.

Common errors

Status
Cause
Fix
401
Missing or malformed header
Check Authorization: Bearer ... or X-API-Key: fos_sk_live_...
401
Expired JWT or revoked key
Re-auth (Supabase) or regen a key
403
User not a member of the workspace
Check X-Workspace-Id; join via an invite
403
/v1/api-keys with X-API-Key
Use a user JWT, not a key
409
A call with the same Idempotency-Key is already in flight
Wait, then retry the same key to fetch the response
429
Rate limit exceeded
Exponential backoff, watch X-RateLimit-Reset
5xx
Transient error
Retry with an Idempotency-Key (dedup) or backoff