Один 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 строк логики маршрутизации и инструменты, которые вы уже используете, могут оказаться достаточными.