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

# Создание кампании

> `POST /v1/campaigns`: заголовки, тело запроса, порядок отказов и успешный ответ.

# Создание кампании

Один запрос делает три вещи: создаёт кампанию, принимает запланированные звонки и — если все проверки запуска прошли — начинает набор. Отдельного шага «старт» в счастливом пути нет.

## Заголовки

| Заголовок                              | Обязателен | Примечания                                                                                                                                                                                                                                                                      |
| -------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Authorization: Bearer YOUR_API_KEY`   | да         |                                                                                                                                                                                                                                                                                 |
| `Content-Type: application/json`       | да         |                                                                                                                                                                                                                                                                                 |
| `Idempotency-Key: <уникальная строка>` | **да**     | В отличие от `POST /v1/calls/*`, здесь не опционален: повтор после сетевого таймаута создал бы вторую кампанию и обзвонил весь список дважды. Отсутствует или пуст → `422 idempotency_key_required`. Протокол — в конце этого раздела, «Идемпотентность запросов по кампаниям». |

## Тело запроса

Неизвестные поля верхнего уровня игнорируются.

| Поле                                  | Тип                                                   | Обяз. | По умолч.                            | Описание                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------------------------------- | ----------------------------------------------------- | ----- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                                | string                                                | да    | —                                    | Название кампании, видное в кабинете; 1–80 символов после обрезки пробелов (иначе `422 campaign_spec_invalid`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `agent_id`                            | string                                                | да    | —                                    | **Имя** агента, разрешается внутри вашей организации. Неизвестное имя → `422 campaign_agent_unknown`. Существующий, но неопубликованный агент принимается: кампания создаётся черновиком с блокером `agent_not_published`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `calls_per_minute`                    | integer                                               | да    | —                                    | Скорость — это **ступень**, а не произвольное число: одно из `1, 2, 5, 10, 20, 30, 60, 100, 200` (иное → `422 campaign_spec_invalid`). Значение применяется как есть: потолка развёртывания, который урезал бы его, нет.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `planned_calls`                       | array                                                 | нет   | `[]`                                 | Номера для набора, см. ниже. Пусто — кампания создана без чего набирать (блокер `no_pending_contacts`, если только не задан `accepts_call_additions`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `starts_at` / `ends_at`               | number \| null                                        | нет   | `null`                               | Окно кампании. `null` в начале означает «сейчас». `ends_at` должен быть позже `starts_at` (иначе `422 campaign_window_invalid`). **Дата** начала в прошлом (по календарной дате в зоне кампании) блокирует запуск (`starts_date_past`); прошедший `ends_at` — тоже (`ends_at_past`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `timezone`                            | string                                                | нет   | `""`                                 | Название зоны IANA (`Asia/Almaty`), в которой трактуются окно и рабочие часы. Не указана → зона организации. Неизвестная → `422 campaign_timezone_unknown`; фиксированные смещения не принимаются.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `working_hours`                       | array                                                 | нет   | `[]`                                 | Строки расписания `{"days": [0..6], "start": "ЧЧ:ММ", "end": "ЧЧ:ММ"}` (`days`: 0 — понедельник, непустой; `start` строго раньше `end`; строка никогда не переходит через полночь — ночная смена это две строки). Неверная форма → `422 campaign_spec_invalid`. Кампания может только **сужать** базовое окно вашей организации: под пакетом рынка США — законное окно юрисдикций контактов, иначе — окно обзвона организации; более широкая строка → `422 working_hours_wider_than_law`. **Пусто означает, что действует само базовое окно** — кампания ничего не сужает, а набор ограничен законным окном (предупреждение `working_hours_law_only`) либо окном обзвона организации (`working_hours_org_window_only`). Круглосуточного набора не бывает. |
| `call_strategy`                       | `"standard"` \| `"expert"`                            | нет   | `"standard"`                         | `standard` повторяет по фиксированной лестнице; `expert` решает по каждому исходу из правил `retry_config.rules`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `retry_config`                        | object                                                | нет   | `{"attempts": 1, "interval_s": 900}` | См. «Настройку повторов» ниже в этом разделе. **По умолчанию — одна попытка, без перезвонов.**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `duplicate_action`                    | `"reject"` \| `"keep_first"` \| `"keep_last"`         | нет   | `"reject"`                           | Что делать, если один и тот же телефон встречается в `planned_calls` дважды (и внутри партии `calls`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `classification`                      | `"marketing"` \| `"servicing"` \| `"debt_collection"` | нет   | `"marketing"`                        | Чем звонит кампания. Определяет **тип согласия**, под которым ставится подпись (`marketing` → `pewc`, `servicing` и `debt_collection` → `pec`), поэтому не угадывается: не указали — берётся самый строгий. Иное → `422 campaign_classification_invalid`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `use_contact_timezone`                | boolean                                               | нет   | `false`                              | Набирать каждый контакт в его собственной зоне (из колонки `timezone`), а не в зоне кампании.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `trunk_id`, `route_id`, `from_number` | string                                                | нет   | разрешается                          | Привязка набора, см. ниже.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `attestation`                         | object                                                | нет   | —                                    | `{"confirmed": true}` — подтверждение согласия, необходимое до набора. При создании необязательно: без него кампания создаётся черновиком с блокером `attestation_required`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `accepts_call_additions`              | boolean                                               | нет   | `false`                              | Держать кампанию открытой к добавлению партий номеров ([Управление кампанией](/ru/v4/web-api/campaign-manage)): опустевшая очередь её не завершает, только `ends_at` или отмена. Требует `ends_at` (`422 campaign_open_ends_at_required`) не дальше горизонта оператора, по умолчанию 30 суток (`422 campaign_open_ends_at_too_far`). Задаётся только при создании.                                                                                                                                                                                                                                                                                                                                                                                       |
| `dnc`                                 | `"block"` \| `"skip"`                                 | нет   | `"block"`                            | Что делать с номерами из реестра «не звонить». Иное значение → `422 dnc_decision_invalid`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

Поля, которые у кампании есть, но через `/v1` **не задаются** (`frequency_override`, кабинетные пресеты), молча игнорируются.

## Порядок отказов на создании

До того как кампания создана (слот идемпотентности освобождается, исправленный повтор с тем же ключом пройдёт):

1. `422 invalid_request` — тело не проходит схему (нет `name`, `agent_id` или `calls_per_minute`, неверные типы).
2. `422 idempotency_key_required`, `422 dnc_decision_invalid`.
3. `422 idempotency_key_reuse` / `409 idempotency_key_in_flight` / переигровка прежнего ответа.
4. `422 campaign_window_invalid`, затем `422 campaign_open_ends_at_required` / `campaign_open_ends_at_too_far`.
5. `422 campaign_agent_unknown`, `422 campaign_timezone_unknown`.
6. Привязка набора: `422 dialing_route_unresolved` / `dialing_route_ambiguous` / `dialing_binding_incomplete`.
7. `422 working_hours_wider_than_law`.
8. Валидация хранилища: `422 campaign_spec_invalid` (ступень, настройка повторов, форма рабочих часов, действие по дублям, длина названия), `422 campaign_classification_invalid`.

После того как кампания создана (слот **остаётся занятым** — повтор с тем же ключом отвечает `409 idempotency_key_in_flight`; кампанию ищите через `GET /v1/campaigns`):

9. Запланированные звонки: `409 market_package_not_installed`, `502 contact_file_storage_unavailable`, `422 contact_rows_rejected` (строки не удалось сохранить вовсе — это не то же самое, что строки, отклонённые разборщиком: те приходят внутри `import` вместе с `201`).
10. Запуск: `409 campaign_transition_invalid` (неожиданная гонка состояний).

## Успешный ответ — `201 Created`

Ответ **всегда `201`**, если кампания создана, независимо от того, начался ли набор. Единственный источник истины об этом — `status`.

```json theme={null}
{
  "campaign_id": "cam-b9b536a86e",
  "status": "running",
  "created_via": "api",
  "launched_via": "api",
  "name": "june collections",
  "agent_id": "collections-agent",
  "timezone": "Asia/Almaty",
  "timezone_source": "request",
  "starts_at": null,
  "ends_at": null,
  "accepts_call_additions": false,
  "calls_per_minute": 10,
  "call_strategy": "standard",
  "classification": "marketing",
  "consent_tier": "pewc",
  "retry_config": { "attempts": 1, "interval_s": 900 },
  "duplicate_action": "reject",
  "use_contact_timezone": false,
  "working_hours": [{ "days": [0, 1, 2, 3, 4], "start": "09:00", "end": "19:00" }],
  "binding": { "trunk_id": "trk-31d4dc745a", "route_id": "rt-out-a", "from_number": "77000000001" },
  "import": {
    "import_id": "imp-353d158dd2",
    "status": "accepted",
    "rows_seen": 2,
    "accepted": 2,
    "warned": 0,
    "rejected": 0,
    "duplicates_found": 0,
    "dnc_matched": 0,
    "refusal_code": "",
    "issues": {},
    "dnc_screen": { "status": "clean", "checked_rows": 2, "unscreened_rows": 0, "matched_rows": 0, "suppressed_contacts": 0, "fingerprint": "20e2…", "items": [], "has_more": false, "hidden_rows": 0, "all_dialable_suppressed": false, "as_of_launch": true, "screened_at": 1788941847.27, "audit_id": 2, "decision": "clean", "import_id": "imp-353d158dd2" },
    "dnc_matches": []
  },
  "dnc_screen": { "status": "clean", "as_of_launch": true, "…": "тот же объект, что import.dnc_screen" },
  "blockers": [],
  "warnings": [
    { "code": "starts_immediately", "message": "…" },
    { "code": "frequency_policy_active", "rolling_7d_cap": 7, "daily_cap": 2, "source": "platform_default", "message": "…" }
  ]
}
```
