On this page

A Workspace API Key authenticates your backend to MIOSA. One key per workspace; the key resolves to a tenant_id, scopes, and rate limits.

Create a key

From the dashboard: Workspace → Settings → API Keys → New key. Or via API:

POST /api/v1/api-keys

The plaintext msk_* value is returned exactly once at creation. The dashboard shows only a prefix (first 12 chars) thereafter; the server stores only a hash.

If you lose a key, rotate — create a new one, swap it in, delete the old.

Key shape


msk_<env>_<random>
  • msk_live_* — production keys, full access.
  • msk_test_* — test-mode keys (planned; usage doesn’t count toward billing).
  • msk_u_* — user-bound keys for personal CLI use; scopes limited to the user’s own resources.

For platform integration (ClinicIQ-style), use msk_live_* and treat it like a Stripe secret key.

Scopes

Each key has a list of scopes. MIOSA enforces scopes on every mutation. Reads typically require the matching :read scope; writes require :write.

Common scopes:

ScopeAllows
sandboxes:readList, get sandboxes
sandboxes:writeCreate, exec, files.write, destroy
deployments:readList, get deployments, versions, domains
deployments:writeCreate, publish, rollback, attach domains
domains:writeCreate, verify, delete custom domains
data:writeProvision managed Postgres / Redis / buckets
usage:readRead usage events
audit:readRead audit log

For server-side platform integration, start with sandboxes:write + deployments:write + domains:write. Add more as needed. Principle of least privilege: don’t give a key *:write unless that’s what it actually needs to do.

Rotation

Rotate keys on a schedule (we recommend every 90 days, or on incident). The flow:

  1. Create a new key with the same scopes.
  2. Roll out the new key to your backend (deploy + restart).
  3. Confirm the new key works (recent activity logged with key_id of the new key).

4. Delete the old key

Deleting a key invalidates it immediately. Any in-flight requests using the old key will start getting 401.

Rate limits

Each key has a rate limit (request-per-minute) scoped by:

  • Key ID (the key’s own bucket)
  • Organization (the account’s overall bucket)
  • Endpoint (publish has its own bucket, separate from list operations)

Limits scale with the plan. Headers in every response tell you where you stand:


X-RateLimit-Limit: 600
X-RateLimit-Remaining: 547
X-RateLimit-Reset: 1715712060

429 responses include a Retry-After header. SDKs back off automatically.

Audit

Every action authenticated by a key emits an audit event with:

  • api_key_id (so you know which key did what)
  • actor (the organization, plus the key’s name)
  • workspace_id, project_id, external_workspace_id, external_user_id (if passed or resolved in the request)
  • The action (e.g. deployments.publish, domains.create)
  • Timestamp + outcome

Read your audit log via:

GET /api/v1/audit?api_key_id=key_...
GET /api/v1/audit?workspace_id=550e8400-e29b-41d4-a716-446655440000

Browser keys (no)

There is no such thing as a browser-safe msk_*. If you need a browser to call MIOSA-like functionality, mint a scoped browser token server-side. See Browser Tokens.

See also

Was this helpful?