# Podda SDK v2

Import the authenticated, same-origin SDK from the reserved platform route:

```js
import { init, PoddaSdkError } from "/__podda/v2/sdk.js";
const app = await init();
```

For bundled projects, install `@deviselabs/podda-sdk` and import `@deviselabs/podda-sdk/browser` or `@deviselabs/podda-sdk/worker`. The package ships ESM and TypeScript declarations. The same browser implementation is also served from the reserved route for build-free clients.

The SDK exposes app.user, app.session, app.members.list(), app.kv.list({ prefix? }), app.kv.get(key), app.kv.set(key, value, { ifVersion?, idempotencyKey }), app.kv.delete(key, { ifVersion?, idempotencyKey }), app.files, app.notifications, app.notify, app.ai.generate, and app.errors.capture.

app.members.list() returns the app's active members as { id, display_name, role } — names come from the account each person signed in with, never their email. Guests are not members: a guest sees only themselves and never appears in a member's list.

Those methods map to same-origin JSON routes under /__podda/v2: session, members, kv, files, notifications, ai/generate, and client-errors. Successful reads return the documented object; mutations require an idempotency key. Failures throw PoddaSdkError with code, safe message, and HTTP status. Do not call the REST routes directly unless implementing a constrained server module; the SDK owns headers, encoding, and error parsing.

KV writes use HTTP preconditions. A numeric ifVersion sends a strong If-Match ETag; null sends If-None-Match: * for create-only; omitted means unconditional. On 412 VERSION_CONFLICT, reread and recompute. KV_NOT_FOUND means the key has not been created. Never retry with stale state, and use a fresh idempotency key for each newly computed write.

All requests use /__podda/v2 routes on the current app origin and the HttpOnly member session. Generated code never receives a reusable Podda credential.
