For AI agents: a documentation index is available at https://docs.plungeai.com/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://docs.plungeai.com/agents.md. Execution planes take an ozk_ key; the models plane takes an sk-ocean- key.

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

The supported integration stance, in order of preference:

  1. Plain HTTPS — every plane is JSON over HTTPS; any HTTP client works.
  2. The OpenAI SDK you already use — for the models plane only (base_url = https://api.plungeai.com/v1, sk-ocean- key). See the plungeai-models skill.
  3. Generate your own client from the live OpenAPI 3.1 spec — the primary typed path today.
  4. @plungeai/one-api — typed TypeScript client for the execution planes, when published.

There is no hand-maintained SDK, deliberately: the OpenAPI document at GET /v1/openapi.json is the contract, and everything typed is generated from it.

Generate your own client (any language)

The spec is OpenAPI 3.1 at https://api.plungeai.com/v1/openapi.json. Any 3.1-capable generator works.

TypeScript:

npx openapi-typescript https://api.plungeai.com/v1/openapi.json -o src/plungeai-schema.d.ts
npm install openapi-fetch
import createClient from 'openapi-fetch'
import type { paths } from './plungeai-schema'

export const plungeai = createClient<paths>({
  baseUrl: 'https://api.plungeai.com',
  headers: { Authorization: `Bearer ${process.env.PLUNGEAI_API_KEY}` },
})

Re-run the generator when the API changes shape — never patch generated types by hand. One thing to know: /v1/discovery/recommend and /v1/discovery/cards/{type}/{id} normalize the registry's own flat {"error":"<string>"} rejections into the standard envelope ({"error":{"code","message"}}, code is not_found on a 404, invalid_request otherwise) before you ever see them — a generated client's error type for these two routes is accurate as-is, no special-casing needed.

Python — plain requests is usually enough; a minimal wrapper:

import os, requests

class PlungeAI:
    BASE = "https://api.plungeai.com"

    def __init__(self, key: str | None = None):
        self.s = requests.Session()
        self.s.headers["Authorization"] = f"Bearer {key or os.environ['PLUNGEAI_API_KEY']}"

    def _call(self, method: str, path: str, **kw):
        r = self.s.request(method, f"{self.BASE}{path}", **kw)
        if r.status_code in (403, 409):
            err = r.json()["error"]
            # Lifecycle refusals (parked agent / unknown card — the reason says)
            # are fixable by re-discovering the id; fence refusals are FINAL.
            if "registry search" in err.get("message", ""):
                raise LookupError(err)     # re-discover the id, then retry
            raise PermissionError(err)     # trust fence — final, never retry
        r.raise_for_status()
        return r.json()

    def execute_agent(self, agent_id: str, prompt: str, sync: bool = True):
        return self._call("POST", f"/v1/agents/{agent_id}/execute",
                          json={"prompt": prompt, "sync": sync})

    def search(self, q: str, **params):
        return self._call("GET", "/v1/discovery/search", params={"q": q, **params})

ai = PlungeAI()
print(ai.execute_agent("llm-agent", "Say exactly: py ok")["content"])

For a fully typed Python client: openapi-python-client generate --url https://api.plungeai.com/v1/openapi.json.

@plungeai/one-api — typed TypeScript client

Not yet published to npm — npm install @plungeai/one-api fails today; generate the identical client yourself (previous section — it is the same two libraries). When published, the package is generated from the live GET /v1/openapi.json via openapi-typescript (opens in a new tab); runtime is openapi-fetch (opens in a new tab) (~6KB). The only handwritten code is a ~15-line createOneApi() factory.

import { createOneApi } from '@plungeai/one-api'

const client = createOneApi({ apiKey: process.env.PLUNGEAI_API_KEY! }) // ozk_YOUR_KEY

// GET /v1/tools — response fully typed
const { data, error } = await client.GET('/v1/tools', {
  params: { query: { limit: 10 } },
})
if (data) console.log(data.count, data.tools.map(t => t.id))

// POST /v1/agents/{id}/execute — path params and body typed
const { data: exec } = await client.POST('/v1/agents/{id}/execute', {
  params: { path: { id: 'llm-agent' } },
  body: { prompt: 'Say exactly: sdk ok', sync: true },
})
console.log(exec?.content) // "sdk ok"

Schema types are exported for reuse:

import type { paths, components } from '@plungeai/one-api'
type Card = components['schemas']['Card']

Every client.GET/POST/DELETE(...) maps 1:1 to a route in the OpenAPI document. The models plane is not this client's job — use the OpenAI SDK for that.

curl cookbook

Agent/tool ids below (brave-agent, llm-agent) are illustrative — take real ids from the discovery call two lines up, never from memory.

BASE=https://api.plungeai.com
AUTH='Authorization: Bearer ozk_YOUR_KEY'

curl -s $BASE/health                                            # liveness, no auth
curl -s $BASE/v1/openapi.json | head -50                        # live contract, no auth
curl -s "$BASE/v1/discovery/search?q=web%20search&limit=3" -H "$AUTH"
curl -s "$BASE/v1/tools?limit=5" -H "$AUTH"
curl -s $BASE/v1/tools/brave-agent -H "$AUTH"                   # contract (id from discovery)
curl -s -X POST $BASE/v1/agents/llm-agent/execute -H "$AUTH" \
  -H 'Content-Type: application/json' -d '{"prompt":"Say: ok"}'
curl -s $BASE/v1/traces/REQUEST_ID_FROM_ABOVE -H "$AUTH"

Self-documenting endpoints

The API teaches itself from the domain — useful for onboarding a coding agent with zero prior context:

  • GET https://api.plungeai.com/llms.txt — index (llmstxt.org format)
  • GET https://api.plungeai.com/llms-full.txt — the full developer guide + route reference as one markdown payload
  • GET https://api.plungeai.com/v1/openapi.json — the machine contract
  • GET https://api.plungeai.com/docs — human-readable docs page

AI agents at runtime can skip HTTP clients entirely: connect an MCP client to https://mcp.plungeai.com/v1 with an ozk_ key (see the plungeai-mcp-setup skill).

AGENTS.md block for generated apps

When you generate an app that calls PlungeAI, drop this block into the app's AGENTS.md (or CLAUDE.md) so future coding agents in that repo handle the API correctly. Paste-ready:

## PlungeAI One API

This app calls the PlungeAI One API at https://api.plungeai.com.

- Auth: `Authorization: Bearer $PLUNGEAI_API_KEY` (an `ozk_` platform key) for
  /v1/discovery, /v1/tools, /v1/agents, /v1/workflows, /v1/mcp, /v1/traces.
  The OpenAI-compatible models plane (/v1/chat/completions, /v1/embeddings,
  /v1/models) uses `$PLUNGEAI_INFERENCE_KEY` (an `sk-ocean-` key) instead.
  Keys live in env vars only — never commit or log them.
- Live contract: `GET /v1/openapi.json`. Live catalog: `GET /v1/agents`,
  `GET /v1/discovery/search?q=...`. Never hardcode agent/tool/model ids or
  counts — discover them, and re-discover on 404 `unknown_tool` /
  `workflow_not_found`.
- Sync vs async: agent execute defaults to sync; `sync:false` returns 202 +
  `{workflow_id, task_id}` — poll `GET /v1/agents/results/:wf/:task`
  (404 `not_ready` is normal in-flight, back off 2s+).
- HARD RULE — trust fences: `403 refused` (a gated/money verb refused
  outright) and `409 approval_required` (a human must approve before the
  action runs — this is implemented and produced today, not a placeholder)
  are both final for now — surface them to the user; never retry, rephrase,
  or route around a `403 refused`. For `409`, approve out-of-band (Ocean
  Studio, or MCP `plungeai_continue` — the One API alone has no REST
  `continue` route) and then re-issue the identical request.
  A separate, unrelated `403 agent_not_active` (a parked/inactive agent id)
  is a lifecycle state, not a fence — re-discover a fresh id and retry with
  that instead.
- `422 invalid_params` echoes the tool contract — self-correct once, then stop.
- Rate limits: execution-plane `429 rate_limited` carries `Retry-After` —
  honour it. The models plane's separate `429 rate_limit_exceeded` has no
  Retry-After — use a fixed ~1s backoff there instead.
- 502 `upstream_error` / 500 `internal_error` can come from any route —
  retry once with backoff.
- Correlation: send `x-trace-id` on writes; debug via `GET /v1/traces/:id`.
- Full docs for agents: `GET https://api.plungeai.com/llms-full.txt`.

Keep the block verbatim except the env-var names, which should match the app's conventions.

Planned: TI-33

Search is not available yet. Until it ships, use the page index or browse the sidebar.

Planned: TI-34

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