← Все статьи
Кейс

Один LINE-вебхук на всю японскую команду: как стартап из Фукуоки направляет сообщения LINE в Slack, CRM и ИИ

Во вторник в 9:47 утра клиент из Осаки написал сообщение своему аккаунт-менеджеру в LINE: «Экспорт CSV постоянно падает — это известная проблема?» Аккаунт-менеджер была на совещании. Сообщение пролежало на её телефоне три часа. К тому моменту, когда она ответила, клиент уже оформил тикет в службу поддержки через сайт — и отметил компанию в X, спросив, следит ли вообще кто-нибудь за их каналом в LINE.

Это не история об ограничениях платформы. LINE отлично работает как мессенджер. Проблема заключалась в том, что шесть человек в офисе Фукуоки получали сообщения клиентов на свои личные аккаунты LINE, на свои телефоны, без какого-либо общего представления о том, кто и на что отвечает. Компания — B2B SaaS-команда, продающая инструмент для планирования логистики складам по всей Японии и Юго-Восточной Азии — переросла тот этап, когда «каждый проверяет свой LINE» был жизнеспособной стратегией поддержки. Но все альтернативы, казалось, требовали перевода клиентов с LINE, а в Японии это неприемлемо.

Очередь, которой не было

В начале 2026 года система поддержки команды выглядела так: три менеджера по продажам и два инженера поддержки, у каждого — свой аккаунт LINE, который клиенты добавляли в друзья. Сообщения приходили на личные телефоны. Не было ни общей входящей очереди, ни отслеживания ответов, ни SLA. Если кто-то болел, его сообщения оставались непрочитанными до возвращения. Если клиент писал после 19:00, он ждал до следующего рабочего дня — не потому что команда не хотела помочь, а потому что никто не знал о поступившем сообщении.

Компания рассматривала путь через официальный аккаунт LINE (Official Account, OA), который предоставляет общую очередь и некоторую автоматизацию. Однако процесс верификации OA занимает до 60 рабочих дней, а уровень Unverified ограничивает список контактов 500 друзьями — жёсткий потолок для команды, клиентская база которой приближалась к 800. Уровни Verified и Premium снимают эти ограничения, но предусматривают ежемесячную плату и правила окна взаимодействия, регулирующие, когда бизнес может инициировать контакт. Эта команда не инициировала контакты — она отвечала. Машина OA-рассылок решала проблему, которой у них не было.

Тем временем операционные издержки от текущего положения накапливались. В первом квартале 2026 года команда зафиксировала 23 случая, когда сообщение клиента оставалось без ответа более четырёх часов. Семь из них привели к эскалации тикетов через другие каналы. Два вылились в публичные жалобы в X. Руководитель поддержки Кэндзи завёл таблицу для отслеживания пропущенных ответов. Через шесть недель он перестал её обновлять.

Один вебхук — три получателя

Переломным моментом стал не кризис, а сообщение в Slack от CTO компании, который изучал маршрутизацию сообщений на основе webhook-ов. Идея была проста: вместо того чтобы каждый проверял свой LINE, подключить все шесть аккаунтов LINE через единый неофициальный интерфейс, который пересылает входящие сообщения в инструменты, которыми команда уже пользуется. Slack — для видимости в реальном времени. CRM — для логирования и последующей работы. А для рутинных вопросов — черновик от ИИ, который команда может просмотреть перед отправкой.

Команда подключила свои аккаунты LINE к UnifyPort через аутентификацию по QR-коду — единственный режим аутентификации, который LINE поддерживает на этой платформе. Сканирование каждого аккаунта заняло около 30 секунд. В течение часа все шесть аккаунтов были подключены, и один webhook-эндпоинт принимал каждое входящее сообщение LINE как событие message.received.

Полезная нагрузка вебхука выглядела так:

{
  "id": "evt_9a3f7c2e01",
  "type": "message.received",
  "provider": "line",
  "account_id": "acc_4b82d1",
  "occurred_at": "2026-05-12T01:47:23Z",
  "data": {
    "conversation": {
      "id": "U4af2c891...",
      "type": "user",
      "title": "Tanaka-san"
    },
    "sender": {
      "id": "U4af2c891...",
      "type": "user",
      "name": "Tanaka-san"
    },
    "message": {
      "id": "msg_18420...",
      "type": "text",
      "text": "The CSV export keeps failing — is this a known issue?",
      "direction": "inbound",
      "sent_at": "2026-05-12T01:47:22Z"
    },
    "event": {
      "kind": "message_received"
    }
  }
}

Каждая доставка сопровождалась заголовком X-Device-Signature — HMAC-SHA256 hex-дайджестом метки времени, объединённой с телом запроса, подписанным с помощью signing_secret вебхука. Обработчик Express на стороне команды проверял подпись перед любой обработкой:

import crypto from 'crypto';
import express from 'express';

const app = express();
const SECRET = process.env.WEBHOOK_SIGNING_SECRET;

app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const timestamp = req.get('X-Device-Timestamp') ?? '';
  const signature = req.get('X-Device-Signature') ?? '';
  const hmac = crypto.createHmac('sha256', SECRET);
  hmac.update(timestamp + '.');
  hmac.update(req.body);
  const expected = hmac.digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).end();
  }

  const event = JSON.parse(req.body.toString('utf8'));
  if (event.type === 'message.received') {
    await routeMessage(event);
  }
  res.status(200).end();
});

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

Логика маршрутизации: Slack, CRM, ИИ — или все три

Правила маршрутизации команды эволюционировали в течение первых двух недель, но итоговая версия включала три уровня:

Уровень 1 — уведомление в Slack (каждое сообщение). Каждое входящее сообщение LINE публиковалось в канале #support-line в Slack с именем отправителя, превью сообщения и account_id, чтобы команда видела, на какой аккаунт пришло сообщение. Одно это решило проблему «сообщение пролежало на чьём-то телефоне». Если владелец аккаунта был на совещании, любой другой участник команды мог увидеть сообщение и ответить через эндпоинт UnifyPort POST /v1/messages, используя reply_to.reply_token из исходного сообщения.

Уровень 2 — логирование в CRM (каждое сообщение). Параллельный вызов создавал или обновлял запись контакта в CRM с полным текстом сообщения, меткой времени и ID разговора. До этого взаимодействия с клиентами в LINE были невидимы для CRM — они существовали только в личных историях чатов на телефонах. Теперь каждый разговор в LINE имел полный аудиторский след наряду с электронной почтой и историей тикетов с сайта.

Уровень 3 — черновик от ИИ (только рутинные вопросы). Простой классификатор по ключевым словам проверял входящие сообщения на совпадение со списком типичных тем: экспорт CSV, выставление счетов, проблемы со входом, запросы API-документации. При совпадении сообщение пересылалось на внутренний LLM-эндпоинт с системным промптом, содержащим соответствующий раздел документации. Черновик ответа от ИИ публиковался в канале Slack #support-drafts с кнопкой «Проверить и отправить». Ни один ответ не уходил без одобрения человека — но черновик был готов за секунды, и менеджеру нужно было сделать один клик.

async function routeMessage(event) {
  const { conversation, sender, message } = event.data;
  const accountId = event.account_id;

  // Tier 1: Always notify Slack
  await postToSlack('#support-line', {
    account: accountId,
    sender: sender.name,
    preview: message.text?.slice(0, 120),
    reply_token: message.reply_token,
  });

  // Tier 2: Always log to CRM
  await crm.upsertContact({
    external_id: sender.id,
    platform: 'line',
    name: sender.name,
    last_message: message.text,
    last_message_at: message.sent_at,
  });

  // Tier 3: AI draft for routine questions
  const topic = classifyTopic(message.text);
  if (topic) {
    const draft = await generateDraft(topic, message.text, sender.name);
    await postToSlack('#support-drafts', {
      sender: sender.name,
      topic,
      draft,
      account_id: accountId,
      reply_token: message.reply_token,
    });
  }
}

Функция classifyTopic была намеренно простой — карта ключевых слов, а не нейронный классификатор. «CSV», «export», «download» сопоставлялись с темой export-docs. «請求», «料金», «支払い» — с billing. Использование правил, а не моделей, позволяло команде отлаживать сбои маршрутизации за минуты, а не за часы.

Метки разговоров для распределения ответственности в команде

На второй неделе команда внедрила ещё одну функцию — метки разговоров UnifyPort. Через эндпоинт POST /v1/conversations/labels они создали метки для каждого участника: kenji, yuki, hiro, sales. При поступлении сообщения функция маршрутизации присваивала разговору метку владельца аккаунта. Если владелец был вне офиса (проверялось через простую интеграцию с календарём), разговор перемаркировался на дежурного менеджера.

Это означало, что в любой момент каждый участник команды мог вызвать GET /v1/conversations/labels и увидеть, какие разговоры назначены ему — по всем шести аккаунтам LINE. Проблема общей очереди была решена не созданием новой очереди, а маркировкой разговоров в существующих.

Метки также обеспечивали еженедельный отчёт: cron-задача собирала все разговоры с меткой каждого менеджера, подсчитывала время ответа (от occurred_at события message.received до первого исходящего вызова POST /v1/messages) и публиковала сводку в #support-metrics каждый понедельник утром.

Первая неделя против четвёртой

Цифры говорили сами за себя. За неделю до запуска вебхука медианное время ответа команды в LINE составляло 3 часа 40 минут, а 11 сообщений оставались без ответа более четырёх часов. На четвёртой неделе медианное время ответа составило 22 минуты. Ни одно сообщение не оставалось без ответа более четырёх часов — худший случай составил 1 час 15 минут во время корпоративного выездного мероприятия.

Уровень черновиков от ИИ обрабатывал около 35% входящих сообщений. Команда одобряла и отправляла примерно 80% этих черновиков без правок. Оставшиеся 20% требовали небольших доработок — обычно потому, что в вопросе клиента был нюанс, который классификатор по ключевым словам упустил. Даже в таких случаях черновик давал менеджеру отправную точку, сокращая время составления ответа с минут до секунд.

Интеграция с CRM дала неожиданный побочный эффект: отдел продаж начал использовать историю разговоров в LINE для подготовки к звонкам о продлении. До вебхука у менеджера, идущего на встречу по продлению, не было записей о прошлых обращениях клиента в поддержку через LINE. Теперь они видели каждое сообщение, каждое время ответа и каждое решение — всё логировалось автоматически.

Что команда не меняла

Клиенты ничего не заметили. Они продолжали писать на те же аккаунты LINE, которыми пользовались месяцами. Ответы приходили от тех же людей. Единственная разница — ответы стали быстрее, и если привычный менеджер был недоступен, подключался кто-то другой — потому что сообщение было видно всей команде в Slack, а не лежало на одном телефоне.

Команда также сохранила свои аккаунты LINE как личные, а не как OA-аккаунты. Вебхук UnifyPort доставляет входящие сообщения независимо от типа аккаунта — очередь верификации OA и окна взаимодействия касаются исходящих рассылок, а рабочий процесс этой команды был полностью входящим. Использование неофициального интерфейса для личных аккаунтов полностью покрывало их потребности. Если они когда-нибудь решат проводить проактивные кампании (сезонные акции, анонсы продуктов), путь через OA станет актуальным. А пока это лишний слой бюрократии, который им не нужен.

Универсальный паттерн

Это не история исключительно о LINE. Любая команда, получающая сообщения клиентов с нескольких личных аккаунтов на любой платформе — WhatsApp, Telegram, X, Zalo — сталкивается с той же проблемой маршрутизации. Вебхуку всё равно, с какой платформы пришло сообщение: меняется поле provider, но структура полезной нагрузки, верификация HMAC-SHA256 и логика маршрутизации остаются идентичными. Команда из Фукуоки уже планирует подключить свой аккаунт WhatsApp (используемый партнёрами-складами в Юго-Восточной Азии) к той же системе маршрутизации. Один обработчик, один набор меток, один конвейер метрик.

Если стратегия поддержки вашей команды — «каждый проверяет свои сообщения», вопрос не в том, нужна ли вам лучшая платформа, а в том, нужен ли вашим сообщениям лучший слой маршрутизации. Один webhook-эндпоинт, 20 строк логики маршрутизации и инструменты, которые вы уже используете, могут оказаться достаточными.