Интеграция Chatwoot и Telegram через Wappi: двусторонний мост с вебхуками

Структура, интеграция, шлюзы
Ответить
Аватара пользователя
MarkT
Site Admin
Сообщения: 79
Зарегистрирован: 27 ноя 2025, 20:51

Интеграция Chatwoot и Telegram через Wappi: двусторонний мост с вебхуками

Сообщение MarkT »

Скриншот-20260418-184827.jpg
Скриншот-20260418-184827.jpg (146.81 КБ) 259 просмотров
В этой теме разберём реальный рабочий пример интеграции Chatwoot и Telegram через сервис Wappi (Telegram User API / tapi) в условиях блокировок.

Результат: входящие сообщения из Telegram попадают в Chatwoot, а ответы оператора из Chatwoot уходят обратно в Telegram, со статусами отправки.

1. Общая схема интеграции

Участники:
– Telegram (пользовательский аккаунт, подключённый в Wappi как профиль «ТЕЛЕГА»).
– Wappi (Telegram User API, вебхуки входящих и статусов).

– Chatwoot (вебхуки событий message_created).

– Наш PHP‑шлюз на сервере.

Потоки:
Входящие: Telegram → Wappi → вебхук wappipro-webhook.php → Chatwoot API (создаём сообщение в нужном Inbox).
Исходящие: Chatwoot → вебхук chatwoot-webhook.php → Wappi /tapi/sync/message/send → Telegram.


2. Вебхук Chatwoot → Telegram (исходящие)

В Chatwoot создаём вебхук на событие message_created и указываем URL:

Код: Выделить всё

https://lmchat.ru/gate/chatwoot-webhook.php
Пример полезной нагрузки Chatwoot при отправке оператором сообщения в Inbox «Телега»:

Код: Выделить всё

{
"event": "message_created",
"id": 746,
"content": "Тест 5",
"message_type": "outgoing",
"conversation": {
"contact_inbox": {
"source_id": "1006345599"
}
},
"account": { "id": 1, "name": "NPO TANDEM" }
}
Ключевые поля:
event — фильтруем только message_created;
message_type — берём только outgoing (ответ оператора);

content — текст сообщения;
conversation.contact_inbox.source_id — Telegram chatId из Wappi.


2.1. Базовый обработчик chatwoot-webhook.php

Ниже упрощённый пример нашего скрипта, который:

– принимает вебхук Chatwoot;
– фильтрует только исходящие сообщения;
– отправляет текст в Telegram через Wappi Telegram API (/tapi).

Код: Выделить всё

<?php
$config = require _DIR_ . '/config.php';

$logFile = _DIR_ . '/chatwoot_telegram_out_log.txt';

// 1. Читаем сырой JSON
$raw = file_get_contents('php://input');
file_put_contents($logFile, date('c') . " | RAW: " . $raw . PHP_EOL, FILE_APPEND);

$data = json_decode($raw, true);
if (!$data) {
http_response_code(400);
echo 'Invalid JSON';
return;
}

// 2. Берём только message_created
$event = $data['event'] ?? null;
if ($event !== 'message_created') {
http_response_code(200);
echo 'Ignored event: ' . $event;
return;
}

// 3. Берём только исходящие (agent -> клиент)
$messageType = $data['message_type'] ?? null;
if ($messageType !== 'outgoing') {
http_response_code(200);
echo 'Ignored message_type: ' . $messageType;
return;
}

// 4. Контент
$content = trim($data['content'] ?? '');
if ($content === '') {
http_response_code(200);
echo 'Empty content';
return;
}

// 5. chatId из conversation.contact_inbox.source_id
$conversation = $data['conversation'] ?? [];
$contactInbox = $conversation['contact_inbox'] ?? [];
$chatId = $contactInbox['source_id'] ?? null;
if (!$chatId) {
http_response_code(200);
echo 'No chatId (source_id)';
return;
}

// 6. Формируем запрос к Wappi Telegram API (tapi)
$profileId = $config['wappipro_profile_id']; // 47d4781b-365b

$wappiUrl = 'https://wappi.pro/tapi/sync/message/send?profile_id=' . urlencode($profileId);

$payload = [
'recipient' => (string)$chatId,
'body' => $content,
];

// 7. Отправляем в Wappi
$ch = curl_init($wappiUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'accept: application/json',
'Content-Type: application/json',
'Authorization: ' . $config['wappipro_api_token'],
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);

// Логируем результат
file_put_contents(
$logFile,
date('c') . " | WAPPI SEND | {$code} | {$wappiUrl} | " .
json_encode($payload, JSON_UNESCAPED_UNICODE) . " | {$response} | {$error}" . PHP_EOL,
FILE_APPEND
);

http_response_code(200);
echo 'OK';
Ключевой момент: вместо /api/sync/message/send нужно использовать /tapi/sync/message/send для Telegram User API.


3. Вебхук Wappi → Chatwoot (входящие)

Со стороны Wappi в профиле «Столовка ТЕЛЕГА» настроен вебхук:

Код: Выделить всё

https://lmchat.ru/gate/wappipro-webhook.php
Сюда Wappi присылает:
– входящие сообщения из Telegram;
– события статусов (delivered/read), если включены нужные типы уведомлений.

Простейшая идея обработчика:

Код: Выделить всё

<?php
// wappipro-webhook.php

$raw = file_get_contents('php://input');
$data = json_decode($raw, true);

// 1. Входящее сообщение от пользователя
if (!empty($data['event']) && $data['event'] === 'message_new') {
$chatId = $data['chat_id']; // см. точные поля по своей доке
$text = $data['text'] ?? '';

// Создаём сообщение в Chatwoot через API (Inbox Телега)
// ...
}

// 2. Обновление статуса отправленного сообщения
if (!empty($data['event']) && $data['event'] === 'message_status') {
$messageId = $data['message_id'];
$status = $data['status']; // pending / delivered / read / error

// Находим соответствующее сообщение в Chatwoot и обновляем его content_attributes
// ...
}

http_response_code(200);
echo 'OK';
Точные названия полей для message_new и message_status смотрим в официальной документации Telegram API на сайте Wappi.


4. Сохранение message_id Wappi в Chatwoot

Когда мы отправляем сообщение через /tapi/sync/message/send, Wappi в ответе отдаёт message_id.

Чтобы потом связать статус (delivered/read) с сообщением в Chatwoot, мы сохраняем этот message_id в content_attributes сообщения Chatwoot.

Шаг 1. Добавляем после отправки в Wappi разбор ответа и PATCH в Chatwoot:

Код: Выделить всё

$responseData = json_decode($response, true);

if ($code === 200 && is_array($responseData) && !empty($responseData['message_id'])) {
$wappiMessageId = $responseData['message_id'];
$chatwootMessageId = $data['id'] ?? null; // id сообщения Chatwoot из вебхука

if ($chatwootMessageId) {
$cwUrl = rtrim($config['chatwoot_api_url'], '/') .
"/api/v1/accounts/{$config['chatwoot_account_id']}/messages/{$chatwootMessageId}";

$cwPayload = [
'content_attributes' => [
'wappi_message_id' => $wappiMessageId,
],
];

$ch2 = curl_init($cwUrl);
curl_setopt_array($ch2, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'api_access_token: ' . $config['chatwoot_api_token'],
],
CURLOPT_POSTFIELDS => json_encode($cwPayload, JSON_UNESCAPED_UNICODE),
]);
$cwResp = curl_exec($ch2);
$cwCode = curl_getinfo($ch2, CURLINFO_HTTP_CODE);
$cwError = curl_error($ch2);
curl_close($ch2);
}
}
[ref]API Chatwoot для обновления сообщений описан в их документации по webhooks и API.[/ref]

Шаг 2. В wappipro-webhook.php по событию message_status по message_id ищем нужное сообщение в Chatwoot (по content_attributes.wappi_message_id) и обновляем, сохраняя текущий статус (например, wappi_status = delivered/read).


5. Фильтрация спама и блокировка пользователей

Часть пользователей может слать спам. Есть два уровня защиты:

5.1. Блокировка на уровне нашего webhook (Wappi → сервер)

В wappipro-webhook.php можно вести простой черный список chatId, сообщения от которых игнорируются:

Код: Выделить всё

$blockedChatIds = [
'1001234567',
'1007654321',
];

$chatId = $data['chat_id'] ?? null;

if ($chatId && in_array($chatId, $blockedChatIds, true)) {
http_response_code(200);
echo 'Blocked sender';
return;
}
Такой пользователь продолжит писать в Telegram, но его сообщения даже не попадут в Chatwoot.

5.2. Блокировка/пометка контакта в Chatwoot

Chatwoot позволяет:

– пометить контакт как blocked или spam (через UI или API);
– добавлять labels вроде [spam] для дальнейшей фильтрации.

Можно комбинировать:

– при первом ручном определении спама оператор в Chatwoot помечает контакт label spam;
– в wappipro-webhook.php при входящем сообщении проверять через API Chatwoot, есть ли у контакта этот label, и если да — игнорировать такие сообщения на своей стороне.


6. Итоги

В рамках интеграции мы реализовали:

– приём входящих сообщений из Telegram в Chatwoot через вебхуки Wappi;

– отправку ответов из Chatwoot обратно в Telegram через Wappi Telegram API (tapi) с эндпоинтом

Код: Выделить всё

POST https://wappi.pro/tapi/sync/message/send?profile_id=...
– логирование всего трафика и разбор ошибок;
– основу для постановки статуса доставки/прочтения через сохранение message_id и обработку статус‑вебхуков;

– возможность фильтровать спамеров на стороне нашего кода.

Дальше можно развивать интеграцию:
– рисовать «двойные галочки» в UI Chatwoot по статусам из content_attributes;
– автоматизировать блокировку по определённым триггерам;
– добавлять команды-бота (например, автоответы при определённых шаблонах сообщений).

Если кому интересно — могу выложить более полный код wappipro-webhook.php и пример конфигов.
Ответить