For AI agents: a documentation index is available at https://www.plungeai.com/docs/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://www.plungeai.com/docs/agents.md. One ozk_ key opens every plane, models included.

Documentation Index: fetch the complete documentation index at /llms.txt. Use this file to discover all available pages before exploring further.

Every route except GET /health and GET /v1/openapi.json needs a key. One ozk_ platform key opens every plane on https://api.plungeai.com (models, tools, agents, workflows, MCP, discovery, traces and the connector proxy) and the MCP server on https://mcp.plungeai.com. Two older prefixes, sk-ocean- and sk-conn-, are still accepted (legacy) on their own plane while integrations move over; new integrations use ozk_.

The one key

PrefixNameOpensAuth checked by
ozk_Ocean account keyEvery plane: models (/v1/chat/completions, /v1/embeddings, /v1/models), tools, agents, workflows, MCP, discovery, traces, and the connector proxy (/v1/connect/:provider/proxy/*)core/core-api-keys — the execution planes through orchestration/api-gateway/lib/auth.ts, the models plane and the connector proxy through inference/gateway/src/auth/api-key.ts

In this guide: $PLUNGE_API_KEY = ozk_.

Billing follows the account: a key carries your account id, so every metered call on it — models, embeddings, the connector proxy — is charged to your account's one wallet, whichever of your ozk_ keys made it.

Legacy keys: sk-ocean- (models plane only) and sk-conn- (connector proxy only) keep working on their own plane, are refused on the execution planes, and can no longer be created in the Dashboard. Replace them with an ozk_ key.

Which routes accept which key

The router (api-gateway.ts) gates /v1/discovery, /v1/tools, /v1/agents, /v1/workflows, /v1/mcp, and /v1/traces with requireAuth, which accepts only a bearer that starts with ozk_ (or a signed internal identity). The models plane and the connector proxy are mounted without requireAuth — the inference gateway resolves the key downstream, and it accepts the same ozk_ key. A legacy sk-ocean- or sk-conn- key is accepted on its own plane only, so the one mistake left is a legacy key on an execution plane, which returns 401.

An ozk_ key on the models plane works (live-verified):

curl -s https://api.plungeai.com/v1/models \
  -H "Authorization: Bearer $PLUNGE_API_KEY"

A legacy model-key shape on an execution plane → 401 (the router rejects any non-ozk_ bearer before dispatch; live-verified):

curl -s -o /dev/null -w '%{http_code}\n' -X POST https://api.plungeai.com/v1/agents/one-agent/execute \
  -H "Authorization: Bearer sk-ocean-EXAMPLE" \  # legacy model key
  -H "Content-Type: application/json" \
  -d '{"prompt":"hi"}'

The 401 body is the standard error envelope with X-Error-Code: unauthorized (live-verified):

curl -s https://api.plungeai.com/v1/tools

Header forms

Both header forms work on the execution planes; the models plane (/v1/chat/completions, /v1/embeddings, /v1/models) takes Authorization: Bearer only — X-API-Key there is a 401, by design.

HeaderPlanesExample
Authorization: Bearer <key>all-H "Authorization: Bearer $PLUNGE_API_KEY"
X-API-Key: <key>execution planes (ozk_); not the models plane-H "X-API-Key: $PLUNGE_API_KEY"

X-API-Key with an ozk_ key is live-verified:

curl -s "https://api.plungeai.com/v1/tools?limit=1" \
  -H "X-API-Key: $PLUNGE_API_KEY"

The same header on the models plane → 401 (live-verified):

curl -s -o /dev/null -w '%{http_code}\n' https://api.plungeai.com/v1/models \
  -H "X-API-Key: $PLUNGE_API_KEY"

How to obtain each key

KeyWhereNotes
ozk_Dashboard → One API → Keys (https://dashboard.plungeai.com)Self-service; session-authenticated (apps/ocean-dashboard/src/worker/routes/platform-keys.routes.ts, POST /api/platform-keys). Name the key, pick an expiry (never / 7–365 days), copy it once — it is shown exactly once and stored hashed. Bound to your account and its tier; revoke any time from the same list.

The tab shows your Ocean account key (prefix and last four characters; Rotate replaces it) — the key the Playground, ocean-cli and OceanCode use — above any extra named keys you create there.

The command-line clients get the account key through a browser sign-in, with no key to paste: ocean-cli login and oceancode login --provider ocean listen on 127.0.0.1:<port> and open https://dashboard.plungeai.com/api/cli/authorize?port=<port>&state=<state>. Once you are signed in (any sign-in method), the Dashboard redirects a one-time code (valid 120 s) to http://127.0.0.1:<port>/callback, and the client exchanges it with POST https://dashboard.plungeai.com/api/cli/token for the key. The key never appears in a browser URL.

Existing sk-ocean- and sk-conn- keys are listed read-only in the same tab under Legacy keys; each can be revoked there, and no new ones are created.

Key fences (scoping)

Keys can be scoped so a leak is bounded.

FenceKey kindEffectSource
allowed_toolsozk_Restrict the key to a named set of toolsorchestration/mcp-gateway/auth-middleware.ts
allowed_ipsozk_Accept the key only from listed IPv4 addresses / CIDR blocks or exact IPv6 addresses; a call from elsewhere is a definitive 401 (no fallback)core/core-api-keys/index.ts (ipAllowed, verifyApiKeyRecord)
allowed_modelssk-ocean- (legacy)Restrict the key to a model allow-list; an off-list model is 403 model_not_allowedinference/gateway/src/auth/api-key.ts (assertModelAllowed)
monthly_limit_usdsk-ocean- / sk-conn- (legacy)Per-key monthly spend cap; exceeding it is 429 insufficient_quota (inference) or 402 insufficient_balance (connector)inference/gateway/src/auth/rate-limit.ts

ozk_ key records are stored hashed only (key:{sha256} in KV, core/core-api-keys); a named key is shown once at mint time. The account key's plaintext is also kept encrypted (ocean-compliance.user_credentials) so the Dashboard can hand it to your signed-in clients.

Tiers and rate limits

Execution-plane rate limiting is per-key (per user uuid), enforced by a Durable Object on POST executions only — catalog GETs are free (api-gateway.ts calls checkRateLimit for POST only). The limits below are the code values in orchestration/mcp-gateway/rate-limiter.ts:

TierRequests / minuteRequests / day
free301,000
pro10010,000
enterprise300100,000

Reaching the day limit pauses the key for ten minutes (Retry-After ≤ 600), after which its day count starts over — a key is never shut out longer than that (2026-10-05); the minute limit waits out the minute. A key with no tier is treated as free: the key resolver defaults it before the limiter sees it (orchestration/mcp-gateway/auth-middleware.ts validateApiKey). A per-key rate_limit override is ignored on these planes (orchestration/api-gateway/lib/auth.ts does not pass it to checkRateLimit); it applies only on https://mcp.plungeai.com/v1.

The numbers above are the defaults. PlungeAI sets the per-tier numbers, or switches the limits off, in the operator console (One API › Keys › Rate limits; KV rate-limits:config, read by the limiter within a minute); while they are off no call is counted and none returns 429, and the failed-authentication meter in 13.4 stays on.

The models plane has its own limiter — a default of 600 req/min per key (RATE_LIMIT_RPM_DEFAULT, inference/gateway/src/routes/chat-completions.ts), also overridable per key.

A separate failed-auth limiter meters bad credentials at 20 attempts / minute per client IP (auth-fail tier in rate-limiter.ts; wired in auth.ts) so key enumeration is bounded.

When you are limited, the response is 429 with a Retry-After header (seconds) and a rate_limited (execution planes) or rate_limit_exceeded (models plane) error code.

Request ids and trace correlation

  • x-request-id is minted server-side on every request and echoed on the response (api-gateway.ts). It is never trusted from the client. Include it when reporting a problem. Live-verified — the header is present:
curl -sD - -o /dev/null https://api.plungeai.com/health | grep -i '^x-request-id'
  • x-trace-id is yours to set for correlating several calls into one trace. It is honoured only if it is a UUID; otherwise the router falls back to the request id. On an execution route the trace id doubles as the execution/workflow primary key, so replaying a UUID that was already used returns 409 duplicate_execution_id — send a fresh UUID or omit the header.

Responses also set X-Content-Type-Options: nosniff. Error responses additionally set X-Error-Code (equal to error.code) so a client can branch on the header regardless of the negotiated body format.

CORS

The router answers CORS for any origin and exposes the response headers a browser client needs (x-request-id, X-Error-Code, Retry-After, …; cors() in api-gateway.ts), and the models plane sets access-control-allow-origin: * with authorization, content-type, x-request-id allowed and x-request-id, x-correlation-id, x-ocean-cost-usd, x-ocean-dropped-params, x-generation-id exposed (inference/gateway/src/index.ts). Browser SDKs work, but do not ship a secret key in client-side code.

Internal HMAC identity (not for customers)

Service-to-service calls inside the platform authenticate with a signed internal identity (X-Internal-Signature, HMAC over the request) instead of a key, verified before the ozk_ path in auth.ts. This is the mechanism Ocean Studio and the engine use to call each other; it is not available to external developers and needs no action from you.

Planned: TI-34

The docs assistant is not available yet. You can hand these docs to your own assistant instead.