# Сегменты, рассылки и цепочки

Source: <https://telegafirst.com/docs/marketing>
Locale: ru
releaseGitSha: 0bb11ef116e17ec64c802d5476eaff442e53d252
sourceContentDigest: b7e0829bd5727e2b6ed5d450272b4fef44d9a6204fe810d6fe9a1956a00a8a2a
Version: 2

TelegaFirst помогает микробизнесу продолжать разговор с клиентом: выбрать аудиторию, подготовить сообщение, согласовать отправку и увидеть результат. Владелец и операторы управляют этим из Telegram, а собственный AI-агент владельца может работать через Hub с выданными правами. Клиенты получают сообщения в своём поддерживаемом канале; выбор аудитории и право доставить сообщение проверяются отдельно.

Результат работы — сохранённый сегмент, подготовленный черновик и, после подтверждения человеком, принятая задача отправки с доступным статусом. `queued` означает постановку в очередь. Итоговые счётчики показывают, сколько сообщений действительно отправлено и сколько завершилось ошибкой.

## Перед началом

Подключите бизнес по [инструкции запуска](https://telegafirst.com/docs/getting-started) и проверьте активный `slug` и бота. Для MCP выполните [авторизацию](https://telegafirst.com/docs/authorization), обновите `tools/list` и получите схему нужной операции по [руководству MCP](https://telegafirst.com/docs/mcp-guide). Наличие схемы ещё не означает установленный в вашем AI-клиенте инструмент.

Для REST ниже указаны относительные пути Hub. `X-Api-Key` и `Authorization: Bearer tgf_*` — альтернативные способы передать допустимый ключ. Owner/customer JWT нельзя подставлять вместо ключа на этих маршрутах. Нужные права и текущий доступ человека или credential проверяются при каждом вызове; права одной операции не заменяют права другой.

| Задача | REST scope |
| - | - |
| Оси, цели, preview и чтение сохранённых сегментов | `broadcasts:read` |
| Выборка клиентов сегмента | `dialogs:read` |
| Создание, изменение, удаление сохранённого сегмента; запись и запуск рассылки | `broadcasts:write` |
| Чтение кампаний и источников | `marketing:read` |
| Изменение кампаний и источников | `marketing:write` |
| Чтение цепочек и шагов через MCP | `chains:read` |
| Изменение цепочек, шагов и подготовка пакетного входа | `chains:write` |

Все required scopes операции обязательны одновременно. Тариф, readiness, актуальные permissions, лимиты и согласие на денежное действие сохраняют силу при наличии scope. [Права и ограничения](https://telegafirst.com/docs/scopes-and-permissions).

Примеры используют демонстрационные номера и контрактные ответы. Они не являются записью реальной рассылки. Перед записью получите номера из своего бизнеса: номер клиента, кампании, товара или цепочки — tenant-local `seq_num`, а не идентификатор базы данных. `client_id` приходит из аутентификации и не передаётся в JSON. [Идентификаторы и страницы результатов](https://telegafirst.com/docs/identifiers-and-pagination).

## Соберите и проверьте аудиторию

1. Прочитайте `GET /api/v1/tools/segments/axes` (`200`), в MCP — `describe_segment_axes`. Выберите доступные `kind`/`key` и проверьте `requiresTarget`, `targetEntity`, `periodSupported` и `available`.
2. Для условий с целью вызовите `POST /api/v1/tools/segments/targets` (`201`), в MCP — `list_segment_targets`. Возвращённый `seq` — строка с номером объекта вашего бизнеса. Здесь default/maximum `limit` — `50`; строка поиска ограничена `200` символами.
3. Соберите фильтр: внутри `any` условия объединяются через «ИЛИ», разные группы `include` — через «И», условия `exclude` вычитаются как объединение. Плоский старый список условий не подходит.
4. Выполните `POST /api/v1/tools/segments/reach` (`201`), в MCP — `preview_segment_reach`. Прочитайте `valid`, `issues`, `reachable` и `breakdown`. Число `0` при `valid:false` не означает корректный пустой сегмент.
5. После успешной проверки при необходимости вызовите `POST /api/v1/tools/segments/sample` (`201`), в MCP — `sample_segment_audience`. Default `limit` — `20`, maximum — `50`; результат содержит `userSeqNums`, без внешних chat IDs.

Пример запроса целей; для POST с непустым телом нужен отдельный `Idempotency-Key`:

```http
POST /api/v1/tools/segments/targets
Content-Type: application/json
Idempotency-Key: audience-targets-1

{
  "kind": "commerce",
  "key": "bought_product",
  "search": "Course"
}
```

Контрактный ответ `201`:

```json
{
  "targets": [
    {
      "seq": "7",
      "title": "Course"
    }
  ]
}
```

Фильтр «Вся база», который можно передать в `filter` для preview и sample:

```json
{
  "include": [
    {
      "any": [
        {
          "kind": "preset",
          "key": "all_subscribers"
        }
      ]
    }
  ],
  "exclude": []
}
```

Название `all_subscribers` обозначает базовое условие аудитории. Оно не доказывает рекламное согласие каждого человека. Получайте необходимое согласие на сообщения и учитывайте актуальные ограничения доставки; блокировка бота исключает получателя, а ограничения канала и поддерживаемых возможностей могут привести к пропуску. Preview не резервирует аудиторию и не гарантирует доставку каждому выбранному клиенту.

Например, структурно неверный фильтр в reach:

```json
{
  "filter": {
    "malformed": true
  }
}
```

Этот запрос даёт диагностический ответ `201`, а не разрешение отправлять:

```json
{
  "valid": false,
  "issues": [
    "Malformed filter"
  ],
  "reachable": 0,
  "breakdown": {
    "valid": false,
    "issues": [
      "Malformed filter"
    ],
    "reachable": null,
    "include": [],
    "exclude": [],
    "excludedUnion": null
  }
}
```

Попытка получить sample с непригодным фильтром возвращает `422 INVALID_INPUT`. Исправьте фильтр по описанию осей, снова выполните preview, затем sample. Ошибка выбора аудитории не должна превращаться в отправку всей базе.

## Сохраните сегмент и работайте с его версией

`POST /api/v1/tools/segments/saved` создаёт сегмент и возвращает `201`. Заголовок `Idempotency-Key` обязателен. Заголовок сегмента после обрезки пробелов должен содержать `1..120` символов.

```json
{
  "title": " New audience ",
  "filter": {
    "include": [
      {
        "any": [
          {
            "kind": "preset",
            "key": "all_subscribers"
          }
        ]
      }
    ],
    "exclude": []
  }
}
```

Полный контрактный результат:

```json
{
  "seqNum": 9,
  "title": "New audience",
  "filter": {
    "include": [
      {
        "any": [
          {
            "kind": "preset",
            "key": "all_subscribers"
          }
        ]
      }
    ],
    "exclude": []
  },
  "version": 1,
  "updatedAt": "2026-10-01T10:00:00.000Z"
}
```

Для чтения используйте `GET /api/v1/tools/segments/saved/{seqNum}`. Список `GET /api/v1/tools/segments/saved?afterSeqNum=6&limit=1` возвращает `segments` и `nextAfterSeqNum`; следующий запрос получает возвращённый номер. Default `limit` — `100`, maximum — `500`. Не переносите этот параметр на списки рассылок или цепочек: у них другой контракт, без такой пагинации.

Изменение `PATCH /api/v1/tools/segments/saved/7` требует текущего `expectedVersion` и хотя бы одного из `title`/`filter`. Например, после чтения версии `2`:

```json
{
  "expectedVersion": 2,
  "title": " Updated audience "
}
```

Успех `200` содержит тот же `seqNum:7`, обновлённое название `Updated audience` и `version:3`. При `409 CONFLICT` с detail `Saved segment version changed; reload and retry` перечитайте сегмент, покажите изменения человеку и решите, нужна ли прежняя правка. Удаление `DELETE /api/v1/tools/segments/saved/7` также принимает тело `{"expectedVersion":2}` для удаления именно прочитанной версии.

В рассылке `saved_segment_seq_num` — номер сохранённого сегмента. Не передавайте одновременно противоречащие друг другу источники аудитории. При подготовке запуска версия и содержимое сегмента входят в проверяемый снимок; изменение аудитории требует новой подготовки.

## Подготовьте рассылку и отдельно согласуйте запуск

Черновик REST создаётся `POST /api/v1/tools/broadcasts` (`201`), меняется `PATCH` того же пути (`200`). Непустой POST требует `Idempotency-Key`. Пример создания:

```json
{
  "title": "Autumn",
  "saved_segment_seq_num": null,
  "segment_labels": "Everyone",
  "message_ttl_minutes": 90,
  "button_title": "Open",
  "button_target": {
    "kind": "section_root",
    "section": "catalog"
  }
}
```

Полный контрактный результат:

```json
{
  "seqNum": 3,
  "status": "draft",
  "title": "Autumn",
  "savedSegmentSeqNum": null,
  "target": {
    "kind": "section_root",
    "section": "catalog"
  },
  "isAwaitingReply": false,
  "segmentLabels": "Everyone",
  "segmentFilter": null,
  "scheduledAt": null,
  "scheduleEcho": null,
  "messageTtlMinutes": 90,
  "buttonTitle": "Open",
  "buttonTarget": {
    "kind": "section_root",
    "section": "catalog"
  }
}
```

Черновик ещё не отправляется. Текст/медиа и аудитория должны быть подготовлены до запуска; REST shell-запрос выше не заменяет подготовку rich content. У MCP `create_broadcast` отдельная rich-схема с обязательным `content`: не копируйте REST JSON в этот инструмент. Его описанный путь состоит из четырёх вызовов: `create_broadcast`, один `get_content_draft`, затем `prepare_broadcast_launch` и после окончательного подтверждения человеком — `execute_broadcast_launch`. Если единственная проверка draft ещё не вернула опубликованный `seqNum`, остановитесь и разберитесь с готовностью контента.

В REST при PATCH отсутствующий `segment_filter` сохраняет прежнюю аудиторию, а `null` сбрасывает её на всю базу. Проверьте это перед подтверждением. Для `schedule` передайте `kind:"once"` и `at_local` — локальное время бизнеса без offset/`Z`; абсолютное время разрешает сервер по часовому поясу бизнеса. Проверяйте возвращённый `scheduleEcho`. Нельзя подменять `at_local` произвольной UTC-строкой.

REST-порядок запуска:

1. Прочитайте `GET /api/v1/tools/broadcasts` и проверьте черновик, содержание, аудиторию, время, срок сообщения и доступный баланс.
2. Вызовите `POST /api/v1/tools/broadcasts/prepare-launch` с `{"seq_num":3}` и новым `Idempotency-Key`. Ответ `200` содержит `seqNum`, текущий `status` и `revision` — строку из `64` hex-символов. Подготовка не отправляет сообщения.
3. Покажите человеку именно подготовленный сценарий и получите окончательное подтверждение запуска: отправка может расходовать баланс.
4. Передайте тот же `seq_num` и точную возвращённую `revision` в `POST /api/v1/tools/broadcasts/execute-launch`, с отдельным новым `Idempotency-Key`. Успех `202`:

```json
{
  "seqNum": 3,
  "status": "queued"
}
```

Чтобы не перепечатать и не выдумать revision, сформируйте тело из сохранённого успешного ответа подготовки:

```sh
jq -c '{seq_num: .seqNum, revision: .revision}' preparation.json > launch.json
```

Передайте `launch.json` как JSON-тело execute только после подтверждения. Если черновик изменился после подготовки, сервер возвращает `409 CONFLICT`: получите новую preparation и новое подтверждение, а не заменяйте hash вручную.

MCP использует серверную квитанцию: `prepare_broadcast_launch` возвращает `preparation_id`, `payload_hash`, `expires_at`, `payload` и `launch`. `execute_broadcast_launch` получает только точные `preparation_id`/`payload_hash`; REST revision-body не подходит вместо этой квитанции. Выполняйте пару из одного авторизованного контекста и не переносите подготовку между бизнесами или credential.

После запуска вызовите `POST /api/v1/tools/broadcasts/status` с `{"seq_num":3}` (`201`, scope `broadcasts:read`, отдельный `Idempotency-Key`); в MCP — `get_broadcast_status`. Читайте статус рассылки и последнюю `execution` вместе. Например, полный контрактный ответ показывает отдельные состояния и фактические счётчики:

```json
{
  "seqNum": 3,
  "status": "draft",
  "execution": {
    "status": "completed",
    "totalRecipients": 21,
    "totalSent": 19,
    "failed": 2,
    "startedAt": "2026-09-30T11:00:00.000Z",
    "completedAt": "2026-09-30T11:01:00.000Z"
  }
}
```

Это демонстрация формы ответа, не продолжение реального запуска из примера. Для свежего status-read после изменения состояния используйте новый ключ: повтор прежнего идемпотентного POST может вернуть прежний ответ из кэша. В списке и карточке предусмотрены состояния `draft`, `scheduled`, `sending`, `completed`, `failed`, `cancelled`; `execution:null` означает отсутствие записанного запуска.

## Цепочки сообщений

`GET /api/v1/tools/chains` читает цепочки, `POST` создаёт shell по `{"title":"Welcome"}`, `PATCH` меняет название по `{"seq_num":7,"title":"Welcome"}`, а `POST /api/v1/tools/chains/delete` удаляет по `{"seq_num":7}`. Создание/удаление возвращают `201`; создание требует `Idempotency-Key` и даёт:

```json
{
  "seqNum": 7,
  "title": "Welcome",
  "isActive": false,
  "deeplinkCode": null
}
```

Активность определяется настройкой шагов; поле `isActive` нельзя записать в shell-body. Через MCP используйте `list_chain_steps`, `create_chain_step`, `update_chain_step`, `delete_chain_step` с `chain_seq_num` и возвращённым номером шага. Оператор также настраивает цепочку в Telegram. У shell REST нет отдельного придуманного маршрута шагов или массового старта.

Для пакетного входа через MCP сначала вызовите `prepare_chain_batch_entry`. Пример аргументов, если указанные клиенты и цепочка существуют в выбранном бизнесе:

```json
{
  "chain_seq_num": 7,
  "user_seq_nums": [
    17,
    18
  ],
  "on_active": "noop"
}
```

Допустимо `1..50` клиентов. `on_active` выбирается явно: `noop` сохраняет активный проход, `deliver` доставляет выбранный шаг без перемещения, `restart` прекращает активный проход перед новым. Покажите возвращённый неизменяемый сценарий человеку; после подтверждения `execute_chain_batch_entry` получает `preparation_id` и `payload_hash` из preparation. Повторно придумывать массив клиентов в execute нельзя. Проверка состояния, доставки и актуальных прав сохраняется при исполнении.

## Кампании и ссылки на источники

Кампания связывает источник обращения с целевым содержимым и статистикой. `GET /api/v1/tools/marketing` и `GET /api/v1/tools/marketing/links` возвращают кампании/источники; для записи используйте `POST`/`PATCH` соответствующих путей. Например, новый источник в кампании `2`:

```json
{
  "campaign_seq_num": 2,
  "kind": "code_word",
  "title": "Summer source",
  "code_word": "summer",
  "comment": null,
  "is_active": true
}
```

`POST /api/v1/tools/marketing/links` с новым `Idempotency-Key` возвращает `201`:

```json
{
  "seqNum": 5,
  "campaignSeqNum": 2,
  "kind": "code_word",
  "title": "Summer source",
  "comment": null,
  "wordNormalized": "summer",
  "isActive": true,
  "qrUrl": "https://storage.example.test/qr/opaque.png?sig=signed",
  "qrUrlExpiresAt": "2026-09-30T10:15:00.000Z"
}
```

В примере домен `.test` и подпись демонстрационные; рабочий QR URL берите из ответа и учитывайте `qrUrlExpiresAt`. Истёкший signed URL нельзя считать постоянным публичным адресом. В управлении кампаниями цель `{"kind":"deeplink","entity_type":"product","entity_seq":3}` использует guarded номер товара. Публичную ссылку на товар, событие или цепочку берите по серверному opaque-коду; не превращайте `entity_seq`, `campaignSeqNum` или `seqNum` в анонимный URL. Единственная читаемая строка адреса бизнеса — `Client.slug`.

## Ошибки и повтор запросов

| Ответ | Что делать |
| - | - |
| `400 VALIDATION_ERROR` / `INVALID_REQUEST` | Исправить конкретные поля, типы и строгую форму запроса; `client_id` и внутренние IDs не добавлять |
| `400 IDEMPOTENCY_KEY_REQUIRED` | Добавить ключ к непустому POST; новый замысел получает новый ключ |
| `401 INVALID_API_KEY` | Проверить допустимый транспорт credential; пройти нужную авторизацию |
| `403 INSUFFICIENT_SCOPE`, `PUBLISHABLE_KEY_NOT_ALLOWED`, `NO_ACTIVE_BOT` | Сверить scope, вид ключа, активного бота и актуальный доступ |
| `404 NOT_FOUND` | Получить актуальный номер в выбранном бизнесе; чужой объект также недоступен |
| `409 CONFLICT` | Прочитать detail: старая версия сегмента, изменённый launch-снимок или ещё выполняющийся HTTP-запрос требуют разных действий |
| `422 INVALID_INPUT` | Исправить значение, которое называет detail, например фильтр или зарезервированное кодовое слово; исправленное тело отправить с новым ключом |
| `422 IDEMPOTENCY_KEY_MISMATCH` | Для изменённого тела использовать новый ключ; прежний ключ повторяет прежний запрос |
| `413 PAYLOAD_TOO_LARGE` / `ITEM_COUNT_EXCEEDED` | Уменьшить объём и размер пакета |
| `429 RATE_LIMIT_EXCEEDED` / `RATE_LIMIT_UNAVAILABLE` | Учитывать `Retry-After`, если он возвращён; отказ лимитера не означает успешную отправку |
| `500 INTERNAL_ERROR` | Сохранить `traceId`, проверить состояние до повтора действия |

REST HTTP-ответ хранится `86400` секунд для применимых идемпотентных запросов. У PATCH ключ необязателен; если он передан, изменённое тело с тем же ключом даёт `422`. Заголовки `X-Client-Slug`/`X-Bot-Username` помогают сверить контекст, а `X-RateLimit-*` — бюджет запроса. ETag не заменяет `expectedVersion` сохранённого сегмента или launch revision. [Идемпотентность](https://telegafirst.com/docs/etag-and-idempotency), [справочник ошибок](https://telegafirst.com/docs/errors).

Точные формы отдельных операций: [сегменты](https://telegafirst.com/docs/api-segments), [рассылки](https://telegafirst.com/docs/api-broadcasts), [цепочки REST](https://telegafirst.com/docs/api-chains), [кампании](https://telegafirst.com/docs/api-marketing), [цепочки MCP](https://telegafirst.com/docs/mcp-chains), [рассылки MCP](https://telegafirst.com/docs/mcp-broadcasts). Сегменты посещения мероприятия связывают маркетинг с [регистрациями и записями](https://telegafirst.com/docs/events-and-booking). Внутренние разговорные AI-агенты советуют и передают запрос человеку; операции с расходованием денег выполняет только собственный scoped агент клиента через разрешённый сценарий.
