@besales/mcp 0.43.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/instructions/server-instructions.d.ts +1 -1
  2. package/dist/instructions/server-instructions.js +5 -2
  3. package/dist/instructions/server-instructions.js.map +1 -1
  4. package/dist/resources/docs/crm-integration.md +3 -1
  5. package/dist/resources/workflows/compare-models.md +4 -3
  6. package/dist/resources/workflows/connect-crm-from-scratch.md +8 -0
  7. package/dist/schemas/mcp-tools.json +1098 -54
  8. package/dist/tools/definitions/agent-design.d.ts +8 -0
  9. package/dist/tools/definitions/agent-design.js +3 -0
  10. package/dist/tools/definitions/agent-design.js.map +1 -1
  11. package/dist/tools/definitions/broadcast-analytics.d.ts +5 -4
  12. package/dist/tools/definitions/broadcast-analytics.js +17 -6
  13. package/dist/tools/definitions/broadcast-analytics.js.map +1 -1
  14. package/dist/tools/definitions/broadcast-mailing-variants.js +8 -4
  15. package/dist/tools/definitions/broadcast-mailing-variants.js.map +1 -1
  16. package/dist/tools/definitions/broadcast-scheduler.d.ts +82 -0
  17. package/dist/tools/definitions/broadcast-scheduler.js +317 -0
  18. package/dist/tools/definitions/broadcast-scheduler.js.map +1 -0
  19. package/dist/tools/definitions/crm-platform.js +20 -0
  20. package/dist/tools/definitions/crm-platform.js.map +1 -1
  21. package/dist/tools/definitions/follow-up-setup.d.ts +6 -0
  22. package/dist/tools/definitions/follow-up-setup.js +31 -0
  23. package/dist/tools/definitions/follow-up-setup.js.map +1 -1
  24. package/dist/tools/definitions/follow-up.d.ts +18 -1
  25. package/dist/tools/definitions/follow-up.js +80 -5
  26. package/dist/tools/definitions/follow-up.js.map +1 -1
  27. package/dist/tools/definitions/getcourse-cold-welcome.d.ts +11 -0
  28. package/dist/tools/definitions/getcourse-cold-welcome.js +77 -8
  29. package/dist/tools/definitions/getcourse-cold-welcome.js.map +1 -1
  30. package/dist/tools/definitions/getcourse-wave.d.ts +3 -3
  31. package/dist/tools/definitions/getcourse-wave.js +5 -5
  32. package/dist/tools/definitions/getcourse-wave.js.map +1 -1
  33. package/dist/tools/definitions/link-tracking.js +22 -0
  34. package/dist/tools/definitions/link-tracking.js.map +1 -1
  35. package/dist/tools/definitions/model-comparison.js +6 -3
  36. package/dist/tools/definitions/model-comparison.js.map +1 -1
  37. package/dist/tools/definitions/platform-setup.d.ts +38 -3
  38. package/dist/tools/definitions/platform-setup.js +52 -2
  39. package/dist/tools/definitions/platform-setup.js.map +1 -1
  40. package/dist/tools/definitions/shared.d.ts +127 -5
  41. package/dist/tools/definitions/shared.js +103 -5
  42. package/dist/tools/definitions/shared.js.map +1 -1
  43. package/dist/tools/definitions/trigger-contact-claims.d.ts +7 -0
  44. package/dist/tools/definitions/trigger-contact-claims.js +58 -0
  45. package/dist/tools/definitions/trigger-contact-claims.js.map +1 -0
  46. package/dist/tools/definitions.d.ts +141 -7
  47. package/dist/tools/definitions.js +4 -0
  48. package/dist/tools/definitions.js.map +1 -1
  49. package/dist/tools/registry-mapping-cases-core.js +11 -2
  50. package/dist/tools/registry-mapping-cases-core.js.map +1 -1
  51. package/dist/tools/registry-mapping-cases-platform.js +29 -0
  52. package/dist/tools/registry-mapping-cases-platform.js.map +1 -1
  53. package/dist/tools/trigger-action-config.d.ts +49 -0
  54. package/dist/tools/trigger-action-config.js +171 -0
  55. package/dist/tools/trigger-action-config.js.map +1 -0
  56. package/dist/types/api-contract.gen.d.ts +2285 -221
  57. package/docs/agent-usage-guide.full.ru.md +1 -0
  58. package/package.json +1 -1
@@ -235,7 +235,7 @@ export interface paths {
235
235
  /** @description PKCE S256 challenge — SHA256(code_verifier) base64url-encoded */
236
236
  code_challenge: string;
237
237
  code_challenge_method: "S256";
238
- /** @description Requested scopes: base `mcp:*` plus any subset of the optional scopes, in the canonical order `mcp:platform-setup`, `mcp:funnel-test`, `read:campaigns`, `launch:campaigns`. `besales-mcp connect` always requests the widest string. INVARIANT: a new scope is APPENDED to the optional list — never swapped in for an existing one, or every reconnect silently narrows live keys. */
238
+ /** @description Requested scopes: base `mcp:*` plus any subset of the optional scopes, in the canonical order `mcp:platform-setup`, `mcp:funnel-test`, `read:campaigns`, `launch:campaigns`. `mcp:*` enables PromptHub/ICP/Sandbox/Knowledge tools; `mcp:platform-setup` enables Platform Setup Bridge mutations; `mcp:funnel-test` permits frozen-plan funnel tests that can send real messages; `read:campaigns` covers cold-welcome preview and broadcast reads; `launch:campaigns` covers cold-welcome/broadcast launches. `besales-mcp connect` always requests the widest string. INVARIANT: a new scope is APPENDED to the optional list — never swapped in for an existing one, or every reconnect silently narrows live keys. */
239
239
  scope: "mcp:*" | "mcp:* mcp:platform-setup" | "mcp:* mcp:funnel-test" | "mcp:* mcp:platform-setup mcp:funnel-test" | "mcp:* read:campaigns" | "mcp:* mcp:platform-setup read:campaigns" | "mcp:* mcp:funnel-test read:campaigns" | "mcp:* mcp:platform-setup mcp:funnel-test read:campaigns" | "mcp:* launch:campaigns" | "mcp:* mcp:platform-setup launch:campaigns" | "mcp:* mcp:funnel-test launch:campaigns" | "mcp:* mcp:platform-setup mcp:funnel-test launch:campaigns" | "mcp:* read:campaigns launch:campaigns" | "mcp:* mcp:platform-setup read:campaigns launch:campaigns" | "mcp:* mcp:funnel-test read:campaigns launch:campaigns" | "mcp:* mcp:platform-setup mcp:funnel-test read:campaigns launch:campaigns";
240
240
  };
241
241
  header?: never;
@@ -414,8 +414,12 @@ export interface paths {
414
414
  * @description Public PKCE token endpoint (RFC 7636). Аутентификация — владение одноразовым `code`
415
415
  * (из redirect approve) + `code_verifier`. Code консьюмится атомарно (single-use),
416
416
  * проверяется SHA256(code_verifier) === code_challenge. Только после этого создаётся
417
- * ApiKey (`mcp_<48 chars>`, scopes `mcp:*` + optional `mcp:platform-setup`, expiry 90 days,
417
+ * ApiKey (`mcp_<48 chars>`, scopes из approved гранта, expiry 90 days,
418
418
  * SHA256 hash в `api_keys`) и raw api_key возвращается в теле ответа (НЕ в URL).
419
+ *
420
+ * `dropped_scopes` называет права, которые нёс заменяемый этим реконнектом ключ, а новый
421
+ * не несёт. Сужение набора scope сам connect НЕ ломает — оно всплывает много позже как 403
422
+ * одного эндпоинта, поэтому клиент ОБЯЗАН показать этот список оператору.
419
423
  */
420
424
  post: {
421
425
  parameters: {
@@ -5014,8 +5018,13 @@ export interface paths {
5014
5018
  /**
5015
5019
  * S3.8: Apply batch patch operations + reset activity TTL (24h)
5016
5020
  * @description Применяет операции к draft.currentContent через `applyPromptPatchOperations`.
5017
- * Resets TTL на каждом вызове (activity-based 24h). Возвращает diff-stats:
5018
- * `appliedCount` + `skippedCount` (anchor не нашёлся → ops пропущены).
5021
+ * Resets TTL на каждом вызове (activity-based 24h). Возвращает `appliedCount` +
5022
+ * `skippedCount` (anchor не нашёлся → ops пропущены) и `diff` — построчную
5023
+ * разницу «до → после».
5024
+ *
5025
+ * Текст черновика в ответе НЕ отдаётся: клиент прочитал промпт целиком при создании
5026
+ * черновика, а здесь ждёт подтверждения правки. Перечитать полностью —
5027
+ * `GET /prompt/drafts/{draftId}`.
5019
5028
  *
5020
5029
  * Growth guard: операции, увеличивающие размер >30% от baseContent → пропускаются
5021
5030
  * с skippedCount > 0.
@@ -5080,6 +5089,10 @@ export interface paths {
5080
5089
  *
5081
5090
  * Idempotency: повторный commit того же draft возвращает existing newVersion
5082
5091
  * (детектируется через 410 Gone + GET draft → COMMITTED).
5092
+ *
5093
+ * Ответ несёт только адресацию новой версии (`id` + `version`) и метаданные
5094
+ * черновика: `draft.currentContent` и `newVersion.content` — две копии одного
5095
+ * текста, который клиент сам и собрал.
5083
5096
  */
5084
5097
  post: {
5085
5098
  parameters: {
@@ -6094,7 +6107,7 @@ export interface paths {
6094
6107
  * @enum {string}
6095
6108
  */
6096
6109
  launchType?: "status" | "board" | "group";
6097
- channels: string[];
6110
+ channels: components["schemas"]["GetCourseTransport"][];
6098
6111
  /** @description Канонический ключ/название бизнес-воронки. Не имя файла, batch/resend или дата конкретного запуска; для этого используется cohortLabel. */
6099
6112
  funnel?: string;
6100
6113
  segment?: string;
@@ -6327,7 +6340,7 @@ export interface paths {
6327
6340
  patch?: never;
6328
6341
  trace?: never;
6329
6342
  };
6330
- "/api/v2/workspaces/{workspaceId}/wazzup-waves/import": {
6343
+ "/api/v2/workspaces/{workspaceId}/getcourse-cold-welcome/preview": {
6331
6344
  parameters: {
6332
6345
  query?: never;
6333
6346
  header?: never;
@@ -6337,8 +6350,8 @@ export interface paths {
6337
6350
  get?: never;
6338
6351
  put?: never;
6339
6352
  /**
6340
- * Запуск волны WhatsApp через Wazzup (WABA-шаблон по когорте телефонов)
6341
- * @description v1.5 Increment 24. Без `confirm=true` — dry-run: прогоняется ПОЛНЫЙ preflight (платформа Wazzup активна и с включённым AI, «обрабатывать все входящие», живой WABA-канал, одобренный текстовый шаблон, число значений переменных) и возвращается previewText — ни одно сообщение не отправляется. HTTP-эндпоинт гейтит запуск по `confirm=true`; MCP-тул `besales_wazzup_wave_import` дополнительно требует `explicit_confirmation=true` (это защита от того, чтобы AI-оператор запустил платную рассылку мимоходом — поле потребляется на слое MCP и в тело запроса не передаётся). Каждое маркетинговое сообщение тарифицируется Meta. Политика at-most-once: строка занимается под advisory-локом ДО внешнего вызова, повтор того же шаблона тому же контакту в течение 24 часов пропускается. Scope `mcp:platform-setup`.
6353
+ * Охват рассылки «Первое сообщение» без отправки
6354
+ * @description Read-only. foundContacts — всего под границей; alreadyWelcomed — из них уже получали первое сообщение (оно одноразово НА КОНТАКТ, не на рассылку); totalContacts — сколько ещё может получить. Часть отсеется уже в прогоне (мьют, нет якоря, недостижимость). Аудитория задаётся ЛИБО createdAfter, ЛИБО contacts. Scope `read:campaigns`.
6342
6355
  */
6343
6356
  post: {
6344
6357
  parameters: {
@@ -6351,51 +6364,21 @@ export interface paths {
6351
6364
  };
6352
6365
  requestBody: {
6353
6366
  content: {
6354
- "application/json": {
6355
- /** Format: uuid */
6356
- platformId: string;
6357
- templateGuid: string;
6358
- templateValues?: string[];
6359
- contacts: {
6360
- phone: string;
6361
- name?: string;
6362
- }[];
6363
- funnel?: string;
6364
- segment?: string;
6365
- productCode?: string;
6366
- productName?: string;
6367
- cohortLabel?: string;
6368
- confirm?: boolean;
6369
- };
6367
+ "application/json": components["schemas"]["GetCourseColdWelcomePreviewRequest"];
6370
6368
  };
6371
6369
  };
6372
6370
  responses: {
6373
- /** @description Волна запущена либо выполнен dry-run */
6371
+ /** @description Охват без отправки */
6374
6372
  200: {
6375
6373
  headers: {
6376
6374
  [name: string]: unknown;
6377
6375
  };
6378
6376
  content: {
6379
- "application/json": {
6380
- dryRun: boolean;
6381
- /** Format: uuid */
6382
- jobId?: string;
6383
- totalContacts: number;
6384
- previewText: string;
6385
- message: string;
6386
- rejectedRows?: string[];
6387
- /** @description Некритичные предупреждения preflight — волну не блокируют. Сейчас это мёртвая подписка на статусы доставки (у Wazzup один webhook URI на аккаунт, его мог перезаписать другой сервис): сообщения уйдут и будут оплачены, но доставка не отследится и «дошло» в аналитике останется почти нулевым. */
6388
- warnings?: string[];
6389
- };
6390
- };
6391
- };
6392
- /** @description Непригодные платформа, канал, шаблон или когорта */
6393
- 400: {
6394
- headers: {
6395
- [name: string]: unknown;
6377
+ "application/json": components["schemas"]["GetCourseColdWelcomePreviewResponse"];
6396
6378
  };
6397
- content?: never;
6398
6379
  };
6380
+ 400: components["responses"]["ValidationError"];
6381
+ 404: components["responses"]["NotFound"];
6399
6382
  };
6400
6383
  };
6401
6384
  delete?: never;
@@ -6404,127 +6387,110 @@ export interface paths {
6404
6387
  patch?: never;
6405
6388
  trace?: never;
6406
6389
  };
6407
- "/api/v2/workspaces/{workspaceId}/wazzup-waves/templates/{platformId}": {
6390
+ "/api/v2/workspaces/{workspaceId}/getcourse-cold-welcome": {
6408
6391
  parameters: {
6409
6392
  query?: never;
6410
6393
  header?: never;
6411
6394
  path?: never;
6412
6395
  cookie?: never;
6413
6396
  };
6397
+ get?: never;
6398
+ put?: never;
6414
6399
  /**
6415
- * Шаблоны WABA платформы с признаком пригодности для волны
6416
- * @description v1.5 Increment 24. usable=false — шаблон не одобрен Meta либо содержит медиа-заголовок или переменную в URL-кнопке (значения ушли бы не в те слоты). Scope `mcp:platform-setup`.
6400
+ * Запустить рассылку «Первое сообщение» по когорте GetCourse
6401
+ * @description НЕОБРАТИМО: у GetCourse нет идемпотентности, отправку нельзя отозвать. Приветствие одноразово НА КОНТАКТ навсегда. Текст берётся из mailingVariantId ЛИБО message (ровно один источник). Если у рассылки заданы посегментные тексты и segment совпал — уедет текст сегмента, и тогда аудитория обязана быть файловой (contacts): с createdAfter такой запуск отвергается 400, потому что метка сегмента аудиторию не отбирает. Поля сделки штампуются ПОСЛЕ успешной отправки. Scope `launch:campaigns`.
6417
6402
  */
6418
- get: {
6403
+ post: {
6419
6404
  parameters: {
6420
6405
  query?: never;
6421
6406
  header?: never;
6422
6407
  path: {
6423
6408
  workspaceId: components["parameters"]["WorkspaceIdPath"];
6424
- platformId: string;
6425
6409
  };
6426
6410
  cookie?: never;
6427
6411
  };
6428
- requestBody?: never;
6412
+ requestBody: {
6413
+ content: {
6414
+ "application/json": components["schemas"]["GetCourseColdWelcomeLaunchRequest"];
6415
+ };
6416
+ };
6429
6417
  responses: {
6430
- /** @description Список шаблонов */
6418
+ /** @description Рассылка поставлена в очередь */
6431
6419
  200: {
6432
6420
  headers: {
6433
6421
  [name: string]: unknown;
6434
6422
  };
6435
6423
  content: {
6436
- "application/json": {
6437
- templateGuid: string;
6438
- title: string;
6439
- status: string;
6440
- bodyText: string;
6441
- variableCount: number;
6442
- usable: boolean;
6443
- unsupportedReasons?: string[];
6444
- }[];
6424
+ "application/json": components["schemas"]["GetCourseColdWelcomeLaunchResponse"];
6425
+ };
6426
+ };
6427
+ 400: components["responses"]["ValidationError"];
6428
+ 404: components["responses"]["NotFound"];
6429
+ /** @description В воркспейсе уже идёт задача импорта */
6430
+ 409: {
6431
+ headers: {
6432
+ [name: string]: unknown;
6433
+ };
6434
+ content: {
6435
+ "application/json": components["schemas"]["ErrorResponse"];
6445
6436
  };
6446
6437
  };
6447
6438
  };
6448
6439
  };
6449
- put?: never;
6450
- post?: never;
6451
6440
  delete?: never;
6452
6441
  options?: never;
6453
6442
  head?: never;
6454
6443
  patch?: never;
6455
6444
  trace?: never;
6456
6445
  };
6457
- "/api/v2/workspaces/{workspaceId}/wazzup-waves/{jobId}": {
6446
+ "/api/v2/workspaces/{workspaceId}/getcourse-anchor-refresh/preview": {
6458
6447
  parameters: {
6459
6448
  query?: never;
6460
6449
  header?: never;
6461
6450
  path?: never;
6462
6451
  cookie?: never;
6463
6452
  };
6453
+ get?: never;
6454
+ put?: never;
6464
6455
  /**
6465
- * Статус волны WhatsApp
6466
- * @description v1.5 Increment 24. skipped — сознательные пропуски (стоп-бот, ожидание оператора, недавний повтор), НЕ ошибки. unknownOutcome — строки, где отправка началась, но ответ Wazzup не дошёл; автоматически они не переотправляются. Scope `mcp:platform-setup`.
6456
+ * Что перепишет перечитывание календарных якорей
6457
+ * @description Read-only и БЕЗ обращений к школе — считает по базе. contactsMatched — сколько контактов в отборе; withoutPinnedDeal — скольким прогон откажет (без пина читалась бы произвольная сделка, и верная дата была бы затёрта чужой); currentValues — какие значения якорей они несут СЕЙЧАС. НОВЫЕ значения предпросмотр не знает: для этого надо прочитать все сделки, то есть выполнить сам прогон. Scope `read:campaigns`.
6467
6458
  */
6468
- get: {
6459
+ post: {
6469
6460
  parameters: {
6470
6461
  query?: never;
6471
6462
  header?: never;
6472
6463
  path: {
6473
6464
  workspaceId: components["parameters"]["WorkspaceIdPath"];
6474
- jobId: string;
6475
6465
  };
6476
6466
  cookie?: never;
6477
6467
  };
6478
- requestBody?: never;
6468
+ requestBody: {
6469
+ content: {
6470
+ "application/json": components["schemas"]["GetCourseAnchorRefreshRequest"];
6471
+ };
6472
+ };
6479
6473
  responses: {
6480
- /** @description Статус волны */
6474
+ /** @description Охват перечитывания без записи */
6481
6475
  200: {
6482
6476
  headers: {
6483
6477
  [name: string]: unknown;
6484
6478
  };
6485
6479
  content: {
6486
- "application/json": {
6487
- jobId: string;
6488
- /** @enum {string} */
6489
- status: "PROCESSING" | "COMPLETED";
6490
- totalRows: number;
6491
- processedRows: number;
6492
- sent: number;
6493
- failed: number;
6494
- skipped: number;
6495
- unknownOutcome: number;
6496
- /** @description Подтверждено вебхуком WhatsApp. Живёт ОТДЕЛЬНО от sent: sent означает лишь что Wazzup принял сообщение. Взаимоисключающе с deliveryFailed. */
6497
- delivered?: number;
6498
- /** @description Подмножество delivered — получатель открыл сообщение */
6499
- read?: number;
6500
- /** @description Отказ доставки по данным WhatsApp. НЕ меняет исход самой отправки: status строки описывает результат нашего вызова, а не доставку. */
6501
- deliveryFailed?: number;
6502
- /** @description Разбивка отказов по кодам ошибок Wazzup */
6503
- deliveryErrors?: {
6504
- [key: string]: number;
6505
- };
6506
- errors?: string[];
6507
- };
6508
- };
6509
- };
6510
- /** @description Волна не найдена в этом рабочем пространстве */
6511
- 404: {
6512
- headers: {
6513
- [name: string]: unknown;
6480
+ "application/json": components["schemas"]["GetCourseAnchorRefreshPreviewResponse"];
6514
6481
  };
6515
- content?: never;
6516
6482
  };
6483
+ 400: components["responses"]["ValidationError"];
6484
+ 404: components["responses"]["NotFound"];
6517
6485
  };
6518
6486
  };
6519
- put?: never;
6520
- post?: never;
6521
6487
  delete?: never;
6522
6488
  options?: never;
6523
6489
  head?: never;
6524
6490
  patch?: never;
6525
6491
  trace?: never;
6526
6492
  };
6527
- "/api/v2/platforms/{platformId}/agents/{agentId}/tools": {
6493
+ "/api/v2/workspaces/{workspaceId}/getcourse-anchor-refresh": {
6528
6494
  parameters: {
6529
6495
  query?: never;
6530
6496
  header?: never;
@@ -6533,40 +6499,45 @@ export interface paths {
6533
6499
  };
6534
6500
  get?: never;
6535
6501
  put?: never;
6536
- post?: never;
6537
- delete?: never;
6538
- options?: never;
6539
- head?: never;
6540
- /** Patch agent tool bindings without deleting omitted tools */
6541
- patch: {
6502
+ /**
6503
+ * Перечитать календарные якоря контактов из запинённой сделки
6504
+ * @description Единственный способ донести ПЕРЕНЕСЁННУЮ дату эфира: автоматический добор якоря — set-if-absent и к заполненному значению не возвращается, поэтому «Первое сообщение» будет возвращать SKIPPED_ANCHOR_IN_PAST, сколько его ни запускай. Перечитываются ТОЛЬКО якоря включённых календарных цепочек площадки и ТОЛЬКО с ЗАПИНЁННОЙ сделки; переменные ветвления не трогаются. Прогресс цепочек НЕ откатывается: ушедшие касания остаются ушедшими, перепланируются только не ушедшие. Каждое изменение пишется строкой audit_logs (entityType=ChatUser, action=GETCOURSE_ANCHOR_REFRESH) с прежним и новым значением. Прогон асинхронный — ответ подтверждает старт. Scope `launch:campaigns`.
6505
+ */
6506
+ post: {
6542
6507
  parameters: {
6543
6508
  query?: never;
6544
6509
  header?: never;
6545
6510
  path: {
6546
- platformId: components["parameters"]["PlatformIdPath"];
6547
- agentId: components["parameters"]["AgentIdPath"];
6511
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6548
6512
  };
6549
6513
  cookie?: never;
6550
6514
  };
6551
6515
  requestBody: {
6552
6516
  content: {
6553
- "application/json": components["schemas"]["AgentToolsPatchRequest"];
6517
+ "application/json": components["schemas"]["GetCourseAnchorRefreshRequest"];
6554
6518
  };
6555
6519
  };
6556
6520
  responses: {
6557
- 200: {
6521
+ /** @description Прогон принят (либо отказ с причиной в полях ответа) */
6522
+ 202: {
6558
6523
  headers: {
6559
6524
  [name: string]: unknown;
6560
6525
  };
6561
6526
  content: {
6562
- "application/json": components["schemas"]["PlatformSetupMutationResult"];
6527
+ "application/json": components["schemas"]["GetCourseAnchorRefreshStartResponse"];
6563
6528
  };
6564
6529
  };
6530
+ 400: components["responses"]["ValidationError"];
6531
+ 404: components["responses"]["NotFound"];
6565
6532
  };
6566
6533
  };
6534
+ delete?: never;
6535
+ options?: never;
6536
+ head?: never;
6537
+ patch?: never;
6567
6538
  trace?: never;
6568
6539
  };
6569
- "/api/v2/platforms/{platformId}/router": {
6540
+ "/api/v2/workspaces/{workspaceId}/getcourse-cold-welcome/batch": {
6570
6541
  parameters: {
6571
6542
  query?: never;
6572
6543
  header?: never;
@@ -6575,153 +6546,820 @@ export interface paths {
6575
6546
  };
6576
6547
  get?: never;
6577
6548
  put?: never;
6578
- post?: never;
6579
- delete?: never;
6580
- options?: never;
6581
- head?: never;
6582
- /** Patch router metadata/additionalPrompt only */
6583
- patch: {
6549
+ /**
6550
+ * Запустить пакет сегментов «Первого сообщения»
6551
+ * @description НЕОБРАТИМО. До 10 сегментов, у каждого свой список контактов, свои метки и свои поля сделки. Идут ПО ОЧЕРЕДИ: задачи импорта в воркспейсе не выполняются параллельно. Весь пакет проверяется ДО первой отправки — сегмент без текста отменяет пакет целиком. Один сегмент МОЖЕТ идти несколькими блоками (разбивка по продуктам через funnel/productCode); запрещено пересечение СПИСКОВ контактов между блоками, а не совпадение меток. Scope `launch:campaigns`.
6552
+ */
6553
+ post: {
6584
6554
  parameters: {
6585
6555
  query?: never;
6586
6556
  header?: never;
6587
6557
  path: {
6588
- platformId: components["parameters"]["PlatformIdPath"];
6558
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6589
6559
  };
6590
6560
  cookie?: never;
6591
6561
  };
6592
6562
  requestBody: {
6593
6563
  content: {
6594
- "application/json": components["schemas"]["RouterPatchRequest"];
6564
+ "application/json": components["schemas"]["GetCourseColdWelcomeBatchRequest"];
6595
6565
  };
6596
6566
  };
6597
6567
  responses: {
6568
+ /** @description Пакет поставлен в очередь целиком */
6598
6569
  200: {
6599
6570
  headers: {
6600
6571
  [name: string]: unknown;
6601
6572
  };
6602
6573
  content: {
6603
- "application/json": components["schemas"]["PlatformSetupMutationResult"];
6574
+ "application/json": components["schemas"]["GetCourseColdWelcomeBatchResponse"];
6575
+ };
6576
+ };
6577
+ 400: components["responses"]["ValidationError"];
6578
+ 404: components["responses"]["NotFound"];
6579
+ /** @description В воркспейсе уже идёт пакет */
6580
+ 409: {
6581
+ headers: {
6582
+ [name: string]: unknown;
6583
+ };
6584
+ content: {
6585
+ "application/json": components["schemas"]["ErrorResponse"];
6604
6586
  };
6605
6587
  };
6606
6588
  };
6607
6589
  };
6590
+ delete?: never;
6591
+ options?: never;
6592
+ head?: never;
6593
+ patch?: never;
6608
6594
  trace?: never;
6609
6595
  };
6610
- "/api/v2/platforms/{platformId}/router/routing-rules": {
6596
+ "/api/v2/workspaces/{workspaceId}/getcourse-cold-welcome/batch/{batchId}": {
6611
6597
  parameters: {
6612
6598
  query?: never;
6613
6599
  header?: never;
6614
6600
  path?: never;
6615
6601
  cookie?: never;
6616
6602
  };
6617
- get?: never;
6618
- put?: never;
6619
- /** Create one granular routing rule */
6620
- post: {
6603
+ /**
6604
+ * Состояние пакета сегментов
6605
+ * @description Агрегат state плюс разбивка segments[] со своим статусом, importJobId и причиной отказа у каждого. stalled=true означает доказанный обрыв драйвера (протух пульс) — остаток поднимается через resume. Scope `read:campaigns`.
6606
+ */
6607
+ get: {
6621
6608
  parameters: {
6622
6609
  query?: never;
6623
6610
  header?: never;
6624
6611
  path: {
6625
- platformId: components["parameters"]["PlatformIdPath"];
6612
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6613
+ batchId: components["parameters"]["ColdWelcomeBatchIdPath"];
6626
6614
  };
6627
6615
  cookie?: never;
6628
6616
  };
6629
- requestBody: {
6630
- content: {
6631
- "application/json": components["schemas"]["RoutingRuleUpsertRequest"];
6632
- };
6633
- };
6617
+ requestBody?: never;
6634
6618
  responses: {
6635
- 201: {
6619
+ /** @description Состояние пакета */
6620
+ 200: {
6636
6621
  headers: {
6637
6622
  [name: string]: unknown;
6638
6623
  };
6639
6624
  content: {
6640
- "application/json": components["schemas"]["PlatformSetupMutationResult"];
6625
+ "application/json": components["schemas"]["GetCourseColdWelcomeBatchStatus"];
6641
6626
  };
6642
6627
  };
6628
+ 404: components["responses"]["NotFound"];
6643
6629
  };
6644
6630
  };
6631
+ put?: never;
6632
+ post?: never;
6645
6633
  delete?: never;
6646
6634
  options?: never;
6647
6635
  head?: never;
6648
- /** Patch one granular routing rule; no bulk router replace */
6649
- patch: {
6636
+ patch?: never;
6637
+ trace?: never;
6638
+ };
6639
+ "/api/v2/workspaces/{workspaceId}/getcourse-cold-welcome/batch/{batchId}/resume": {
6640
+ parameters: {
6641
+ query?: never;
6642
+ header?: never;
6643
+ path?: never;
6644
+ cookie?: never;
6645
+ };
6646
+ get?: never;
6647
+ put?: never;
6648
+ /**
6649
+ * Возобновить остаток пакета после обрыва драйвера
6650
+ * @description Разрешено ТОЛЬКО пакету, чей статус подтвердил обрыв (stalled). Источник текста хранится в плане — списки контактов пересобирать не нужно. Повтора отправки не будет: приветствие одноразово на контакт. Scope `launch:campaigns`.
6651
+ */
6652
+ post: {
6650
6653
  parameters: {
6651
6654
  query?: never;
6652
6655
  header?: never;
6653
6656
  path: {
6654
- platformId: components["parameters"]["PlatformIdPath"];
6657
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6658
+ batchId: components["parameters"]["ColdWelcomeBatchIdPath"];
6655
6659
  };
6656
6660
  cookie?: never;
6657
6661
  };
6658
- requestBody: {
6659
- content: {
6660
- "application/json": components["schemas"]["RoutingRuleUpsertRequest"];
6661
- };
6662
- };
6662
+ requestBody?: never;
6663
6663
  responses: {
6664
+ /** @description Остаток пакета поднят */
6664
6665
  200: {
6665
6666
  headers: {
6666
6667
  [name: string]: unknown;
6667
6668
  };
6668
6669
  content: {
6669
- "application/json": components["schemas"]["PlatformSetupMutationResult"];
6670
+ "application/json": {
6671
+ /** @description Сегментов осталось в очереди */
6672
+ pending: number;
6673
+ };
6674
+ };
6675
+ };
6676
+ 404: components["responses"]["NotFound"];
6677
+ /** @description Пакет не в состоянии обрыва — возобновлять нечего */
6678
+ 409: {
6679
+ headers: {
6680
+ [name: string]: unknown;
6681
+ };
6682
+ content: {
6683
+ "application/json": components["schemas"]["ErrorResponse"];
6670
6684
  };
6671
6685
  };
6672
6686
  };
6673
6687
  };
6688
+ delete?: never;
6689
+ options?: never;
6690
+ head?: never;
6691
+ patch?: never;
6674
6692
  trace?: never;
6675
6693
  };
6676
- "/api/v2/platforms/{platformId}/dialogue-audit/config": {
6694
+ "/api/v2/workspaces/{workspaceId}/getcourse-cold-welcome/batch/{batchId}/cancel": {
6677
6695
  parameters: {
6678
6696
  query?: never;
6679
6697
  header?: never;
6680
6698
  path?: never;
6681
6699
  cookie?: never;
6682
6700
  };
6701
+ get?: never;
6702
+ put?: never;
6683
6703
  /**
6684
- * Reviewer settings of the channel (read-only)
6685
- * @description `isConfigured=false` means the config row does not exist yet and the returned values are defaults. GET never creates anything. Writing settings is intentionally not exposed to MCP.
6704
+ * Отменить остаток пакета
6705
+ * @description Действует на не начатые сегменты и идущую задачу. Уже отправленное не отзывается. Scope `launch:campaigns`.
6686
6706
  */
6687
- get: {
6707
+ post: {
6688
6708
  parameters: {
6689
6709
  query?: never;
6690
6710
  header?: never;
6691
6711
  path: {
6692
- platformId: components["parameters"]["PlatformIdPath"];
6712
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6713
+ batchId: components["parameters"]["ColdWelcomeBatchIdPath"];
6693
6714
  };
6694
6715
  cookie?: never;
6695
6716
  };
6696
6717
  requestBody?: never;
6697
6718
  responses: {
6719
+ /** @description Остаток помечен отменённым */
6698
6720
  200: {
6699
6721
  headers: {
6700
6722
  [name: string]: unknown;
6701
6723
  };
6702
6724
  content: {
6703
- "application/json": components["schemas"]["DialogueAuditConfig"];
6725
+ "application/json": {
6726
+ /** @description Сколько сегментов снято */
6727
+ cancelled: number;
6728
+ };
6704
6729
  };
6705
6730
  };
6731
+ 404: components["responses"]["NotFound"];
6706
6732
  };
6707
6733
  };
6708
- put?: never;
6709
- post?: never;
6710
6734
  delete?: never;
6711
6735
  options?: never;
6712
6736
  head?: never;
6713
6737
  patch?: never;
6714
6738
  trace?: never;
6715
6739
  };
6716
- "/api/v2/platforms/{platformId}/dialogue-audit/runs": {
6740
+ "/api/v2/workspaces/{workspaceId}/getcourse-cold-welcome/{jobId}/cancel": {
6717
6741
  parameters: {
6718
6742
  query?: never;
6719
6743
  header?: never;
6720
6744
  path?: never;
6721
6745
  cookie?: never;
6722
6746
  };
6723
- /** Reviewer run history (cursor pagination) */
6724
- get: {
6747
+ get?: never;
6748
+ put?: never;
6749
+ /**
6750
+ * Остановить идущую рассылку «Первое сообщение»
6751
+ * @description Действует на остаток когорты в пределах ~10 секунд; уже отправленное не отзывается. Scope `launch:campaigns`.
6752
+ */
6753
+ post: {
6754
+ parameters: {
6755
+ query?: never;
6756
+ header?: never;
6757
+ path: {
6758
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6759
+ jobId: components["parameters"]["ColdWelcomeJobIdPath"];
6760
+ };
6761
+ cookie?: never;
6762
+ };
6763
+ requestBody?: never;
6764
+ responses: {
6765
+ /** @description Остановка запрошена */
6766
+ 200: {
6767
+ headers: {
6768
+ [name: string]: unknown;
6769
+ };
6770
+ content: {
6771
+ "application/json": {
6772
+ /** @enum {boolean} */
6773
+ cancelRequested: true;
6774
+ };
6775
+ };
6776
+ };
6777
+ 404: components["responses"]["NotFound"];
6778
+ };
6779
+ };
6780
+ delete?: never;
6781
+ options?: never;
6782
+ head?: never;
6783
+ patch?: never;
6784
+ trace?: never;
6785
+ };
6786
+ "/api/v2/workspaces/{workspaceId}/chat-users/import/getcourse-contacts": {
6787
+ parameters: {
6788
+ query?: never;
6789
+ header?: never;
6790
+ path?: never;
6791
+ cookie?: never;
6792
+ };
6793
+ get?: never;
6794
+ put?: never;
6795
+ /**
6796
+ * Импорт контактов GetCourse списком (без файла)
6797
+ * @description Заводит или обновляет контакты GetCourse в базе платформы, чтобы по ним можно было запускать «Нашу отправку». НИЧЕГО НЕ ОТПРАВЛЯЕТ. Нужен ровно тогда, когда preview показал notInBase > 0: отправке нужен ChatUser, иначе контакт получает исход SKIPPED_NOT_IN_BASE. Матчинг существующих — по contactId (getcourse_user_id). Максимум 5000 контактов, идёт фоном; прогресс — GET /chat-users/import/jobs/{jobId}. Гейт «один активный импорт на воркспейс» общий с волнами и пакетами. Ключи строк — имена колонок экспорта GetCourse: их читает тот же разбор, что и файл. Scope `launch:campaigns`, а НЕ `mcp:platform-setup` — тот разворачивается в право настройки платформы.
6798
+ */
6799
+ post: {
6800
+ parameters: {
6801
+ query?: never;
6802
+ header?: never;
6803
+ path: {
6804
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6805
+ };
6806
+ cookie?: never;
6807
+ };
6808
+ requestBody: {
6809
+ content: {
6810
+ "application/json": components["schemas"]["GetCourseContactsImportRequest"];
6811
+ };
6812
+ };
6813
+ responses: {
6814
+ /** @description Импорт запущен либо строки отбракованы разбором */
6815
+ 200: {
6816
+ headers: {
6817
+ [name: string]: unknown;
6818
+ };
6819
+ content: {
6820
+ "application/json": components["schemas"]["GetCourseContactsImportResponse"];
6821
+ };
6822
+ };
6823
+ 400: components["responses"]["ValidationError"];
6824
+ 404: components["responses"]["NotFound"];
6825
+ /** @description В воркспейсе уже идёт задача импорта */
6826
+ 409: {
6827
+ headers: {
6828
+ [name: string]: unknown;
6829
+ };
6830
+ content: {
6831
+ "application/json": components["schemas"]["ErrorResponse"];
6832
+ };
6833
+ };
6834
+ };
6835
+ };
6836
+ delete?: never;
6837
+ options?: never;
6838
+ head?: never;
6839
+ patch?: never;
6840
+ trace?: never;
6841
+ };
6842
+ "/api/v2/workspaces/{workspaceId}/broadcasts/launches": {
6843
+ parameters: {
6844
+ query?: never;
6845
+ header?: never;
6846
+ path?: never;
6847
+ cookie?: never;
6848
+ };
6849
+ /**
6850
+ * История запусков — наша отправка и волны по файлу одним списком
6851
+ * @description Scope `read:campaigns`.
6852
+ */
6853
+ get: {
6854
+ parameters: {
6855
+ query?: {
6856
+ mailingVariantId?: string;
6857
+ limit?: number;
6858
+ };
6859
+ header?: never;
6860
+ path: {
6861
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6862
+ };
6863
+ cookie?: never;
6864
+ };
6865
+ requestBody?: never;
6866
+ responses: {
6867
+ /** @description Страница истории запусков */
6868
+ 200: {
6869
+ headers: {
6870
+ [name: string]: unknown;
6871
+ };
6872
+ content: {
6873
+ "application/json": components["schemas"]["BroadcastLaunchesPage"];
6874
+ };
6875
+ };
6876
+ };
6877
+ };
6878
+ put?: never;
6879
+ post?: never;
6880
+ delete?: never;
6881
+ options?: never;
6882
+ head?: never;
6883
+ patch?: never;
6884
+ trace?: never;
6885
+ };
6886
+ "/api/v2/workspaces/{workspaceId}/broadcasts/variants-summary": {
6887
+ parameters: {
6888
+ query?: never;
6889
+ header?: never;
6890
+ path?: never;
6891
+ cookie?: never;
6892
+ };
6893
+ /**
6894
+ * Сводка по каждой рассылке — запусков, отправлено, последний запуск
6895
+ * @description Scope `read:campaigns`.
6896
+ */
6897
+ get: {
6898
+ parameters: {
6899
+ query?: never;
6900
+ header?: never;
6901
+ path: {
6902
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6903
+ };
6904
+ cookie?: never;
6905
+ };
6906
+ requestBody?: never;
6907
+ responses: {
6908
+ /** @description Сводка по рассылкам */
6909
+ 200: {
6910
+ headers: {
6911
+ [name: string]: unknown;
6912
+ };
6913
+ content: {
6914
+ "application/json": components["schemas"]["BroadcastVariantSummary"][];
6915
+ };
6916
+ };
6917
+ };
6918
+ };
6919
+ put?: never;
6920
+ post?: never;
6921
+ delete?: never;
6922
+ options?: never;
6923
+ head?: never;
6924
+ patch?: never;
6925
+ trace?: never;
6926
+ };
6927
+ "/api/v2/workspaces/{workspaceId}/broadcasts/label-suggestions": {
6928
+ parameters: {
6929
+ query?: never;
6930
+ header?: never;
6931
+ path?: never;
6932
+ cookie?: never;
6933
+ };
6934
+ /**
6935
+ * Метки прошлых запусков — чтобы переиспользовать значения, а не плодить опечатки
6936
+ * @description Scope `read:campaigns`.
6937
+ */
6938
+ get: {
6939
+ parameters: {
6940
+ query?: never;
6941
+ header?: never;
6942
+ path: {
6943
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6944
+ };
6945
+ cookie?: never;
6946
+ };
6947
+ requestBody?: never;
6948
+ responses: {
6949
+ /** @description Ранее использованные метки */
6950
+ 200: {
6951
+ headers: {
6952
+ [name: string]: unknown;
6953
+ };
6954
+ content: {
6955
+ "application/json": components["schemas"]["BroadcastLabelSuggestions"];
6956
+ };
6957
+ };
6958
+ };
6959
+ };
6960
+ put?: never;
6961
+ post?: never;
6962
+ delete?: never;
6963
+ options?: never;
6964
+ head?: never;
6965
+ patch?: never;
6966
+ trace?: never;
6967
+ };
6968
+ "/api/v2/workspaces/{workspaceId}/wazzup-waves/import": {
6969
+ parameters: {
6970
+ query?: never;
6971
+ header?: never;
6972
+ path?: never;
6973
+ cookie?: never;
6974
+ };
6975
+ get?: never;
6976
+ put?: never;
6977
+ /**
6978
+ * Запуск волны WhatsApp через Wazzup (WABA-шаблон по когорте телефонов)
6979
+ * @description v1.5 Increment 24. Без `confirm=true` — dry-run: прогоняется ПОЛНЫЙ preflight (платформа Wazzup активна и с включённым AI, «обрабатывать все входящие», живой WABA-канал, одобренный текстовый шаблон, число значений переменных) и возвращается previewText — ни одно сообщение не отправляется. HTTP-эндпоинт гейтит запуск по `confirm=true`; MCP-тул `besales_wazzup_wave_import` дополнительно требует `explicit_confirmation=true` (это защита от того, чтобы AI-оператор запустил платную рассылку мимоходом — поле потребляется на слое MCP и в тело запроса не передаётся). Каждое маркетинговое сообщение тарифицируется Meta. Политика at-most-once: строка занимается под advisory-локом ДО внешнего вызова, повтор того же шаблона тому же контакту в течение 24 часов пропускается. Scope `mcp:platform-setup`.
6980
+ */
6981
+ post: {
6982
+ parameters: {
6983
+ query?: never;
6984
+ header?: never;
6985
+ path: {
6986
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
6987
+ };
6988
+ cookie?: never;
6989
+ };
6990
+ requestBody: {
6991
+ content: {
6992
+ "application/json": {
6993
+ /** Format: uuid */
6994
+ platformId: string;
6995
+ templateGuid: string;
6996
+ templateValues?: string[];
6997
+ contacts: {
6998
+ phone: string;
6999
+ name?: string;
7000
+ }[];
7001
+ funnel?: string;
7002
+ segment?: string;
7003
+ productCode?: string;
7004
+ productName?: string;
7005
+ cohortLabel?: string;
7006
+ confirm?: boolean;
7007
+ };
7008
+ };
7009
+ };
7010
+ responses: {
7011
+ /** @description Волна запущена либо выполнен dry-run */
7012
+ 200: {
7013
+ headers: {
7014
+ [name: string]: unknown;
7015
+ };
7016
+ content: {
7017
+ "application/json": {
7018
+ dryRun: boolean;
7019
+ /** Format: uuid */
7020
+ jobId?: string;
7021
+ totalContacts: number;
7022
+ previewText: string;
7023
+ message: string;
7024
+ rejectedRows?: string[];
7025
+ /** @description Некритичные предупреждения preflight — волну не блокируют. Сейчас это мёртвая подписка на статусы доставки (у Wazzup один webhook URI на аккаунт, его мог перезаписать другой сервис): сообщения уйдут и будут оплачены, но доставка не отследится и «дошло» в аналитике останется почти нулевым. */
7026
+ warnings?: string[];
7027
+ };
7028
+ };
7029
+ };
7030
+ /** @description Непригодные платформа, канал, шаблон или когорта */
7031
+ 400: {
7032
+ headers: {
7033
+ [name: string]: unknown;
7034
+ };
7035
+ content?: never;
7036
+ };
7037
+ };
7038
+ };
7039
+ delete?: never;
7040
+ options?: never;
7041
+ head?: never;
7042
+ patch?: never;
7043
+ trace?: never;
7044
+ };
7045
+ "/api/v2/workspaces/{workspaceId}/wazzup-waves/templates/{platformId}": {
7046
+ parameters: {
7047
+ query?: never;
7048
+ header?: never;
7049
+ path?: never;
7050
+ cookie?: never;
7051
+ };
7052
+ /**
7053
+ * Шаблоны WABA платформы с признаком пригодности для волны
7054
+ * @description v1.5 Increment 24. usable=false — шаблон не одобрен Meta либо содержит медиа-заголовок или переменную в URL-кнопке (значения ушли бы не в те слоты). Scope `mcp:platform-setup`.
7055
+ */
7056
+ get: {
7057
+ parameters: {
7058
+ query?: never;
7059
+ header?: never;
7060
+ path: {
7061
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
7062
+ platformId: string;
7063
+ };
7064
+ cookie?: never;
7065
+ };
7066
+ requestBody?: never;
7067
+ responses: {
7068
+ /** @description Список шаблонов */
7069
+ 200: {
7070
+ headers: {
7071
+ [name: string]: unknown;
7072
+ };
7073
+ content: {
7074
+ "application/json": {
7075
+ templateGuid: string;
7076
+ title: string;
7077
+ status: string;
7078
+ bodyText: string;
7079
+ variableCount: number;
7080
+ usable: boolean;
7081
+ unsupportedReasons?: string[];
7082
+ }[];
7083
+ };
7084
+ };
7085
+ };
7086
+ };
7087
+ put?: never;
7088
+ post?: never;
7089
+ delete?: never;
7090
+ options?: never;
7091
+ head?: never;
7092
+ patch?: never;
7093
+ trace?: never;
7094
+ };
7095
+ "/api/v2/workspaces/{workspaceId}/wazzup-waves/{jobId}": {
7096
+ parameters: {
7097
+ query?: never;
7098
+ header?: never;
7099
+ path?: never;
7100
+ cookie?: never;
7101
+ };
7102
+ /**
7103
+ * Статус волны WhatsApp
7104
+ * @description v1.5 Increment 24. skipped — сознательные пропуски (стоп-бот, ожидание оператора, недавний повтор), НЕ ошибки. unknownOutcome — строки, где отправка началась, но ответ Wazzup не дошёл; автоматически они не переотправляются. Scope `mcp:platform-setup`.
7105
+ */
7106
+ get: {
7107
+ parameters: {
7108
+ query?: never;
7109
+ header?: never;
7110
+ path: {
7111
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
7112
+ jobId: string;
7113
+ };
7114
+ cookie?: never;
7115
+ };
7116
+ requestBody?: never;
7117
+ responses: {
7118
+ /** @description Статус волны */
7119
+ 200: {
7120
+ headers: {
7121
+ [name: string]: unknown;
7122
+ };
7123
+ content: {
7124
+ "application/json": {
7125
+ jobId: string;
7126
+ /** @enum {string} */
7127
+ status: "PROCESSING" | "COMPLETED";
7128
+ totalRows: number;
7129
+ processedRows: number;
7130
+ sent: number;
7131
+ failed: number;
7132
+ skipped: number;
7133
+ unknownOutcome: number;
7134
+ /** @description Подтверждено вебхуком WhatsApp. Живёт ОТДЕЛЬНО от sent: sent означает лишь что Wazzup принял сообщение. Взаимоисключающе с deliveryFailed. */
7135
+ delivered?: number;
7136
+ /** @description Подмножество delivered — получатель открыл сообщение */
7137
+ read?: number;
7138
+ /** @description Отказ доставки по данным WhatsApp. НЕ меняет исход самой отправки: status строки описывает результат нашего вызова, а не доставку. */
7139
+ deliveryFailed?: number;
7140
+ /** @description Разбивка отказов по кодам ошибок Wazzup */
7141
+ deliveryErrors?: {
7142
+ [key: string]: number;
7143
+ };
7144
+ errors?: string[];
7145
+ };
7146
+ };
7147
+ };
7148
+ /** @description Волна не найдена в этом рабочем пространстве */
7149
+ 404: {
7150
+ headers: {
7151
+ [name: string]: unknown;
7152
+ };
7153
+ content?: never;
7154
+ };
7155
+ };
7156
+ };
7157
+ put?: never;
7158
+ post?: never;
7159
+ delete?: never;
7160
+ options?: never;
7161
+ head?: never;
7162
+ patch?: never;
7163
+ trace?: never;
7164
+ };
7165
+ "/api/v2/platforms/{platformId}/agents/{agentId}/tools": {
7166
+ parameters: {
7167
+ query?: never;
7168
+ header?: never;
7169
+ path?: never;
7170
+ cookie?: never;
7171
+ };
7172
+ get?: never;
7173
+ put?: never;
7174
+ post?: never;
7175
+ delete?: never;
7176
+ options?: never;
7177
+ head?: never;
7178
+ /** Patch agent tool bindings without deleting omitted tools */
7179
+ patch: {
7180
+ parameters: {
7181
+ query?: never;
7182
+ header?: never;
7183
+ path: {
7184
+ platformId: components["parameters"]["PlatformIdPath"];
7185
+ agentId: components["parameters"]["AgentIdPath"];
7186
+ };
7187
+ cookie?: never;
7188
+ };
7189
+ requestBody: {
7190
+ content: {
7191
+ "application/json": components["schemas"]["AgentToolsPatchRequest"];
7192
+ };
7193
+ };
7194
+ responses: {
7195
+ 200: {
7196
+ headers: {
7197
+ [name: string]: unknown;
7198
+ };
7199
+ content: {
7200
+ "application/json": components["schemas"]["PlatformSetupMutationResult"];
7201
+ };
7202
+ };
7203
+ };
7204
+ };
7205
+ trace?: never;
7206
+ };
7207
+ "/api/v2/platforms/{platformId}/router": {
7208
+ parameters: {
7209
+ query?: never;
7210
+ header?: never;
7211
+ path?: never;
7212
+ cookie?: never;
7213
+ };
7214
+ get?: never;
7215
+ put?: never;
7216
+ post?: never;
7217
+ delete?: never;
7218
+ options?: never;
7219
+ head?: never;
7220
+ /** Patch router metadata/additionalPrompt only */
7221
+ patch: {
7222
+ parameters: {
7223
+ query?: never;
7224
+ header?: never;
7225
+ path: {
7226
+ platformId: components["parameters"]["PlatformIdPath"];
7227
+ };
7228
+ cookie?: never;
7229
+ };
7230
+ requestBody: {
7231
+ content: {
7232
+ "application/json": components["schemas"]["RouterPatchRequest"];
7233
+ };
7234
+ };
7235
+ responses: {
7236
+ 200: {
7237
+ headers: {
7238
+ [name: string]: unknown;
7239
+ };
7240
+ content: {
7241
+ "application/json": components["schemas"]["PlatformSetupMutationResult"];
7242
+ };
7243
+ };
7244
+ };
7245
+ };
7246
+ trace?: never;
7247
+ };
7248
+ "/api/v2/platforms/{platformId}/router/routing-rules": {
7249
+ parameters: {
7250
+ query?: never;
7251
+ header?: never;
7252
+ path?: never;
7253
+ cookie?: never;
7254
+ };
7255
+ get?: never;
7256
+ put?: never;
7257
+ /** Create one granular routing rule */
7258
+ post: {
7259
+ parameters: {
7260
+ query?: never;
7261
+ header?: never;
7262
+ path: {
7263
+ platformId: components["parameters"]["PlatformIdPath"];
7264
+ };
7265
+ cookie?: never;
7266
+ };
7267
+ requestBody: {
7268
+ content: {
7269
+ "application/json": components["schemas"]["RoutingRuleUpsertRequest"];
7270
+ };
7271
+ };
7272
+ responses: {
7273
+ 201: {
7274
+ headers: {
7275
+ [name: string]: unknown;
7276
+ };
7277
+ content: {
7278
+ "application/json": components["schemas"]["PlatformSetupMutationResult"];
7279
+ };
7280
+ };
7281
+ };
7282
+ };
7283
+ delete?: never;
7284
+ options?: never;
7285
+ head?: never;
7286
+ /** Patch one granular routing rule; no bulk router replace */
7287
+ patch: {
7288
+ parameters: {
7289
+ query?: never;
7290
+ header?: never;
7291
+ path: {
7292
+ platformId: components["parameters"]["PlatformIdPath"];
7293
+ };
7294
+ cookie?: never;
7295
+ };
7296
+ requestBody: {
7297
+ content: {
7298
+ "application/json": components["schemas"]["RoutingRuleUpsertRequest"];
7299
+ };
7300
+ };
7301
+ responses: {
7302
+ 200: {
7303
+ headers: {
7304
+ [name: string]: unknown;
7305
+ };
7306
+ content: {
7307
+ "application/json": components["schemas"]["PlatformSetupMutationResult"];
7308
+ };
7309
+ };
7310
+ };
7311
+ };
7312
+ trace?: never;
7313
+ };
7314
+ "/api/v2/platforms/{platformId}/dialogue-audit/config": {
7315
+ parameters: {
7316
+ query?: never;
7317
+ header?: never;
7318
+ path?: never;
7319
+ cookie?: never;
7320
+ };
7321
+ /**
7322
+ * Reviewer settings of the channel (read-only)
7323
+ * @description `isConfigured=false` means the config row does not exist yet and the returned values are defaults. GET never creates anything. Writing settings is intentionally not exposed to MCP.
7324
+ */
7325
+ get: {
7326
+ parameters: {
7327
+ query?: never;
7328
+ header?: never;
7329
+ path: {
7330
+ platformId: components["parameters"]["PlatformIdPath"];
7331
+ };
7332
+ cookie?: never;
7333
+ };
7334
+ requestBody?: never;
7335
+ responses: {
7336
+ 200: {
7337
+ headers: {
7338
+ [name: string]: unknown;
7339
+ };
7340
+ content: {
7341
+ "application/json": components["schemas"]["DialogueAuditConfig"];
7342
+ };
7343
+ };
7344
+ };
7345
+ };
7346
+ put?: never;
7347
+ post?: never;
7348
+ delete?: never;
7349
+ options?: never;
7350
+ head?: never;
7351
+ patch?: never;
7352
+ trace?: never;
7353
+ };
7354
+ "/api/v2/platforms/{platformId}/dialogue-audit/runs": {
7355
+ parameters: {
7356
+ query?: never;
7357
+ header?: never;
7358
+ path?: never;
7359
+ cookie?: never;
7360
+ };
7361
+ /** Reviewer run history (cursor pagination) */
7362
+ get: {
6725
7363
  parameters: {
6726
7364
  query?: {
6727
7365
  cursor?: string;
@@ -7702,6 +8340,21 @@ export interface paths {
7702
8340
  sequenceId?: string[];
7703
8341
  /** @description Горизонт сравнительной метрики. Фиксированный набор — иначе окно подбирали бы под ответ */
7704
8342
  horizonMinutes?: 30 | 60 | 90 | 180 | 360 | 720 | 1440;
8343
+ /**
8344
+ * @description Считать ли блок runs. Передайте false, если читаете только шаговые метрики:
8345
+ * расчёт стоит отдельного запроса к БД, а строки таблицы сравнения вариантов и
8346
+ * кастомные отчёты его выбрасывают.
8347
+ */
8348
+ withRuns?: boolean;
8349
+ /**
8350
+ * @description Окно ПРОХОЖДЕНИЯ цепочки для метрики runs: ответил ли человек хоть раз за N дней от входа.
8351
+ *
8352
+ * Не путать с horizonMinutes. Тот живёт на ШАГЕ и обязан вырезать касания, у которых
8353
+ * следующий шаг ушёл раньше конца окна, — на частых цепочках это съедает выборку
8354
+ * (замер 25.08.2026: 56 % при 90 мин). Здесь единица другая — прохождение, — и вырезать
8355
+ * некого: все шаги внутри окна принадлежат этому же прохождению.
8356
+ */
8357
+ runWindowDays?: 1 | 3 | 5 | 7 | 14;
7705
8358
  /**
7706
8359
  * @description Сегмент волны, действовавший на момент отправки шага (последняя волна до касания).
7707
8360
  * У воркспейса без рассылок значений нет — см. `dimensions` в ответе.
@@ -7711,6 +8364,15 @@ export interface paths {
7711
8364
  product?: string[];
7712
8365
  /** @description Транспорт волны (мессенджер). Строгий enum GetCourseTransport */
7713
8366
  channel?: string[];
8367
+ /**
8368
+ * @description Оставить только контакты, которые хоть раз написали сами: у кого за всю переписку
8369
+ * ноль входящих, из отчёта уходят ВСЕ его касания.
8370
+ *
8371
+ * ⚠️ Линза, а не поправка: отбор идёт по исходу, поэтому доли ответов поднимаются во
8372
+ * всех колонках, а шаги перестают быть независимыми — контакт, ответивший на третий
8373
+ * шаг, остаётся в знаменателе первого. Цифры с фильтром и без него несравнимы.
8374
+ */
8375
+ onlyRepliedContacts?: boolean;
7714
8376
  /** @description Момент снимка. Значение в будущем отбрасывается до текущего момента */
7715
8377
  asOf?: string;
7716
8378
  };
@@ -8650,13 +9312,125 @@ export interface paths {
8650
9312
  headers: {
8651
9313
  [name: string]: unknown;
8652
9314
  };
8653
- content: {
8654
- "application/json": components["schemas"]["ContactMergeLog"];
9315
+ content: {
9316
+ "application/json": components["schemas"]["ContactMergeLog"];
9317
+ };
9318
+ };
9319
+ };
9320
+ };
9321
+ delete?: never;
9322
+ options?: never;
9323
+ head?: never;
9324
+ patch?: never;
9325
+ trace?: never;
9326
+ };
9327
+ "/api/v2/contacts/{contactId}/trigger-claims": {
9328
+ parameters: {
9329
+ query?: never;
9330
+ header?: never;
9331
+ path?: never;
9332
+ cookie?: never;
9333
+ };
9334
+ /**
9335
+ * List burnt one-time trigger claims for contact
9336
+ * @description Права одноразовых триггеров (AgentTrigger.runOncePerContact), уже занятые этим контактом. canReset=false означает, что право держит идущий прогон.
9337
+ */
9338
+ get: {
9339
+ parameters: {
9340
+ query?: never;
9341
+ header?: never;
9342
+ path: {
9343
+ contactId: string;
9344
+ };
9345
+ cookie?: never;
9346
+ };
9347
+ requestBody?: never;
9348
+ responses: {
9349
+ 200: {
9350
+ headers: {
9351
+ [name: string]: unknown;
9352
+ };
9353
+ content: {
9354
+ "application/json": components["schemas"]["TriggerContactClaimsPage"];
9355
+ };
9356
+ };
9357
+ /** @description Контакт не найден в воркспейсе */
9358
+ 404: {
9359
+ headers: {
9360
+ [name: string]: unknown;
9361
+ };
9362
+ content?: never;
9363
+ };
9364
+ };
9365
+ };
9366
+ put?: never;
9367
+ post?: never;
9368
+ delete?: never;
9369
+ options?: never;
9370
+ head?: never;
9371
+ patch?: never;
9372
+ trace?: never;
9373
+ };
9374
+ "/api/v2/contacts/{contactId}/trigger-claims/{triggerId}": {
9375
+ parameters: {
9376
+ query?: never;
9377
+ header?: never;
9378
+ path?: never;
9379
+ cookie?: never;
9380
+ };
9381
+ get?: never;
9382
+ put?: never;
9383
+ post?: never;
9384
+ /**
9385
+ * Allow a one-time trigger to fire for the contact again
9386
+ * @description Возвращает контакту сожжённое право. Снимается ТОЛЬКО status=COMPLETED: право со status=IN_PROGRESS держит владелец, а его finalize адресует пару «триггер+контакт», и удаление такой строки дало бы двух владельцев и повторные необратимые действия.
9387
+ */
9388
+ delete: {
9389
+ parameters: {
9390
+ query?: never;
9391
+ header?: never;
9392
+ path: {
9393
+ contactId: string;
9394
+ triggerId: string;
9395
+ };
9396
+ cookie?: never;
9397
+ };
9398
+ requestBody: {
9399
+ content: {
9400
+ "application/json": components["schemas"]["ResetTriggerClaimRequest"];
9401
+ };
9402
+ };
9403
+ responses: {
9404
+ /** @description Право возвращено */
9405
+ 204: {
9406
+ headers: {
9407
+ [name: string]: unknown;
9408
+ };
9409
+ content?: never;
9410
+ };
9411
+ /** @description Нет explicitConfirmation */
9412
+ 400: {
9413
+ headers: {
9414
+ [name: string]: unknown;
9415
+ };
9416
+ content?: never;
9417
+ };
9418
+ /** @description Контакт не найден либо право не занято */
9419
+ 404: {
9420
+ headers: {
9421
+ [name: string]: unknown;
9422
+ };
9423
+ content?: never;
9424
+ };
9425
+ /** @description Право держит прогон триггера */
9426
+ 409: {
9427
+ headers: {
9428
+ [name: string]: unknown;
8655
9429
  };
9430
+ content?: never;
8656
9431
  };
8657
9432
  };
8658
9433
  };
8659
- delete?: never;
8660
9434
  options?: never;
8661
9435
  head?: never;
8662
9436
  patch?: never;
@@ -9280,7 +10054,7 @@ export interface paths {
9280
10054
  parameters: {
9281
10055
  query?: {
9282
10056
  includeArchived?: boolean;
9283
- /** @description Глубина сводки в днях */
10057
+ /** @description Глубина сводки в днях. НЕ ЗАДАН — за всё время. Прежде подставлялось окно 60 дней, и оно расходилось само с собой: выданное раньше него показывалось как «выдано 0», тогда как выручка в той же строке считалась за всё время. */
9284
10058
  days?: number;
9285
10059
  limit?: number;
9286
10060
  offset?: number;
@@ -9446,6 +10220,7 @@ export interface paths {
9446
10220
  get: {
9447
10221
  parameters: {
9448
10222
  query?: {
10223
+ /** @description Глубина разреза в днях; не задан — за всё время */
9449
10224
  days?: number;
9450
10225
  };
9451
10226
  header?: never;
@@ -9476,6 +10251,51 @@ export interface paths {
9476
10251
  patch?: never;
9477
10252
  trace?: never;
9478
10253
  };
10254
+ "/api/v2/workspaces/{workspaceId}/tracked-links/{linkId}/reach": {
10255
+ parameters: {
10256
+ query?: never;
10257
+ header?: never;
10258
+ path?: never;
10259
+ cookie?: never;
10260
+ };
10261
+ /**
10262
+ * Разрез ссылки по месту применения
10263
+ * @description Где ссылка работала: площадка и агент, через которых она уходила людям. Отвечает на «где», тогда как /breakdown — на «после какого касания». Оси независимые: одна выдача принадлежит ровно одной площадке и одному агенту, а тип источника — отдельное измерение. ⚠️ null в оси — это «не определён», отдельная строка, а не ноль: у контакта могло не быть ни одного ответа агента. ⚠️ Пустое имя при заполненном id значит, что площадку или агента удалили: id хранится снимком без внешнего ключа, чтобы история кликов пережила удаление.
10264
+ */
10265
+ get: {
10266
+ parameters: {
10267
+ query?: {
10268
+ /** @description Глубина разреза в днях; не задан — за всё время */
10269
+ days?: number;
10270
+ };
10271
+ header?: never;
10272
+ path: {
10273
+ workspaceId: components["parameters"]["BroadcastWorkspaceId"];
10274
+ linkId: components["parameters"]["TrackedLinkIdPath"];
10275
+ };
10276
+ cookie?: never;
10277
+ };
10278
+ requestBody?: never;
10279
+ responses: {
10280
+ /** @description OK */
10281
+ 200: {
10282
+ headers: {
10283
+ [name: string]: unknown;
10284
+ };
10285
+ content: {
10286
+ "application/json": components["schemas"]["TrackedLinkReachBreakdown"][];
10287
+ };
10288
+ };
10289
+ };
10290
+ };
10291
+ put?: never;
10292
+ post?: never;
10293
+ delete?: never;
10294
+ options?: never;
10295
+ head?: never;
10296
+ patch?: never;
10297
+ trace?: never;
10298
+ };
9479
10299
  "/api/v2/workspaces/{workspaceId}/tracked-links/{linkId}/clicks": {
9480
10300
  parameters: {
9481
10301
  query?: never;
@@ -9490,6 +10310,7 @@ export interface paths {
9490
10310
  get: {
9491
10311
  parameters: {
9492
10312
  query?: {
10313
+ /** @description Глубина разреза в днях; не задан — за всё время */
9493
10314
  days?: number;
9494
10315
  page?: number;
9495
10316
  pageSize?: number;
@@ -9522,6 +10343,90 @@ export interface paths {
9522
10343
  patch?: never;
9523
10344
  trace?: never;
9524
10345
  };
10346
+ "/api/v2/workspaces/{workspaceId}/link-tracking-domain": {
10347
+ parameters: {
10348
+ query?: never;
10349
+ header?: never;
10350
+ path?: never;
10351
+ cookie?: never;
10352
+ };
10353
+ /**
10354
+ * Домен коротких ссылок воркспейса
10355
+ * @description Хост, с которого уходят короткие ссылки этого воркспейса, и зоны, доступные для назначения. ⚠️ Чтение под `mcp:platform-setup`, а не под правом аналитики: ответ содержит список зон ПЛАТФОРМЫ, а не цифры воркспейса.
10356
+ */
10357
+ get: {
10358
+ parameters: {
10359
+ query?: never;
10360
+ header?: never;
10361
+ path: {
10362
+ workspaceId: components["parameters"]["BroadcastWorkspaceId"];
10363
+ };
10364
+ cookie?: never;
10365
+ };
10366
+ requestBody?: never;
10367
+ responses: {
10368
+ /** @description OK */
10369
+ 200: {
10370
+ headers: {
10371
+ [name: string]: unknown;
10372
+ };
10373
+ content: {
10374
+ "application/json": components["schemas"]["WorkspaceLinkDomain"];
10375
+ };
10376
+ };
10377
+ };
10378
+ };
10379
+ /**
10380
+ * Назначить или сбросить домен коротких ссылок
10381
+ * @description `domain: null` возвращает воркспейс на общий домен платформы. ⚠️ Прежний хост остаётся закреплённым за воркспейсом НАВСЕГДА: короткий адрес собирается в момент отправки и вшит в уже разосланные сообщения, поэтому отдать имя другому клиенту нельзя — 409. Смена влияет только на НОВЫЕ ссылки; уже отправленные продолжают открываться на прежнем адресе.
10382
+ */
10383
+ put: {
10384
+ parameters: {
10385
+ query?: never;
10386
+ header?: never;
10387
+ path: {
10388
+ workspaceId: components["parameters"]["BroadcastWorkspaceId"];
10389
+ };
10390
+ cookie?: never;
10391
+ };
10392
+ requestBody: {
10393
+ content: {
10394
+ "application/json": components["schemas"]["UpdateWorkspaceLinkDomainRequest"];
10395
+ };
10396
+ };
10397
+ responses: {
10398
+ /** @description OK */
10399
+ 200: {
10400
+ headers: {
10401
+ [name: string]: unknown;
10402
+ };
10403
+ content: {
10404
+ "application/json": components["schemas"]["WorkspaceLinkDomain"];
10405
+ };
10406
+ };
10407
+ /** @description Домен не проходит правила платформы (зона, формат имени, занятое имя) */
10408
+ 400: {
10409
+ headers: {
10410
+ [name: string]: unknown;
10411
+ };
10412
+ content?: never;
10413
+ };
10414
+ /** @description Хост занят другим воркспейсом, в том числе выведенным из обращения */
10415
+ 409: {
10416
+ headers: {
10417
+ [name: string]: unknown;
10418
+ };
10419
+ content?: never;
10420
+ };
10421
+ };
10422
+ };
10423
+ post?: never;
10424
+ delete?: never;
10425
+ options?: never;
10426
+ head?: never;
10427
+ patch?: never;
10428
+ trace?: never;
10429
+ };
9525
10430
  "/api/v2/workspaces/{workspaceId}/broadcast-analytics": {
9526
10431
  parameters: {
9527
10432
  query?: never;
@@ -9553,6 +10458,8 @@ export interface paths {
9553
10458
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
9554
10459
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
9555
10460
  mechanism?: components["parameters"]["BroadcastMechanism"];
10461
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
10462
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
9556
10463
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
9557
10464
  product?: components["parameters"]["BroadcastProduct"];
9558
10465
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -9561,8 +10468,10 @@ export interface paths {
9561
10468
  freshness?: components["parameters"]["BroadcastFreshness"];
9562
10469
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
9563
10470
  channels?: components["parameters"]["BroadcastChannels"];
9564
- /** @description cohort — дата запуска; period — дата события. */
9565
- view?: "cohort" | "period";
10471
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at). В entry строки без даты входа выпадают всегда, включая mode=all. */
10472
+ view?: "cohort" | "period" | "entry";
10473
+ /** @description day — календарные бакеты; period — один компактный бакет __period__ за весь диапазон. */
10474
+ granularity?: "day" | "period";
9566
10475
  };
9567
10476
  header?: never;
9568
10477
  path: {
@@ -9853,6 +10762,152 @@ export interface paths {
9853
10762
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
9854
10763
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
9855
10764
  mechanism?: components["parameters"]["BroadcastMechanism"];
10765
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
10766
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10767
+ /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10768
+ product?: components["parameters"]["BroadcastProduct"];
10769
+ /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
10770
+ productMode?: components["parameters"]["BroadcastProductMode"];
10771
+ /** @description Корзины свежести лида (мультивыбор). Под фильтром из ВСЕХ метрик выпадают контакты с неизвестным возрастом. Выбраны все корзины = фильтра нет. */
10772
+ freshness?: components["parameters"]["BroadcastFreshness"];
10773
+ /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10774
+ channels?: components["parameters"]["BroadcastChannels"];
10775
+ };
10776
+ header?: never;
10777
+ path: {
10778
+ workspaceId: components["parameters"]["BroadcastWorkspaceId"];
10779
+ };
10780
+ cookie?: never;
10781
+ };
10782
+ requestBody?: never;
10783
+ responses: {
10784
+ /** @description OK */
10785
+ 200: {
10786
+ headers: {
10787
+ [name: string]: unknown;
10788
+ };
10789
+ content: {
10790
+ "application/json": components["schemas"]["BroadcastCohortsResponse"];
10791
+ };
10792
+ };
10793
+ };
10794
+ };
10795
+ put?: never;
10796
+ post?: never;
10797
+ delete?: never;
10798
+ options?: never;
10799
+ head?: never;
10800
+ patch?: never;
10801
+ trace?: never;
10802
+ };
10803
+ "/api/v2/workspaces/{workspaceId}/broadcast-analytics/skip-reasons": {
10804
+ parameters: {
10805
+ query?: never;
10806
+ header?: never;
10807
+ path?: never;
10808
+ cookie?: never;
10809
+ };
10810
+ /** Причины неотправки контактов */
10811
+ get: {
10812
+ parameters: {
10813
+ query?: {
10814
+ mode?: components["parameters"]["BroadcastPeriodMode"];
10815
+ days?: components["parameters"]["BroadcastDays"];
10816
+ /** @description Начальная календарная дата МСК для mode=range. */
10817
+ from?: components["parameters"]["BroadcastFrom"];
10818
+ /** @description Конечная календарная дата МСК для mode=range. */
10819
+ to?: components["parameters"]["BroadcastTo"];
10820
+ platformId?: components["parameters"]["BroadcastPlatformId"];
10821
+ /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10822
+ funnel?: components["parameters"]["BroadcastFunnel"];
10823
+ /** @description Добавляет строки без воронки. Можно сочетать с funnel: значения и NULL объединяются через OR. */
10824
+ funnelMode?: components["parameters"]["BroadcastFunnelMode"];
10825
+ /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10826
+ segment?: components["parameters"]["BroadcastSegment"];
10827
+ /** @description Один или несколько ID именованных вариантов рассылки. */
10828
+ mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10829
+ /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10830
+ mechanism?: components["parameters"]["BroadcastMechanism"];
10831
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
10832
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10833
+ /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10834
+ product?: components["parameters"]["BroadcastProduct"];
10835
+ /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
10836
+ productMode?: components["parameters"]["BroadcastProductMode"];
10837
+ /** @description Корзины свежести лида (мультивыбор). Под фильтром из ВСЕХ метрик выпадают контакты с неизвестным возрастом. Выбраны все корзины = фильтра нет. */
10838
+ freshness?: components["parameters"]["BroadcastFreshness"];
10839
+ /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10840
+ channels?: components["parameters"]["BroadcastChannels"];
10841
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10842
+ view?: components["parameters"]["BroadcastView"];
10843
+ /** @description Конкретный день кликнутой ячейки (МСК). */
10844
+ date?: components["parameters"]["BroadcastDate"];
10845
+ /** @description ID конкретной волны. */
10846
+ importJobId?: components["parameters"]["BroadcastImportJobId"];
10847
+ };
10848
+ header?: never;
10849
+ path: {
10850
+ workspaceId: components["parameters"]["BroadcastWorkspaceId"];
10851
+ };
10852
+ cookie?: never;
10853
+ };
10854
+ requestBody?: never;
10855
+ responses: {
10856
+ /** @description OK */
10857
+ 200: {
10858
+ headers: {
10859
+ [name: string]: unknown;
10860
+ };
10861
+ content: {
10862
+ "application/json": components["schemas"]["BroadcastSkipReasonsResponse"];
10863
+ };
10864
+ };
10865
+ };
10866
+ };
10867
+ put?: never;
10868
+ post?: never;
10869
+ delete?: never;
10870
+ options?: never;
10871
+ head?: never;
10872
+ patch?: never;
10873
+ trace?: never;
10874
+ };
10875
+ "/api/v2/workspaces/{workspaceId}/broadcast-analytics/unique-contacts": {
10876
+ parameters: {
10877
+ query?: never;
10878
+ header?: never;
10879
+ path?: never;
10880
+ cookie?: never;
10881
+ };
10882
+ /**
10883
+ * Уникальных контактов за период (НЕ аддитивно)
10884
+ * @description Сколько РАЗНЫХ людей стоит за «Отправлено» той же выборки. Периметр совпадает с тоталом
10885
+ * sent; отличие только в единице счёта: строка реестра это «волна × контакт», а тут считается
10886
+ * контакт. Складывать по дням/сегментам/продуктам НЕЛЬЗЯ — один человек живёт в каждой группе,
10887
+ * куда ему уходила волна.
10888
+ */
10889
+ get: {
10890
+ parameters: {
10891
+ query?: {
10892
+ mode?: components["parameters"]["BroadcastPeriodMode"];
10893
+ days?: components["parameters"]["BroadcastDays"];
10894
+ /** @description Начальная календарная дата МСК для mode=range. */
10895
+ from?: components["parameters"]["BroadcastFrom"];
10896
+ /** @description Конечная календарная дата МСК для mode=range. */
10897
+ to?: components["parameters"]["BroadcastTo"];
10898
+ platformId?: components["parameters"]["BroadcastPlatformId"];
10899
+ /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10900
+ funnel?: components["parameters"]["BroadcastFunnel"];
10901
+ /** @description Добавляет строки без воронки. Можно сочетать с funnel: значения и NULL объединяются через OR. */
10902
+ funnelMode?: components["parameters"]["BroadcastFunnelMode"];
10903
+ /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10904
+ segment?: components["parameters"]["BroadcastSegment"];
10905
+ /** @description Один или несколько ID именованных вариантов рассылки. */
10906
+ mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10907
+ /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10908
+ mechanism?: components["parameters"]["BroadcastMechanism"];
10909
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
10910
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
9856
10911
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
9857
10912
  product?: components["parameters"]["BroadcastProduct"];
9858
10913
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -9861,6 +10916,8 @@ export interface paths {
9861
10916
  freshness?: components["parameters"]["BroadcastFreshness"];
9862
10917
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
9863
10918
  channels?: components["parameters"]["BroadcastChannels"];
10919
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10920
+ view?: components["parameters"]["BroadcastView"];
9864
10921
  };
9865
10922
  header?: never;
9866
10923
  path: {
@@ -9876,7 +10933,7 @@ export interface paths {
9876
10933
  [name: string]: unknown;
9877
10934
  };
9878
10935
  content: {
9879
- "application/json": components["schemas"]["BroadcastCohortsResponse"];
10936
+ "application/json": components["schemas"]["BroadcastUniqueContacts"];
9880
10937
  };
9881
10938
  };
9882
10939
  };
@@ -9889,14 +10946,20 @@ export interface paths {
9889
10946
  patch?: never;
9890
10947
  trace?: never;
9891
10948
  };
9892
- "/api/v2/workspaces/{workspaceId}/broadcast-analytics/skip-reasons": {
10949
+ "/api/v2/workspaces/{workspaceId}/broadcast-analytics/per-person": {
9893
10950
  parameters: {
9894
10951
  query?: never;
9895
10952
  header?: never;
9896
10953
  path?: never;
9897
10954
  cookie?: never;
9898
10955
  };
9899
- /** Причины неотправки контактов */
10956
+ /**
10957
+ * Итоги верхних карточек по уникальным контактам за период
10958
+ * @description Счётчики верхних карточек «Обзора», дедуплицированные по chat_user_id за весь выбранный
10959
+ * период. Ручная историческая статистика не входит: её агрегированные строки не несут
10960
+ * идентификатора контакта. Денежные суммы не пересчитываются и в этот ответ не включены.
10961
+ * Результат НЕ аддитивен — складывать его по дням или измерениям нельзя.
10962
+ */
9900
10963
  get: {
9901
10964
  parameters: {
9902
10965
  query?: {
@@ -9917,6 +10980,8 @@ export interface paths {
9917
10980
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
9918
10981
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
9919
10982
  mechanism?: components["parameters"]["BroadcastMechanism"];
10983
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
10984
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
9920
10985
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
9921
10986
  product?: components["parameters"]["BroadcastProduct"];
9922
10987
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -9925,12 +10990,8 @@ export interface paths {
9925
10990
  freshness?: components["parameters"]["BroadcastFreshness"];
9926
10991
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
9927
10992
  channels?: components["parameters"]["BroadcastChannels"];
9928
- /** @description cohort — дата запуска; period — дата события. */
10993
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
9929
10994
  view?: components["parameters"]["BroadcastView"];
9930
- /** @description Конкретный день кликнутой ячейки (МСК). */
9931
- date?: components["parameters"]["BroadcastDate"];
9932
- /** @description ID конкретной волны. */
9933
- importJobId?: components["parameters"]["BroadcastImportJobId"];
9934
10995
  };
9935
10996
  header?: never;
9936
10997
  path: {
@@ -9946,7 +11007,7 @@ export interface paths {
9946
11007
  [name: string]: unknown;
9947
11008
  };
9948
11009
  content: {
9949
- "application/json": components["schemas"]["BroadcastSkipReasonsResponse"];
11010
+ "application/json": components["schemas"]["BroadcastPerPersonMetrics"];
9950
11011
  };
9951
11012
  };
9952
11013
  };
@@ -9987,6 +11048,8 @@ export interface paths {
9987
11048
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
9988
11049
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
9989
11050
  mechanism?: components["parameters"]["BroadcastMechanism"];
11051
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11052
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
9990
11053
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
9991
11054
  product?: components["parameters"]["BroadcastProduct"];
9992
11055
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -9995,7 +11058,7 @@ export interface paths {
9995
11058
  freshness?: components["parameters"]["BroadcastFreshness"];
9996
11059
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
9997
11060
  channels?: components["parameters"]["BroadcastChannels"];
9998
- /** @description cohort — дата запуска; period — дата события. */
11061
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
9999
11062
  view?: components["parameters"]["BroadcastView"];
10000
11063
  /** @description Конкретный день кликнутой ячейки (МСК). */
10001
11064
  date?: components["parameters"]["BroadcastDate"];
@@ -10009,8 +11072,13 @@ export interface paths {
10009
11072
  sortBy?: components["parameters"]["BroadcastRecipientSortBy"];
10010
11073
  /** @description Направление серверной сортировки списка получателей. */
10011
11074
  sortOrder?: components["parameters"]["BroadcastRecipientSortOrder"];
11075
+ /** @description Сузить выборку одной отслеживаемой ссылкой. Уточнение оператора внутри окна: применяется и к списку, и к счётчику — «показано N из M» обязано сходиться. */
11076
+ linkId?: string;
10012
11077
  metric: "sent" | "delivered" | "entered" | "deepDialog" | "linkIssued" | "clicked" | "handedOff" | "notDelivered" | "notSent";
10013
- reason?: "NO_MESSENGER" | "ACTIVE_INVOICE_SAME_PRODUCT" | "ACTIVE_DEAL_SAME_PRODUCT" | "PAID_SAME_PRODUCT" | "ACTIVE_DEAL_OTHER_PRODUCT" | "MANAGER_ASSIGNED_ACTIVE_DEAL" | "PRODUCT_CONTEXT_MISSING" | "GETCOURSE_CHECK_ERROR" | "ALREADY_SENT" | "USER_NOT_FOUND";
11078
+ /** @description Откуда брать неотправленных при metric=notSent: preflight — проверка волны школы, schedule — журнал подач авторассылки, ownSend — след отсева ручной холодной отправки. Причины трёх источников живут в разных таблицах. У ownSend список бывает короче числа причины: число — агрегат задачи и полно за всю историю, а построчный след начинается с выкатки (см. tracedCount у причины). */
11079
+ reasonSource?: "preflight" | "schedule" | "ownSend";
11080
+ /** @description Код причины неотправки. Словарь выбирает reasonSource: у preflight это GetCourseWavePreflightReason (NO_MESSENGER, ALREADY_SENT, USER_NOT_FOUND и т.д. — другой код там отвергается, потому что значение кастуется в enum прямо в SQL); у schedule это исход подачи, у ownSend — исход прогона (SKIPPED_BOT_SILENCED и т.д.), и у этих двух проверяется только форма кода: заглавные латинские буквы, цифры и подчёркивания. */
11081
+ reason?: string;
10014
11082
  };
10015
11083
  header?: never;
10016
11084
  path: {
@@ -10067,6 +11135,8 @@ export interface paths {
10067
11135
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10068
11136
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10069
11137
  mechanism?: components["parameters"]["BroadcastMechanism"];
11138
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11139
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10070
11140
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10071
11141
  product?: components["parameters"]["BroadcastProduct"];
10072
11142
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10075,7 +11145,7 @@ export interface paths {
10075
11145
  freshness?: components["parameters"]["BroadcastFreshness"];
10076
11146
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10077
11147
  channels?: components["parameters"]["BroadcastChannels"];
10078
- /** @description cohort — дата запуска; period — дата события. */
11148
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10079
11149
  view?: components["parameters"]["BroadcastView"];
10080
11150
  /** @description Конкретный день кликнутой ячейки (МСК). */
10081
11151
  date?: components["parameters"]["BroadcastDate"];
@@ -10146,6 +11216,8 @@ export interface paths {
10146
11216
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10147
11217
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10148
11218
  mechanism?: components["parameters"]["BroadcastMechanism"];
11219
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11220
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10149
11221
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10150
11222
  product?: components["parameters"]["BroadcastProduct"];
10151
11223
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10154,7 +11226,7 @@ export interface paths {
10154
11226
  freshness?: components["parameters"]["BroadcastFreshness"];
10155
11227
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10156
11228
  channels?: components["parameters"]["BroadcastChannels"];
10157
- /** @description cohort — дата запуска; period — дата события. */
11229
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10158
11230
  view?: components["parameters"]["BroadcastView"];
10159
11231
  /** @description Конкретный день кликнутой ячейки (МСК). */
10160
11232
  date?: components["parameters"]["BroadcastDate"];
@@ -10222,6 +11294,8 @@ export interface paths {
10222
11294
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10223
11295
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10224
11296
  mechanism?: components["parameters"]["BroadcastMechanism"];
11297
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11298
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10225
11299
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10226
11300
  product?: components["parameters"]["BroadcastProduct"];
10227
11301
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10230,7 +11304,7 @@ export interface paths {
10230
11304
  freshness?: components["parameters"]["BroadcastFreshness"];
10231
11305
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10232
11306
  channels?: components["parameters"]["BroadcastChannels"];
10233
- /** @description cohort — дата запуска; period — дата события. */
11307
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10234
11308
  view?: components["parameters"]["BroadcastView"];
10235
11309
  /** @description Конкретный день кликнутой ячейки (МСК). */
10236
11310
  date?: components["parameters"]["BroadcastDate"];
@@ -10238,6 +11312,10 @@ export interface paths {
10238
11312
  channel?: components["parameters"]["BroadcastChannel"];
10239
11313
  /** @description ID конкретной волны. */
10240
11314
  importJobId?: components["parameters"]["BroadcastImportJobId"];
11315
+ /** @description Колонка сортировки косвенных оплат — те же, что у вкладки «Оплаты», минус `confidence`/`matchReason`: атрибуции по сделке у кандидата нет, её признал оператор. */
11316
+ sortBy?: components["parameters"]["BroadcastIndirectSortBy"];
11317
+ /** @description Направление серверной сортировки списка сделок и оплат. */
11318
+ sortOrder?: components["parameters"]["BroadcastDealSortOrder"];
10241
11319
  page?: components["parameters"]["BroadcastPage"];
10242
11320
  pageSize?: components["parameters"]["BroadcastPageSize"];
10243
11321
  };
@@ -10296,6 +11374,8 @@ export interface paths {
10296
11374
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10297
11375
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10298
11376
  mechanism?: components["parameters"]["BroadcastMechanism"];
11377
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11378
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10299
11379
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10300
11380
  product?: components["parameters"]["BroadcastProduct"];
10301
11381
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10304,7 +11384,7 @@ export interface paths {
10304
11384
  freshness?: components["parameters"]["BroadcastFreshness"];
10305
11385
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10306
11386
  channels?: components["parameters"]["BroadcastChannels"];
10307
- /** @description cohort — дата запуска; period — дата события. */
11387
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10308
11388
  view?: components["parameters"]["BroadcastView"];
10309
11389
  /** @description Конкретный день кликнутой ячейки (МСК). */
10310
11390
  date?: components["parameters"]["BroadcastDate"];
@@ -10370,6 +11450,8 @@ export interface paths {
10370
11450
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10371
11451
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10372
11452
  mechanism?: components["parameters"]["BroadcastMechanism"];
11453
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11454
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10373
11455
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10374
11456
  product?: components["parameters"]["BroadcastProduct"];
10375
11457
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10378,7 +11460,7 @@ export interface paths {
10378
11460
  freshness?: components["parameters"]["BroadcastFreshness"];
10379
11461
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10380
11462
  channels?: components["parameters"]["BroadcastChannels"];
10381
- /** @description cohort — дата запуска; period — дата события. */
11463
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10382
11464
  view?: components["parameters"]["BroadcastView"];
10383
11465
  };
10384
11466
  header?: never;
@@ -10436,6 +11518,8 @@ export interface paths {
10436
11518
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10437
11519
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10438
11520
  mechanism?: components["parameters"]["BroadcastMechanism"];
11521
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11522
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10439
11523
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10440
11524
  product?: components["parameters"]["BroadcastProduct"];
10441
11525
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10444,7 +11528,7 @@ export interface paths {
10444
11528
  freshness?: components["parameters"]["BroadcastFreshness"];
10445
11529
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10446
11530
  channels?: components["parameters"]["BroadcastChannels"];
10447
- /** @description cohort — дата запуска; period — дата события. */
11531
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10448
11532
  view?: components["parameters"]["BroadcastView"];
10449
11533
  };
10450
11534
  header?: never;
@@ -10502,6 +11586,8 @@ export interface paths {
10502
11586
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10503
11587
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10504
11588
  mechanism?: components["parameters"]["BroadcastMechanism"];
11589
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11590
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10505
11591
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10506
11592
  product?: components["parameters"]["BroadcastProduct"];
10507
11593
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10510,7 +11596,7 @@ export interface paths {
10510
11596
  freshness?: components["parameters"]["BroadcastFreshness"];
10511
11597
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10512
11598
  channels?: components["parameters"]["BroadcastChannels"];
10513
- /** @description cohort — дата запуска; period — дата события. */
11599
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10514
11600
  view?: components["parameters"]["BroadcastView"];
10515
11601
  };
10516
11602
  header?: never;
@@ -10568,6 +11654,8 @@ export interface paths {
10568
11654
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10569
11655
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10570
11656
  mechanism?: components["parameters"]["BroadcastMechanism"];
11657
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11658
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10571
11659
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10572
11660
  product?: components["parameters"]["BroadcastProduct"];
10573
11661
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10576,7 +11664,7 @@ export interface paths {
10576
11664
  freshness?: components["parameters"]["BroadcastFreshness"];
10577
11665
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10578
11666
  channels?: components["parameters"]["BroadcastChannels"];
10579
- /** @description cohort — дата запуска; period — дата события. */
11667
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
10580
11668
  view?: components["parameters"]["BroadcastView"];
10581
11669
  };
10582
11670
  header?: never;
@@ -10637,6 +11725,8 @@ export interface paths {
10637
11725
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10638
11726
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10639
11727
  mechanism?: components["parameters"]["BroadcastMechanism"];
11728
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11729
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10640
11730
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10641
11731
  product?: components["parameters"]["BroadcastProduct"];
10642
11732
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -10646,7 +11736,9 @@ export interface paths {
10646
11736
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
10647
11737
  channels?: components["parameters"]["BroadcastChannels"];
10648
11738
  /** @description Сегмент очереди. `resolved` = `confirmed` + `rejected` одним списком; UI пользуется раздельными сегментами, выгрузке чаще нужен общий. */
10649
- view?: "decidable" | "external_mailing" | "excluded" | "confirmed" | "rejected" | "resolved";
11739
+ view?: "decidable" | "external_mailing" | "excluded" | "confirmed" | "rejected" | "resolved" | "potential";
11740
+ /** @description Режим атрибуции для сегмента `potential`: `cohort` датирует по волне, `period` — по оплате. Отдельное имя потому, что `view` занят сегмент-переключателем; остальные сегменты параметр игнорируют. */
11741
+ attributionView?: "cohort" | "period";
10650
11742
  status?: components["schemas"]["PaymentCandidateStatus"];
10651
11743
  eligibility?: components["schemas"]["PaymentCandidateEligibility"];
10652
11744
  /** @description Кем принято решение: `human` — пользователь в вебе или оператор в Telegram, `script` — служебный прогон сверки. Сужает выбранное `view`, а не заменяет его. */
@@ -10712,6 +11804,8 @@ export interface paths {
10712
11804
  mailingVariantId?: components["parameters"]["BroadcastMailingVariantId"];
10713
11805
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
10714
11806
  mechanism?: components["parameters"]["BroadcastMechanism"];
11807
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
11808
+ launchSource?: components["parameters"]["BroadcastLaunchSource"];
10715
11809
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
10716
11810
  product?: components["parameters"]["BroadcastProduct"];
10717
11811
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
@@ -14936,6 +16030,26 @@ export interface paths {
14936
16030
  patch?: never;
14937
16031
  trace?: never;
14938
16032
  };
16033
+ "/api/v2/workspaces/{workspaceId}/amocrm/channel-registration": {
16034
+ parameters: {
16035
+ query?: never;
16036
+ header?: never;
16037
+ path?: never;
16038
+ cookie?: never;
16039
+ };
16040
+ /**
16041
+ * AmoCRM chat-channel registration request (webhook URL + support email template)
16042
+ * @description Чтобы переписка бота появлялась в карточке сделки AmoCRM, их поддержка должна ЗАРЕГИСТРИРОВАТЬ канал по письму заданной формы; channelId/channelSecretKey выдают только так. Текст письма и адрес вебхука собирает бэкенд (канон ai-aniomaly/src/core/application/crms/amocrm/constants/amocrm-channel-registration.constants.ts) — тем же ответом пользуется страница AmoCRM в интерфейсе. Копий у клиентов нет намеренно: письмо регистрирует адрес, на который потом идут входящие, и разошедшийся текст дал бы канал, смотрящий не туда, — это обнаружилось бы только пропажей сообщений.
16043
+ */
16044
+ get: operations["getAmoCrmChannelRegistration"];
16045
+ put?: never;
16046
+ post?: never;
16047
+ delete?: never;
16048
+ options?: never;
16049
+ head?: never;
16050
+ patch?: never;
16051
+ trace?: never;
16052
+ };
14939
16053
  "/api/v2/workspaces/{workspaceId}/crms/{crmId}/field-mapping": {
14940
16054
  parameters: {
14941
16055
  query?: never;
@@ -18238,10 +19352,201 @@ export interface paths {
18238
19352
  patch?: never;
18239
19353
  trace?: never;
18240
19354
  };
19355
+ "/api/v2/workspaces/{workspaceId}/custom-reports/{reportId}/report": {
19356
+ parameters: {
19357
+ query?: never;
19358
+ header?: never;
19359
+ path?: never;
19360
+ cookie?: never;
19361
+ };
19362
+ /**
19363
+ * Живой расчёт сохранённой таблицы за период
19364
+ * @description Для источника «Перс воронка» дополнительно возвращает единый snapshot: calculatedAt, executionDbSnapshot, currentStepsFingerprint и reportUpdatedAt. Все четыре значения нужно без изменений передать в drill-down; у legacy-источников snapshot-поля отсутствуют.
19365
+ */
19366
+ get: operations["getCustomReportData"];
19367
+ put?: never;
19368
+ post?: never;
19369
+ delete?: never;
19370
+ options?: never;
19371
+ head?: never;
19372
+ patch?: never;
19373
+ trace?: never;
19374
+ };
19375
+ "/api/v2/workspaces/{workspaceId}/custom-reports/{reportId}/drilldown": {
19376
+ parameters: {
19377
+ query?: never;
19378
+ header?: never;
19379
+ path?: never;
19380
+ cookie?: never;
19381
+ };
19382
+ /**
19383
+ * Контакты и сделки за числом сохранённой таблицы
19384
+ * @description Возвращает конкретные исполнения, контакты или сделки за числовой ячейкой источников «Обзор», «Фоллоу-апы» и «Перс воронка». Сервер перечитывает определение отчёта и проверяет updatedAt; сводная передаёт полный путь строки. Snapshot и fingerprint обязательны только для personalized-источника. Для процентной колонки раскрывается фактический числитель.
19385
+ */
19386
+ get: operations["getCustomReportDrilldown"];
19387
+ put?: never;
19388
+ post?: never;
19389
+ delete?: never;
19390
+ options?: never;
19391
+ head?: never;
19392
+ patch?: never;
19393
+ trace?: never;
19394
+ };
18241
19395
  }
18242
19396
  export type webhooks = Record<string, never>;
18243
19397
  export interface components {
18244
19398
  schemas: {
19399
+ TriggerContactClaim: {
19400
+ /** Format: uuid */
19401
+ triggerId: string;
19402
+ triggerName: string;
19403
+ /** Format: uuid */
19404
+ agentId: string;
19405
+ agentName: string | null;
19406
+ /** @enum {string} */
19407
+ status: "IN_PROGRESS" | "COMPLETED";
19408
+ /** Format: date-time */
19409
+ claimedAt: string;
19410
+ /** @description false у status=IN_PROGRESS — право держит владелец */
19411
+ canReset: boolean;
19412
+ /** @enum {string|null} */
19413
+ blockedReason: "RUNNING" | null;
19414
+ triggerIsEnabled: boolean;
19415
+ /** @description Осталась ли включённой настройка «сработать один раз». Право переживает её выключение: тогда строка висит, но триггер срабатывает как обычный. */
19416
+ stillOneTime: boolean;
19417
+ };
19418
+ TriggerContactClaimsPage: {
19419
+ claims: components["schemas"]["TriggerContactClaim"][];
19420
+ truncated: boolean;
19421
+ };
19422
+ ResetTriggerClaimRequest: {
19423
+ /**
19424
+ * @description Обязательное подтверждение: триггер сможет повторить необратимые действия во внешних системах. Проверяется на сервере, а не только в MCP-клиенте.
19425
+ * @enum {boolean}
19426
+ */
19427
+ explicitConfirmation: true;
19428
+ };
19429
+ CustomReportMetricValues: {
19430
+ [key: string]: number | null;
19431
+ };
19432
+ CustomReportBucket: {
19433
+ /** Format: date */
19434
+ key: string;
19435
+ /** Format: date */
19436
+ from: string;
19437
+ /** Format: date */
19438
+ to: string;
19439
+ partial: boolean;
19440
+ rows: {
19441
+ [key: string]: components["schemas"]["CustomReportMetricValues"];
19442
+ };
19443
+ total: components["schemas"]["CustomReportMetricValues"];
19444
+ comparableReliable?: boolean;
19445
+ };
19446
+ CustomReportGrandTotal: {
19447
+ /** Format: date */
19448
+ from: string;
19449
+ /** Format: date */
19450
+ to: string;
19451
+ rows: {
19452
+ [key: string]: components["schemas"]["CustomReportMetricValues"];
19453
+ };
19454
+ total: components["schemas"]["CustomReportMetricValues"];
19455
+ comparableReliable?: boolean;
19456
+ };
19457
+ CustomReportDrilldownSnapshot: {
19458
+ /** Format: date-time */
19459
+ calculatedAt: string;
19460
+ executionDbSnapshot: string;
19461
+ currentStepsFingerprint: string;
19462
+ /** Format: date-time */
19463
+ reportUpdatedAt: string;
19464
+ };
19465
+ CustomReportStepSchedule: {
19466
+ /** @enum {string} */
19467
+ kind: "offset" | "clock" | "beforeMeeting" | "unknown";
19468
+ minutes?: number;
19469
+ dayOffset?: number;
19470
+ atTime?: string;
19471
+ };
19472
+ CustomReportDataResponse: {
19473
+ metricKeys: string[];
19474
+ dimensionValues: string[];
19475
+ buckets: components["schemas"]["CustomReportBucket"][];
19476
+ grandTotal: components["schemas"]["CustomReportGrandTotal"] | null;
19477
+ availableDimensionValues: string[];
19478
+ availableMetricKeys: string[];
19479
+ dimensionLabels?: {
19480
+ [key: string]: string;
19481
+ };
19482
+ rowSequenceNames?: {
19483
+ [key: string]: string;
19484
+ };
19485
+ /** @description Только personalized-funnel: безопасное расписание шага по адресу строки. Текст сообщения, условия, variable hints и вложения не возвращаются. */
19486
+ rowStepSchedules?: {
19487
+ [key: string]: components["schemas"]["CustomReportStepSchedule"];
19488
+ };
19489
+ /** Format: date-time */
19490
+ historyStartsAt?: string | null;
19491
+ nestedRows?: {
19492
+ [key: string]: unknown;
19493
+ }[];
19494
+ nestedTruncated?: boolean;
19495
+ nestedTotalRowCount?: number;
19496
+ /** Format: date-time */
19497
+ calculatedAt?: string;
19498
+ executionDbSnapshot?: string;
19499
+ currentStepsFingerprint?: string;
19500
+ /** Format: date-time */
19501
+ reportUpdatedAt?: string;
19502
+ };
19503
+ CustomReportDrilldownLink: {
19504
+ /** @description Идентификатор выдачи ссылки; для агрегированных источников может быть составным. */
19505
+ issueId: string;
19506
+ name: string;
19507
+ /** Format: uri */
19508
+ targetUrl: string;
19509
+ /** Format: date-time */
19510
+ clickedAt: string | null;
19511
+ };
19512
+ CustomReportDrilldownRow: {
19513
+ id: string;
19514
+ /** Format: uuid */
19515
+ chatUserId: string | null;
19516
+ contactName: string | null;
19517
+ contactPhone: string | null;
19518
+ /** Format: date-time */
19519
+ happenedAt: string | null;
19520
+ status: string | null;
19521
+ failedCondition: string | null;
19522
+ failedValue: string | null;
19523
+ /** Format: uri */
19524
+ getcourseUserUrl: string | null;
19525
+ /** Format: uri */
19526
+ getcourseDealUrl: string | null;
19527
+ /**
19528
+ * Format: uri
19529
+ * @description Сделка/лид в активной AmoCRM или Bitrix24.
19530
+ */
19531
+ crmUrl: string | null;
19532
+ links: components["schemas"]["CustomReportDrilldownLink"][];
19533
+ };
19534
+ CustomReportDrilldownResponse: {
19535
+ items: components["schemas"]["CustomReportDrilldownRow"][];
19536
+ total: number;
19537
+ /** @description Фактический числитель для процентной колонки. */
19538
+ resolvedMetricKey: string;
19539
+ };
19540
+ /**
19541
+ * @description Минимальная длина включительного period-окна, на котором считаются доли исходов custom-reports и карточек «Обзора». Литеральный тип механически связывает backend и frontend через сгенерированный API-контракт.
19542
+ * @enum {integer}
19543
+ */
19544
+ CustomReportOutcomeRateMinWindowDays: 21;
19545
+ /**
19546
+ * @description Канонические доли исходов, которые в period-режиме доступны только на окне не короче CustomReportOutcomeRateMinWindowDays. Исчерпывающие backend/frontend-реестры типизированы этим enum, поэтому удаление или добавление ключа только на одной стороне ломает компиляцию.
19547
+ * @enum {string}
19548
+ */
19549
+ CustomReportOutcomeRateMetric: "clickedRate" | "enteredDialogRate" | "replyRate" | "deepDialogRate" | "handedRate" | "paidRate";
18245
19550
  UpdateDialogScriptRequest: {
18246
19551
  /** @description Вводная проза §6 до первой ветки (опц.) */
18247
19552
  preamble?: string;
@@ -18315,8 +19620,7 @@ export interface components {
18315
19620
  contactId: string;
18316
19621
  /** @description Registration deal id для свежего пина Шага 1 */
18317
19622
  dealId?: string;
18318
- /** @enum {string} */
18319
- transport?: "VK" | "Telegram" | "MAX" | "SMS" | "Email" | "Site";
19623
+ transport?: components["schemas"]["GetCourseTransport"];
18320
19624
  dialogId?: string;
18321
19625
  /** Format: email */
18322
19626
  email?: string;
@@ -18358,7 +19662,11 @@ export interface components {
18358
19662
  * @enum {string}
18359
19663
  */
18360
19664
  launchType: "status";
18361
- channels: ("VK" | "Telegram" | "MAX" | "SMS" | "Email" | "Site")[];
19665
+ channels: components["schemas"]["GetCourseTransport"][];
19666
+ /**
19667
+ * @description Воронка ШКОЛЫ в форме «f11 — ДБО / NR / ВК / In Stream» — код fNN обязателен. ⚠️ Это НЕ когорта и НЕ подпись запуска: «reg-no-show», «post-web|дбо» сюда класть нельзя — тип отбора идёт в segment, продукт в productCode, подпись запуска в cohortLabel. Ось «Воронка» сравнивается по коду, поэтому значение без кода становится отдельной «воронкой» и засоряет фильтр аналитики.
19668
+ * @example f11 — ДБО / NR / ВК / In Stream
19669
+ */
18362
19670
  funnel?: string;
18363
19671
  segment?: string;
18364
19672
  /** @description Явное бизнес-правило отбора; требует segment. */
@@ -18401,19 +19709,307 @@ export interface components {
18401
19709
  /** @description Разрешён ли server-side intentional repeat (`dedupWindowDays=0`). */
18402
19710
  repeatEnabled: boolean;
18403
19711
  /** Format: uuid */
18404
- runId?: string;
19712
+ runId?: string;
19713
+ totalContacts: number;
19714
+ pendingContacts: number;
19715
+ skippedAlreadySent: number;
19716
+ /** @description Сколько контактов когда-либо имели подтверждённую отправку. */
19717
+ historicalConfirmedCount: number;
19718
+ /** @description Контакты с живым либо неопределённым исходом другого прогона. */
19719
+ unsafeBlockedCount: number;
19720
+ chunkSize: number;
19721
+ /** @description Snapshot для идемпотентного confirm. */
19722
+ dryRunHash: string;
19723
+ state?: components["schemas"]["GetCourseWaveRunState"];
19724
+ };
19725
+ GetCourseColdWelcomeContact: {
19726
+ /** @description getcourse_user_id контакта. */
19727
+ contactId: string;
19728
+ /** @description Пин заказа для штампа полей сделки. */
19729
+ dealId?: string;
19730
+ /**
19731
+ * Format: date-time
19732
+ * @description Точный момент входа контакта в когорту (ISO 8601, зона ОБЯЗАТЕЛЬНА — …Z либо ±ЧЧ:ММ). На нём считается свежесть в «Аналитике рассылок»: возраст = время отправки минус segmentEnteredAt. Заполняется, когда предсписок собран ПРАВИЛОМ и у каждой строки есть свой момент события (например eventAt регистрации). Не передан — возраст строки остаётся неизвестным. Дату запуска сюда подставлять нельзя: она схлопнула бы месяцы когорт в одну корзину.
19733
+ */
19734
+ segmentEnteredAt?: string;
19735
+ /** @description Воронка ЭТОГО контакта (например «f11 — ДБО / NR / ВК / In Stream»). Заполняется, когда файл собран из НЕСКОЛЬКИХ воронок: одна метка на запуск заставляла писать в поле воронки когорту («reg-no-show|дбо»), и фильтр по воронке переставал отвечать на свой вопрос — по f11 он показывал ноль отправок за 30 дней при 3267 регистрациях (замер 02.09.2026). Когорта и продукт лежат в своих полях segment и productCode. Не передана — берётся воронка запуска (funnel). */
19736
+ funnel?: string;
19737
+ };
19738
+ /** @description Ровно одна аудитория — createdAfter ЛИБО contacts. */
19739
+ GetCourseColdWelcomePreviewRequest: {
19740
+ /** Format: uuid */
19741
+ platformId: string;
19742
+ /**
19743
+ * Format: uuid
19744
+ * @description Источник каналов и «Платформы по умолчанию».
19745
+ */
19746
+ mailingVariantId?: string;
19747
+ /**
19748
+ * Format: date-time
19749
+ * @description Аудитория «по дате» — нижняя граница даты создания контакта.
19750
+ */
19751
+ createdAfter?: string;
19752
+ contacts?: components["schemas"]["GetCourseColdWelcomeContact"][];
19753
+ channels?: components["schemas"]["GetCourseTransport"][];
19754
+ /** @deprecated */
19755
+ channelsMode?: components["schemas"]["ColdWelcomeChannelsMode"];
19756
+ };
19757
+ /**
19758
+ * @deprecated
19759
+ * @description ⚠️ УСТАРЕЛО и на поведение НЕ влияет (с 23.08.2026). Режим применялся ко ВСЕМУ списку сразу, из-за чего отметка Email годами оставалась молчаливым no-op. Теперь список channels значит «слать сюда», а судьбу каждого канала решает сервер: мессенджер (Telegram/VK/MAX) уходит, только если школа подтвердила его наличие у контакта; SMS — только при известном телефоне; Email, WhatsApp, Viber, Сайт, Chatium уходят вслепую. Поле принимается ради обратной совместимости и игнорируется.
19760
+ * @enum {string}
19761
+ */
19762
+ ColdWelcomeChannelsMode: "RESTRICT" | "ADD";
19763
+ GetCourseColdWelcomePreviewResponse: {
19764
+ /** @description Выбранные каналы, которых НЕТ в allowlist площадки: они не уедут ни в каком режиме. Чинится галочкой в настройках площадки, поэтому возвращаются ИМЕНАМИ, а не числом. */
19765
+ channelsNotAllowedByPlatform?: components["schemas"]["GetCourseTransport"][];
19766
+ /** @description Сколько ещё МОЖЕТ получить первое сообщение. */
19767
+ totalContacts: number;
19768
+ /** @description Уже получали — приветствие одноразово НА КОНТАКТ, а не на рассылку. */
19769
+ alreadyWelcomed: number;
19770
+ /** @description Всего найдено под границей. */
19771
+ foundContacts: number;
19772
+ /** @description Строк файла БЕЗ момента входа в сегмент (segment_entered_at). Такой контакт не попадёт ни в один период оси «вход в сегмент» на «Аналитике коммуникации» — он невидим ровно там, где спрашивают «сколько людей пришло за месяц». Предупреждение, а не запрет: у аудитории, заданной границей даты или файлом без события, момента входа нет вовсе. Считается по СЫРЫМ строкам запроса, чтобы число сходилось с файлом. */
19773
+ rowsWithoutSegmentEntry?: number;
19774
+ };
19775
+ /** @description Не больше ОДНОЙ аудитории: contacts (поимённый список) ЛИБО currentAnchorValue (когорта). Без обеих — вся площадка (все контакты с непустым якорем). */
19776
+ GetCourseAnchorRefreshRequest: {
19777
+ /**
19778
+ * Format: uuid
19779
+ * @description Обязателен: набор перечитываемых якорей площадочный — якоря включённых календарных цепочек, пересечённые с картой полей сделки.
19780
+ */
19781
+ platformId: string;
19782
+ /** @description Когортным предикатом НЕ фильтруется — оператор назвал этих людей поимённо. */
19783
+ contacts?: components["schemas"]["GetCourseColdWelcomeContact"][];
19784
+ /** @description Только контакты, чей якорь СЕЙЧАС равен этой дате — случай «эфир 19.08 перенесли». Сравнение по КАЛЕНДАРНОМУ ДНЮ: «19.08.2026» и «2026-08-19» — одна дата. Неразбираемое значение отвергается 400, а не даёт пустой прогон. */
19785
+ currentAnchorValue?: string;
19786
+ };
19787
+ GetCourseAnchorRefreshPreviewResponse: {
19788
+ /** @description Якоря включённых календарных цепочек площадки. */
19789
+ anchorVariables: string[];
19790
+ /** @description Из них замаплены на поля сделки — только эти прогон и перечитает. Пустой список означает «перечитывать нечем». */
19791
+ refreshableVariables: string[];
19792
+ contactsMatched: number;
19793
+ /** @description Им прогон откажет (SKIPPED_NO_PINNED_DEAL). */
19794
+ withoutPinnedDeal: number;
19795
+ /** @description Строк присланного списка, которым не нашлось контакта в базе площадки (только файловая аудитория). «Прислали 500, найдено 200» — сначала импорт контактов. */
19796
+ notInBase: number;
19797
+ /** @description Переменная → текущее значение → сколько контактов его несут. */
19798
+ currentValues: {
19799
+ [key: string]: {
19800
+ [key: string]: number;
19801
+ };
19802
+ };
19803
+ };
19804
+ GetCourseAnchorRefreshStartResponse: {
19805
+ /** @description Отдаётся ВСЕГДА, включая отказные ветки: по нему ищутся итоги в логах и строки audit_logs этого прогона. */
19806
+ correlationId: string;
19807
+ started: boolean;
19808
+ /** @description По этой площадке прогон уже идёт — второй не запускается. */
19809
+ alreadyRunning: boolean;
19810
+ refreshableVariables: string[];
19811
+ };
19812
+ /** @description Ровно один источник текста (message ЛИБО mailingVariantId) и ровно одна аудитория (createdAfter ЛИБО contacts). */
19813
+ GetCourseColdWelcomeLaunchRequest: {
19814
+ /**
19815
+ * Format: uuid
19816
+ * @description Можно опустить, если у рассылки задана «Платформа по умолчанию».
19817
+ */
19818
+ platformId?: string;
19819
+ /** Format: date-time */
19820
+ createdAfter?: string;
19821
+ contacts?: components["schemas"]["GetCourseColdWelcomeContact"][];
19822
+ /** @description Разовый текст запуска. */
19823
+ message?: string;
19824
+ /**
19825
+ * Format: uuid
19826
+ * @description Сохранённая рассылка — текст и метки берутся из неё.
19827
+ */
19828
+ mailingVariantId?: string;
19829
+ /** @description Ключ — числовой fieldId GetCourse. Штампуются ПОСЛЕ успешной отправки. Пустой объект НЕ равен отсутствию ключа: он означает «на этом запуске без полей» и гасит дефолты. */
19830
+ dealFields?: {
19831
+ [key: string]: string | number | boolean | null;
19832
+ };
19833
+ /** @description Метка сегмента. Аудиторию НЕ отбирает. Если у рассылки есть текст именно для этого сегмента, он выбирает текст запуска — и тогда аудитория обязана быть файловой. */
19834
+ segment?: string;
19835
+ productCode?: string;
19836
+ /**
19837
+ * @description Воронка ШКОЛЫ в форме «f11 — ДБО / NR / ВК / In Stream» — код fNN обязателен. ⚠️ Это НЕ когорта и НЕ подпись запуска: «reg-no-show», «post-web|дбо» сюда класть нельзя — тип отбора идёт в segment, продукт в productCode, подпись запуска в cohortLabel. Ось «Воронка» сравнивается по коду, поэтому значение без кода становится отдельной «воронкой» и засоряет фильтр аналитики.
19838
+ * @example f11 — ДБО / NR / ВК / In Stream
19839
+ */
19840
+ funnel?: string;
19841
+ /** @description Человекочитаемое имя ЭТОГО запуска — подпись когорты в «Аналитике рассылок». Не имя рассылки и не метка сегмента: те одинаковы у всех запусков, а разрез «по запускам» строится именно по подписи. Пусто — подпись собирается из даты запуска, имени рассылки и меток, так что запуски всё равно остаются различимыми. */
19842
+ cohortLabel?: string;
19843
+ channels?: components["schemas"]["GetCourseTransport"][];
19844
+ /** @deprecated */
19845
+ channelsMode?: components["schemas"]["ColdWelcomeChannelsMode"];
19846
+ };
19847
+ GetCourseColdWelcomeLaunchResponse: {
19848
+ /** Format: uuid */
19849
+ jobId: string;
19850
+ totalContacts: number;
19851
+ };
19852
+ GetCourseColdWelcomeBatchSegment: {
19853
+ /** @description Он же выбирает текст, если у рассылки есть посегментные тексты. */
19854
+ segment?: string;
19855
+ productCode?: string;
19856
+ /**
19857
+ * @description Воронка ШКОЛЫ в форме «f11 — ДБО / NR / ВК / In Stream» — код fNN обязателен. ⚠️ Это НЕ когорта и НЕ подпись запуска: «reg-no-show», «post-web|дбо» сюда класть нельзя — тип отбора идёт в segment, продукт в productCode, подпись запуска в cohortLabel. Ось «Воронка» сравнивается по коду, поэтому значение без кода становится отдельной «воронкой» и засоряет фильтр аналитики.
19858
+ * @example f11 — ДБО / NR / ВК / In Stream
19859
+ */
19860
+ funnel?: string;
19861
+ /** @description Подпись запуска ЭТОГО блока. У пакета каждый сегмент — отдельный запуск со своей задачей и когортой, поэтому подпись задаётся посегментно; общая на пакет схлопнула бы их в отчёте в одну корзину. */
19862
+ cohortLabel?: string;
19863
+ dealFields?: {
19864
+ [key: string]: string | number | boolean | null;
19865
+ };
19866
+ contacts: components["schemas"]["GetCourseColdWelcomeContact"][];
19867
+ };
19868
+ /** @description Ровно один источник текста — message ЛИБО mailingVariantId. */
19869
+ GetCourseColdWelcomeBatchRequest: {
19870
+ /** Format: uuid */
19871
+ platformId?: string;
19872
+ message?: string;
19873
+ /** Format: uuid */
19874
+ mailingVariantId?: string;
19875
+ segments: components["schemas"]["GetCourseColdWelcomeBatchSegment"][];
19876
+ /** @description Политика на ВЕСЬ пакет, снимок на старте. Ключ не передан — дефолт рассылки; пустой массив — без политики. */
19877
+ channels?: components["schemas"]["GetCourseTransport"][];
19878
+ /** @deprecated */
19879
+ channelsMode?: components["schemas"]["ColdWelcomeChannelsMode"];
19880
+ /** @description Перекрытие предохранителей на ЭТОТ пакет (аварийный обход). Ключ не передан — берётся настройка площадки. Снимок кладётся в строку durable-плана, поэтому resume после рестарта едет с тем же решением. */
19881
+ guards?: components["schemas"]["OutboundGuardModes"];
19882
+ };
19883
+ /** @description Предохранители холодных отправок. Не писать, пока идёт вебинарная серия человека, пока с ним работает менеджер по действующей заявке и если он уже оплатил ЭТОТ продукт. Пропуск ключа = не трогать; null = «не настраивали» (действует дефолт: activeSeries BLOCK, остальные WARN). Подробности — docs/features/outbound-guards.md. */
19884
+ OutboundGuardModes: {
19885
+ activeSeries?: components["schemas"]["OutboundGuardMode"];
19886
+ activeApplication?: components["schemas"]["OutboundGuardMode"];
19887
+ paid?: components["schemas"]["OutboundGuardMode"];
19888
+ };
19889
+ /**
19890
+ * @description OFF — правило не работает; WARN — причина пишется в аудит, отправка идёт; BLOCK — отправка останавливается.
19891
+ * @enum {string|null}
19892
+ */
19893
+ OutboundGuardMode: "OFF" | "WARN" | "BLOCK" | null;
19894
+ GetCourseColdWelcomeBatchResponse: {
19895
+ /** Format: uuid */
19896
+ batchId: string;
19897
+ /** @description Сколько сегментов поставлено в очередь */
19898
+ segments: number;
19899
+ /** @description Строк файла БЕЗ момента входа в сегмент (segment_entered_at). Такой контакт не попадёт ни в один период оси «вход в сегмент» на «Аналитике коммуникации» — он невидим ровно там, где спрашивают «сколько людей пришло за месяц». Предупреждение, а не запрет: у аудитории, заданной границей даты или файлом без события, момента входа нет вовсе. Считается по СЫРЫМ строкам запроса, чтобы число сходилось с файлом. */
19900
+ rowsWithoutSegmentEntry?: number;
19901
+ };
19902
+ GetCourseColdWelcomeBatchSegmentStatus: {
19903
+ position: number;
19904
+ segment: string | null;
19905
+ /** @enum {string} */
19906
+ status: "PENDING" | "RUNNING" | "COMPLETED" | "FAILED" | "CANCELLED";
19907
+ contactsCount: number;
19908
+ /** Format: uuid */
19909
+ importJobId: string | null;
19910
+ error: string | null;
19911
+ /** @description Каналы, подтверждённые на старте пакета. Пусто — ограничения нет. */
19912
+ coldWelcomeChannels: components["schemas"]["GetCourseTransport"][];
19913
+ /** @description true — каналы заданы явно на запуске; false — унаследованы от рассылки. */
19914
+ coldWelcomeChannelsExplicit: boolean;
19915
+ };
19916
+ GetCourseColdWelcomeBatchStatus: {
19917
+ /** Format: uuid */
19918
+ batchId: string;
19919
+ /** @enum {string} */
19920
+ state: "RUNNING" | "COMPLETED" | "FAILED" | "CANCELLED";
19921
+ segments: components["schemas"]["GetCourseColdWelcomeBatchSegmentStatus"][];
19922
+ /** @description Драйвер пакета доказуемо оборвался (протух пульс) — остаток поднимается через resume. Судить по статусу задачи нельзя: она живёт в том же процессе и замерзает вместе с ним. */
19923
+ stalled: boolean;
19924
+ };
19925
+ /** @description Ключи — имена колонок экспорта GetCourse (snake_case), а не поля API: их читает тот же разбор, что и файловый импорт. Пустая строка считается отсутствующим значением. */
19926
+ GetCourseContactImportRow: {
19927
+ /** @description getcourse_user_id */
19928
+ contact_id: string;
19929
+ /** @description Пин заказа */
19930
+ deal_id?: string;
19931
+ /** @description resp_id */
19932
+ dialog_id?: string;
19933
+ transport?: string;
19934
+ /** Format: email */
19935
+ email?: string;
19936
+ phone?: string;
19937
+ /** @description Влияет на текст: обращение подставляется системным {greeting}, и у контакта без имени обращения не будет вовсе (а не голая запятая). */
19938
+ first_name?: string;
19939
+ last_name?: string;
19940
+ };
19941
+ GetCourseContactsImportRequest: {
19942
+ /** Format: uuid */
19943
+ platformId: string;
19944
+ contacts: components["schemas"]["GetCourseContactImportRow"][];
19945
+ /**
19946
+ * @description Отсеивать контакты без Telegram/MAX/VK. Проверка — API-вызов на КАЖДЫЙ контакт, поэтому на больших списках импорт идёт заметно дольше.
19947
+ * @default true
19948
+ */
19949
+ checkMessengerPresence: boolean;
19950
+ };
19951
+ /** @description При наличии валидных строк возвращается jobId и totalRows; если валидных не оказалось вовсе — validationErrors и errorCount, задача при этом НЕ создаётся. */
19952
+ GetCourseContactsImportResponse: {
19953
+ /** Format: uuid */
19954
+ jobId?: string;
19955
+ totalRows?: number;
19956
+ validationErrors?: string[];
19957
+ errorCount?: number;
19958
+ message: string;
19959
+ };
19960
+ BroadcastLaunch: {
19961
+ id: string;
19962
+ /** @description Наша отправка либо волна по файлу */
19963
+ kind: string;
19964
+ status: string;
19965
+ channel: string;
19966
+ /** Format: uuid */
19967
+ platformId?: string | null;
19968
+ /** Format: uuid */
19969
+ mailingVariantId?: string | null;
19970
+ mailingVariantName?: string | null;
19971
+ /** @description Снимок текста на момент запуска — правка рассылки его не меняет. */
19972
+ messageSnapshot?: string | null;
19973
+ segment?: string | null;
19974
+ productCode?: string | null;
19975
+ funnel?: string | null;
18405
19976
  totalContacts: number;
18406
- pendingContacts: number;
18407
- skippedAlreadySent: number;
18408
- /** @description Сколько контактов когда-либо имели подтверждённую отправку. */
18409
- historicalConfirmedCount: number;
18410
- /** @description Контакты с живым либо неопределённым исходом другого прогона. */
18411
- unsafeBlockedCount: number;
18412
- chunkSize: number;
18413
- /** @description Snapshot для идемпотентного confirm. */
18414
- dryRunHash: string;
18415
- state?: components["schemas"]["GetCourseWaveRunState"];
19977
+ sentCount: number;
19978
+ failedCount: number;
19979
+ /** @description Счётчик по каждому исходу отправки. */
19980
+ outcomes?: {
19981
+ [key: string]: number;
19982
+ } | null;
19983
+ /** @description Сколько контактов каждого исхода разбирается ПОИМЁННО — по построчному следу отсева. Ключи те же, что в outcomes, но только у неотправленных: у SENT след это строка реестра получателей. Числа исходов остаются в outcomes (агрегат полон за всю историю), а след начинается с 02.09.2026, поэтому у прежних запусков здесь пусто — витрина по этому полю решает, открывать ли список. Null у волны и у прогона расписания: у них свои носители. */
19984
+ tracedOutcomes?: {
19985
+ [key: string]: number;
19986
+ } | null;
19987
+ /** @description Сколько отправок ушло ВСЛЕПУЮ: канал взят резервным транспортом площадки, а не доказан привязками контакта или его ответом. Это ПОДМНОЖЕСТВО sentCount, а не отдельный исход — сообщение ушло. Без него «доставлено в мессенджер» и «упало в личный кабинет сайта» в истории неразличимы. null — у волн (отправляет процесс школы) и у запусков до появления счётчика; это НЕ то же, что 0. */
19988
+ sentWithoutChannelEvidence?: number | null;
19989
+ /** Format: date-time */
19990
+ createdAt: string;
19991
+ /** Format: date-time */
19992
+ completedAt?: string | null;
19993
+ };
19994
+ BroadcastLaunchesPage: {
19995
+ items: components["schemas"]["BroadcastLaunch"][];
19996
+ hasMore: boolean;
19997
+ };
19998
+ BroadcastVariantSummary: {
19999
+ /** Format: uuid */
20000
+ mailingVariantId: string;
20001
+ launches: number;
20002
+ sentTotal: number;
20003
+ /** Format: date-time */
20004
+ lastLaunchAt?: string | null;
20005
+ };
20006
+ BroadcastLabelSuggestions: {
20007
+ segments: string[];
20008
+ productCodes: string[];
20009
+ funnels: string[];
18416
20010
  };
20011
+ /** @enum {string} */
20012
+ GetCourseTransport: "Site" | "Email" | "SMS" | "Telegram" | "Facebook" | "VK" | "Chatium" | "WhatsApp" | "Viber" | "MAX";
18417
20013
  GetCourseWaveRunCounters: {
18418
20014
  PENDING: number;
18419
20015
  CLAIMED: number;
@@ -18451,7 +20047,7 @@ export interface components {
18451
20047
  position: number;
18452
20048
  getcourseUserId: number;
18453
20049
  dealId: number | null;
18454
- transport: ("VK" | "Telegram" | "MAX" | "SMS" | "Email" | "Site") | null;
20050
+ transport: components["schemas"]["GetCourseTransport"] | null;
18455
20051
  dialogId: string | null;
18456
20052
  leadLastActiveAt: string | null;
18457
20053
  segmentEnteredAt: string | null;
@@ -18469,7 +20065,11 @@ export interface components {
18469
20065
  * @enum {string}
18470
20066
  */
18471
20067
  launchType: "status";
18472
- channels: ("VK" | "Telegram" | "MAX" | "SMS" | "Email" | "Site")[];
20068
+ channels: components["schemas"]["GetCourseTransport"][];
20069
+ /**
20070
+ * @description Воронка ШКОЛЫ в форме «f11 — ДБО / NR / ВК / In Stream» — код fNN обязателен. ⚠️ Это НЕ когорта и НЕ подпись запуска: «reg-no-show», «post-web|дбо» сюда класть нельзя — тип отбора идёт в segment, продукт в productCode, подпись запуска в cohortLabel. Ось «Воронка» сравнивается по коду, поэтому значение без кода становится отдельной «воронкой» и засоряет фильтр аналитики.
20071
+ * @example f11 — ДБО / NR / ВК / In Stream
20072
+ */
18473
20073
  funnel?: string;
18474
20074
  segment?: string;
18475
20075
  /** @description Явное бизнес-правило отбора; требует segment. */
@@ -18813,9 +20413,21 @@ export interface components {
18813
20413
  metadata?: {
18814
20414
  [key: string]: unknown;
18815
20415
  };
18816
- actions?: {
20416
+ /** @description Набор действий триггера. Конфиг действия кладётся в ОТДЕЛЬНОЕ поле, имя которого зависит от actionType: правило camelCase(actionType)+"Config" (CRM_UPDATE_FIELD → crmUpdateFieldConfig). Пять легаси-исключений: CRM_MOVE_STAGE → crmConfig, SCHEDULE_FOLLOWUP → scheduleFollowUpConfig, SUMMARIZE_DIALOG → summarizeConfig, SEND_TELEGRAM_CHANNEL_MESSAGE → telegramChannelConfig, CRM_RENAME_DEAL → renameDealConfig. В ОТВЕТЕ (GET триггеров, platform-context) тот же конфиг приходит под именем СВЯЗИ Prisma (crmMoveStage, scheduleFollowUp, summarizeAction, telegramChannelMessage, renameDeal) — пересылая прочитанное на запись, его надо переименовать в ключ входа, иначе whitelist+forbidNonWhitelisted ответит «property … should not exist». Действие с ОБЯЗАТЕЛЬНЫМ конфигом, присланное без него, отвергается 400 (раньше оно сохранялось пустым и отказывало только в рантайме). Канон имён и обязательности — ai-aniomaly/src/core/application/tools/constants/trigger-action-config.constants.ts. */
20417
+ actions?: ({
20418
+ /** @description Prisma ActionType */
20419
+ actionType: string;
20420
+ priority?: number;
20421
+ isEnabled?: boolean;
20422
+ /** @description Следующие действия выполнятся даже при падении этого */
20423
+ continueOnError?: boolean;
20424
+ /** @description Конфиг CRM_MOVE_STAGE: crmId, crmType (AMOCRM|BITRIX24|GETCOURSE), statusId, pipelineId + pipelineCrmId (рекомендуются), note. В ответе — crmMoveStage. */
20425
+ crmConfig?: {
20426
+ [key: string]: unknown;
20427
+ };
20428
+ } & {
18817
20429
  [key: string]: unknown;
18818
- }[];
20430
+ })[];
18819
20431
  /** @description true → replace the full action set (delete-and-recreate, like UI). Without it, actions on an existing trigger are rejected. */
18820
20432
  replaceActions?: boolean;
18821
20433
  };
@@ -18878,7 +20490,7 @@ export interface components {
18878
20490
  /** @description Ненулевое значение означает, что пункт не будет отправлен. */
18879
20491
  blockedReason: string | null;
18880
20492
  /** @description null означает выбор транспорта по каноническому каналу контакта. */
18881
- getcourseTransports: ("VK" | "Telegram" | "MAX" | "SMS" | "Email" | "Site")[] | null;
20493
+ getcourseTransports: components["schemas"]["GetCourseTransport"][] | null;
18882
20494
  skippedEffects: ("crm_stage" | "crm_note" | "webhook" | "platform_log" | "attachments")[];
18883
20495
  attachmentCount: number;
18884
20496
  };
@@ -18964,6 +20576,14 @@ export interface components {
18964
20576
  comparableSent: number;
18965
20577
  /** @description Ответили в пределах равного горизонта */
18966
20578
  horizonReplied: number;
20579
+ /**
20580
+ * @description Отреагировали ХОТЬ КАК-ТО в том же горизонте: ответили ИЛИ перешли по ссылке
20581
+ * этого касания. Всегда >= horizonReplied, разность — те, кто НЕ ответил, но кликнул.
20582
+ * ⚠️ Складывать horizonReplied и linkClicked вместо этого нельзя: ответивший часто
20583
+ * ещё и кликает, и сумма задваивала бы его. Знаменатель тот же (comparableSent),
20584
+ * включая касания без ссылки: это доля отреагировавших на касание, а не CTR ссылки.
20585
+ */
20586
+ horizonEngaged: number;
18967
20587
  /** @description Прервано чужим касанием до конца горизонта */
18968
20588
  censored: number;
18969
20589
  /** @description Доля вырезанных от СОЗРЕВШЕГО пула (comparableSent + censored) */
@@ -18987,6 +20607,33 @@ export interface components {
18987
20607
  /** @description Медиана длительности ЗАКРЫТЫХ окон, минуты */
18988
20608
  medianWindowMinutes: number | null;
18989
20609
  };
20610
+ FollowUpRunReply: {
20611
+ /**
20612
+ * Format: uuid
20613
+ * @description null — итог по разрезу
20614
+ */
20615
+ sequenceId: string | null;
20616
+ /** @description Прохождений, начавшихся в периоде и уже созревших */
20617
+ started: number;
20618
+ /** @description Из них ответивших хотя бы раз за окно */
20619
+ replied: number;
20620
+ /**
20621
+ * @description Начавшихся, но окно ещё не вышло. Отдельным числом, а не нулём в числителе: ответ ещё
20622
+ * может прийти, и ноль занижал бы долю тем сильнее, чем свежее период.
20623
+ */
20624
+ immature: number;
20625
+ };
20626
+ /**
20627
+ * @description Отклик на ПРОХОЖДЕНИЕ цепочки — метрика уровня цепочки, независимая от horizonMinutes.
20628
+ *
20629
+ * Отвечает на вопрос «работает ли цепочка», а НЕ «какой шаг сработал»: атрибутировать ответ
20630
+ * конкретному шагу она не пытается, поэтому и вырезать никого не должна.
20631
+ */
20632
+ FollowUpRunsSummary: {
20633
+ windowDays: number;
20634
+ total: components["schemas"]["FollowUpRunReply"];
20635
+ bySequence: components["schemas"]["FollowUpRunReply"][];
20636
+ };
18990
20637
  FollowUpReactionsResponse: {
18991
20638
  byStep: (components["schemas"]["FollowUpReactionMetrics"] & {
18992
20639
  /** Format: uuid */
@@ -19042,7 +20689,19 @@ export interface components {
19042
20689
  * @description Момент снимка; передайте его в drill-down как asOf
19043
20690
  */
19044
20691
  calculatedAt: string;
20692
+ /**
20693
+ * @description Окно, ПО КОТОРОМУ посчитаны сравнительные цифры. Подбирается сервером автоматически —
20694
+ * самый длинный кандидат, у которого отсев цензурированием в пределах порога.
20695
+ * Явно переданный horizonMinutes уважается как экспертный обход.
20696
+ */
19045
20697
  horizonMinutes: number;
20698
+ /**
20699
+ * @description picked — окно подобрано (или задано клиентом); no-reliable-horizon — ни один кандидат
20700
+ * не прошёл порог, сравнивать нельзя; no-data — сравнивать нечего.
20701
+ * @enum {string}
20702
+ */
20703
+ horizonReason: "picked" | "no-reliable-horizon" | "no-data";
20704
+ runs: components["schemas"]["FollowUpRunsSummary"];
19046
20705
  /** @description Потолок операционного окна */
19047
20706
  maxWindowMinutes: number;
19048
20707
  /** Format: date-time */
@@ -19120,6 +20779,34 @@ export interface components {
19120
20779
  } | null;
19121
20780
  replyToStoryMentions?: boolean;
19122
20781
  };
20782
+ funnelAnalytics?: {
20783
+ /** @description Тройка стадий «отправлено → одобрено | отклонено» (у Aslzar — скоринг рассрочки). null — сбросить ворота: блок перестаёт рисоваться. */
20784
+ decisionGate?: {
20785
+ submitted: {
20786
+ pipelineCrmId: string;
20787
+ pipelineId: number;
20788
+ statusId: number;
20789
+ };
20790
+ approved: {
20791
+ pipelineCrmId: string;
20792
+ pipelineId: number;
20793
+ statusId: number;
20794
+ };
20795
+ rejected: {
20796
+ pipelineCrmId: string;
20797
+ pipelineId: number;
20798
+ statusId: number;
20799
+ };
20800
+ } | null;
20801
+ /** @description Целевая стадия карточки «Путь до стадии». null — сбросить выбор. */
20802
+ pathTargetStage?: {
20803
+ pipelineCrmId: string;
20804
+ pipelineId: number;
20805
+ statusId: number;
20806
+ } | null;
20807
+ engagedInboundCount?: number | null;
20808
+ stuckThresholdHours?: number | null;
20809
+ };
19123
20810
  /** @description Closes Phase B gap для name/offMessage/timezone/isActive. Any channel type. */
19124
20811
  generalSettings?: {
19125
20812
  name?: string | null;
@@ -19174,6 +20861,9 @@ export interface components {
19174
20861
  channels?: components["schemas"]["GetCourseWaveFieldBinding"];
19175
20862
  } | null;
19176
20863
  deliveryCheckEnabled?: boolean;
20864
+ guardActiveSeries?: components["schemas"]["OutboundGuardMode"];
20865
+ guardActiveApplication?: components["schemas"]["OutboundGuardMode"];
20866
+ guardPaid?: components["schemas"]["OutboundGuardMode"];
19177
20867
  /** @description Transport → exact deal custom field NAME (read API returns no field ids). Clear with {}. */
19178
20868
  deliveryFieldMap?: {
19179
20869
  [key: string]: string;
@@ -19873,6 +21563,20 @@ export interface components {
19873
21563
  pipelineTransitionsLog?: Record<string, never>[];
19874
21564
  toolCallLog?: Record<string, never>[];
19875
21565
  ragTestResults?: Record<string, never>[];
21566
+ /** @description Рубрика прогона: `TestScenario.situations` сценариев этого прогона, как их написал автор. Строки role=agent — ОЖИДАЕМОЕ поведение агента; рантайм их не исполняет (`extractTurns` берёт только role=client/user), и `passRate` их не измеряет — он считает лишь долю turn-ов с непустым ответом. Заполняется только на findings-instructions (`/sandbox/runs/{runId}/findings/instructions`); `GET /sandbox-runs/{runId}` поле не отдаёт. Отсутствие поля = «рубрика не читалась», пустой `situations` = «у сценария нет реплик». Сценария, удалённого после прогона, здесь нет вовсе — хотя в `perScenarioMetrics` он остаётся. */
21567
+ scenarioExpectations?: {
21568
+ /** Format: uuid */
21569
+ scenarioId: string;
21570
+ scenarioName?: string;
21571
+ /** @description Что именно проверяет сценарий — часть рубрики, а не подпись. */
21572
+ description?: string | null;
21573
+ /** @description Реплики в исходном порядке (role=client — вход, role=agent — ожидание). Порядок и есть привязка ожидания к turn-у: индекс транскрипта смещается при OUTBOUND-seeding, поэтому готового номера turn-а здесь нет намеренно. */
21574
+ situations: {
21575
+ /** @enum {string} */
21576
+ role?: "client" | "agent";
21577
+ text?: string;
21578
+ }[];
21579
+ }[];
19876
21580
  };
19877
21581
  /** @description A single router decision recorded for one turn of a sandbox run. */
19878
21582
  SandboxRoutingLogEntry: {
@@ -20407,8 +22111,65 @@ export interface components {
20407
22111
  PatchDraftOperationsRequest: {
20408
22112
  operations: components["schemas"]["PromptPatchOperation"][];
20409
22113
  };
22114
+ /**
22115
+ * @description Черновик БЕЗ `currentContent` и без истории `operations[]`.
22116
+ *
22117
+ * Полный текст отдают `POST /prompt/drafts` (первое чтение промпта) и
22118
+ * `GET /prompt/drafts/{draftId}` (перечитать по требованию). Эхо текста в ответе
22119
+ * КАЖДОГО `_apply`/`_commit` — накладные расходы: клиент уже прочитал промпт на
22120
+ * старте, а история операций повторяет то, что он сам же и отправил.
22121
+ */
22122
+ PromptDraftMeta: {
22123
+ /** Format: uuid */
22124
+ id: string;
22125
+ /** Format: uuid */
22126
+ agentId: string;
22127
+ status: components["schemas"]["PromptDraftStatus"];
22128
+ /** Format: uuid */
22129
+ baseVersionId: string;
22130
+ baseContentHash: string;
22131
+ /** Format: uuid */
22132
+ committedVersionId?: string | null;
22133
+ /**
22134
+ * @description Длина `currentContent`. Сверяется с остатком `GET /prompt/headroom`
22135
+ * без чтения самого текста.
22136
+ */
22137
+ characters: number;
22138
+ /** @description Сколько patch-операций накоплено черновиком за всю жизнь. */
22139
+ operationsCount: number;
22140
+ /** Format: date-time */
22141
+ expiresAt: string;
22142
+ /** Format: date-time */
22143
+ updatedAt: string;
22144
+ };
22145
+ /** @description Построчная разница состояния черновика ДО и ПОСЛЕ применённых операций. */
22146
+ PromptPatchDiff: {
22147
+ /**
22148
+ * @description Текст черновика реально изменился.
22149
+ *
22150
+ * Отдельный признак обязателен: `removedLines`/`addedLines` — multiset-разность
22151
+ * строк, и `move_text_after_text` (как и правка одних пробелов) даёт ПУСТОЙ дифф
22152
+ * при изменившемся тексте. Без этого поля пустые списки читались бы как
22153
+ * «ничего не применилось».
22154
+ */
22155
+ contentChanged: boolean;
22156
+ /**
22157
+ * @description Насколько вырос (отрицательное — сжался) черновик, в символах.
22158
+ * Абсолютная длина — `draft.characters`, чтобы одно число не жило в двух полях.
22159
+ */
22160
+ charactersDelta: number;
22161
+ /** @description Строки, исчезнувшие из черновика. */
22162
+ removedLines: components["schemas"]["PromptDiffLine"][];
22163
+ /** @description Строки, появившиеся в черновике. */
22164
+ addedLines: components["schemas"]["PromptDiffLine"][];
22165
+ /**
22166
+ * @description Списки обрезаны по потолку строк на сторону (`PROMPT_PATCH_DIFF_MAX_LINES`).
22167
+ * Полный текст читать через `GET /prompt/drafts/{draftId}`.
22168
+ */
22169
+ truncated: boolean;
22170
+ };
20410
22171
  PromptDraftPatchResponse: {
20411
- draft: components["schemas"]["PromptDraft"];
22172
+ draft: components["schemas"]["PromptDraftMeta"];
20412
22173
  /** @description Сколько ops успешно применились */
20413
22174
  appliedCount: number;
20414
22175
  /**
@@ -20416,15 +22177,23 @@ export interface components {
20416
22177
  * Клиент должен показать warning если > 0.
20417
22178
  */
20418
22179
  skippedCount: number;
22180
+ diff: components["schemas"]["PromptPatchDiff"];
20419
22181
  };
20420
22182
  PromptDraftCommitResponse: {
20421
- draft: components["schemas"]["PromptDraft"];
22183
+ draft: components["schemas"]["PromptDraftMeta"];
22184
+ /**
22185
+ * @description Только адресация новой версии. `content` намеренно НЕ отдаётся: это была бы
22186
+ * вторая копия текста, который клиент сам и собрал.
22187
+ */
20422
22188
  newVersion: {
20423
22189
  /** Format: uuid */
20424
22190
  id: string;
20425
- /** @description 0 если synthesized из 410-retry path */
20426
- version?: number;
20427
- content: string;
22191
+ /**
22192
+ * @description `null` — идемпотентный повтор commit'а (draft уже был COMMITTED): номер версии
22193
+ * на этом пути неизвестен, черновик его не несёт. Внутренний сентинел `-1` наружу
22194
+ * НЕ выпускается: в JSON он неотличим от настоящего номера версии.
22195
+ */
22196
+ version: number | null;
20428
22197
  };
20429
22198
  };
20430
22199
  /** @enum {string} */
@@ -20710,9 +22479,11 @@ export interface components {
20710
22479
  [key: string]: unknown;
20711
22480
  } | null;
20712
22481
  /** @enum {string|null} */
20713
- llmProvider?: "openai" | "yandex-gpt" | "deepseek" | "xai" | "zai" | "moonshot" | "alibaba" | "anthropic" | "cerebras" | null;
22482
+ llmProvider?: "openai" | "yandex-gpt" | "deepseek" | "groq" | "openrouter" | "xai" | "zai" | "moonshot" | "alibaba" | "anthropic" | "cerebras" | null;
20714
22483
  llmModel?: string | null;
20715
22484
  /** @enum {string|null} */
22485
+ llmReasoningEffort?: "none" | "low" | "medium" | "high" | null;
22486
+ /** @enum {string|null} */
20716
22487
  realtimeProvider?: "openai" | "yandex" | "google" | "phonic" | "xai" | null;
20717
22488
  realtimeModel?: string | null;
20718
22489
  realtimeVoice?: string | null;
@@ -20733,10 +22504,8 @@ export interface components {
20733
22504
  fillerStatus?: string | null;
20734
22505
  vadProvider?: string | null;
20735
22506
  turnDetector?: string | null;
20736
- /** @description Ручки turn-taking/barge-in (A2): interruption/endpointing (мс) + vad (мс) */
20737
- turnTakingConfig?: {
20738
- [key: string]: unknown;
20739
- } | null;
22507
+ /** @description Typed ручки turn-taking/barge-in (A2) */
22508
+ turnTakingConfig?: components["schemas"]["VoiceProfileTurnTakingConfig"] | null;
20740
22509
  sentimentAnalysisEnabled: boolean;
20741
22510
  ttsFailoverEnabled: boolean;
20742
22511
  recordingCopyEnabled: boolean;
@@ -21311,6 +23080,11 @@ export interface components {
21311
23080
  /** @description Ручки turn-taking/barge-in (A2): typed-схема входа (незнакомые ключи отвергаются, диапазоны зеркалят клампы воркера). Время — мс. */
21312
23081
  VoiceProfileTurnTakingConfig: {
21313
23082
  allowInterruptions?: boolean;
23083
+ /**
23084
+ * @description CASCADE: adaptive требует STT с aligned transcript и LiveKit Cloud/dev runtime; внешний production worker использует VAD. REALTIME использует нативный turn detection
23085
+ * @enum {string}
23086
+ */
23087
+ interruptionMode?: "vad" | "adaptive";
21314
23088
  minInterruptionDuration?: number;
21315
23089
  minInterruptionWords?: number;
21316
23090
  minEndpointingDelay?: number;
@@ -21359,8 +23133,10 @@ export interface components {
21359
23133
  ttsPronunciationCaseSensitive?: boolean;
21360
23134
  ttsProviderSettings?: components["schemas"]["VoiceProfileTtsProviderSettings"];
21361
23135
  /** @enum {string} */
21362
- llmProvider?: "openai" | "yandex-gpt" | "deepseek" | "xai" | "zai" | "moonshot" | "alibaba" | "anthropic" | "cerebras";
23136
+ llmProvider?: "openai" | "yandex-gpt" | "deepseek" | "groq" | "openrouter" | "xai" | "zai" | "moonshot" | "alibaba" | "anthropic" | "cerebras";
21363
23137
  llmModel?: string;
23138
+ /** @enum {string|null} */
23139
+ llmReasoningEffort?: "none" | "low" | "medium" | "high" | null;
21364
23140
  /** @enum {string} */
21365
23141
  realtimeProvider?: "openai" | "yandex" | "google" | "phonic" | "xai";
21366
23142
  realtimeModel?: string;
@@ -21448,9 +23224,11 @@ export interface components {
21448
23224
  [key: string]: unknown;
21449
23225
  } | null;
21450
23226
  /** @enum {string|null} */
21451
- llmProvider?: "openai" | "yandex-gpt" | "deepseek" | "xai" | "zai" | "moonshot" | "alibaba" | "anthropic" | "cerebras" | null;
23227
+ llmProvider?: "openai" | "yandex-gpt" | "deepseek" | "groq" | "openrouter" | "xai" | "zai" | "moonshot" | "alibaba" | "anthropic" | "cerebras" | null;
21452
23228
  llmModel?: string | null;
21453
23229
  /** @enum {string|null} */
23230
+ llmReasoningEffort?: "none" | "low" | "medium" | "high" | null;
23231
+ /** @enum {string|null} */
21454
23232
  realtimeProvider?: "openai" | "yandex" | "google" | "phonic" | "xai" | null;
21455
23233
  realtimeModel?: string | null;
21456
23234
  realtimeVoice?: string | null;
@@ -21472,10 +23250,8 @@ export interface components {
21472
23250
  telephonyFilterEnabled: boolean;
21473
23251
  vadProvider?: string | null;
21474
23252
  turnDetector?: string | null;
21475
- /** @description Ручки turn-taking/barge-in (A2): interruption/endpointing (мс) + vad (мс) */
21476
- turnTakingConfig?: {
21477
- [key: string]: unknown;
21478
- } | null;
23253
+ /** @description Typed ручки turn-taking/barge-in (A2) */
23254
+ turnTakingConfig?: components["schemas"]["VoiceProfileTurnTakingConfig"] | null;
21479
23255
  /** @description Сентимент-анализ user-реплик (A1) */
21480
23256
  sentimentAnalysisEnabled: boolean;
21481
23257
  /** @description false (дефолт) — отказ TTS завершает звонок, голос не подменяется */
@@ -21629,6 +23405,8 @@ export interface components {
21629
23405
  /** Format: uuid */
21630
23406
  platformId?: string;
21631
23407
  inputTokens?: number;
23408
+ /** @description Часть inputTokens, прочитанная из provider prompt cache */
23409
+ cacheReadTokens?: number;
21632
23410
  outputTokens?: number;
21633
23411
  totalTokens?: number;
21634
23412
  inputAudioSeconds?: number;
@@ -22010,7 +23788,7 @@ export interface components {
22010
23788
  isBotActive?: boolean;
22011
23789
  isFollowUpActive?: boolean;
22012
23790
  /** @enum {string|null} */
22013
- lastWorkLogEvent?: "START" | "IN_PROCESS" | "FINISH_WIN" | "FINISH_LOST" | "FAILED" | "OPERATOR_TAKEOVER" | "FINISH_AUTO" | null;
23791
+ lastWorkLogEvent?: "START" | "IN_PROCESS" | "FINISH_WIN" | "FINISH_LOST" | "FAILED" | "OPERATOR_TAKEOVER" | "FINISH_AUTO" | "FINISH_RESOLVED" | null;
22014
23792
  /**
22015
23793
  * Format: date-time
22016
23794
  * @description Время последней отправки волны/рассылки этому контакту (BroadcastRecipient.receivedAt). Опорная точка атрибуции: от неё считается «сколько прошло до ответа клиента и до оплаты». null — контакт в волны не попадал.
@@ -22191,6 +23969,50 @@ export interface components {
22191
23969
  defaultChannels?: string[];
22192
23970
  defaultDealFields?: Record<string, never> | null;
22193
23971
  };
23972
+ WorkspaceLinkDomain: {
23973
+ /**
23974
+ * @description Хост без схемы (`ksamata.besales.pro`); null — используется общий домен платформы.
23975
+ * @example ksamata.besales.pro
23976
+ */
23977
+ domain: string | null;
23978
+ /**
23979
+ * @description Зоны, доступные для назначения. Пусто — выбор домена на платформе не настроен (зона без wildcard-сертификата отдала бы человеку ошибку сертификата).
23980
+ * @example [
23981
+ * "besales.pro"
23982
+ * ]
23983
+ */
23984
+ zones: string[];
23985
+ /**
23986
+ * @description Адрес, который используется, пока свой домен не задан.
23987
+ * @example https://go-ru.besales.ai
23988
+ */
23989
+ defaultBaseUrl: string | null;
23990
+ /** @description Места в конфигурации воркспейса, где остался короткий адрес на ЧУЖОМ хосте. ⚠️ Возникают потому, что `staticUrl` вставляется в тексты СНИМКОМ, и переезд домена его не переписывает: такие места надо перевставить вручную. Пустой массив — всё указывает на текущий хост. */
23991
+ staleUsages: {
23992
+ /**
23993
+ * @description Что это за место — чтобы оператор понял, где искать.
23994
+ * @enum {string}
23995
+ */
23996
+ place: "AGENT_FACTS" | "AGENT_PROMPT" | "AGENT_GREETING" | "AGENT_SCRIPT" | "FOLLOW_UP" | "BROADCAST_VARIANT" | "QA" | "WORKSPACE_VARIABLE";
23997
+ /**
23998
+ * @description Имя сущности (агента, цепочки, варианта рассылки).
23999
+ * @example Светлана · вебинарная воронка
24000
+ */
24001
+ name: string;
24002
+ /**
24003
+ * @description Хост, который там остался.
24004
+ * @example go.besales.ai
24005
+ */
24006
+ host: string;
24007
+ }[];
24008
+ };
24009
+ UpdateWorkspaceLinkDomainRequest: {
24010
+ /**
24011
+ * @description Хост без схемы, ровно один уровень под разрешённой зоной; null — вернуться на общий домен платформы. Поле обязательное И nullable одновременно: пустое тело `{}` обязано быть ошибкой, а не молчаливым сбросом.
24012
+ * @example ksamata.besales.pro
24013
+ */
24014
+ domain: string | null;
24015
+ };
22194
24016
  TrackedLink: {
22195
24017
  /** Format: uuid */
22196
24018
  id: string;
@@ -22198,7 +24020,7 @@ export interface components {
22198
24020
  /** @description Часть плейсхолдера; неизменяема после создания. */
22199
24021
  slug: string;
22200
24022
  targetUrl: string;
22201
- /** @description Анонимный короткий адрес для ручной вставки. null — трекинг не сконфигурирован (LINK_TRACKING_BASE_URL не задан). */
24023
+ /** @description Анонимный короткий адрес для ручной вставки. Домен берётся из настройки воркспейса, а при её отсутствии — из LINK_TRACKING_BASE_URL; null означает, что выдавать ссылки некуда. Уже сохранённый где-либо адрес НЕ переписывается при смене домена: он продолжает работать, но содержит прежнее имя. */
22202
24024
  staticUrl: string | null;
22203
24025
  /** @description Готовый токен для текста исходящего, например {{link:webinar-gkt}}. Собирается сервером — вторая сборка на клиенте разошлась бы с разбором. */
22204
24026
  placeholder: string;
@@ -22256,6 +24078,18 @@ export interface components {
22256
24078
  paid: number;
22257
24079
  paidAmount: number;
22258
24080
  };
24081
+ TrackedLinkReachBreakdown: {
24082
+ platformId: string | null;
24083
+ platformName: string | null;
24084
+ /** @description Площадка удалена. Отдельный признак, а не пустое имя: Platform.name nullable, и живая безымянная площадка существует. */
24085
+ platformDeleted: boolean;
24086
+ agentId: string | null;
24087
+ agentName: string | null;
24088
+ /** @description Агент удалён; выдачи и клики сохранены */
24089
+ agentDeleted: boolean;
24090
+ issued: number;
24091
+ clicked: number;
24092
+ };
22259
24093
  TrackedLinkClickEvents: {
22260
24094
  items: components["schemas"]["TrackedLinkClickEvent"][];
22261
24095
  total: number;
@@ -22308,11 +24142,82 @@ export interface components {
22308
24142
  data: components["schemas"]["BroadcastMetricRow"][];
22309
24143
  /** @description Итоги без channel-unnest; использовать для общей цифры вместо суммы data по каналам. */
22310
24144
  totals: components["schemas"]["BroadcastMetricRow"][];
24145
+ /** @description Разрез по площадкам за ВЕСЬ период (без дней). Считается третьим набором тех же GROUPING SETS, что и totals, поэтому сходится с ними по построению. Дней тут нет намеренно: sent/received client-distinct и по дням не аддитивны. Ручная историческая статистика не входит — площадки у неё нет. */
24146
+ platformTotals?: components["schemas"]["BroadcastPlatformTotal"][];
22311
24147
  channels: string[];
22312
24148
  funnels: string[];
22313
24149
  segments: string[];
22314
24150
  products: string[];
22315
24151
  };
24152
+ BroadcastPlatformTotal: {
24153
+ /**
24154
+ * Format: uuid
24155
+ * @description ID площадки рассылки; null — у строки площадка не проставлена.
24156
+ */
24157
+ platformId: string | null;
24158
+ /** @description Воронка волны. Разрез несёт её, потому что страница фильтрует воронки клиентски. */
24159
+ funnel: string | null;
24160
+ sent: number;
24161
+ received: number;
24162
+ enteredDialog: number;
24163
+ handedOff: number;
24164
+ paid: number;
24165
+ paidAmount: number;
24166
+ };
24167
+ BroadcastUniqueContacts: {
24168
+ /**
24169
+ * @description Уникальных контактов (DISTINCT chat_user_id) в периметре «Отправлено». НЕ аддитивно —
24170
+ * сумма по группам больше правды (замер 26.08.2026: по дням +43 %, по сегментам +27 %).
24171
+ */
24172
+ uniqueContacts: number;
24173
+ /**
24174
+ * @description Только при view=entry. Сколько строк за тот же период было ОТПРАВЛЕНО и сколько из них
24175
+ * не имеет даты входа в сегмент — эти строки не попадают ни в один период режима.
24176
+ * Отсутствие поля означает «вопрос не задавался», а не «все даты известны».
24177
+ */
24178
+ entryCoverage?: {
24179
+ sentRows: number;
24180
+ rowsWithoutEntry: number;
24181
+ };
24182
+ };
24183
+ BroadcastPerPersonMetrics: {
24184
+ /**
24185
+ * @description Уникальные контакты, которым отправляли.
24186
+ * @example 32737
24187
+ */
24188
+ sent: number;
24189
+ /**
24190
+ * @description Уникальные контакты с засчитанной доставкой.
24191
+ * @example 29825
24192
+ */
24193
+ received: number;
24194
+ /**
24195
+ * @description Уникальные контакты, вступившие в диалог.
24196
+ * @example 4430
24197
+ */
24198
+ enteredDialog: number;
24199
+ /** @description Уникальные контакты с глубоким диалогом. */
24200
+ deepDialog: number;
24201
+ /** @description Уникальные контакты с выданной отслеживаемой ссылкой. */
24202
+ linkIssued: number;
24203
+ /** @description Уникальные контакты, кликнувшие по отслеживаемой ссылке. */
24204
+ clicked: number;
24205
+ /** @description Уникальные контакты, переданные менеджеру. */
24206
+ handedOff: number;
24207
+ /** @description Уникальные контакты с выставленным счётом. */
24208
+ issued: number;
24209
+ /**
24210
+ * @description Уникальные контакты с прямой оплатой.
24211
+ * @example 71
24212
+ */
24213
+ paid: number;
24214
+ /** @description Уникальные контакты с оплатой, подтверждённой оператором. */
24215
+ confirmedByOperator: number;
24216
+ /** @description Уникальные контакты с косвенной оплатой. */
24217
+ indirect: number;
24218
+ /** @description Уникальные контакты с возможной оплатой, ожидающей решения. */
24219
+ potential: number;
24220
+ };
22316
24221
  BroadcastSegmentCatalogItem: {
22317
24222
  /** Format: uuid */
22318
24223
  id: string;
@@ -22373,8 +24278,16 @@ export interface components {
22373
24278
  items: components["schemas"]["BroadcastCohortRow"][];
22374
24279
  };
22375
24280
  BroadcastSkipReason: {
24281
+ /** @description Код причины из словаря СВОЕГО источника: у preflight это GetCourseWavePreflightReason, у наших отправок — ColdWelcomeOutcome и собственные исходы прогона. Словари не пересекаются, подпись ищется по source. */
22376
24282
  reason: string;
24283
+ /**
24284
+ * @description Чем отсеян: preflight — проверка волны школы, ownSend — ручная холодная отправка, schedule — авторассылка.
24285
+ * @enum {string}
24286
+ */
24287
+ source: "preflight" | "ownSend" | "schedule";
22377
24288
  count: number;
24289
+ /** @description Сколько из count разбирается ПОИМЁННО. Есть только у ownSend: его число — агрегат задачи (полон за всю историю), а построчный след начинается с выкатки, поэтому у старых запусков он законно 0. Витрина открывает список только там, где значение больше нуля, и подписывает «поимённо N из M», когда след неполон. У preflight и schedule поля нет: у них само число и есть сумма построчных строк. */
24290
+ tracedCount?: number;
22378
24291
  };
22379
24292
  BroadcastSkipDayProduct: {
22380
24293
  /** Format: date */
@@ -22406,8 +24319,12 @@ export interface components {
22406
24319
  segment: string | null;
22407
24320
  product: string | null;
22408
24321
  reason: string | null;
24322
+ /** @description Ссылки, ушедшие получателю в окне его волны, со временем перехода. Массив, а не поле: у волны бывает несколько ссылок. */
24323
+ links: components["schemas"]["BroadcastRecipientLink"][];
22409
24324
  };
22410
24325
  BroadcastDealItem: {
24326
+ /** Format: uuid */
24327
+ id: string;
22411
24328
  dealId: number;
22412
24329
  dealNumber: string | null;
22413
24330
  /** Format: uuid */
@@ -22446,11 +24363,30 @@ export interface components {
22446
24363
  actionType: string;
22447
24364
  count: number;
22448
24365
  };
24366
+ BroadcastRecipientLink: {
24367
+ /** @description Идентификатор выдачи — одна ссылка бывает выдана дважды */
24368
+ issueId: string;
24369
+ linkId: string;
24370
+ name: string;
24371
+ /** @description Адрес НА МОМЕНТ ВЫДАЧИ; правка каталога историю не переписывает */
24372
+ targetUrl: string;
24373
+ /** @description Первый живой переход (МСК); null — не нажимали */
24374
+ clickedAt: string | null;
24375
+ /** @description Сколько раз по ЭТОЙ выдаче перешли (боты отсеяны). Не выводится из clickedAt: там MIN, и два перехода по одной выдаче неотличимы от одного. 0 — не нажимали */
24376
+ clickCount: number;
24377
+ };
24378
+ BroadcastLinkOption: {
24379
+ linkId: string;
24380
+ name: string;
24381
+ recipients: number;
24382
+ };
22449
24383
  BroadcastRecipientsDrilldownResponse: {
22450
24384
  items: components["schemas"]["BroadcastRecipientItem"][];
22451
24385
  total: number;
22452
24386
  page: number;
22453
24387
  pageSize: number;
24388
+ /** @description Ссылки ВСЕЙ выборки — справочник фильтра. Считается без самого фильтра и без пагинации: иначе после выбора вернуться к «любой ссылке» будет нечем. */
24389
+ linkOptions: components["schemas"]["BroadcastLinkOption"][];
22454
24390
  };
22455
24391
  BroadcastDealsDrilldownResponse: {
22456
24392
  items: components["schemas"]["BroadcastDealItem"][];
@@ -22489,6 +24425,8 @@ export interface components {
22489
24425
  confirmedBy: string | null;
22490
24426
  /** Format: date-time */
22491
24427
  confirmedAt: string | null;
24428
+ name: string | null;
24429
+ product: string | null;
22492
24430
  };
22493
24431
  BroadcastIndirectPaymentsResponse: {
22494
24432
  items: components["schemas"]["BroadcastIndirectPaymentItem"][];
@@ -22616,7 +24554,7 @@ export interface components {
22616
24554
  /** @enum {string} */
22617
24555
  PaymentCandidateStatus: "PENDING" | "CONFIRMED" | "CONFIRMED_INDIRECT" | "REJECTED";
22618
24556
  /**
22619
- * @description Корзина доказательности возможной оплаты — чем подтверждается участие агента в окне «отправка волны → оплата». DEEP_DIALOG: 3+ реплики клиента и ответы агента. SHORT_DIALOG: 1–2 реплики и ответы агента. NO_AGENT_REPLY: клиент писал, доставленного ответа AI-агента не зафиксировано. SILENT: клиент не отвечал. UNKNOWN: сигналы ещё не посчитаны.
24557
+ * @description Корзина доказательности возможной оплаты — чем подтверждается участие агента в окне «отправка волны → оплата». DEEP_DIALOG: 3+ реплики клиента и минимум два доставленных ответа AI-агента именно на реплику клиента. SHORT_DIALOG: клиент писал и агент отвечал на реплику, но порог глубокого диалога не достигнут. NO_AGENT_REPLY: клиент писал, доставленного ответа AI-агента на его реплику не зафиксировано. SILENT: клиент не отвечал. UNKNOWN: сигналы ещё не посчитаны.
22620
24558
  * @enum {string}
22621
24559
  */
22622
24560
  PaymentEvidenceBucket: "DEEP_DIALOG" | "SHORT_DIALOG" | "NO_AGENT_REPLY" | "SILENT" | "UNKNOWN";
@@ -22828,6 +24766,7 @@ export interface components {
22828
24766
  clientRepliedBeforePayment: boolean | null;
22829
24767
  dialogueInboundCount: number | null;
22830
24768
  dialogueAgentReplyCount: number | null;
24769
+ dialogueAgentResponsiveCount: number | null;
22831
24770
  dialogueOperatorMessageCount: number | null;
22832
24771
  dialogueOtherOutgoingCount: number | null;
22833
24772
  evidenceBucket: components["schemas"]["PaymentEvidenceBucket"];
@@ -23061,6 +25000,24 @@ export interface components {
23061
25000
  /** Format: date-time */
23062
25001
  created_at: string;
23063
25002
  };
25003
+ AmoCrmChannelRegistrationResponse: {
25004
+ /**
25005
+ * @description Адрес вебхука канала для этого воркспейса (пункт 2 письма)
25006
+ * @example https://core.besales.ai/api/webhook/amocrm/055a9626-548b-42bd-8132-afb17925f168
25007
+ */
25008
+ webhookUrl: string;
25009
+ /** @description Текст письма в поддержку AmoCRM целиком, с местами под данные аккаунта */
25010
+ emailTemplate: string;
25011
+ /**
25012
+ * @description Места в письме, которые заполняет человек: их знает только владелец аккаунта. Отдаются списком, чтобы клиент предупредил о них явно, а не надеялся, что человек заметит угловые скобки.
25013
+ * @example [
25014
+ * "<номер учётной записи>",
25015
+ * "<картинку прикладываю>",
25016
+ * "<Id интеграции>"
25017
+ * ]
25018
+ */
25019
+ placeholders: string[];
25020
+ };
23064
25021
  CrmListResponse: {
23065
25022
  crms: components["schemas"]["CrmListItem"][];
23066
25023
  };
@@ -24410,16 +26367,18 @@ export interface components {
24410
26367
  BroadcastMailingVariantId: string[];
24411
26368
  /** @description Механизм запуска: `wave` — доставляет процесс школы (мы штампуем поля сделки), `cold_welcome` — пишем первыми сами. Мультивыбор; ОБА значения = фильтра нет. У строки получателя механизм берётся из её собственного режима, у сделки и кандидата — из когорты по import job (нет метки и нет холодных получателей = wave). */
24412
26369
  BroadcastMechanism: ("wave" | "cold_welcome")[];
26370
+ /** @description ЧТО ЗАПУСТИЛО отправку: `manual` — оператор нажал «Запустить», `registration` — автоприём регистрации по order-вебхуку школы, `schedule` — ночной прогон планировщика. Мультивыбор; выбраны все = фильтра нет. Это ДРУГАЯ ось, а не уточнение механизма: механизм отвечает «чем доставляли». Любой выбор ИСКЛЮЧАЕТ волны школы целиком — у них запускающего в этом смысле нет. */
26371
+ BroadcastLaunchSource: ("manual" | "registration" | "schedule")[];
24413
26372
  /** @description Мультивыбор: повторяйте параметр (`?x=A&x=B`). Одиночное значение остаётся валидным. */
24414
26373
  BroadcastProduct: string[];
24415
26374
  /** @description Добавляет строки без продукта. Можно сочетать с product: значения и NULL объединяются через OR. */
24416
26375
  BroadcastProductMode: "none";
24417
26376
  /** @description Корзины свежести лида (мультивыбор). Под фильтром из ВСЕХ метрик выпадают контакты с неизвестным возрастом. Выбраны все корзины = фильтра нет. */
24418
- BroadcastFreshness: ("0-7" | "8-14" | "15-30" | "31+")[];
26377
+ BroadcastFreshness: ("0-7" | "8-14" | "15-30" | "31-45" | "46-60" | "61+")[];
24419
26378
  /** @description Мессенджеры волны (транспорты GetCourse + UNKNOWN — канал не определён), мультивыбор. Деньги фильтруются по скалярному каналу сделки. */
24420
26379
  BroadcastChannels: string[];
24421
- /** @description cohort — дата запуска; period — дата события. */
24422
- BroadcastView: "cohort" | "period";
26380
+ /** @description cohort — дата запуска; period — дата события; entry — дата входа в сегмент (segment_entered_at: регистрация, конец серии, предсписок). В entry строки без даты входа выпадают всегда, включая mode=all, а события атрибутируются когортно. */
26381
+ BroadcastView: "cohort" | "period" | "entry";
24423
26382
  /** @description Конкретный день кликнутой ячейки (МСК). */
24424
26383
  BroadcastDate: string;
24425
26384
  /** @description Канал кликнутой ячейки; пусто = общий итог. */
@@ -24436,7 +26395,11 @@ export interface components {
24436
26395
  BroadcastDealSortBy: "paidAt" | "client" | "amount" | "channels" | "segment" | "funnel" | "product" | "confidence" | "matchReason";
24437
26396
  /** @description Направление серверной сортировки списка сделок и оплат. */
24438
26397
  BroadcastDealSortOrder: "asc" | "desc";
26398
+ /** @description Колонка сортировки косвенных оплат — те же, что у вкладки «Оплаты», минус `confidence`/`matchReason`: атрибуции по сделке у кандидата нет, её признал оператор. */
26399
+ BroadcastIndirectSortBy: "paidAt" | "client" | "amount" | "channels" | "segment" | "funnel" | "product";
24439
26400
  WorkspaceIdPath: string;
26401
+ ColdWelcomeBatchIdPath: string;
26402
+ ColdWelcomeJobIdPath: string;
24440
26403
  GetCourseWaveRunBatchIdPath: string;
24441
26404
  /** @description workspaceId */
24442
26405
  VoiceTenantHeader: string;
@@ -24681,4 +26644,105 @@ export interface operations {
24681
26644
  };
24682
26645
  };
24683
26646
  };
26647
+ getAmoCrmChannelRegistration: {
26648
+ parameters: {
26649
+ query?: never;
26650
+ header?: never;
26651
+ path: {
26652
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
26653
+ };
26654
+ cookie?: never;
26655
+ };
26656
+ requestBody?: never;
26657
+ responses: {
26658
+ 200: {
26659
+ headers: {
26660
+ [name: string]: unknown;
26661
+ };
26662
+ content: {
26663
+ "application/json": components["schemas"]["AmoCrmChannelRegistrationResponse"];
26664
+ };
26665
+ };
26666
+ };
26667
+ };
26668
+ getCustomReportData: {
26669
+ parameters: {
26670
+ query: {
26671
+ from: string;
26672
+ to: string;
26673
+ granularity?: "day" | "week" | "month" | "total";
26674
+ };
26675
+ header?: never;
26676
+ path: {
26677
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
26678
+ reportId: string;
26679
+ };
26680
+ cookie?: never;
26681
+ };
26682
+ requestBody?: never;
26683
+ responses: {
26684
+ /** @description Данные таблицы и snapshot точного drill-down, если источник его поддерживает. */
26685
+ 200: {
26686
+ headers: {
26687
+ [name: string]: unknown;
26688
+ };
26689
+ content: {
26690
+ "application/json": components["schemas"]["CustomReportDataResponse"];
26691
+ };
26692
+ };
26693
+ 400: components["responses"]["ValidationError"];
26694
+ 401: components["responses"]["Unauthorized"];
26695
+ 403: components["responses"]["Forbidden"];
26696
+ 404: components["responses"]["NotFound"];
26697
+ };
26698
+ };
26699
+ getCustomReportDrilldown: {
26700
+ parameters: {
26701
+ query: {
26702
+ /** @description Начало бакета, YYYY-MM-DD, включительно. */
26703
+ bucketFrom: string;
26704
+ /** @description Конец бакета, YYYY-MM-DD, включительно. */
26705
+ bucketTo: string;
26706
+ /** @description Сохранённая колонка таблицы. */
26707
+ metricKey: string;
26708
+ /** @description Сохранённая строка; отсутствие означает итог бакета. */
26709
+ dimensionValue?: string;
26710
+ /** @description Снимок из ответа живого отчёта; обязателен для источников дожимов. */
26711
+ calculatedAt?: string;
26712
+ /** @description JSON-путь строки сводной; отсутствие означает общий итог. */
26713
+ rowPath?: string;
26714
+ /** @description Непрозрачный MVCC-снимок PostgreSQL из ответа живого отчёта. */
26715
+ executionDbSnapshot?: string;
26716
+ /** @description Fingerprint актуальных шагов и атрибуции из ответа живого отчёта. */
26717
+ expectedCurrentStepsFingerprint?: string;
26718
+ /** @description updatedAt определения из ответа живого отчёта. */
26719
+ expectedReportUpdatedAt: string;
26720
+ limit?: number;
26721
+ offset?: number;
26722
+ };
26723
+ header?: never;
26724
+ path: {
26725
+ workspaceId: components["parameters"]["WorkspaceIdPath"];
26726
+ reportId: string;
26727
+ };
26728
+ cookie?: never;
26729
+ };
26730
+ requestBody?: never;
26731
+ responses: {
26732
+ /** @description Страница исполнений за выбранной ячейкой. */
26733
+ 200: {
26734
+ headers: {
26735
+ [name: string]: unknown;
26736
+ };
26737
+ content: {
26738
+ "application/json": components["schemas"]["CustomReportDrilldownResponse"];
26739
+ };
26740
+ };
26741
+ 400: components["responses"]["ValidationError"];
26742
+ 401: components["responses"]["Unauthorized"];
26743
+ 403: components["responses"]["Forbidden"];
26744
+ 404: components["responses"]["NotFound"];
26745
+ 409: components["responses"]["Conflict"];
26746
+ };
26747
+ };
24684
26748
  }