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

# Python SDK — campaigns

> Python SDK reference for Kataven outbound campaigns — bulk-dial from CSV with cap-aware concurrency and live SSE metrics.

`CampaignsClient` is reachable on every Kataven client as `client.campaigns`. Each method maps to one HTTP endpoint on the [Hub API](/api-reference/introduction); links to the underlying spec entry are inline below.

Bulk outbound campaigns dialled from CSV with cap-aware concurrency, retry logic, and live progress metrics over Server-Sent Events.

## Methods at a glance

| Method          | HTTP                                           | Summary                                         |
| --------------- | ---------------------------------------------- | ----------------------------------------------- |
| `list`          | `GET /api/v1/campaigns`                        | List campaigns                                  |
| `get`           | `GET /api/v1/campaigns/{campaign_id}`          | Get a campaign                                  |
| `create`        | `POST /api/v1/campaigns`                       | Create a campaign                               |
| `start`         | `POST /api/v1/campaigns/{campaign_id}/start`   | Start a campaign                                |
| `pause`         | `POST /api/v1/campaigns/{campaign_id}/pause`   | Pause a running campaign                        |
| `resume`        | `POST /api/v1/campaigns/{campaign_id}/resume`  | Resume a paused campaign                        |
| `stop`          | `POST /api/v1/campaigns/{campaign_id}/stop`    | Stop a campaign permanently                     |
| `delete`        | `DELETE /api/v1/campaigns/{campaign_id}`       | Delete a campaign                               |
| `list_contacts` | `GET /api/v1/campaigns/{campaign_id}/contacts` | List contacts in a campaign                     |
| `stream_events` | *(client-side)*                                | Iterate over Server-Sent Events for a campaign. |

## Reference

### `client.campaigns.list(...)`

List campaigns

**HTTP** — `GET /api/v1/campaigns` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/getApiV1Campaigns)

```python theme={null}
    def list(self) -> Dict[str, Any]:
```

### `client.campaigns.get(...)`

Get a campaign

**HTTP** — `GET /api/v1/campaigns/{id}` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/getApiV1CampaignsById)

```python theme={null}
    def get(self, campaign_id: str) -> Dict[str, Any]:
```

### `client.campaigns.create(...)`

Create a campaign

**HTTP** — `POST /api/v1/campaigns` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/postApiV1Campaigns)

```python theme={null}
    def create(
        self,
        name: str,
        agent_id: str,
        phone_number_id: str,
        contacts: BinaryIO,
        max_concurrent_calls: int = 5,
        retries_per_contact: int = 0,
        retry_delay_seconds: int = 300,
        scheduled_at: Optional[str] = None,
    ) -> Dict[str, Any]:
```

`contacts` must be a binary file-like (open in `rb` mode). The CSV's
first row is headers and must include `phone_number`. Other columns
become `custom_fields`.

Multipart form upload — `contacts` is a CSV file, every other field is a form value. The CSV must contain at least a `phone_number` column. The campaign is created in `draft` state and dispatch starts only after `start`.

### `client.campaigns.start(...)`

Start a campaign

**HTTP** — `POST /api/v1/campaigns/{id}/start` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/postApiV1CampaignsByIdStart)

```python theme={null}
    def start(self, campaign_id: str) -> Dict[str, Any]:
```

Flips the campaign from `draft`/`paused` to `running`. The dispatcher goroutine begins originating calls subject to per-tenant rate caps.

### `client.campaigns.pause(...)`

Pause a running campaign

**HTTP** — `POST /api/v1/campaigns/{id}/pause` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/postApiV1CampaignsByIdPause)

```python theme={null}
    def pause(self, campaign_id: str) -> Dict[str, Any]:
```

Stops the dispatcher from originating new calls; in-flight calls finish naturally.

### `client.campaigns.resume(...)`

Resume a paused campaign

**HTTP** — `POST /api/v1/campaigns/{id}/resume` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/postApiV1CampaignsByIdResume)

```python theme={null}
    def resume(self, campaign_id: str) -> Dict[str, Any]:
```

### `client.campaigns.stop(...)`

Stop a campaign permanently

**HTTP** — `POST /api/v1/campaigns/{id}/stop` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/postApiV1CampaignsByIdStop)

```python theme={null}
    def stop(self, campaign_id: str) -> Dict[str, Any]:
```

Terminal state — no further dispatches, contacts in `pending` move to `cancelled`. Cannot be reversed; create a new campaign to redo the work.

### `client.campaigns.delete(...)`

Delete a campaign

**HTTP** — `DELETE /api/v1/campaigns/{id}` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/deleteApiV1CampaignsById)

```python theme={null}
    def delete(self, campaign_id: str) -> None:
```

Refuses if the campaign is `running`. Pause or stop it first.

### `client.campaigns.list_contacts(...)`

List contacts in a campaign

**HTTP** — `GET /api/v1/campaigns/{id}/contacts` · [API reference →](/api-reference/introduction#tag/Campaigns/operation/getApiV1CampaignsByIdContacts)

```python theme={null}
    def list_contacts(
        self,
        campaign_id: str,
        status: Optional[str] = None,
        page: int = 0,
    ) -> Dict[str, Any]:
```

### `client.campaigns.stream_events(...)`

Iterate over Server-Sent Events for a campaign.

```python theme={null}
    def stream_events(self, campaign_id: str) -> Iterator[Union[Dict[str, Any], str]]:
```

Yields decoded JSON dicts for `data:` frames. Heartbeat comments
and `event: end` markers are yielded as raw strings so the caller
can choose to filter or react. Iteration ends naturally when the
server closes the stream (campaign reaches a terminal status).
