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

# Create Campaign

> Create a new outbound calling campaign

## Endpoint

**POST** `https://api.graine.ai/api/v1/campaigns/`

Also available as **POST** `/campaigns/create` (Merlin alias — identical behaviour).

## Headers

| Header          | Required | Description          |
| --------------- | -------- | -------------------- |
| `Authorization` | Yes      | `Bearer gat_<token>` |
| `Content-Type`  | Yes      | `application/json`   |

## Request Body

| Field                    | Type      | Required | Description                                                            |
| ------------------------ | --------- | -------- | ---------------------------------------------------------------------- |
| `name`                   | string    | Yes      | Human-readable campaign name                                           |
| `agent_id`               | string    | Yes      | ID of the AI agent that will make calls                                |
| `phone_numbers`          | string\[] | Yes      | One or more E.164 outbound caller IDs                                  |
| `organization_id`        | string    | No       | Defaults to the token's org                                            |
| `phone_number_strategy`  | string    | No       | `round_robin` (default) · `random` · `least_loaded`                    |
| `working_hours_enforced` | boolean   | No       | Whether to enforce the per-day calling windows                         |
| `timezone`               | string    | No       | IANA timezone string (e.g. `Asia/Kolkata`). Applies to `working_hours` |
| `working_hours`          | object    | No       | Per-day schedule — see schema below                                    |
| `retry_policy`           | object    | No       | Retry configuration — see schema below                                 |
| `default_call_variables` | object    | No       | Key-value pairs merged into every contact's call context               |
| `metadata`               | object    | No       | Arbitrary metadata. `concurrency_limit` controls max parallel calls    |

### working\_hours schema

```json theme={null}
{
  "monday":    { "start": "09:00", "end": "18:00", "enabled": true },
  "tuesday":   { "start": "09:00", "end": "18:00", "enabled": true },
  "wednesday": { "start": "09:00", "end": "18:00", "enabled": true },
  "thursday":  { "start": "09:00", "end": "18:00", "enabled": true },
  "friday":    { "start": "09:00", "end": "18:00", "enabled": true },
  "saturday":  { "start": "10:00", "end": "14:00", "enabled": false },
  "sunday":    { "start": "10:00", "end": "14:00", "enabled": false }
}
```

Times are in `HH:MM` 24-hour format. Days where `enabled: false` never receive calls.

### retry\_policy schema

| Field              | Type    | Default | Description                      |
| ------------------ | ------- | ------- | -------------------------------- |
| `max_retries`      | integer | `3`     | Total retry attempts per contact |
| `strategy`         | string  | `fixed` | `fixed` or `exponential` backoff |
| `cooldown_minutes` | integer | `30`    | Wait time between retry attempts |

<Note>
  `callee_name` should live in each **contact's** `call_variables`, not in `default_call_variables`. The AI uses it in its greeting — if it's missing the agent cannot address the person by name.
</Note>

## Example Request

```json theme={null}
{
  "name": "Q2 Insurance Renewals",
  "organization_id": "org_xyz",
  "agent_id": "agent_abc123",
  "phone_numbers": ["+919876543210", "+919876543211"],
  "phone_number_strategy": "round_robin",
  "working_hours_enforced": true,
  "timezone": "Asia/Kolkata",
  "working_hours": {
    "monday":    { "start": "09:00", "end": "18:00", "enabled": true },
    "tuesday":   { "start": "09:00", "end": "18:00", "enabled": true },
    "wednesday": { "start": "09:00", "end": "18:00", "enabled": true },
    "thursday":  { "start": "09:00", "end": "18:00", "enabled": true },
    "friday":    { "start": "09:00", "end": "18:00", "enabled": true },
    "saturday":  { "start": "10:00", "end": "14:00", "enabled": false },
    "sunday":    { "start": "10:00", "end": "14:00", "enabled": false }
  },
  "retry_policy": {
    "max_retries": 3,
    "strategy": "fixed",
    "cooldown_minutes": 30
  },
  "default_call_variables": {
    "language": "en",
    "product": "Health Insurance"
  },
  "metadata": {
    "concurrency_limit": 20
  }
}
```

## Responses

### 200 OK

```json theme={null}
{
  "campaign_id": "cmp_abc123",
  "name": "Q2 Insurance Renewals",
  "status": "draft",
  "organization_id": "org_xyz",
  "agent_id": "agent_abc123"
}
```

<Tip>
  Save the returned `campaign_id` — you'll need it when creating batches.
</Tip>

### 400 Bad Request

```json theme={null}
{ "detail": "agent_id is required" }
```

### 401 Unauthorized

```json theme={null}
{ "detail": "Invalid or expired token" }
```

## Code Examples

```python theme={null}
import requests

url = "https://api.graine.ai/api/v1/campaigns/"
headers = {
    "Authorization": "Bearer gat_your_token",
    "Content-Type": "application/json"
}
payload = {
    "name": "Q2 Insurance Renewals",
    "agent_id": "agent_abc123",
    "phone_numbers": ["+919876543210"],
    "timezone": "Asia/Kolkata",
    "retry_policy": {
        "max_retries": 3,
        "strategy": "fixed",
        "cooldown_minutes": 30
    }
}

response = requests.post(url, json=payload, headers=headers)
campaign = response.json()
print(campaign["campaign_id"])
```

```javascript theme={null}
const response = await fetch("https://api.graine.ai/api/v1/campaigns/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer gat_your_token",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "Q2 Insurance Renewals",
    agent_id: "agent_abc123",
    phone_numbers: ["+919876543210"],
    timezone: "Asia/Kolkata",
    retry_policy: { max_retries: 3, strategy: "fixed", cooldown_minutes: 30 }
  })
});

const campaign = await response.json();
console.log(campaign.campaign_id);
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Create a Batch" icon="users" href="/api-reference/batches/create">
    Upload contacts and start dispatching
  </Card>

  <Card title="Campaign Lifecycle" icon="circle-pause" href="/api-reference/campaigns/lifecycle">
    Pause, resume, or cancel
  </Card>
</CardGroup>
