# Create a campaign

> POST /v1/campaigns

A list of people for an outbound agent to call, at the pace and in the hours you set. It is a draft until it starts: send `start: true` to start dialling at once, `start_at` to start at a moment of your choosing, or neither and start it later. Up to 1,000 contacts in one request; add more with `POST /v1/campaigns/{id}/contacts`. Needs `campaigns:write`, a live key and an `Idempotency-Key`.

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `Idempotency-Key` | header | string | Yes | Your own id for this request, up to 120 characters. Required. |

## Body

Sent as JSON. A field this operation does not take is refused, so a typo fails loudly.

| Field | Type | Required | Description |
|---|---|---|---|
| `agent_id` | string (uuid) | Yes | The outbound agent that makes the calls. |
| `callbacks` | [CampaignCallbacks](/reference/objects/CampaignCallbacks) or null | No |  |
| `calling_hours` | [CampaignCallingHours](/reference/objects/CampaignCallingHours) or null | No | When calls may start, read in each contact's own `timezone` — or your organization's, for a contact without one. |
| `contacts` | array of [CampaignContactCreate](/reference/objects/CampaignContactCreate) | No | The people to call, up to 1,000 in one request. |
| `name` | string | Yes | What the campaign is called in the console. |
| `pacing` | [CampaignPacing](/reference/objects/CampaignPacing) or null | No |  |
| `phone_number_id` | string (uuid) or null | No | One of the agent's numbers to call from. The agent's own unless you say. |
| `start` | boolean | No | Start dialling now. |
| `start_at` | string (date-time) or null | No | Start dialling at this moment instead, with its offset — `2026-10-12T09:00:00+03:00`. A time without one is UTC. |
| `voicemail` | [CampaignVoicemail](/reference/objects/CampaignVoicemail) or null | No |  |

## Answer

`201` with [Campaign](/reference/objects/Campaign).

## Errors

Every error is a [problem document](/errors) with a stable `code`.

| Status | When |
|---|---|
| `400` | No `Idempotency-Key`. |
| `401` | The key is missing, mistyped, unknown, revoked or expired. |
| `403` | A test key: a campaign rings real people. |
| `404` | This key reaches no such agent, or no such number to call from. |
| `409` | The agent answers calls rather than placing them, it cannot place a call yet — not published, no number to call from — or its project is frozen. |
| `422` | A contact does not fit — `errors` names each by its place in `contacts` — the start time has passed, or the `Idempotency-Key` was used for another request. |
| `429` | Too many requests for this key or its organization; see `Retry-After`. |
| `500` | Something went wrong on our side. Quote the `request_id` to support. |
| `501` | This deployment does not place phone calls. |

## Examples

**curl**

```sh
#!/bin/sh
# Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/campaigns" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY" \
  -H "Idempotency-Key: reminders-october" \
  --json '{
  "agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
  "name": "Visit reminders, October",
  "calling_hours": {
    "start_hour": 9,
    "end_hour": 18,
    "days": [
      "mon",
      "tue",
      "wed",
      "thu",
      "fri"
    ]
  },
  "contacts": [
    {
      "to_number": "+12025550123",
      "variables": {
        "first_name": "Sara"
      },
      "metadata": {
        "crm_lead_id": "L-20931"
      },
      "external_id": "lead-20931"
    },
    {
      "to_number": "+12025550124",
      "variables": {
        "first_name": "Omar"
      },
      "timezone": "America/Chicago",
      "external_id": "lead-20932"
    }
  ]
}'
```

**JavaScript**

```js
// Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
const response = await fetch("https://api.aigently.ai/v1/campaigns", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "reminders-october",
  },
  body: JSON.stringify({
    "agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
    "name": "Visit reminders, October",
    "calling_hours": {
      "start_hour": 9,
      "end_hour": 18,
      "days": [
        "mon",
        "tue",
        "wed",
        "thu",
        "fri"
      ]
    },
    "contacts": [
      {
        "to_number": "+12025550123",
        "variables": {
          "first_name": "Sara"
        },
        "metadata": {
          "crm_lead_id": "L-20931"
        },
        "external_id": "lead-20931"
      },
      {
        "to_number": "+12025550124",
        "variables": {
          "first_name": "Omar"
        },
        "timezone": "America/Chicago",
        "external_id": "lead-20932"
      }
    ]
  }),
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
# pip install httpx
import os

import httpx

response = httpx.post(
    "https://api.aigently.ai/v1/campaigns",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
        "Idempotency-Key": "reminders-october",
    },
    json={
        "agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
        "name": "Visit reminders, October",
        "calling_hours": {
            "start_hour": 9,
            "end_hour": 18,
            "days": ["mon", "tue", "wed", "thu", "fri"],
        },
        "contacts": [{"to_number": "+12025550123", "variables": {"first_name": "Sara"}, "metadata": {"crm_lead_id": "L-20931"}, "external_id": "lead-20931"}, {"to_number": "+12025550124", "variables": {"first_name": "Omar"}, "timezone": "America/Chicago", "external_id": "lead-20932"}],
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	payload := []byte(`{
  "agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
  "name": "Visit reminders, October",
  "calling_hours": {
    "start_hour": 9,
    "end_hour": 18,
    "days": [
      "mon",
      "tue",
      "wed",
      "thu",
      "fri"
    ]
  },
  "contacts": [
    {
      "to_number": "+12025550123",
      "variables": {
        "first_name": "Sara"
      },
      "metadata": {
        "crm_lead_id": "L-20931"
      },
      "external_id": "lead-20931"
    },
    {
      "to_number": "+12025550124",
      "variables": {
        "first_name": "Omar"
      },
      "timezone": "America/Chicago",
      "external_id": "lead-20932"
    }
  ]
}`)
	request, err := http.NewRequest("POST", "https://api.aigently.ai/v1/campaigns", bytes.NewReader(payload))
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("Idempotency-Key", "reminders-october")
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        String body = """
            {
              "agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
              "name": "Visit reminders, October",
              "calling_hours": {
                "start_hour": 9,
                "end_hour": 18,
                "days": [
                  "mon",
                  "tue",
                  "wed",
                  "thu",
                  "fri"
                ]
              },
              "contacts": [
                {
                  "to_number": "+12025550123",
                  "variables": {
                    "first_name": "Sara"
                  },
                  "metadata": {
                    "crm_lead_id": "L-20931"
                  },
                  "external_id": "lead-20931"
                },
                {
                  "to_number": "+12025550124",
                  "variables": {
                    "first_name": "Omar"
                  },
                  "timezone": "America/Chicago",
                  "external_id": "lead-20932"
                }
              ]
            }
            """;
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/campaigns"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .header("Content-Type", "application/json")
            .header("Idempotency-Key", "reminders-october")
            .method("POST", HttpRequest.BodyPublishers.ofString(body))
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.aigently.ai/v1/campaigns")
{
    Content = new StringContent(
        """
        {
          "agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
          "name": "Visit reminders, October",
          "calling_hours": {
            "start_hour": 9,
            "end_hour": 18,
            "days": [
              "mon",
              "tue",
              "wed",
              "thu",
              "fri"
            ]
          },
          "contacts": [
            {
              "to_number": "+12025550123",
              "variables": {
                "first_name": "Sara"
              },
              "metadata": {
                "crm_lead_id": "L-20931"
              },
              "external_id": "lead-20931"
            },
            {
              "to_number": "+12025550124",
              "variables": {
                "first_name": "Omar"
              },
              "timezone": "America/Chicago",
              "external_id": "lead-20932"
            }
          ]
        }
        """,
        Encoding.UTF8,
        "application/json"),
};
request.Headers.Add("Idempotency-Key", "reminders-october");
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
$curl = curl_init("https://api.aigently.ai/v1/campaigns");
curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
        "Content-Type: application/json",
        "Idempotency-Key: reminders-october",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "agent_id" => "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
        "name" => "Visit reminders, October",
        "calling_hours" => [
            "start_hour" => 9,
            "end_hour" => 18,
            "days" => ["mon", "tue", "wed", "thu", "fri"],
        ],
        "contacts" => [
            [
                "to_number" => "+12025550123",
                "variables" => [
                    "first_name" => "Sara",
                ],
                "metadata" => [
                    "crm_lead_id" => "L-20931",
                ],
                "external_id" => "lead-20931",
            ],
            [
                "to_number" => "+12025550124",
                "variables" => [
                    "first_name" => "Omar",
                ],
                "timezone" => "America/Chicago",
                "external_id" => "lead-20932",
            ],
        ],
    ]),
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```
