> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plungeai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Per-language detail — the four One API SDKs

> Shared by all four: the key comes from PLUNGEAIAPIKEY; base URL https://api.plungeai.com; retries 2 with exponential backoff honouring Retry-After on connection errors, timeouts, 408, 429 and ≥ 500 — never on 409 or 424 (semantic answers: approvalrequired, duplicateexecutionid, a missing…


<!-- sources-of-truth: sdk/one-api-client/README.md sdk/one-api-python/README.md sdk/one-api-go/README.md sdk/one-api-rust/README.md orchestration/api-gateway/docs/guide-3.0/15-sdks-and-clients.md | last-synced: 2026-10-14 (One API 2.4.0, 133 operations; SDKs 1.0.0) -->
Shared by all four: the key comes from `PLUNGEAI_API_KEY`; base URL `https://api.plungeai.com`; retries 2 with
exponential backoff honouring `Retry-After` on connection errors, timeouts, 408, 429 and ≥ 500 — never on 409 or
424 (semantic answers: `approval_required`, `duplicate_execution_id`, a missing connection; a retried execute
would start a second run); 10-minute timeout; the idempotency key is sent as `x-trace-id`, becomes the run's
execution id, is re-sent on every retry of the call, and a replay answers 409 `duplicate_execution_id`. Agent and
tool ids below (`calculator-agent`) are illustrative — discover real ids with `discovery.search` first.

Error statuses map the same way in TypeScript and Python:

| Status | Error class |
|---|---|
| 400 | `BadRequestError` |
| 401 | `AuthenticationError` |
| 403 | `PermissionDeniedError` |
| 404 | `NotFoundError` |
| 409 | `ConflictError` |
| 422 | `UnprocessableEntityError` |
| 424 | `FailedDependencyError` — `connect: { provider, method, link }` says where to connect the missing account |
| 429 | `RateLimitError` |
| ≥ 500 | `InternalServerError` |
| no response | `APIConnectionError` (timeout: TS `APIConnectionTimeoutError`, Python `APITimeoutError`) |

`code` is the envelope's `error.code`; the request id is the `x-request-id` header.

## TypeScript — `@plungeai/one-api`

```ts
import PlungeAI from '@plungeai/one-api'

const client = new PlungeAI({ apiKey: process.env['PLUNGEAI_API_KEY'] }) // the default; can be omitted

const stream = await client.workflows.executeInlineStream({ workflow })   // workflow: CNL YAML string
for await (const event of stream) {
  if (event.event === 'token') process.stdout.write((event.data as { delta: string }).delta)
}

for await (const w of client.workflows.list({ kind: 'bot' })) console.log(w)   // walks every page
let page = await client.workflows.list({ limit: 50 })
while (page.hasNextPage()) page = await page.getNextPage()

try {
  await client.agents.execute('calculator-agent', { prompt: '6*7' }, { maxRetries: 5 })
} catch (err) {
  if (err instanceof PlungeAI.FailedDependencyError) console.log(err.connect?.link)
  else if (err instanceof PlungeAI.APIError) console.log(err.status, err.code, err.requestID)
  else throw err
}

const { data, request_id } = await client.whoami().withResponse()
```

- Streams: `break` or `stream.controller.abort()` aborts the request; `stream.tee()`, `stream.toReadableStream()`.
  `stream: true` on `client.agents.execute` / `client.chat.completions.create` returns the same `Stream`.
- Options per request: `maxRetries`, `timeout` (ms), `idempotencyKey`. Client: `new PlungeAI({ maxRetries: 0, timeout: 20_000 })`.
- Raw: `.withResponse()` → `{ data, response, request_id }`; `.asResponse()` → the raw `Response`, body unread.
- Error classes are exported by name and as statics on `PlungeAI`.
- Runtimes: Node.js 20+, Deno, Bun, Cloudflare Workers, Vercel Edge. Browsers refused unless `dangerouslyAllowBrowser: true`.

## Python — `plungeai`

```python
from plungeai import PlungeAI, APIError, FailedDependencyError

client = PlungeAI()  # PlungeAI(api_key="ozk_…", max_retries=0, timeout=20.0)

for event in client.workflows.execute_inline_stream(workflow=workflow):
    if event.event == "token":
        print(event.json()["delta"], end="")

for w in client.workflows.list(kind="bot"):   # walks every page
    print(w)
page = client.workflows.list(limit=50)   # page.data, page.has_more
while page.has_next_page():
    page = page.get_next_page()

try:
    client.agents.execute("calculator-agent", prompt="6*7", max_retries=5)
except FailedDependencyError as err:
    print(err.connect["link"])
except APIError as err:
    print(err.status_code, err.code, err.request_id)

response = client.agents.with_raw_response.execute("calculator-agent", prompt="6*7")
print(response.status_code, response.headers["x-request-id"]); run = response.parse()
```

- Async: `AsyncPlungeAI()` has every method with the same signature, awaited; streams iterate with `async for event in await …`.
- `snake_case` methods; request fields are keyword arguments typed as `TypedDict`s (`plungeai.types`); responses
  are plain `dict`s. Path parameters come first, positionally: `client.workflows.versions.restore(workflow_id, version)`.
- Streams: `event.data` raw string, `event.json()` parsed; leaving the loop closes the response. `stream=True` on
  `agents.execute` / `chat.completions.create` returns a `Stream`.
- Per-call options: `extra_headers`, `extra_query`, `timeout` (seconds), `max_retries`, `idempotency_key`.
  `client.get(path, query=…)`, `client.post(path, body=…)` reach routes outside the generated layer; `executions.continue` is `continue_`.
- Python 3.10+, one runtime dependency (`httpx`), ships `py.typed`.

## Go — `github.com/PlungeAI/plungeai-go`

```go
client := plungeai.NewClient() // plungeai.NewClient(plungeai.WithAPIKey("ozk_…"), plungeai.WithMaxRetries(0))

stream, err := client.Workflows.ExecuteInlineStream(ctx, plungeai.WorkflowExecuteInlineStreamParams{Workflow: workflow})
if err != nil {
    return err
}
defer stream.Close()
for stream.Next() {
    ev := stream.Current() // ev.Event, ev.Data (raw string), ev.JSON(&v)
}
err = stream.Err()

pager := client.Workflows.ListAutoPaging(ctx, plungeai.WorkflowListParams{Kind: "bot"}) // walks every page
for pager.Next() {
    fmt.Println(pager.Current())
}

var raw *http.Response
_, err = client.Agents.Execute(ctx, "calculator-agent", plungeai.AgentExecuteParams{Prompt: "6*7"}, plungeai.WithResponseInto(&raw))
var apiErr *plungeai.Error
if errors.As(err, &apiErr) && apiErr.StatusCode == 424 {
    fmt.Println(apiErr.Connect.Link)
}
```

- Every method: `ctx`, path parameters, a params struct (`plungeai.<Resource><Method>Params`), then options.
  Nested resources are fields: `client.Workflows.Versions.List(ctx, workflowID)`.
- Options (client or per call): `WithAPIKey`, `WithBaseURL`, `WithMaxRetries`, `WithRequestTimeout`, `WithHeader`,
  `WithQuery`, `WithIdempotencyKey`, `WithResponseInto`. A deadline on `ctx` bounds the whole call, retries included.
- Streaming twins: `Agents.ExecuteStreaming`, `Chat.Completions.CreateStreaming`; list twins: `…AutoPaging`;
  manual pages: `page.Data`, `page.HasNextPage()`, `page.GetNextPage(ctx)`.
- Errors: one type `*plungeai.Error` (`StatusCode`, `Code`, `Message`, `RequestID`, `Connect` on 424); no response →
  the transport error (`errors.Is(err, context.DeadlineExceeded)` on timeout); no key → `plungeai.ErrMissingAPIKey`.
- `client.Get(ctx, path, params, &out)`, `client.Post(ctx, path, body, &out)` reach routes outside the generated layer; the root `POST /v1/execute` is `client.ExecuteCall`.
- Go 1.24+, standard library only; module published from `github.com/PlungeAI/plungeai-go`, source `sdk/one-api-go/`.

## Rust — `plungeai`

```rust
use futures_util::StreamExt;
use plungeai::{types::*, Client, RequestOptions};

let client = Client::builder().max_retries(0).build()?; // or Client::new()?

let mut stream = client
    .workflows()
    .execute_inline_stream(&WorkflowExecuteInlineStreamParams { workflow: workflow.into(), ..Default::default() })
    .await?;
while let Some(event) = stream.next().await {
    let event = event?; // event.event, event.data, event.json::<T>()
}

let mut items = client.workflows().list(&Default::default()).await?.into_stream(); // walks every page
while let Some(w) = items.next().await {
    println!("{:?}", w?);
}

match client.with_options(RequestOptions::new().max_retries(5)).agents().execute("calculator-agent", &params).await {
    Err(plungeai::Error::Api(err)) if err.status == 424 => println!("{:?}", err.connect.map(|c| c.link)),
    other => { other?; }
}

let response = client.agents().execute_raw("calculator-agent", &params).await?;
println!("{} {:?}", response.status, response.request_id); // response.parse::<AgentExecuteResponse>()?
```

- Resources are methods (`client.agents()`, `client.workflows().versions()`); path parameters first, then a
  reference to the `Default` params struct. Optional fields `Option<T>`; response enums carry `Unknown`.
- `client.with_options(RequestOptions::new()…)` (`header`, `query`, `timeout`, `max_retries`, `idempotency_key`)
  returns a client carrying those options; every JSON operation has a `…_raw` twin (`status`, `headers`,
  `request_id`, `parse::<T>()`); streaming twins `…_stream` (`agents().execute_stream`,
  `chat().completions().create_stream`); pages `data`, `has_next_page()`, `next_page()`, `into_stream()`.
- Errors: `Error::Api(Box<ApiError>)` (`status`, `code`, `message`, `request_id`, `connect`), `Connection`, `Timeout`,
  `Decode`; predicates `status()`, `is_not_found()`, `is_rate_limit()`.
- `client.get(path)`, `client.post(path, &body)` reach routes outside the generated layer.
- Rust 1.85+ (edition 2021), `tokio` runtime, TLS through rustls.

## Models plane

Every SDK covers the OpenAI-compatible routes (`chat.completions.create`, `embeddings`, `models`); the OpenAI SDK
works too with base URL `https://api.plungeai.com/v1` and the same key — see `plungeai-models`.
