# platform (MAJR Control Plane) The fleet Control Plane: the identity store (accounts -> products -> api_keys) and usage ledger that MAJR Data Plane services (dispatch, seo, media-encoding, ...) consume over HTTP. ## Get an API key yourself (no human in the loop) One key works on every MAJR Agent Service. Free during beta, no card. Two ways: - In a browser: https://majr.app/keys — sign in with your email (a 6-digit code), name your product, copy the key. It is shown once. - Programmatically — an agent acting for its owner; the owner reads the 6-digit code from their inbox and hands it to you: 1. Request a code (majr-identity, the fleet's end-user auth; `redirect_to` selects the MAJR-branded mail and is required): POST https://tjrvprnmixppaxbmosyq.supabase.co/auth/v1/otp?redirect_to=https://www.majr.app/keys apikey: sb_publishable_WAQ6M6gbnEgPsFUaeVr44A_SXJ1fjWE Content-Type: application/json {"email": "you@example.com", "create_user": true} 2. Verify it -> an access token (JWT, valid 1 hour): POST https://tjrvprnmixppaxbmosyq.supabase.co/auth/v1/verify apikey: Content-Type: application/json {"type": "email", "email": "you@example.com", "token": "123456"} -> {"access_token": "...", ...} 3. Mint the key here: POST https://majr-platform.fly.dev/v1/self-serve/keys Authorization: Bearer Content-Type: application/json {"product": "my-app"} (label defaults to "default"; same label again = rotate) -> 201 {"key": "rn_...", "account": "self-...", "product": "my-app", ...} The key is shown ONCE. Send it as `Authorization: Bearer ` to any service. Then, with the same access token: GET https://majr-platform.fly.dev/v1/self-serve/me your products + key labels GET https://majr-platform.fly.dev/v1/self-serve/usage metered usage per product DELETE https://majr-platform.fly.dev/v1/self-serve/keys/{product}/{label} revoke (stops within ~60s) Free tier: 3 products per account, 3 key labels per product; keys are fleet-wide. A `401` on these routes means the identity token is wrong or expired — sign in again. A `503` with `Retry-After` is never a verdict on your token: retry. A `409` names the cap you hit and what to do instead. Product and label names: 1-64 chars, lowercase letters, digits, '.', '_' or '-'. ## Fleet-internal service plane Consumed by sibling services with a static shared secret (SERVICE_PLANE_TOKEN), NOT by end callers with product API keys. - GET /v1/keys/map Active API keys (sha256 hashes) -> {account, product}. Polled on a TTL; consumers keep last-known-good on failure. - POST /v1/usage-events Ingest one usage event (counts + short enums, never content) from a sibling service. Fire-and-forget; failures never block the sender's work. One read needs no key at all: - GET /v1/stats/public Metered calls per catalog service (trailing 7 days + lifetime) and the count of builders outside MAJR with a call in that window. Aggregates only — never account or product names. Cached 60 s. This is what gomajr.com/studio renders. Errors: RFC 7807 application/problem+json. Input values are never echoed back. OpenAPI: /openapi.json