Skip to content
main-compute

Security

Authentication

Issue, scope, rotate and revoke MainAI API keys.

Updated 2026-10-25 · MainAI Compute docs

The inference API uses bearer keys. Portal endpoints use the browser session cookie instead. The two are separate: an API key cannot read the portal, and a portal session cannot call /v1.

Send the keyLink to this section

bash
curl -s https://cloud.mainai.dk/v1/models \
  -H "Authorization: Bearer $MAINAI_API_KEY"

Send the header on every /v1 request. Keys start with sk-mai_. The API accepts only that prefix; an upstream-style key or a missing Bearer scheme returns 401 invalid_api_key.

Key anatomyLink to this section

name

Meaning
Human label, 64 characters maximum.

models

Meaning
Allow-list. Empty means every public model. A denied model returns 403 model_not_allowed.

rpmLimit

Meaning
Requests per minute for this key.

tpmLimit

Meaning
Tokens per minute for this key.

budgetCents / budgetPeriod

Meaning
Hard key budget in EUR cents, monthly or total.

expiresAt

Meaning
Optional absolute expiry.

prefix / last4

Meaning
Display hints. The full key is shown once.

The portal stores a routing-token hash, the prefix and the last four characters. The plaintext key never comes back from GET /api/portal/keys.

Create a keyLink to this section

Use Keys → Create key in the portal. The request is a session-authenticated mutation:

POST /api/portal/keys
curl -s https://cloud.mainai.dk/api/portal/keys \
  -H "Content-Type: application/json" \
  -H "Origin: https://cloud.mainai.dk" \
  -H "Cookie: $PORTAL_COOKIE" \
  -d '{
    "name": "production-api",
    "models": ["mainai-coder", "mainai-cyber"],
    "rpmLimit": 600,
    "budgetCents": 20000,
    "budgetPeriod": "monthly"
  }'

The 201 body contains key metadata and plaintextKey. Copy it immediately. Owner, admin and developer roles can create keys; billing and viewer roles can read them.

RotationLink to this section

  1. 01

    Create the successor

    New key, same allow-list, same limits. Keep the name distinct, for example production-api-2026-11.

  2. 02

    Deploy the new value

    Roll the secret to every worker and environment. Leave the old key active.

  3. 03

    Observe

    Watch Usage until the old key's lastUsedAt stops moving for a full deploy window.

  4. 04

    Revoke the predecessor

    Delete it in the portal or call DELETE /api/portal/keys/:id. Revocation is synchronous.

Rotate on a schedule your team can keep, and immediately after a suspected leak. There is no automatic rotation in the MVP.

Revocation and suspensionLink to this section

  • Deleting a key sets its status to revoked, removes its routing credential and zeroes its budget.
  • Requests with a revoked key return 401 invalid_api_key.
  • Suspending the organization blocks all of its keys with 403 org_suspended, even though key records remain active.
  • Closing an organization makes its keys unusable.

Status codesLink to this section

401

code
invalid_api_key
Action
Check the Bearer scheme, prefix, revocation and expiry.

403

code
model_not_allowed
Action
Add the model to the key allow-list or use an allowed model.

403

code
org_suspended
Action
Resolve billing or policy with the organization owner.

429

code
rate_limit_exceeded
Action
Back off. See Rate limits.

Portal sessionsLink to this section

Portal and /api calls use an HttpOnly, Secure, SameSite=Lax session cookie. Production uses the __Host-mc_session name. Mutating /api routes check the Origin header; a cross-origin request without a matching origin is rejected with 403 csrf.

IdempotencyLink to this section

Idempotency-Key is accepted on /v1 inference routes and forwarded upstream. Use a stable UUID when a client may retry a non-streaming POST. Streaming retries are best treated as a new generation.