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

# Update campaign

> Change the settings of a call, WhatsApp, or SMS campaign

Change the settings of a campaign you own, including one that is running. Only the fields you send change: everything you leave out stays as it is, and a list you send (`schedule_windows`, `allowed_days`, `phone_number_ids`) replaces the current one.

You can send back the `data` object of [Get campaign](/api-reference/campaigns/get-campaign) as it is, with your changes applied. The channel of a campaign cannot be changed, and you start or stop it with [Update campaign status](/api-reference/campaigns/update-status).

<Note>
  Changes to a running campaign apply to calls and messages placed after the update. Calls already in progress or queued finish with the previous settings.
</Note>

### Path Parameters

<ParamField path="id" type="integer" required>
  The ID of the campaign to update
</ParamField>

### Request Body

#### Shared

<ParamField body="name" type="string">
  Campaign name. Maximum 255 characters.
</ParamField>

<ParamField body="timezone" type="string">
  IANA timezone for the send/call windows (e.g. `America/New_York`).
</ParamField>

<ParamField body="schedule_windows" type="array">
  1 to 6 daily windows as objects with `start` and `end` in `HH:MM`. A window runs overnight when `end` is earlier than `start` (e.g. `16:00` → `02:00`). Replaces the current windows.
</ParamField>

<ParamField body="allowed_hours_start_time" type="string">
  Legacy single-window start (`HH:MM`). Sets the start of the first window when `schedule_windows` is not sent.
</ParamField>

<ParamField body="allowed_hours_end_time" type="string">
  Legacy single-window end (`HH:MM`). Sets the end of the first window when `schedule_windows` is not sent. Overnight when end \< start.
</ParamField>

<ParamField body="allowed_days" type="array">
  Weekdays when calls or messages can go out: `monday` … `sunday`. At least one. Replaces the current days.
</ParamField>

<ParamField body="scheduled_start_at" type="string">
  ISO 8601 date and time to start the campaign automatically. Without an offset it is read in the campaign timezone. The date cannot be before today.

  A campaign that isn't running (for example `draft`, `paused` or `completed`) becomes `scheduled` and starts by itself at that time. A running campaign keeps running. Set to `null` to clear it: a `scheduled` campaign goes back to `draft`.
</ParamField>

<ParamField body="max_retries" type="integer">
  Max retry attempts per lead. Range: 1–5.
</ParamField>

<ParamField body="retry_interval" type="integer">
  Minutes between retries. Range: 10–4320.
</ParamField>

<ParamField body="mark_complete_when_no_leads" type="boolean">
  `true` completes the campaign once every lead has been processed. `false` keeps it waiting for new leads, which campaigns fed by an automation or the API need.

  Turning it off doesn't reopen a campaign that has already completed: start it again with [Update campaign status](/api-reference/campaigns/update-status).
</ParamField>

#### Call campaigns

<ParamField body="assistant_id" type="integer">
  An OUTBOUND assistant you own. Changing it also moves the campaign to that assistant's timezone, unless you send `timezone` in the same request. The goal variable is cleared if the new assistant doesn't have it as a True/False post-call variable.
</ParamField>

<ParamField body="max_calls_in_parallel" type="integer">
  Concurrent calls, up to your plan's limit (max 10).
</ParamField>

<ParamField body="phone_number_ids" type="array">
  The numbers to call from. **Replaces the whole pool.** Send `[]` to remove all numbers; calls then use the assistant's own number. Numbers you add must be available to your account.
</ParamField>

<ParamField body="retry_on_voicemail" type="boolean">
  Retry when a call hits voicemail.
</ParamField>

<ParamField body="retry_on_goal_incomplete" type="boolean">
  Keep retrying until the goal variable is true. Turning it off clears `goal_completion_variable`.
</ParamField>

<ParamField body="goal_completion_variable" type="string">
  A True/False (`bool`) post-call variable of the campaign's assistant, used with `retry_on_goal_incomplete`. It is cleared while `retry_on_goal_incomplete` is off.
</ParamField>

<ParamField body="fallback_channel" type="string">
  Text follow-up after the last call retry: `whatsapp` or `sms`. Set to `null` to turn the follow-up off, which also clears its settings. Switching between `whatsapp` and `sms` clears the settings of the other one.
</ParamField>

<ParamField body="fallback_whatsapp_sender_id" type="integer">
  WhatsApp sender for the follow-up. A new sender also needs `fallback_whatsapp_template_id`.
</ParamField>

<ParamField body="fallback_whatsapp_template_id" type="integer">
  An approved template on that sender. Placeholders it shares with the current follow-up template keep their mapping; if it has other placeholders, send the full `fallback_variable_mapping` in the same request.
</ParamField>

<ParamField body="fallback_variable_mapping" type="object">
  Maps every placeholder of the follow-up template (e.g. `"1"`) to a lead variable key, and nothing else.
</ParamField>

<ParamField body="fallback_sms_from_phone_number_id" type="integer">
  SMS-capable number for the follow-up, available to your account.
</ParamField>

<ParamField body="fallback_sms_body" type="string">
  Follow-up SMS text. Max 1600 characters. Supports `{{variable}}` placeholders.
</ParamField>

#### WhatsApp campaigns

<ParamField body="whatsapp_sender_id" type="integer">
  A sender you own. A new sender also needs `whatsapp_template_id`.
</ParamField>

<ParamField body="whatsapp_template_id" type="integer">
  An approved template on that sender. Placeholders it shares with the current template keep their mapping; if it has other placeholders, send the full `text_variable_mapping` in the same request.
</ParamField>

<ParamField body="text_variable_mapping" type="object">
  Maps every template placeholder (e.g. `"1"`) to a lead variable key, and nothing else. Replaces the current mapping.
</ParamField>

<ParamField body="messages_per_minute" type="integer">
  Per-campaign send rate. Range: 1–10.
</ParamField>

#### SMS campaigns

<ParamField body="sms_from_phone_number_id" type="integer">
  An SMS-capable number available to your account.
</ParamField>

<ParamField body="sms_body" type="string">
  Message text. Max 1600 characters. Supports `{{variable}}` placeholders.
</ParamField>

<ParamField body="messages_per_minute" type="integer">
  Per-campaign send rate. Range: 1–10.
</ParamField>

***

## Example Requests

### Rename and set new calling windows

```json theme={null}
{
  "name": "Spring Renewals",
  "schedule_windows": [
    { "start": "09:00", "end": "12:00" },
    { "start": "14:00", "end": "18:00" }
  ]
}
```

### Keep waiting for leads from an automation

The campaign keeps waiting for new leads instead of completing once its current leads have been processed.

```json theme={null}
{
  "mark_complete_when_no_leads": false
}
```

### Replace the phone number pool

The campaign calls from exactly these numbers. Send `[]` to remove them all and call from the assistant's own number.

```json theme={null}
{
  "phone_number_ids": [11, 14, 15]
}
```

### Schedule a start

Without an offset, the time is read in the campaign timezone. The campaign becomes `scheduled` and starts by itself at that time. Send `null` to clear it.

```json theme={null}
{
  "scheduled_start_at": "2026-10-12T09:00:00"
}
```

***

## Response

<ResponseField name="message" type="string">
  Success message
</ResponseField>

<ResponseField name="data" type="object">
  The campaign after the update, in the same shape as [Get campaign](/api-reference/campaigns/get-campaign).
</ResponseField>

### Error responses

<ResponseField name="403 Forbidden">
  The account has no active plan, its plan doesn't include campaigns, or campaigns are turned off for it.
</ResponseField>

<ResponseField name="404 Not Found">
  The campaign does not exist or does not belong to you. Also returned for a campaign beyond your plan's campaign limit.
</ResponseField>

<ResponseField name="422 Unprocessable Entity">
  Validation errors, a change of `channel` or `status`, or an unknown field. Nothing is saved.
</ResponseField>

<ResponseExample>
  ```json 200 Success Response theme={null}
  {
    "message": "Campaign updated successfully",
    "data": {
      "id": 1,
      "name": "Spring Renewals",
      "channel": "call",
      "status": "in-progress",
      "assistant_id": 42,
      "timezone": "Europe/Bucharest",
      "max_calls_in_parallel": 3,
      "messages_per_minute": 10,
      "schedule_windows": [
        { "start": "09:00", "end": "12:00" },
        { "start": "14:00", "end": "18:00" }
      ],
      "scheduled_start_at": null,
      "allowed_hours_start_time": "09:00:00",
      "allowed_hours_end_time": "12:00:00",
      "allowed_days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
      "max_retries": 3,
      "retry_interval": 60,
      "retry_on_voicemail": false,
      "retry_on_goal_incomplete": false,
      "goal_completion_variable": null,
      "mark_complete_when_no_leads": false,
      "phone_number_ids": [11, 12],
      "whatsapp_sender_id": null,
      "whatsapp_template_id": null,
      "sms_from_phone_number_id": null,
      "sms_body": null,
      "text_variable_mapping": null,
      "fallback_channel": null,
      "fallback_whatsapp_sender_id": null,
      "fallback_whatsapp_template_id": null,
      "fallback_sms_from_phone_number_id": null,
      "fallback_sms_body": null,
      "fallback_variable_mapping": null,
      "created_at": "2026-07-24 10:00:00",
      "updated_at": "2026-10-05 14:30:00"
    }
  }
  ```

  ```json 403 No Active Plan theme={null}
  {
    "message": "This account has no active plan, so this feature is not available."
  }
  ```

  ```json 404 Not Found theme={null}
  {
    "message": "Campaign not found"
  }
  ```

  ```json 422 Channel Change theme={null}
  {
    "message": "The channel of an existing campaign cannot be changed.",
    "errors": {
      "channel": ["The channel of an existing campaign cannot be changed."]
    }
  }
  ```

  ```json 422 Status Change theme={null}
  {
    "message": "The status cannot be changed here. Start or stop the campaign instead.",
    "errors": {
      "status": ["The status cannot be changed here. Start or stop the campaign instead."]
    }
  }
  ```

  ```json 422 Unsupported Field theme={null}
  {
    "message": "The priority field is not supported.",
    "errors": {
      "priority": ["The priority field is not supported."]
    }
  }
  ```

  ```json 422 Unmapped Placeholder theme={null}
  {
    "message": "Map every placeholder of the WhatsApp template to a lead variable. Missing: 2.",
    "errors": {
      "text_variable_mapping": ["Map every placeholder of the WhatsApp template to a lead variable. Missing: 2."]
    }
  }
  ```

  ```json 422 Start Date In The Past theme={null}
  {
    "message": "The scheduled start date cannot be before today.",
    "errors": {
      "scheduled_start_at": ["The scheduled start date cannot be before today."]
    }
  }
  ```
</ResponseExample>

***

## Notes

* Only the fields you send change. A list you send (`schedule_windows`, `allowed_days`, `phone_number_ids`) replaces the current one
* You can send back the `data` object of [Get campaign](/api-reference/campaigns/get-campaign) as it is. Its read-only fields (`id`, `created_at`, `updated_at`) are ignored, and so are `channel` and `status` while they keep their current values
* Fields of another channel are ignored. `phone_number_ids` on a WhatsApp or SMS campaign returns 422
* Changing `channel` returns 422 ("The channel of an existing campaign cannot be changed."). Changing `status` also returns 422: start or stop the campaign with [Update campaign status](/api-reference/campaigns/update-status)
* An unknown field returns 422 ("The X field is not supported.")
* When a request returns an error, nothing is saved
* Running campaigns can be edited. Changes apply to calls and messages placed after the update; calls already in progress or queued finish with the previous settings
* Leading and trailing spaces are removed from text values, and an empty string counts as `null`
* If your plan limits the number of campaigns, only your newest campaigns up to that limit can be updated; older ones return 404


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