# SDKs

> **TL;DR** — Official JavaScript/TypeScript and Python clients, generated from the OpenAPI. They send idempotency keys, retry safely, poll with backoff and verify webhooks. Private preview: ask for access.

Official clients for JavaScript/TypeScript and Python, generated from the [OpenAPI](https://api.wandura.ai/v2/openapi.json) plus a small hand-written layer. They are correct by default:

- **Idempotency**: every submit sends an `Idempotency-Key`, and a retry reuses it, so a retry never runs or charges twice.
- **Retries**: only on 429, 5xx and network errors. A 429 waits for `Retry-After`; others back off 0.5 s, 1 s, 2 s with jitter. 400, 401, 402, 404, 409 and 422 are never retried. A `Retry-After` longer than 60 s (the daily end-user cap) raises at once instead of sleeping for hours.
- **Polling**: from 2 s, ×1.5, capped at 10 s, with jitter (Relax: 10 s to 60 s). No hidden time limit.
- **Webhooks**: a verify helper checks the signature and the 5-minute window.
- **Uploads**: one call uploads a file and returns the `file_url` for `inputs`.

The SDKs are in private preview and not on npm or PyPI yet. Ask us for access; until then the cURL samples in the [Quickstart](https://docs.wandura.ai/developers/api-v2/quickstart) work with no SDK.

## JavaScript / TypeScript
Node 18+, no dependencies.

```ts
import { Wandura, verifyWebhook } from '@wandura/sdk';

const wandura = new Wandura(); // reads WANDURA_API_KEY

const run = await wandura.runs.createAndWait('<style id>', {
  lane: 'priority',
  end_user_id: 'user_123',
  inputs: { image_url: await wandura.uploads.upload(bytes, 'image/png') },
});

// In your webhook route (raw body, not parsed JSON):
const event = verifyWebhook(rawBody, req.headers['wandura-signature'], process.env.WANDURA_WEBHOOK_SECRET);
```

## Python
Python 3.11+, standard library only.

```python
from wandura import Wandura, verify_webhook

wandura = Wandura()  # reads WANDURA_API_KEY

run = wandura.runs.create_and_wait("<style id>", {
    "lane": "priority",
    "end_user_id": "user_123",
    "inputs": {"image_url": wandura.uploads.upload(data, "image/png")},
})

# In your webhook handler (raw body bytes):
event = verify_webhook(raw_body, headers["Wandura-Signature"], os.environ["WANDURA_WEBHOOK_SECRET"])
```

Both raise a `WanduraError` with `status`, `code`, the request id and `Retry-After`. See [Errors](https://docs.wandura.ai/developers/api-v2/errors) for every code.

## AI agents and MCP
Coding agents can read the [OpenAPI](https://api.wandura.ai/v2/openapi.json) and each style's own schema. Agents that act at run time can use the MCP server at `https://api.wandura.ai/mcp` with the same Bearer key: it lists styles, quotes, creates uploads and runs.
