---
name: plungeai-api-setup
description: "Setup for the PlungeAI One API (https://api.plungeai.com) — a self-service ozk_ key, the base URL, the Bearer/X-API-Key auth header, your first curl call, the live OpenAPI 3.1 contract at /v1/openapi.json, typed-client codegen (openapi-typescript, openapi-python-client, the future @plungeai/one-api), and the shared error-code/rate-limit basics. Use whenever writing or GENERATING code that calls PlungeAI, or answering \"how do I authenticate\", \"where's the OpenAPI spec\", or \"how do I generate a typed client\". Triggers: \"PlungeAI API\", \"api.plungeai.com\", \"One API\", \"call plungeai from code\", \"plungeai openapi\", \"plungeai curl\", \"plungeai SDK\". Route-by-route capability detail lives in the matching capability skill (`plungeai-models`, `plungeai-agents`, `plungeai-tools-connectors`, `plungeai-workflows`, `plungeai-discovery`, `plungeai-results-traces`) — load one next. MCP calls → `plungeai-mcp-setup`; terminal → `plungeai-cli-setup`; unsure which door → `choose-your-plungeai-door`."
---

# PlungeAI One API — setup

One base URL for the whole platform: **`https://api.plungeai.com`**. Plain JSON over
HTTPS — no SDK required. The models ("money") plane is OpenAI-compatible. Machine-readable
contract: `GET /v1/openapi.json` (OpenAPI 3.1). This skill gets you authenticated and making
calls; the route-by-route manual for each capability (what params, what the response looks
like, error handling per route) lives in that capability's own skill — load it next.

## Prerequisites — get a key

Self-service `ozk_` key: **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`) →
create → name it, pick an expiry (never, or 7–365 days) → copy it once, it is shown exactly
once and stored hashed thereafter. Ask the account owner only for a shared/team key minted
under someone else's account. Keys inherit your account's tier (free by default).

The models plane uses a **separate** key with a different prefix, minted at
**Dashboard → One API → Keys** (same page, "Model gateway keys" panel): `sk-ocean-YOUR_KEY` for `/v1/chat/completions`,
`/v1/embeddings`, `/v1/models` (see `plungeai-models`). Sending the wrong prefix to the wrong
plane is a `401`, not a silent fallback — never mix them.

## Discovery first — hard rule

The catalog is **live**. Never hardcode agent ids, tool lists, model slugs, or route shapes
from memory:

- `GET /v1/openapi.json` — the live route contract, no auth required. This is the one
  authority for what routes exist; regenerate any typed client from it, never patch by hand.
- `GET /v1/agents` / `GET /v1/discovery/search?q=<capability>` — what's callable right now
  (full capability detail: `plungeai-discovery`, `plungeai-agents`).

## Quick start — first call

```bash
curl -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \
  -H "Authorization: Bearer ozk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Say exactly: hello ocean", "sync": true}'
```

```json
{
  "content": "hello ocean",
  "workflow_id": "2cecae7f-a8da-4844-b75b-b6d3fe9419f6",
  "task_id": "t1",
  "request_id": "2cecae7f-a8da-4844-b75b-b6d3fe9419f6"
}
```

That is the whole integration pattern: bearer key, JSON body, JSON result. Every other plane
(tools, workflows, models, MCP pass-through, discovery, traces) works the same shape — the
per-plane request/response detail is in that plane's capability skill.

## Authentication — header and error basics

| Key | Planes | How to send |
|---|---|---|
| `ozk_YOUR_KEY` | Execution planes: `/v1/discovery`, `/v1/tools`, `/v1/agents`, `/v1/workflows`, `/v1/mcp`, `/v1/traces` | `Authorization: Bearer ozk_YOUR_KEY` (or `X-API-Key: ozk_YOUR_KEY`) |
| `sk-ocean-YOUR_KEY` | Models plane: `/v1/chat/completions`, `/v1/embeddings`, `/v1/models` | `Authorization: Bearer sk-ocean-YOUR_KEY` |

- Never hardcode keys in generated code — read them from env vars (`PLUNGEAI_API_KEY` for
  `ozk_`, `PLUNGEAI_INFERENCE_KEY` for `sk-ocean-`).
- Execution-plane errors use the envelope `{"error":{"code","message",…}}` — this includes
  `/v1/discovery/recommend` and `/v1/discovery/cards/:type/:id`, which normalize the
  registry's own flat `{"error":"<string>"}` rejections into the envelope before you see
  them (`code` is `not_found` on a 404, `invalid_request` otherwise). The models plane
  uses the OpenAI error shape (`{"error":{"message","type","code","request_id"}}`).
- Every response carries a **server-minted** `x-request-id` header. To correlate your own
  calls, send **`x-trace-id`** and keep your own copy — it is not echoed back, but it is
  threaded across every internal hop and queryable at `GET /v1/traces/<your id>`
  (`plungeai-results-traces`).

## Error semantics — the ones every caller needs

| Status | Code | Meaning | What your code does |
|---|---|---|---|
| 401 | `unauthorized` | Missing/invalid key, or the wrong key prefix for this plane | Fix the key. Never retry in a loop |
| 403 | `refused` | **Trust fence.** The agent/tool refused the action outright — a gated/money verb, unattended surface. A policy verdict, not a lifecycle state | **FINAL. Surface verbatim. NEVER retry, rephrase, or route around** |
| 403 | `agent_not_active` | A named agent (in a workflow or a single-agent execute) is parked/inactive — a lifecycle state, distinct from `refused` above | Re-discover a fresh id (`GET /v1/discovery/search`); don't retry the same id |
| 404 | `unknown_agent` / `unknown_tool` / `workflow_not_found` | No such (or unknown) id | Re-discover; don't retry the same id |
| 404 | `not_ready` | Async result not landed yet | Poll again with backoff (2s+) |
| 409 | `approval_required` | **Trust fence.** A human must approve before the action runs — implemented and produced today, not a placeholder | Approve out-of-band (Studio, or MCP `plungeai_continue` — the One API itself has no REST `continue` route), then re-issue the identical request |
| 422 | `invalid_params` | Outcome `needs_input` — body fails the tool contract; response echoes `missing` and the full contract | Self-correct from the echoed contract, then retry once |
| 424 | `connection_required` / `credential_required` | Outcome `needs_connection` / `needs_api_key` — no connected account, or no API key for a connector | Connect the account or add the key (Ocean Studio → Connectors), then retry |
| 429 | `rate_limited` | **Execution planes** — per-tier RPM/RPD cap, or failed-auth metering | Honour the `Retry-After` header; back off |
| 429 | `rate_limit_exceeded` / `spend_cap_exceeded` / `insufficient_quota` | **Models plane only** — separate codes, separate plane; rate, spend-cap, or quota limit | Back off; caps/quotas are policy, not transients |
| 5xx | `engine_error` / `upstream_error` / `internal_error` | Upstream or router failure | One retry with backoff is reasonable |

Canonical code list (all planes, every status): `docs/guide-3.0/13-errors-limits.md` §13.2
(execution-plane codes), §13.3 (outcome→HTTP mapping), §13.5 (the two trust-fence statuses).
`403 refused` and `409 approval_required` are the fence; everything else is caller-fixable.

Sync vs async, per-route detail, and the full route list are in each capability's own skill —
this skill only carries the pattern, not the catalog.

## Rate limits

Execution-plane tiers: free 30/min · 1,000/day, pro 100/min · 10,000/day, enterprise
300/min · 100,000/day (an unset tier defaults to pro; a per-key override can replace the
per-minute cap). Enforced per-key on `POST` executions only (catalog `GET`s are free); a hit
answers `429 rate_limited` with a `Retry-After` header — honour it. The models plane has its
own, separate limiter, default 600 req/min per key, answering `429 rate_limit_exceeded` with
**no** `Retry-After` header — back off on a short fixed interval (~1s) instead. Don't hammer
result-polling endpoints; use 2s+ intervals.

## Self-documenting endpoints (no auth)

- `GET /v1/openapi.json` — OpenAPI 3.1 contract
- `GET /llms.txt` — index (llmstxt.org format) · `GET /llms-full.txt` — full guide + route
  reference as one markdown payload
- `GET /docs` — human docs page
- `GET /health` — liveness

AI agents at runtime can skip HTTP entirely: connect an MCP client to
`https://mcp.plungeai.com/v1` with an `ozk_` key — see `plungeai-mcp-setup`.

## SDK and codegen

The supported path is generating a typed client from the live OpenAPI spec — there is no
hand-maintained SDK. Full snippets (TypeScript via `openapi-typescript` + `openapi-fetch`,
a minimal Python wrapper, the `@plungeai/one-api` shape for when it's published, the curl
cookbook, and a paste-ready `AGENTS.md` block for apps you generate):
`references/sdk-and-codegen.md`.

## Verify

```bash
# 1. Liveness (no auth) — expect {"status":"ok","service":"one-api-router",...}
curl -s https://api.plungeai.com/health

# 2. Authenticated GET — expect {"tools":[...],"count":N}
curl -s "https://api.plungeai.com/v1/tools?limit=1" \
  -H "Authorization: Bearer ozk_YOUR_KEY"

# 3. A 401 here means the key is wrong; a 200 with cards means you're in:
curl -s "https://api.plungeai.com/v1/discovery/search?q=web%20search&limit=1" \
  -H "Authorization: Bearer ozk_YOUR_KEY"
```

For the models plane, verify separately with the `sk-ocean-` key:
`curl -s https://api.plungeai.com/v1/models -H "Authorization: Bearer sk-ocean-YOUR_KEY"`.

## References

- `references/sdk-and-codegen.md` — typed-client generation (TS/Python), the
  `@plungeai/one-api` client shape, curl cookbook, self-documenting endpoints, the
  paste-ready `AGENTS.md` block for generated apps.

## Related skills

- `plungeai-models` — the OpenAI-compatible plane in depth: routing, presets, guardrails,
  caching, pricing.
- `plungeai-agents`, `plungeai-tools-connectors` — execute a registry agent or a structured
  tool; contracts, sync/async, 422 handling.
- `plungeai-workflows` — CNL YAML authoring and the workflow execution routes (inline + saved,
  SSE streaming).
- `plungeai-discovery` — catalog search, recommendations, cards.
- `plungeai-results-traces` — execution traces, MCP-as-server routes, results/conversation.
- `plungeai-mcp-setup` — the same platform over MCP instead of REST.
- `plungeai-cli-setup` — operate PlungeAI from a terminal.
