Результат: входящие сообщения из 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Код: Выделить всё
{
"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';
3. Вебхук Wappi → Chatwoot (входящие)
Со стороны Wappi в профиле «Столовка ТЕЛЕГА» настроен вебхук:
Код: Выделить всё
https://lmchat.ru/gate/wappipro-webhook.php– входящие сообщения из 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';
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);
}
}
Шаг 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;
}
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 и пример конфигов.