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

# Create Campaign

> Create an outbound campaign from a recipient CSV. Calls start now or at a set time

Create a campaign. The CSV is parsed and stored as recipients in this request. Invalid numbers and do-not-call numbers are stored as `skipped` recipients. Duplicate numbers are dropped. A campaign with `start: "now"` starts dialing on the next scheduler tick. A future `start` makes it `scheduled`.

Check the file first with [Preview campaign recipients](https://docs.60db.ai/api-reference/agents/preview-campaign-recipients.md). For the rules, see [Outbound campaigns](https://docs.60db.ai/features/agents-campaigns.md).

## Request

### Headers

**Authorization** `string` *required*

Bearer token with your API key (scope `agents`)

**Content-Type** `string` *required*

application/json

**Idempotency-Key** `string`

1 to 128 printable characters with no spaces. Send the same key and the same body to retry safely. The retry gets the first campaign back with `200`. The same key with a different body returns `409 IDEMPOTENCY_CONFLICT`

### Body

**name** `string` *required*

1 to 120 characters

**agent\_id** `string` *required*

The agent `id`. The agent must be in your workspace

**phone\_line\_id** `string` *required*

The phone line `id` to call from. The line must be ready to place calls

**timezone** `string` *required*

An IANA time zone name, for example `Asia/Kolkata`. It sets the calling windows only

**start** `string` (default: now)

`"now"`, or an ISO 8601 time with an offset or `Z` that is in the future, for example `2026-12-01T09:00:00+05:30`. A time without an offset is refused

**calling\_windows** `object[]`

1 to 20 windows. Each is `{ "days": [1, ...], "start": "HH:MM", "end": "HH:MM" }`. `days` are ISO weekdays: 1 is Monday, 7 is Sunday. `end` may be `24:00`. A window cannot cross midnight. Default: every day, 09:00 to 20:00, in `timezone`. Nothing dials outside a window

**concurrency\_limit** `integer`

How many calls run at once. On a 60db Dialer line this is always 3, and any value you send is ignored. On your own line (`byo`), send 1 to 50. Default 3. The workspace limit also applies. See [Concurrency](https://docs.60db.ai/features/agents-campaigns.md#concurrency)

**max\_attempts** `integer` (default: 3)

1 to 30. Total calls to each recipient, including the first call

**retry\_delay\_secs** `integer` (default: 1800)

0 to 604800 (7 days). Wait before the next attempt. A retry that falls outside the calling windows waits for the next window to open

**max\_consecutive\_failures** `integer | null` (default: null)

1 to 1000, or `null` for no limit. The campaign pauses after this many calls in a row that did not connect

**csv\_text** `string` *required*

The recipient CSV as text. Up to 5 MB and 20,000 rows. It needs a phone column. See [CSV format](https://docs.60db.ai/features/agents-campaigns.md#csv-format)

**variable\_mapping** `object` (default: \{})

Maps an agent variable to a CSV column, as `{ "agent_variable": "csv_column" }`. Both are lowercase keys. The column must exist in the CSV

**variable\_defaults** `object` (default: \{})

Fallback text for an agent variable, as `{ "agent_variable": "text" }`. Up to 500 characters each. Used when the row has no value

## Response

**201 Created** with the campaign. **200 OK** with the first campaign when the `Idempotency-Key` and body match an earlier request.

The response has the same fields as [Get campaign](https://docs.60db.ai/api-reference/agents/get-campaign.md), with `status` set to `running` or `scheduled`.

```json theme={null}
{
  "success": true,
  "data": {
    "id": "3f1c9a2e-7b44-4d0e-9a5f-1c2d3e4f5a6b",
    "name": "Spring renewals",
    "agent_id": "9c2e1d7a-0b3f-4e6a-8f1d-5a7b9c0e2d44",
    "agent_name": "Front desk",
    "phone_line_id": "2d8e4f10-6a3b-4c9d-8e7f-0b1a2c3d4e5f",
    "phone_line_name": "Main line",
    "status": "scheduled",
    "pause_reason": null,
    "timezone": "Asia/Kolkata",
    "start_at": "2026-12-01T03:30:00.000Z",
    "calling_windows": [{ "days": [1, 2, 3, 4, 5], "start": "09:00", "end": "20:00" }],
    "concurrency_limit": 3,
    "max_attempts": 3,
    "retry_delay_secs": 1800,
    "max_consecutive_failures": null,
    "consecutive_failures": 0,
    "variable_mapping": {},
    "variable_defaults": {},
    "counts": { "total": 250, "pending": 247, "calling": 0, "completed": 0, "no_answer": 0, "failed": 0, "skipped": 3, "cancelled": 0 },
    "created_at": "2026-11-12T09:00:00.000Z",
    "updated_at": "2026-11-12T09:00:00.000Z",
    "started_at": null,
    "completed_at": null
  }
}
```

## Errors

| Status | Code | Meaning |
| - | - | - |
| 400 | `VALIDATION_ERROR` | A body field or the `Idempotency-Key` header is invalid. `field` names it |
| 400 | `CAMPAIGN_INVALID` | The request is valid in shape but not usable. `field` names it. See the list below |
| 403 | `POLICY_DENY` | No active plan, or your role cannot create campaigns |
| 404 | `AGENT_NOT_FOUND` | No agent with this `agent_id` in your workspace |
| 404 | `PHONE_LINE_NOT_FOUND` | No phone line with this `phone_line_id` in your workspace |
| 409 | `LINE_NOT_READY` | The phone line is not ready to place calls |
| 409 | `IDEMPOTENCY_CONFLICT` | This `Idempotency-Key` was used for a different request |
| 429 | `RATE_LIMITED` | More than 10 campaigns created in the last minute |

`CAMPAIGN_INVALID` covers these cases:

* The CSV has no phone column, has a duplicate header, has more than 20,000 rows, is larger than 5 MB, or cannot be parsed. `field` is `csv_text`.
* No row can be called after the do-not-call check. `field` is `csv_text`.
* `start` is not in the future. `field` is `start`.
* `concurrency_limit` is outside 1 to 50 on your own line. `field` is `concurrency_limit`.
* `variable_mapping` or `variable_defaults` has a bad key or value, or maps to a column the CSV does not have. `field` is `variable_mapping` or `variable_defaults`.

## Example

```bash cURL theme={null}
curl -X POST https://api.60db.ai/agents/campaigns \
  -H "Authorization: Bearer your-api-key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: spring-renewals-2026-11-12" \
  -d '{
    "name": "Spring renewals",
    "agent_id": "AGENT_ID",
    "phone_line_id": "PHONE_LINE_ID",
    "timezone": "Asia/Kolkata",
    "start": "now",
    "calling_windows": [{ "days": [1, 2, 3, 4, 5], "start": "09:00", "end": "20:00" }],
    "max_attempts": 3,
    "retry_delay_secs": 1800,
    "max_consecutive_failures": 10,
    "variable_mapping": { "customer_name": "name" },
    "csv_text": "phone_number,name\n+919876543210,Asha\n+919812345678,Ravi\n"
  }'
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.