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

# Campaigns CRUD

> Create, list, read, update, and delete campaigns.

All campaign endpoints require an API key with the appropriate scope.
Campaigns are scoped to the tenant bound to your API key.

## Create a campaign

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.yotel.in/api/v1/campaigns \
    -H "Authorization: Bearer yt_live_YOUR_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "May outreach",
      "dial_mode": "progressive",
      "voice_agent_id": "va_abc123"
    }'
  ```

  ```python Python theme={null}
  from yotel import Client

  client = Client(api_key="yt_live_YOUR_KEY")
  campaign = client.campaigns.create(
      name="May outreach",
      dial_mode="progressive",
      voice_agent_id="va_abc123",
  )
  print(campaign.id)
  ```

  ```typescript TypeScript theme={null}
  import { YotelClient } from "@yotel/client";

  const client = new YotelClient({ apiKey: "yt_live_YOUR_KEY" });
  const campaign = await client.campaigns.create({
    name: "May outreach",
    dial_mode: "progressive",
    voice_agent_id: "va_abc123",
  });
  console.log(campaign.id);
  ```
</CodeGroup>

### Request body

| Field                       | Type   | Required | Description                                                               |
| --------------------------- | ------ | -------- | ------------------------------------------------------------------------- |
| `name`                      | string | Yes      | Campaign display name                                                     |
| `dial_mode`                 | string | Yes      | `"preview"`, `"progressive"`, or `"predictive"`                           |
| `voice_agent_id`            | string | No       | Attach a [voice agent](/voice-agents/quickstart) to handle answered calls |
| `post_answer_action`        | string | No       | `"connect_agent"` (default), `"connect_voice_agent"`, or `"run_flow"`     |
| `predictive_target_abandon` | number | No       | Target abandon rate for predictive mode (max `0.03` — TRAI hard cap)      |
| `predictive_max_wait_s`     | number | No       | Max seconds an answered lead waits for an agent in predictive mode        |

**Scope:** `campaigns:write`  |  **Status:** `201 Created`

### Response

Returns a `CampaignResponse` object with `id`, `name`, `dial_mode`, `status` (`"draft"`), timestamps, and all configured fields.

***

## List campaigns

Returns all campaigns for the tenant bound to your API key.

<CodeGroup>
  ```bash curl theme={null}
  curl https://api.yotel.in/api/v1/campaigns \
    -H "Authorization: Bearer yt_live_YOUR_KEY"
  ```

  ```python Python theme={null}
  campaigns = client.campaigns.list()
  ```

  ```typescript TypeScript theme={null}
  const campaigns = await client.campaigns.list();
  ```
</CodeGroup>

**Scope:** `campaigns:read`  |  **Status:** `200 OK`

***

## Get a campaign

<CodeGroup>
  ```bash curl theme={null}
  curl https://api.yotel.in/api/v1/campaigns/{campaign_id} \
    -H "Authorization: Bearer yt_live_YOUR_KEY"
  ```

  ```python Python theme={null}
  campaign = client.campaigns.get("campaign_id")
  ```

  ```typescript TypeScript theme={null}
  const campaign = await client.campaigns.get("campaign_id");
  ```
</CodeGroup>

**Scope:** `campaigns:read`  |  **Status:** `200 OK`

Returns `404` if the campaign does not exist or belongs to a different tenant.

***

## Update a campaign

PATCH semantics — only include the fields you want to change.

<CodeGroup>
  ```bash curl theme={null}
  curl -X PATCH https://api.yotel.in/api/v1/campaigns/{campaign_id} \
    -H "Authorization: Bearer yt_live_YOUR_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "Updated name"}'
  ```

  ```python Python theme={null}
  campaign = client.campaigns.update("campaign_id", name="Updated name")
  ```

  ```typescript TypeScript theme={null}
  const campaign = await client.campaigns.update("campaign_id", {
    name: "Updated name",
  });
  ```
</CodeGroup>

**Scope:** `campaigns:write`  |  **Status:** `200 OK`

***

## Delete a campaign

<CodeGroup>
  ```bash curl theme={null}
  curl -X DELETE https://api.yotel.in/api/v1/campaigns/{campaign_id} \
    -H "Authorization: Bearer yt_live_YOUR_KEY"
  ```

  ```python Python theme={null}
  client.campaigns.delete("campaign_id")
  ```

  ```typescript TypeScript theme={null}
  await client.campaigns.delete("campaign_id");
  ```
</CodeGroup>

**Scope:** `campaigns:write`  |  **Status:** `204 No Content`

Returns `409 Conflict` if the campaign is in a state that cannot be deleted (e.g., currently running).

***

## Errors

| Status | Condition                                                   |
| ------ | ----------------------------------------------------------- |
| `404`  | Campaign not found or belongs to another tenant             |
| `409`  | Campaign is in a state that prevents the operation          |
| `422`  | Validation error (e.g., `predictive_target_abandon > 0.03`) |
