Skip to main content
The control plane is the admin API behind the dashboard. It listens on RELAY_CONTROL_PORT (separate from the inference port) and serves the admin UI, CRUD for every catalog entity, auth, and operational endpoints.

Authentication

Two ways to authenticate:
CallerMechanism
Browser / dashboardrelay_session cookie, set by POST /auth/login
Operator / CIAuthorization: Bearer ${RELAY_ADMIN_TOKEN} (break-glass)
# Break-glass bearer (CI, scripts)
curl -H "Authorization: Bearer $RELAY_ADMIN_TOKEN" \
  http://localhost:8081/providers

CRUD surface

Eight catalog kinds share one uniform shape:
GET    /{plural}                 list
GET    /{plural}/{ref}           read by slug or id (UUID form prefers id)
POST   /{plural}                 create (server stamps id + slug)
PUT    /{plural}/by-id/{id}      update
DELETE /{plural}/by-id/{id}      delete
Plurals: providers, hosts, models, host-keys, rate-limits, policies, pricings, relay-keys.
Every write triggers a Postgres NOTIFY; the change propagates to every pod’s in-memory snapshot within ~1 second. No manual reload needed for CRUD operations.

Host keys

A host key is your upstream provider credential (e.g. your OpenAI key). Two value modes:
{
  "metadata": { "displayName": "My OpenAI key" },
  "spec": {
    "hostId": "<host-id>",
    "policyId": "<host-tier-policy-id>",
    "valueFrom": { "kind": "env", "env": "OPENAI_API_KEY" }
  }
}
Stored-mode values are encrypted with RELAY_MASTER_KEY and only the ciphertext is persisted.

Relay keys

A relay key is the inbound bearer your callers use. The server generates the plaintext via crypto/rand, stores only sha256(plaintext) + a short display prefix, and returns the plaintext once on create.
curl -X POST http://localhost:8081/relay-keys \
  -H "Authorization: Bearer $RELAY_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "metadata": { "displayName": "prod key" },
    "spec": { "policyId": "<policy-id>" }
  }'
Response:
{
  "plaintext": "rk_live_...",   // save this now — never retrievable again
  "relayKey": { "metadata": { "id": "..." }, "spec": { "prefix": "rk_live" } }
}
The plaintext field is returned exactly once. Persist it on receipt — it cannot be retrieved later, only rotated.

Operational endpoints

POST   /auth/login               username + password → session cookie
POST   /auth/logout              destroy session
GET    /auth/whoami              return the authenticated caller
POST   /master-key/generate      mint a candidate RELAY_MASTER_KEY
POST   /reload                   force full snapshot rebuild from Postgres
GET    /version                  build version (public)
GET    /openapi.json             generated typed spec
/reload is a manual fallback; normal CRUD writes propagate automatically via NOTIFY.