Интеграция · через API и вебхуки

WhatsApp → Telegram: входящие в рабочий чат и ответ реплаем

Обновлено

Клиенты пишут в WhatsApp, а команда живёт в Telegram. Вместо того чтобы передавать телефон с рабочим номером из рук в руки, можно пересылать каждое входящее в общий чат Telegram и отвечать клиенту реплаем — ответ уйдёт в WhatsApp с номера компании.

Страница для небольших команд — магазинов, служб доставки, сервисов, — которым нужен простой общий «почтовый ящик» для WhatsApp без CRM. Понадобится Telegram-бот и небольшой сервер на Node.js.

Из Telegram в WhatsApp
  1. Менеджер отвечает реплаем в Telegram
  2. ваш бот
  3. POST /messages/send
  4. клиент в WhatsApp
Из WhatsApp в Telegram
  1. Клиент пишет в WhatsApp
  2. вебхук wapi.kz
  3. ваш бот
  4. сообщение в рабочем чате Telegram

Что можно автоматизировать

  • Входящие в общий чат. Каждое сообщение клиента появляется в группе Telegram с телефоном и номером, на который он написал.
  • Ответ реплаем. Менеджер отвечает на пересланное сообщение — бот отправляет текст клиенту в WhatsApp и подтверждает отправку.
  • Несколько номеров — разные чаты. Номер продаж пишет в чат продаж, номер сервиса — в чат сервиса. Подробнее — в гайде о нескольких номерах.
  • Ответили с телефона. Если кто-то ответил клиенту прямо с телефона (событие message.out), бот показывает это в чате, чтобы никто не ответил второй раз.
  • Номер отключился. Событие session.status со статусом FAILED или STOPPED — тревога в чат: пора переподключить по QR.
  • Баланс на исходе. Раз в день бот проверяет GET /balance и пишет в чат, если days_left меньше трёх.

Как это устроено

Со стороны Telegram: бот получает обновления через вебхук (setWebhook с параметром secret_token — Telegram пришлёт его в заголовке X-Telegram-Bot-Api-Secret-Token) и пишет в чат методом sendMessage с chat_id и text. В группе бот в режиме приватности всё равно получает ответы на свои сообщения — для реплаев этого достаточно.

Со стороны wapi.kz — вебхук номера с событием message (документация) и POST /messages/send для ответа (документация).

Как бот понимает, кому отвечать: в первой строке пересланного сообщения он пишет телефон клиента и id номера. Когда менеджер отвечает реплаем, бот читает эту строку из цитаты. База данных не нужна, и после перезапуска сервера ответы на старые сообщения тоже работают.

Настройка по шагам

  1. Подключите номер в wapi.kz (как подключить) и возьмите ключ в разделе «API и MCP».
  2. Создайте бота у @BotFather, получите токен, добавьте бота в рабочую группу и узнайте chat_id группы.
  3. Разверните код ниже на сервере с публичным https-адресом, задайте переменные окружения.
  4. Укажите Telegram адрес бота: вызовите setWebhook с url = https://ваш-сервер.kz/tg и своим secret_token.
  5. В кабинете wapi.kz задайте вебхук номера https://ваш-сервер.kz/wapi?token=СЕКРЕТ.
  6. Напишите на номер с другого телефона, ответьте реплаем в группе и проверьте, что ответ пришёл в WhatsApp.

Пример кода

Node.js 18+ и Express. Первый маршрут пересылает в Telegram входящие, ответы с телефона и отключение номера, второй — отправляет реплаи клиенту.

JavaScript
const express = require("express");
const app = express();
app.use(express.json());

const TG = `https://api.telegram.org/bot${process.env.TG_TOKEN}`;
const CHAT = process.env.TG_CHAT_ID; // id рабочей группы, например -1001234567890

const tg = (method, body) =>
  fetch(`${TG}/${method}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });

// 1. WhatsApp → Telegram
app.post("/wapi", (req, res) => {
  if (req.query.token !== process.env.WAPI_HOOK_TOKEN) return res.sendStatus(403);
  res.sendStatus(200); // ответить сразу, обработать — после
  const e = req.body;
  let text;
  if (e.event === "message" && e.payload.from.endsWith("@c.us")) { // только личные чаты с телефоном
    const body = e.payload.hasMedia ? "[фото или файл — откройте чат на телефоне]" : e.payload.body;
    text = `WhatsApp ${e.payload.from.split("@")[0]} · номер ${e.wapi.number_id}\n\n${body}`;
  } else if (e.event === "message.out") {
    text = `С телефона ответили ${String(e.payload.from).split("@")[0]}: ${e.payload.body}`; // чат — всегда в from
  } else if (e.event === "session.status" && ["FAILED", "STOPPED"].includes(e.payload.status)) {
    text = `Номер ${e.wapi.phone} отключился (${e.payload.status}) — переподключите в кабинете`;
  }
  if (text) tg("sendMessage", { chat_id: CHAT, text }).catch(console.error);
});

// 2. Реплай в Telegram → WhatsApp
app.post("/tg", async (req, res) => {
  if (req.get("X-Telegram-Bot-Api-Secret-Token") !== process.env.TG_SECRET) return res.sendStatus(403);
  res.sendStatus(200);
  const msg = req.body.message;
  const head = msg?.reply_to_message?.text?.match(/^WhatsApp (\d{10,15}) · номер (\d+)/);
  if (!head || !msg.text || String(msg.chat.id) !== CHAT) return;
  try {
    const r = await fetch("https://wapi.kz/api/v1/messages/send", {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.WAPI_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({ to: head[1], text: msg.text, from: Number(head[2]) }),
    });
    const data = await r.json();
    await tg("sendMessage", {
      chat_id: CHAT,
      reply_parameters: { message_id: msg.message_id },
      text: r.ok ? "Отправлено в WhatsApp" : `Не отправлено: ${data.code} — ${data.error}`,
    });
  } catch (err) {
    console.error(err);
  }
});

app.listen(3000);

Здесь ключ аккаунта: бот отвечает с того номера, на который написал клиент, — его id берётся из пересланного сообщения и уходит в поле from.

Ограничения

  • Это не операторский чат: нет назначения ответственного, статусов обращений и поиска по истории, как в helpdesk или CRM. Для небольшой команды этого обычно хватает.
  • Фото и документы от клиентов бот из примера не пересылает — в событии hasMedia: true, и бот пишет об этом в чат. Сам файл сохраняется у нас и доступен по ссылке media.url в GET /messages/{id}: бот может скачать его и отправить в Telegram.
  • Сообщения клиентов окажутся на серверах Telegram. Если для вас важна локализация персональных данных, учтите это — подробнее в гайде о хранении ПД в Казахстане.
  • Вебхуки wapi.kz не повторяются: если сервер бота лежал, пропущенное заберите через GET /messages?since=… (история).
  • Лимит — 1 сообщение в секунду с номера (лимиты). Ответы тем, кто написал сам, не расходуют лимит первых сообщений новым людям.

Не хотите поднимать бота сами? Зарегистрируйтесь, подключите номер и оставьте заявку из кабинета — поможем с настройкой. Номер — 9 900 ₸ в месяц, сообщения и вебхуки бесплатны (цены).

Частые вопросы

Увидит ли клиент, что ему ответили из Telegram?

Нет. Для клиента это обычное сообщение с вашего номера WhatsApp. В истории wapi.kz оно будет с source: "api".

Можно ли собрать это без своего сервера?

Да, на n8n или Make: узел приёма вебхука, запрос к Telegram Bot API и обратная цепочка для реплаев. Логика та же.

Что, если два менеджера ответят одновременно?

Клиент получит оба ответа. Договоритесь в команде: кто первым поставил реакцию на сообщение, тот и отвечает.

Можно ли так отвечать в группы WhatsApp?

Нет, отправка в группы через API недоступна — только личные чаты. Поэтому бот пропускает сообщения из групп.

Подключите WhatsApp к Telegram

9 900 ₸ в месяц за номер, без платы за сообщения. Сервер в Казахстане, оплата Kaspi или счётом на ТОО/ИП. Подключение — около 5 минут.

Гайды по теме

Другие интеграции