Перейти к основному содержанию
External Agent доступен на тарифных планах YCloud Pro и выше.
Подключите собственного ИИ-агента к YCloud в качестве External Agent. Ваш агент работает в вашей инфраструктуре и функционирует бок о бок с операторами в Inbox: он принимает сообщения клиентов, отправляет ответы, запрашивает историю переписки и передает диалоги сотрудникам. YCloud отправляет события на ваш URL-адрес Webhook. Ваш сервис обрабатывает эти события и вызывает REST API Inbox для отправки ответа или управления диалогом. YCloud не обращается к вашему API инференса ИИ, а HTTP-ответ от вашего Webhook не отправляется клиенту.

Перед началом работы

Подготовьте:
  • Публично доступную конечную точку HTTPS, принимающую запросы JSON POST.
  • Сервис, который проверяет подписи Webhook, сохраняет события, предотвращает дублирование обработки и запускает вашего ИИ-агента.
  • Стандартный API-ключ аккаунта YCloud, хранящийся на вашем сервере. Ключи API приложений разработчика (Developer App) не поддерживаются этими конечными точками Inbox.
  • Бизнес-номер WhatsApp, подключенный к YCloud, а также команду операторов или отдельного сотрудника для перевода обращений.
Используйте https://api.ycloud.com в качестве базового URL API.

Подключение агента

1. Создайте External Agent

  1. В консоли YCloud перейдите в раздел AI Agent > AI Agent.
  2. Выберите Create Agent > External Agent.
  3. Укажите Name и ваш Webhook URL, например https://agent.example.com/webhooks/ycloud.
  4. Нажмите Save.
  5. Скопируйте сгенерированный Bot ID из параметров агента. Используйте это значение как botId в запросах к API; передавать идентификатор из вашей собственной ИИ-системы не требуется.
Форма создания External Agent в YCloud с полями Name, Webhook URL и кнопкой Save.

Create an External Agent with a name and a webhook URL. This example shows the form before saving.

На странице сведений отображаются конечная точка Webhook, ее Signing secret и четыре типа событий. Используйте секрет подписи для проверки входящих событий. Выберите View delivery logs , чтобы проанализировать доставку Webhook. Эта же конечная точка доступна на странице Webhooks . Храните секрет подписи конечной точки отдельно от вашего API-ключа. Секрет проверяет входящие события Webhook; X-API-Key аутентифицирует ваши исходящие REST-запросы. Bot ID является идентификатором, а не учетными данными.

2. Назначьте номер WhatsApp

Перейдите в WhatsApp Manager > WhatsApp accounts, откройте настройки бизнес-номера и выберите Inbox > Assignment. В блоке Priority 3 Assign to выберите AI Agent, а затем укажите своего агента в разделе External Agent списка агентов. Проверьте приоритет правил: назначение ответственному за клиента сотруднику или последнему обрабатывавшему оператору может иметь более высокий приоритет. См. Conversation assignment rules. Один External Agent может обрабатывать несколько номеров. Каждый номер связывается только с одним ботом одновременно. Управлять этими связями можно в настройках назначения номера.

3. Обработайте диалог

  1. Клиент отправляет сообщение в WhatsApp на ваш бизнес-номер.
  2. YCloud открывает или продолжает диалог в Inbox и применяет правила назначения для этого номера.
  3. Когда ваш External Agent обрабатывает диалог, YCloud отправляет соответствующие события Webhook на его конечную точку.
  4. Ваш сервис проверяет и сохраняет событие, возвращает 2xx и обрабатывает входящие данные от клиента асинхронно.
  5. Ваш сервис вызывает API Inbox для отправки ответа, перевода диалога или его закрытия.
  6. Ваш сервис отслеживает статус доставки с помощью whatsapp.message.updated.

Идентификаторы и их назначение

Идентификаторы представляют собой строки. Метки времени используют формат UTC RFC 3339. Используйте dialogId, а не conversationId, в путях API для диалогов.

Получение событий Webhook

Все четыре типа событий поступают на один и тот же webhook URL. Каждая специальная доставка External Agent включает id, type, apiVersion, createTime и externalBotContext, а также соответствующий бизнес-объект.

Проверка, сохранение и подтверждение

Проверяйте заголовок YCloud-Signature с помощью секретного ключа подписи эндпоинта и необработанного тела HTTP-запроса перед парсингом JSON. Формат подписи:
Используйте сравнение с постоянным временем выполнения и проверяйте метку времени с разумным допуском, например пять минут. См. примеры проверки подписи в разделе Реализация получателя Webhook. Сохраните событие и его состояние дедупликации, а затем незамедлительно верните любой успешный ответ 2xx. Выполняйте инференс ИИ и другие ресурсоемкие операции асинхронно. Ответы, отличные от 2xx, и таймауты могут приводить к ограниченному количеству повторных попыток. Выполняйте дедупликацию по (botId, event.id) в рамках вашего аккаунта YCloud. Изменение назначения может отправлять уведомления как исходящему, так и входящему агентам; использование только глобального ID события может привести к отбрасыванию уведомления для одного из агентов. Сохраняйте состояние обработки, чтобы повторное событие не вызвало отправку второго ответа.

Пример: сообщение клиента

Считывайте содержимое от клиента из inboxMessage.inbound. События создания исходящих сообщений используют вместо этого inboxMessage.outbound. Сохраняйте неизвестные типы сообщений и поля для совместимости, а не обрабатывайте их как текст.

Решение об ответе

externalBotContext — это снимок состояния, сделанный в момент формирования уведомления. Поле botId определяет бота-получателя; assignee определяет фактического обработчика в этом снимке. После передачи диалога эти значения могут различаться. Значение actionable=true означает, что в этот момент бот-получатель обрабатывал открытый диалог. Оно также может быть true в событии создания исходящего сообщения или в отчете о доставке.
Не запускайте ответ ИИ исключительно на основании actionable. Проверяйте тип события и направление сообщения. Задержанное событие не гарантирует, что диалог все еще обрабатывается вашим агентом. Запрашивайте текущий диалог при необходимости и обрабатывайте ошибки владения при каждом запросе на запись.
События могут приходить неоднократно или в нарушенном порядке. Поле очередности событий отсутствует. Группируйте задачи по dialogId и избегайте повторной обработки одних и тех же входящих данных клиента. Событие первоначального назначения не должно отдельно вызывать второй ответ на первое сообщение клиента.

Что происходит после передачи диалога или его закрытия?

Новые сообщения клиентов и ответы операторов больше не доставляются предыдущему External Agent, как только диалог переходит к человеку, попадает в очередь, остается без исполнителя или закрывается. Предыдущий агент по-прежнему получает соответствующее уведомление о передаче диалога или его закрытии. Уведомления о создании сообщений и отчеты о доставке для сообщений, которые он уже отправил, остаются связанными с этим агентом-отправителем даже после передачи диалога или смены привязки номера. Ранее созданные уведомления могут поступать с опозданием. Отменяйте ожидающие задачи при смене ответственного или закрытии диалога и не возобновляйте их только потому, что у старого события указано actionable=true. Обычные эндпоинты webhook сохраняют существующее поведение подписки и формат полезной нагрузки. Специальная доставка External Agent добавляет поле externalBotContext; не требуйте наличия этого поля при обычных доставках whatsapp.message.updated.

Использование Inbox API

Передавайте X-API-Key в каждом запросе и Content-Type: application/json в запросах POST. Во всех приведенных ниже примерах используются плейсхолдеры идентификаторов. Замените их значениями вашего агента и полученных событий. Успешные ответы возвращают бизнес-объект напрямую, без оболочки data. Операции записи проверяют, открыт ли диалог и обрабатывается ли он указанным ботом в данный момент. YCloud определяет отправителя и клиента по диалогу; не передавайте tenantId, from, to, recipient, operatorId или source для их переопределения.

Получение текущего диалога

Проверьте status, assignee и canAct. Поле bot может указывать на последнего связанного внешнего бота и не является подтверждением текущего владения диалогом. canAct отражает разрешения запрашиваемого бота на момент запроса; последующая запись все равно выполняет свои собственные проверки.

Получение истории переписки

Ответ содержит items и nextCursor. Каждый элемент включает сообщение Inbox id, direction, type, content и createTime. Для текстового сообщения прочитайте content.text.body. История включает видимые клиенту сообщения из той же переписки, возможно, из предыдущих диалогов. Собственное значение dialogId сообщения может отличаться от запрашиваемого диалога или отсутствовать в более старой истории. Внутренние заметки, приватные сводки передачи диалога и внутренние системные сообщения исключаются. Сообщения возвращаются по возрастанию ID сообщения, от более старых к более новым. Опустите after в первом запросе; передавайте nextCursor без изменений в качестве after в последующих запросах, пока оно не станет null. Значение limit по умолчанию равно 50, допустимый диапазон — от 1 до 100. Список целей для передачи диалога использует ту же схему пагинации.

Отправка ответа

Параметры botId и message обязательны. sourceEventId и replyToMessageId необязательны. Ссылка на ответ представляет собой ID сообщения Inbox, например inboxMessage.id; она не является wamid.
Проверяйте status, даже когда HTTP возвращает 200. accepted означает, что сообщение поступило в конвейер отправки, а не то, что оно дошло до клиента. Ответ 200 также может содержать failed; поле channelMessageId может быть еще недоступно. Используйте whatsapp.message.updated для отслеживания последующих состояний, включая sent, delivered, read, failed, expired или deleted. Сопоставляйте externalBotContext.inboxMessageId в квитанции с inboxMessageId из ответа на отправку. Проверяйте whatsappMessage.errorCode и errorMessage на предмет ошибок.

Типы сообщений

Объект message использует стандартную модель сообщений WhatsApp: type плюс соответствующее поле с контентом. Примеры включают text, image, video, audio, document, sticker, location, contacts, interactive, template и reaction. Существующие требования WhatsApp к отправке сообщений и шаблонам по-прежнему действуют. Например, замените объект message на:
Для медиафайлов укажите либо id, либо link. Сведения о структуре тела сообщения см. в разделе Отправка сообщения WhatsApp. Отправляйте ответ через указанный выше эндпоинт Inbox, чтобы он использовал проверки обработчика диалога и контекст Inbox. Не передавайте и не полагайтесь на filterUnsubscribed или filterBlocked в этом запросе на отправку сообщения Inbox. Ответы клиентов могут содержать interactive.button_reply, interactive.list_reply, interactive.nfm_reply или button. Поле response_json в ответе Flow является строкой JSON. Входящий тип button не является исходящим типом сообщения для этого эндпоинта.

Передача диалога человеку

Сначала запросите список доступных команд или операторов для бизнес-номера диалога:
Используйте type=agent, чтобы вместо этого получить список участников. Каждый возвращенный целевой объект предоставляет id и type для запроса на передачу диалога. Необязательное поле online оператора отражает статус присутствия; оно не гарантирует немедленного назначения.
Вы должны указать target с type (team или agent) и id. Запасного варианта передачи человеку по умолчанию нет. Необязательное поле reason поддерживает до 256 символов; необязательное поле summary поддерживает до 4 000 символов и не отображается в видимой клиенту истории сообщений. Ответ содержит outcome и обновленный dialog. Возможные результаты: assigned, queued, team_unassigned или unassigned. Проверяйте фактический результат, а не предполагайте, что человек принял диалог. При передаче сохраняется тот же dialogId. Как только ваш агент теряет владение, прекратите отвечать или пытаться закрыть этот диалог.

Закрытие решенного диалога

Ответ содержит dialog с status=closed и canAct=false. Ваш агент не может продолжать отправку сообщений или передачу этого закрытого диалога. Последующее валидное сообщение от клиента начинает новый диалог и повторно запускает правила распределения для этого номера.

Обработка ошибок и повторные попытки

В ответах с ошибками используется объект error с status, code, message и requestId. Сохраняйте ID запроса при обращении в службу поддержки YCloud.
sourceEventId и X-Request-Id поддерживают трассировку; ни один из них не является ключом идемпотентности. API не обеспечивает дедупликацию между запросами. Слепая повторная попытка после неоднозначного результата может привести к отправке дублирующего сообщения.
Отслеживайте ошибки Webhook в разделе View delivery logs . Сохраняйте идентификаторы событий, диалогов, сообщений, запросов и результаты обработки. Количество повторных попыток отправки Webhook ограничено, поэтому при необходимости используйте запросы диалогов и истории для восстановления контекста.

Часто задаваемые вопросы

Можно ли подключить агента, созданного на базе моего собственного ИИ-фреймворка?

Да. Ваш сервис должен принимать и верифицировать вебхуки YCloud, а также вызывать REST API Inbox. Вы сами определяете, как ваш сервис генерирует ответы, обращается к базе знаний и вызывает собственные инструменты.

Будет ли мой агент получать все переписки Inbox?

Нет. Его выделенный эндпоинт получает события только в рамках назначенной ему зоны ответственности, а также соответствующие уведомления о назначении и закрытии и отчеты о доставке для отправленных им сообщений. Новые сообщения после передачи диалога человеку не пересылаются предыдущему агенту. Ранее сгенерированные события могут приходить с задержкой.

Может ли мой агент использовать сообщения из предыдущих диалогов?

Да. Эндпоинт истории возвращает видимую клиенту историю переписки, включая более ранние диалоги. Используйте собственное значение dialogId каждого сообщения, если оно доступно; не предполагайте, что каждое возвращенное сообщение относится к текущей сессии обслуживания.

Что произойдет, если я сменю агента, назначенного на номер?

Открытые диалоги, которые в данный момент обрабатываются ботом, асинхронно переназначаются в соответствии с правилами маршрутизации номера. Сменяемый агент получает assignmentRole=outgoing и должен прекратить работу. Новый агент получает reason=phone_binding_changed со значением assignmentRole=incoming; он должен запросить текущий диалог и историю, прежде чем продолжить. Идентификатор диалога и история остаются неизменными. Диалоги, которые в данный момент обрабатываются оператором-человеком, не передаются новому боту при таком переназначении номера. После того как другой бот заменит его, прежний бот больше не сможет запрашивать этот диалог через данные эндпоинты.

Становится ли ответ моего вебхука ответом клиенту?

Нет. Верните 2xx, чтобы подтвердить получение события, а затем отправьте ответ клиенту через POST /v2/inbox/dialogs/{dialogId}/messages.

Почему мой агент получает actionable=true для своего собственного ответа?

Это поле описывает, кто вел открытый диалог в момент генерации события. Поэтому события создания исходящих сообщений и отчеты о доставке могут содержать actionable=true. Запускайте стандартный ответ ИИ только для входящего события inbox.message.created и учитывайте изменения владельца активного диалога.