> For the complete documentation index, see [llms.txt](https://docs.graspil.com/ru/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.graspil.com/ru/api/broadcasts.md).

# Рассылки

Методы для управления рассылками: создание, редактирование, запуск, остановка, просмотр статуса и статистики доставки. Это те же действия, что доступны в личном кабинете в разделе [«Рассылки»](/ru/app/broadcast.md), но через API — удобно, если вы создаёте и запускаете рассылки автоматически из своей системы (CRM, внутренний сервис и т.д.).

{% hint style="info" %}
Методы рассылок доступны только на тарифе **Premium**.
{% endhint %}

### Как это работает вкратце

1. Вы создаёте черновик рассылки — метод `create`. Можно указать только тип сообщения, а можно сразу передать текст и аудиторию.
2. Пока рассылка не запущена, она в статусе «черновик» — её можно сколько угодно раз менять через `save`.
3. Если получателей нужно задать собственным списком (а не выбрать по условиям) — проще всего указать `chat_ids` прямо в аудитории через тип сегмента `list` (см. ниже), без отдельного запроса. Метод `upload-segment` нужен только для очень больших списков, которые не помещаются в одно тело запроса — он позволяет загрузить список по частям несколькими вызовами; возвращаемый `segment_id` (тип `custom`) работает **только для той рассылки**, в которую список загружен, использовать его в другой рассылке нельзя.
4. Когда всё готово — запускаете рассылку через `activate`. Она встаёт в очередь на отправку.
5. Следить за статусом и статистикой доставки можно через `get` и `list`.
6. Уже запущенную рассылку можно остановить через `cancel`.

{% hint style="info" %}
Как оформить текст сообщения (жирный, курсив, ссылки, эмодзи) — см. [инструкцию по форматированию](/ru/app/broadcast/create-msg.md).
{% endhint %}

### Авторизация

Если ваш API-ключ привязан к одному боту (обычный ключ из раздела «Мои боты» — см. [Авторизацию](/ru/api/auth.md)) — ничего дополнительно указывать не нужно, все методы применяются к этому боту.

Если вы используете ключ из раздела [«API-ключи»](https://app.graspil.com/api-keys), выданный сразу на несколько ботов или на все ваши боты, в каждом запросе нужно явно указать, какого бота он касается — заголовком `Resource-Key` либо полем (для `POST`) или параметром (для `GET`) `resource_key`. Значение — публичный ключ бота: часть до двоеточия в API-ключе бота, который вы видите в разделе «Мои боты» рядом с иконкой ключа (формат `ключ_бота:api_key`).

### Формат ответа

Успешный ответ:

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { ... } }
```

{% endcode %}

Ответ с ошибкой:

{% code overflow="wrap" %}

```json
{ "ok": false, "error": "...", "error_code": 400 }
```

{% endcode %}

***

## Объект рассылки

Рассылка (`task`) — это то, что возвращают методы `create`, `save`, `get`, `activate`, `cancel`, и каждый элемент в `list`.

| Поле                  | Тип          | Описание                                                                                  |
| --------------------- | ------------ | ----------------------------------------------------------------------------------------- |
| `id`                  | int          | ID рассылки                                                                               |
| `status`              | int          | Статус — см. таблицу ниже                                                                 |
| `name`                | string       | Название (для вашего удобства, получателям не показывается)                               |
| `type`                | string       | Тип сообщения — `sendMessage`, `sendPhoto` и т.д., см. раздел «Содержимое сообщения» ниже |
| `segmentations`       | object       | Аудитория — см. раздел «Аудитория рассылки» ниже                                          |
| `message`             | object       | Текст и медиа сообщения                                                                   |
| `settings`            | object       | Настройки отправки — см. раздел «Настройки отправки» ниже                                 |
| `date_send`           | string\|null | Когда запланирован запуск                                                                 |
| `date_finish`         | string\|null | Когда рассылка завершилась или была остановлена                                           |
| `count_recipients`    | int          | Сколько всего получателей у рассылки                                                      |
| `count_delivered`     | int          | Сколько сообщений доставлено                                                              |
| `count_not_delivered` | int          | Сколько сообщений не доставлено (например, пользователь заблокировал бота)                |

#### Статусы рассылки

| Код           | Значение                                                                   |
| ------------- | -------------------------------------------------------------------------- |
| `0`           | Черновик — можно редактировать                                             |
| `1`           | Запланирована, ждёт обработки                                              |
| `2`           | В процессе отправки                                                        |
| `3`           | Завершена                                                                  |
| `4`           | Остановлена                                                                |
| `5`           | Ошибка                                                                     |
| `6`, `7`, `8` | Промежуточные технические статусы — рассылка готовится к отправке системой |

{% hint style="info" %}
Редактировать (`save`) можно только рассылку в статусе **черновик** (`0`). Для остальных статусов `save` вернёт текущую рассылку без изменений — то есть правки молча не применятся.
{% endhint %}

***

## Аудитория рассылки

Поле `segmentations` определяет, кому будет отправлена рассылка:

{% code overflow="wrap" %}

```json
{
  "include": [ { "type": "all", "config": {} } ],
  "exclude": [ { "type": "filter", "config": { "user_conditions": [...] } } ]
}
```

{% endcode %}

`include` и `exclude` — списки сегментов одного формата `{ "type": ..., "config": ... }`. Итоговая аудитория — это объединение всех сегментов из `include`, из которого вычитается объединение всех сегментов из `exclude`.

{% hint style="info" %}
Если хотя бы один сегмент в `include` имеет `type: "all"`, остальные сегменты `include` не учитываются — берутся все пользователи бота.
{% endhint %}

Доступные типы сегментов:

| `type`      | `config`                | Описание                                                                                                                                                                                                 |
| ----------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `all`       | `{}`                    | Все пользователи бота                                                                                                                                                                                    |
| `list`      | `{ "chat_ids": [...] }` | Готовый список получателей прямо в запросе — без отдельной загрузки. Подходит для одноразового списка; работает и в `exclude`                                                                            |
| `custom`    | `{ "segment_id": ... }` | Список получателей, загруженный заранее через метод `upload-segment` (см. ниже) или через дашборд. Сегмент жёстко привязан к той рассылке, в которую был загружен — в другой рассылке его указать нельзя |
| `channel`   | `{ "chat_ids": [...] }` | Конкретные пользователи, чаты, группы или каналы по `chat_id` (для групп и каналов `chat_id` — отрицательное число). По смыслу то же самое, что `list`                                                   |
| `from_task` | `{ "task_id": ... }`    | Получатели другой вашей рассылки                                                                                                                                                                         |
| `filter`    | см. ниже                | Аудитория по условиям — поля пользователя и/или совершённые события                                                                                                                                      |

### Сегмент `type: "filter"`

{% code overflow="wrap" %}

```json
{
  "user_conditions": ["and", ["=", "users.language_code", "ru"], ["=", "users.is_premium", 1]],
  "event_filters": [
    "and",
    ["performed_event", { "event_id": 42, "negation": false, "period_days": 30 }]
  ]
}
```

{% endcode %}

| Ключ              | Описание                                     |
| ----------------- | -------------------------------------------- |
| `user_conditions` | Условие на поля пользователя                 |
| `event_filters`   | Условие на совершённые пользователем события |

**Формат условия** (`user_conditions`) — вложенный массив `[оператор, ...аргументы]`:

* Логика: `["and", условие1, условие2, ...]`, `["or", ...]`, `["not", условие]`
* Сравнение: `["=", "поле", значение]`, `["!=", ...]`, `[">", ...]`, `["<", ...]`, `[">=", ...]`, `["<=", ...]`
* Текст: `["like", "поле", "%подстрока%"]`, `["not like", ...]`
* Список значений: `["in", "поле", [значение1, значение2, ...]]`, `["not in", ...]`
* Диапазон: `["between", "поле", от, до]`, `["not between", ...]`
* Проверка на пустое значение: `["is", "поле", null]`

Доступные поля: `users.user_id`, `users.full_name`, `users.username`, `users.first_name`, `users.last_name`, `users.date_create`, `users.date_last_active`, `users.gender`, `users.is_bot`, `users.user_status`, `users.is_premium`, `users.language_code`, `users.timezone`, а также ваши кастомные поля — `users.custom_fields.<имя>` / `users.addition_fields.<имя>`.

**Пример:** пользователи с русским языком интерфейса, у которых либо была активность после 1 июня, либо стоит кастомный флаг `vip`:

{% code overflow="wrap" %}

```json
["and",
  ["=", "users.language_code", "ru"],
  ["or",
    [">", "users.date_last_active", "2026-06-01"],
    ["=", "users.custom_fields.vip", "1"]
  ]
]
```

{% endcode %}

**Формат `event_filters`** — дерево такого же вида, но листья — это `performed_event`:

* Группа: `["and"|"or", узел1, узел2, ...]`
* Лист: `["performed_event", { "event_id": ..., "negation": ..., "period_days": ... }]`

| Поле листа    | Описание                                                                                                    |
| ------------- | ----------------------------------------------------------------------------------------------------------- |
| `event_id`    | ID события (необязателен — если не указан, проверяется любое событие)                                       |
| `negation`    | `false` — «совершил событие», `true` — «не совершал»                                                        |
| `period_days` | За сколько последних дней проверять (`0` — за всё время)                                                    |
| `conditions`  | Дополнительные условия на свойства события, в том же формате, что `user_conditions`, но по полям `events.*` |

***

## Содержимое сообщения

Поле `message` зависит от `type` рассылки. Все текстовые поля поддерживают переменные `{{user.first_name}}` и условия `{% raw %}{% if %}{% endraw %}` — они подставляются индивидуально для каждого получателя в момент отправки.

| `type`           | Поля `message`                                                                                                                                                                                       |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sendMessage`    | `text` (обязательно), `parse_mode` (`html` или `MarkdownV2`), `reply_markup` (инлайн-кнопки Telegram), `disable_notification`, `protect_content`, `pin_message` (закрепить сообщение после отправки) |
| `sendPhoto`      | `photo` (ссылка на изображение или `file_id`), `caption`, `parse_mode`, `reply_markup`, `pin_message`                                                                                                |
| `sendVideo`      | `video`, `caption`, `parse_mode`, `reply_markup`, `pin_message`                                                                                                                                      |
| `sendDocument`   | `document`, `caption`, `parse_mode`                                                                                                                                                                  |
| `sendAnimation`  | `animation`, `caption`, `parse_mode`                                                                                                                                                                 |
| `sendAudio`      | `audio`, `caption`                                                                                                                                                                                   |
| `sendVoice`      | `voice`, `caption`                                                                                                                                                                                   |
| `sendMediaGroup` | `media` — массив `{ "type": "photo"\|"video", "media": "<ссылка>", "caption"?: "..." }` (альбом из нескольких фото/видео)                                                                            |

**Пример для `sendMessage`:**

{% code overflow="wrap" %}

```json
{
  "text": "Привет, {{user.first_name}}! У нас акция.",
  "parse_mode": "html",
  "reply_markup": {
    "inline_keyboard": [[{ "text": "Перейти", "url": "https://example.com" }]]
  }
}
```

{% endcode %}

`reply_markup` — обычная структура инлайн-клавиатуры Telegram Bot API.

***

## Настройки отправки

Поле `settings` — необязательное, все ключи имеют значения по умолчанию:

{% code overflow="wrap" %}

```json
{
  "intervalCap": 10,
  "rateLimitOnError": { "stop": true, "extraDelay": 0 }
}
```

{% endcode %}

| Ключ                          | Тип      | По умолчанию | Описание                                                                       |
| ----------------------------- | -------- | ------------ | ------------------------------------------------------------------------------ |
| `intervalCap`                 | int      | `10`         | Сколько сообщений отправлять в секунду                                         |
| `rateLimitOnError.stop`       | bool     | `true`       | Останавливать рассылку, если Telegram ответил ограничением по скорости (`429`) |
| `rateLimitOnError.extraDelay` | int (мс) | `0`          | Дополнительная задержка между отправками при срабатывании ограничения          |

***

## Методы

### POST /v1/broadcast/create

Создаёт новый черновик рассылки.

Можно ограничиться только `type` (пустой черновик — как при создании рассылки в дашборде), а можно сразу передать содержимое и аудиторию и/или запустить рассылку — без отдельных вызовов `save`/`activate`.

#### Параметры

| Параметр        | Тип    | Обязательный                                    | Описание                                           |
| --------------- | ------ | ----------------------------------------------- | -------------------------------------------------- |
| `resource_key`  | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше                      |
| `type`          | string | да                                              | Тип сообщения — `sendMessage`, `sendPhoto` и т.д.  |
| `name`          | string | нет                                             | Название рассылки                                  |
| `segmentations` | object | нет                                             | Аудитория                                          |
| `message`       | object | нет                                             | Текст и медиа сообщения                            |
| `settings`      | object | нет                                             | Настройки отправки                                 |
| `date_send`     | string | нет                                             | Дата и время запуска, формат `YYYY-MM-DD HH:MM:SS` |
| `activate`      | bool   | нет                                             | `true` — запустить рассылку сразу после создания   |

#### Пример запроса

{% code overflow="wrap" %}

```json
POST /v1/broadcast/create
Api-Key: YOUR_API_KEY
Content-Type: application/json

{
  "type": "sendMessage",
  "name": "Анонс акции",
  "segmentations": { "include": [{ "type": "all", "config": {} }] },
  "message": { "text": "У нас акция, {{user.first_name}}!" }
}
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { "task": { "id": 4821, "status": 0, "...": "..." } } }
```

{% endcode %}

***

### POST /v1/broadcast/save

Обновляет рассылку — работает только для черновика (статус `0`).

#### Параметры

| Параметр        | Тип    | Обязательный                                    | Описание                                           |
| --------------- | ------ | ----------------------------------------------- | -------------------------------------------------- |
| `resource_key`  | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше                      |
| `id`            | int    | да                                              | ID рассылки                                        |
| `name`          | string | нет                                             | Название                                           |
| `segmentations` | object | нет                                             | Аудитория                                          |
| `message`       | object | нет                                             | Текст и медиа сообщения                            |
| `settings`      | object | нет                                             | Настройки отправки                                 |
| `date_send`     | string | нет                                             | Дата и время запуска, формат `YYYY-MM-DD HH:MM:SS` |

#### Пример запроса

{% code overflow="wrap" %}

```json
POST /v1/broadcast/save
Api-Key: YOUR_API_KEY
Content-Type: application/json

{
  "id": 4821,
  "message": { "text": "У нас акция, {{user.first_name}}! Успей забрать скидку." }
}
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { "task": { "id": 4821, "status": 0, "...": "..." } } }
```

{% endcode %}

***

### GET /v1/broadcast/get

Возвращает рассылку по ID — текущее содержимое, статус и статистику доставки.

#### Параметры

| Параметр       | Тип    | Обязательный                                    | Описание                      |
| -------------- | ------ | ----------------------------------------------- | ----------------------------- |
| `resource_key` | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше |
| `id`           | int    | да                                              | ID рассылки                   |

#### Пример запроса

{% code overflow="wrap" %}

```
GET /v1/broadcast/get?id=4821
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { "task": { "id": 4821, "status": 3, "count_recipients": 1200, "count_delivered": 1180, "count_not_delivered": 20, "...": "..." } } }
```

{% endcode %}

***

### GET /v1/broadcast/list

Возвращает список рассылок ресурса с фильтрами и сортировкой.

#### Параметры

| Параметр               | Тип           | Обязательный                                    | Описание                                                |
| ---------------------- | ------------- | ----------------------------------------------- | ------------------------------------------------------- |
| `resource_key`         | string        | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше                           |
| `filters[status]`      | int           | нет                                             | Фильтр по статусу                                       |
| `filters[name]`        | string        | нет                                             | Фильтр по названию (частичное совпадение)               |
| `filters[date_create]` | string        | нет                                             | Фильтр по дате создания                                 |
| `orders[<поле>]`       | `asc`\|`desc` | нет                                             | Сортировка по полю, например `orders[date_create]=desc` |
| `limit`                | int           | нет                                             | Количество записей, по умолчанию `100`, максимум `500`  |
| `offset`               | int           | нет                                             | Смещение, по умолчанию `0`                              |

#### Пример запроса

{% code overflow="wrap" %}

```
GET /v1/broadcast/list?filters[status]=3&orders[date_create]=desc&limit=20
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{
  "ok": true,
  "data": {
    "tasks": [
      { "id": 4821, "status": 3, "name": "Анонс акции", "...": "..." }
    ],
    "count": 1
  }
}
```

{% endcode %}

***

### POST /v1/broadcast/activate

Сохраняет переданные поля (как `save`) и запускает рассылку.

{% hint style="info" %}
Если для вашего тарифа исчерпана квота на рассылки, запрос вернёт ошибку `error: "mailing_not_allowed"`. Подробности о лимитах — на странице [тарифов](/ru/other/pricing.md).
{% endhint %}

#### Параметры

Те же, что у метода `save` выше.

#### Пример запроса

{% code overflow="wrap" %}

```json
POST /v1/broadcast/activate
Api-Key: YOUR_API_KEY
Content-Type: application/json

{ "id": 4821 }
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { "task": { "id": 4821, "status": 1, "...": "..." } } }
```

{% endcode %}

***

### POST /v1/broadcast/cancel

Останавливает рассылку. Если она уже запущена — переводит в статус «остановлена» (`4`) и помечает неотправленным получателям, что для них рассылка отменена (повторный запуск не отправит им сообщение). Если рассылка ещё не была подхвачена в обработку — просто возвращает её в черновик.

#### Параметры

| Параметр       | Тип    | Обязательный                                    | Описание                      |
| -------------- | ------ | ----------------------------------------------- | ----------------------------- |
| `resource_key` | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше |
| `id`           | int    | да                                              | ID рассылки                   |

#### Пример запроса

{% code overflow="wrap" %}

```json
POST /v1/broadcast/cancel
Api-Key: YOUR_API_KEY
Content-Type: application/json

{ "id": 4821 }
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { "task": { "id": 4821, "status": 4, "...": "..." } } }
```

{% endcode %}

***

### POST /v1/broadcast/upload-segment

Загружает список получателей для конкретной рассылки (`task_id`) — список привязывается именно к ней и не может быть использован в других рассылках. Работает только для рассылки в статусе **черновик** (`0`). Получатели передаются как массив Telegram ID (для групп и каналов — отрицательные числа).

{% hint style="info" %}
В большинстве случаев этот метод не нужен — передайте `chat_ids` прямо в `segmentations` через тип сегмента `list`: `{ "include": [{ "type": "list", "config": { "chat_ids": [...] } }] }`. `upload-segment` пригождается только для очень больших списков, которые нужно загрузить несколькими запросами (по частям), указав затем несколько `segment_id` в `include`.
{% endhint %}

После загрузки используйте полученный `segment_id` в `segmentations` рассылки:

{% code overflow="wrap" %}

```json
{ "include": [{ "type": "custom", "config": { "segment_id": 17 } }] }
```

{% endcode %}

#### Параметры

| Параметр       | Тип          | Обязательный                                    | Описание                                    |
| -------------- | ------------ | ----------------------------------------------- | ------------------------------------------- |
| `resource_key` | string       | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше               |
| `task_id`      | int          | да                                              | ID рассылки, к которой привязывается список |
| `chat_ids`     | array of int | да, непустой                                    | Telegram ID получателей                     |

#### Пример запроса

{% code overflow="wrap" %}

```json
POST /v1/broadcast/upload-segment
Api-Key: YOUR_API_KEY
Content-Type: application/json

{
  "task_id": 4821,
  "chat_ids": [123456789, 987654321, -1001670520580]
}
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { "segment_id": 17, "count_list": 3, "duplicates": 0 } }
```

{% endcode %}

| Поле         | Описание                                               |
| ------------ | ------------------------------------------------------ |
| `segment_id` | ID загруженного списка — используйте в `segmentations` |
| `count_list` | Сколько получателей сохранено (после удаления дублей)  |
| `duplicates` | Сколько повторов было удалено из переданного списка    |

***

## Возможные ошибки

| Код   | Когда возникает                                                                          |
| ----- | ---------------------------------------------------------------------------------------- |
| `400` | Не передан обязательный параметр, или параметр неверного формата                         |
| `401` | API-ключ не передан или недействителен                                                   |
| `403` | Метод недоступен на вашем тарифе (требуется Premium), либо ресурс недоступен этому ключу |
| `404` | Рассылка с указанным `id` не найдена                                                     |
| `500` | Внутренняя ошибка сервера — повторите запрос позже                                       |

**Пример ошибки:**

{% code overflow="wrap" %}

```json
{ "ok": false, "error": { "errors": "Premium tariff required" }, "error_code": 403 }
```

{% endcode %}
