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

# Create campaign

> Create an outbound batch campaign with a contact list, retry logic, optional scheduling, and optional business-hours gating. Campaigns start in draft status until you resume them.

A campaign places outbound AI voice calls to a list of contacts. Campaigns are created in `draft` status and do not start dialing until you call [Resume](/api-reference/campaigns/resume), unless you set `scheduled_at`, in which case they auto-start at that time.

## Request body

<ParamField body="campaign_name" type="string" required>
  Display name shown in the dashboard.
</ParamField>

<ParamField body="agent_id" type="string" required>
  UUID of the agent that will handle calls in this campaign. Must belong to your workspace.
</ParamField>

<ParamField body="phone_number" type="string" required>
  Outbound phone number to dial from, in E.164 format (e.g. `"+15551234567"`). Must be registered to your workspace — the number visible on **Settings → Phone Numbers** in the dashboard.
</ParamField>

<ParamField body="contacts" type="object[]" required>
  Recipients to dial. Must contain at least one entry. There is no upper limit.

  <Expandable title="contact properties">
    <ParamField body="phone_number" type="string" required>
      Number to dial, in E.164 format.
    </ParamField>

    <ParamField body="contact_name" type="string">
      Display name. Available to the agent at runtime as `{{contact_name}}`.
    </ParamField>

    <ParamField body="custom_data" type="object">
      Arbitrary key/value JSON. Each key is exposed to the agent's prompt as `{{key}}` for personalization, and surfaced in post-call analysis.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="max_retries" type="number" default="0">
  Additional attempts per contact after the initial call. `2` means up to 3 total attempts. Retries fire on no-answer, voicemail, busy, or transient dial failure. A connected call that hangs up is considered successful.
</ParamField>

<ParamField body="retry_intervals" type="number[]">
  Wait times in **minutes** between attempts. The Nth retry waits `retry_intervals[N-1]` minutes after the previous attempt. If shorter than `max_retries`, the last value is reused.
</ParamField>

<ParamField body="scheduled_at" type="string">
  Future ISO 8601 UTC timestamp at which the campaign should auto-start. Sets the initial status to `scheduled` instead of `draft`.
</ParamField>

<ParamField body="business_hours" type="object | null">
  Time-of-day / weekday gate for outbound dialing. Omit or send `null` for 24/7 dispatch.

  <Expandable title="business_hours properties">
    <ParamField body="tz" type="string" required>
      IANA timezone (e.g. `"America/New_York"`).
    </ParamField>

    <ParamField body="days" type="number[]" required>
      Allowed ISO weekdays — `1` = Monday … `7` = Sunday. Pick at least one.
    </ParamField>

    <ParamField body="windows" type="object[]" required>
      One or more daily windows. Each is `{ start, end }` in **minutes since local midnight**. Constraints: `0 ≤ start < end ≤ 1440`. Cross-midnight windows aren't supported — split them across two adjacent days.
    </ParamField>
  </Expandable>
</ParamField>

<Note>
  Outside `business_hours`, the campaign moves to `dormant` and resumes automatically when the next allowed window opens.
</Note>

## Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.verbeo.ai/v1/campaigns" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "campaign_name": "Q2 Sales Outreach",
      "agent_id": "550e8400-e29b-41d4-a716-446655440000",
      "phone_number": "+15551234567",
      "contacts": [
        {
          "phone_number": "+12125550001",
          "contact_name": "Alice Johnson",
          "custom_data": { "company": "Acme Corp", "tier": "gold" }
        },
        { "phone_number": "+12125550002", "contact_name": "Bob Smith" }
      ],
      "max_retries": 2,
      "retry_intervals": [5, 30],
      "business_hours": {
        "tz": "America/New_York",
        "days": [1, 2, 3, 4, 5],
        "windows": [{ "start": 540, "end": 1020 }]
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const res = await fetch("https://api.verbeo.ai/v1/campaigns", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.VERBEO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      campaign_name: "Q2 Sales Outreach",
      agent_id: "550e8400-e29b-41d4-a716-446655440000",
      phone_number: "+15551234567",
      contacts: [
        { phone_number: "+12125550001", contact_name: "Alice Johnson" },
      ],
      max_retries: 2,
      retry_intervals: [5, 30],
    }),
  });
  const { data } = await res.json();
  const campaignId = data.campaign_id;
  ```

  ```python Python theme={null}
  import os, requests

  res = requests.post(
      "https://api.verbeo.ai/v1/campaigns",
      headers={
          "Authorization": f"Bearer {os.environ['VERBEO_API_KEY']}",
          "Content-Type": "application/json",
      },
      json={
          "campaign_name": "Q2 Sales Outreach",
          "agent_id": "550e8400-e29b-41d4-a716-446655440000",
          "phone_number": "+15551234567",
          "contacts": [
              {"phone_number": "+12125550001", "contact_name": "Alice Johnson"},
          ],
          "max_retries": 2,
          "retry_intervals": [5, 30],
      },
  )
  campaign_id = res.json()["data"]["campaign_id"]
  ```
</CodeGroup>

## Response

`201 Created`. See [Responses](/api-reference/responses) for the envelope.

```json theme={null}
{
  "success": true,
  "data": {
    "campaign_id": "0175091d-2c3b-4aef-8c45-dbbe24f7b3ff",
    "campaign_name": "Q2 Sales Outreach",
    "status": "draft",
    "total_contacts": 2,
    "business_hours": {
      "tz": "America/New_York",
      "days": [1, 2, 3, 4, 5],
      "windows": [{ "start": 540, "end": 1020 }]
    },
    "scheduled_at": null,
    "created_at": "2026-05-04T15:00:00.000Z"
  }
}
```

## Using custom data in your agent

Reference any field from `custom_data` (and `contact_name`) in your agent's system prompt:

```
You are calling {{contact_name}} from {{company}}.
They are a {{tier}} customer. Be prepared to discuss their renewal options.
```

Each contact gets a personalized call with their own values substituted.

## Errors

This endpoint can return `VALIDATION_FAILED`, `AGENT_NOT_FOUND`, `PHONE_NOT_FOUND`, `CREATE_FAILED`, and `CONTACTS_INSERT_FAILED` — see [Campaigns overview](/api-reference/campaigns/overview#error-codes) for status codes and meanings, and [Errors](/api-reference/errors) for the standard envelope.

<Tip>
  After creating a campaign in `draft` status, call [Resume](/api-reference/campaigns/resume) to start dialing.
</Tip>


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