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.

Every active agent is also callable as a tool with a machine-checkable invocation contract. The flow is always: discover → inspect the contract → execute. This plane runs the platform's trust fence — gated and money operations refuse unattended execution by design.

Auth: Authorization: Bearer ozk_YOUR_KEY on every route here.

GET /v1/tools — list active tool-agents

Query params: limit (default 50, max 100), offset (default 0).

curl -s "https://api.plungeai.com/v1/tools?limit=2" \
  -H "Authorization: Bearer ozk_YOUR_KEY"
{
  "tools": [
    { "id": "brave-agent", "name": "Brave Search", "type": "agent",
      "category": "search", "status": "active",
      "description": "Web search via Brave", "tags": ["search"] },
    { "id": "pdf-agent", "name": "PDF Agent", "type": "agent",
      "category": "documents", "status": "active",
      "description": "Convert and extract PDFs", "tags": ["pdf"] }
  ],
  "count": 2
}

count is the returned page's length, not the catalog total — page until a short page, never until offset >= count. A failed registry hop returns 502 upstream_error.

GET /v1/tools/{id} — the invocation contract

Fetch this before the first execute of any unfamiliar tool. The contract tells you the operations, which are gated, the required params, the JSON Schema for inputs, and worked examples.

curl -s https://api.plungeai.com/v1/tools/brave-agent \
  -H "Authorization: Bearer ozk_YOUR_KEY"
{
  "agent_id": "brave-agent",
  "name": "Brave Search",
  "description": "Web search via the Brave Search API",
  "operations": [
    { "name": "search", "purpose": "Run a web search", "gated": false,
      "required_params": ["query"] },
    { "name": "news", "purpose": "Search recent news", "gated": false,
      "required_params": ["query"] }
  ],
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": { "type": "string" },
      "count": { "type": "integer" }
    }
  },
  "examples": [
    { "title": "Basic web search", "cnl": "operation: search\nparams:\n  query: cloudflare workers" }
  ],
  "output_type": "markdown"
}

404 → {"error":{"code":"unknown_tool","message":"..."}} — the id isn't an active tool. Re-discover via GET /v1/tools or discovery search.

gated: true on an operation means executing it unattended is refused with 403 refused by this route's pre-dispatch fence (checkAgentCall runs in 'unattended' mode here, which always resolves a gated-verb/guarded- category hit to a refusal, never a pause). 409 approval_required is a different, real code path on this same route — see the fence section below.

POST /v1/tools/{id}/execute — execute an operation

Body — two styles, both valid:

FieldTypeNotes
operationstringOperation name from the contract
paramsobjectParams per the contract's inputSchema
promptstringFree-text alternative for prompt-driven tools
formatstringResponse negotiation: json (default) | yaml | markdown | text — same values as an Accept header or the request Content-Type mirror

Validation rules ("reserved" = param names colliding with engine task-envelope fields — agent, type, id, operation, depth, user_id, executor_user_id, workflow, execution_id — never forwardable):

  • Reserved param names → 422, always.
  • Missing required params → 422 only when no prompt is present — a prose prompt satisfies prompt-capable agents, so a prompt-style call skips param validation entirely. The trust fence still runs either way.

Structured style (preferred when the contract defines operations):

curl -s -X POST https://api.plungeai.com/v1/tools/brave-agent/execute \
  -H "Authorization: Bearer ozk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation": "search", "params": {"query": "cloudflare workers pricing"}}'

Prompt style:

curl -s -X POST https://api.plungeai.com/v1/tools/brave-agent/execute \
  -H "Authorization: Bearer ozk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "search: cloudflare workers pricing"}'

Success — HTTP 200:

{
  "ok": true,
  "content": "# Web Search: cloudflare workers pricing\n\n1. ...",
  "outcome": "success",
  "request_id": "00000000-0000-4000-8000-000000000004"
}

Error semantics — features, not failures

StatusCodeMeaningCorrect handling
400invalid_formatformat isn't one of json/yaml/markdown/textFix the field
404unknown_toolNo such active toolRe-discover the id
422invalid_paramsContract violation — response body carries missing, reserved, warnings, and the full contractSelf-correct from the echoed contract; retry once with fixed params
403refused (fence)Gated operation, or payment/blockchain-category agent — never callable unattendedFINAL. Surface verbatim. NEVER retry, rephrase, or work around
403refused (lifecycle)Parked agent (status:developing/development/developed) or unknown card — the reason says whichRe-discover via GET /v1/tools / discovery search
409approval_requiredThe dispatched run's own outcome came back needs_approval (mapped 1:1 via the outcome→HTTP table — guide 3.0 §13.3/§13.5). NOT produced by the pre-dispatch gated-verb/guarded-category fence, which always resolves to 403 on this route (see below)Approve out-of-band (Studio / an attended surface), then re-issue the identical request
409duplicate_execution_idThe x-trace-id header was already used by an earlier runSend a fresh UUID
413payload_too_largeBody over 1 MiB (MAX_REQUEST_SIZE)Shrink the payload (e.g. stream large files through a URL param instead of inline file_data)
424connection_required / credential_requiredThe agent needs a connection or key the acting user hasn't set upTell the user what to connect (Studio → Connectors); retry after
429rate_limitedPer-key limiter — Retry-After headerBack off and retry
502execution_failedThe dispatched agent failed — body carries outcome, detail, contentAct on outcome (needs_input, needs_connection, …) before blind-retrying; one retry only for transient outcomes
502upstream_errorRegistry/engine hop threw (any route in this plane)One retry with backoff
503agent_unavailableAgent temporarily downRetry later or pick an alternative

422 example — the contract comes back to you

{
  "error": {
    "code": "invalid_params",
    "message": "params failed card validation",
    "missing": ["query"],
    "reserved": [],
    "warnings": [],
    "contract": { "agent_id": "brave-agent", "operations": [ "..." ] }
  }
}

Generated code should parse missing and the embedded contract, repair the body, and retry exactly once. If the second attempt also 422s, stop and report.

403 — the trust fence, and how to tell refusals apart

Fence refusals are FINAL. The gated-verb floor (buy, purchase, fetch_paid, send, transfer, pay, send_payment, withdraw, shop), operations the card tags gated:, and payment/blockchain-category agents (refused regardless of operation on this surface):

{ "error": { "code": "refused", "message": "operation \"transfer\" on x is gated (outward/irreversible) and requires human approval — not available in unattended runs." } }

Do not loop, do not reword the prompt to sneak past the fence, do not switch to the prompt style to avoid the operation gate. Tell the user what was refused and why; approvals happen on attended surfaces (Ocean Studio / apps), not through this API.

Lifecycle refusals are not final — the same 403 refused code also covers parked agents ("parked (status:…) — not callable. Use registry search to find an active alternative.") and ids with no registry card. The reason string distinguishes them; the remedy is re-discovery, not surrender.

409 approval_required is real and reachable on this route — but not from the check above. POST /v1/tools/{id}/execute calls the shared gated-verb/guarded-category fence (checkAgentCall, core/core-base/ call-agent.ts) in 'unattended' mode, and in that mode every branch that could otherwise pause for approval (a guarded payment/blockchain category with no recognizable operation, or a gated verb) resolves to 403 refused instead — approval_required is only returned by that function in 'interactive' mode, which this route never uses. The 409 you actually see on this plane comes from a different source: the dispatched run's own outcome. If the downstream agent/tool run itself pauses mid-execution (outcome needs_approval — the same status MCP surfaces as a ⏸ block), the outcome→HTTP mapping (guide 3.0 §13.3, "Trust fence" §13.5) turns that into 409 approval_required here too. Handling: approve out-of-band (Studio or another attended surface), then re-issue the identical request — the One API has no continuation token like MCP's plungeai_continue, so you resend rather than resume.

Tools vs agents — which plane to call

  • /v1/tools/:id/execute — structured, contract-validated, fenced. Use when you know the operation and params (typical for generated app code).
  • /v1/agents/:id/execute — free prompt, sync/async semantics, no operation contract. Use for open-ended instructions to LLM-driven agents.

Same underlying agents, different invocation disciplines.

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.