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

# Python SDK

> Manage your entire woku account from your backend with the woku package: sync and async client over httpx for trackers, VoC tools, tickets, action plans and sends of the v1 API

<Info>
  **Available on the Corporate plan.** This capability is part of woku's enterprise features. [Talk to our sales team](https://woku.app/pricing).
</Info>

The **`woku`** package is the official **server-side** client for the woku
management API in Python. With a synchronous client (`Woku`) and its
asynchronous twin (`AsyncWoku`) over `httpx` you manage external trackers, VoC
tools (**NPS**, **CSAT**, **CES**), wokus, forms, flows, action plans, support
tickets, survey sends and delivery tracking, all over the public **v1** API. It
is the counterpart of the [JavaScript SDK](/docs/en/development/sdk-javascript), with
the same surface.

<Warning>
  This is a **server-side** SDK. The company secret key grants full management
  access, so it must live only on your backend. Never ship it in a client you do
  not control. To capture feedback from a mobile app use the [React Native
  SDK](/docs/en/development/sdk-react-native), which uses a public capture key.
</Warning>

## Installation

```bash theme={null}
pip install woku
```

Requires Python 3.9 or later. The SDK ships `py.typed`, so type checkers pick up
its types with no extra configuration.

## Initialization

Create a `Woku` instance once and reuse it.

```python theme={null}
from woku import Woku

woku = Woku(api_key="sk_...")  # or set WOKU_API_KEY and call Woku()
```

If you omit `api_key`, the SDK reads the `WOKU_API_KEY` environment variable.

| Option        | Required | Description                                                  |
| ------------- | -------- | ------------------------------------------------------------ |
| `api_key`     | yes      | Company secret key. Defaults to the `WOKU_API_KEY` variable. |
| `base_url`    | no       | API base URL. Defaults to `https://clientapi.woku.app`.      |
| `timeout`     | no       | Per-request timeout in seconds. Defaults to `60.0`.          |
| `max_retries` | no       | Automatic retries for transient failures. Defaults to `2`.   |

Request bodies accept a plain dict (as in the examples) or a Pydantic model
generated from `woku._generated.models`.

## Authentication

The SDK authenticates with the **Company Key**, the same secret key the
[API](/docs/en/development/api) uses. The company owner gets it from the company
**Information** section in the admin app:
[admin.woku.app](https://admin.woku.app).

### Rotate or revoke the key

Rotating generates a new key and **immediately invalidates the previous one**;
store the returned key before continuing.

```python theme={null}
result = woku.company.rotate_key()
# store result["secretKey"] securely; the previous key stops working

woku.company.revoke_key()  # leaves the account without an active key
```

## Quickstart

An end-to-end flow: create a tracker, create an NPS tool, send it and read the
response rate.

```python theme={null}
from woku import Woku

woku = Woku(api_key="sk_...")

# 1. Create a tracker definition (idempotent).
tracker = woku.trackers.create({"name": "Store #1", "system": "retail"})

# 2. Create an NPS tool and send it by email or WhatsApp.
tool = woku.nps_tools.create(
    {"name": "Post-purchase", "npsMessage": "How likely are you to recommend us?"}
)
woku.nps.send_invitations(
    {"channel": "email", "npsToolId": tool["_id"], "recipients": ["ana@example.com"]}
)

# 3. Read delivery and response rate.
stats = woku.dispatches.stats({"channel": "email"})
print(stats["responseRate"])
```

## Async client

`AsyncWoku` exposes the same resources with `await` methods and `async for`
iteration. Use it as a context manager to close the connection pool.

```python theme={null}
import asyncio
from woku import AsyncWoku


async def main() -> None:
    async with AsyncWoku(api_key="sk_...") as woku:
        async for ticket in await woku.tickets.list({"severity": "high"}):
            print(ticket["title"])


asyncio.run(main())
```

## Main flows

### Support tickets

Tickets are generated by woku's AI. You can list, filter and curate them.

```python theme={null}
for ticket in woku.tickets.list({"severity": "high"}):
    print(ticket["title"])

stats = woku.tickets.stats()
```

### Action plans

```python theme={null}
woku.action_plans.approve("plan_123")
woku.action_plans.send(
    "plan_123",
    {"provider": "jira", "target": {"projectId": "10032", "issueTypeId": "10001"}},
)
```

## Pagination

List methods return an iterable page. Iterate every item across pages, or walk
page by page:

```python theme={null}
for ticket in woku.tickets.list({"severity": "high"}):
    print(ticket["title"])

first = woku.dispatches.list({"channel": "whatsapp"})
if first.has_next_page():
    second = first.get_next_page()
```

The async client iterates with `async for`.

## Idempotency

Creates carry an automatic `Idempotency-Key`, so a retry after a transient
failure never creates twice. Actions (send, test, reply) are **not** retried on
their own. You can pass your own key per call with the `options` argument.

## Error handling

Every failure is a `WokuError`. HTTP errors are typed subclasses carrying the
server `status`, body and `request_id`:

```python theme={null}
from woku import NotFoundError, RateLimitError

try:
    woku.tickets.get("nonexistent")
except NotFoundError as err:
    print(err.status, err.request_id)  # 404, "req_..."
except RateLimitError as err:
    print("retry after", err.retry_after_seconds)
```

Transport failures (DNS, TLS, timeout) are `WokuConnectionError` and
`WokuTimeoutError`. The SDK retries GETs and idempotent writes automatically
with backoff, honoring the `Retry-After` header.

## Per-call configuration

Every method accepts overrides in the `options` argument:

```python theme={null}
woku.tickets.list({"severity": "high"}, options={"timeout": 10.0, "max_retries": 0})
woku.nps_tools.create(body, options={"idempotency_key": "my-key"})
```

## Resources

`trackers`, `nps_tools` / `csat_tools` / `ces_tools`, `nps` / `csat` / `ces`,
`wokus`, `forms`, `flows`, `action_plans`, `action_plan_groups`, `tickets`,
`ticket_destinations`, `dispatches`, `reports`, `company`, `quarantines`.

## Versioning

The SDK follows **semantic versioning** (`MAJOR.MINOR.PATCH`). The current
published version is **`0.1.0`**. We recommend pinning a compatible range (for
example `>=0.1,<0.2`) and reviewing the changelog before a MAJOR bump. Versions
and their notes are on [PyPI](https://pypi.org/project/woku/) and the
[GitHub releases](https://github.com/wokuApp/woku-python/releases).

## Resources

* **PyPI package:** [woku](https://pypi.org/project/woku/)
* **Code and examples:** [github.com/wokuApp/woku-python](https://github.com/wokuApp/woku-python)
* **Equivalent JavaScript SDK:** [JavaScript SDK](/docs/en/development/sdk-javascript)
* **API reference:** [API Integration Guide](/docs/en/development/api)
