UnifyPort v1 API готов к продакшену: всё, что вошло в первый стабильный релиз — UnifyPort
UnifyPort v1 API теперь готов к продакшену. Это первый стабильный релиз: один эндпоинт отправки, нормализованный слой Webhook-событий и потоки подключения аккаунтов для всех шести каналов — WhatsApp, Telegram, LINE, TikTok, Zalo и X — за единой поверхностью API.
Этот пост — список изменений данного релиза. Если вы ждали версию, на которой можно строить, не опасаясь, что фундамент под вами внезапно изменится, — это она. Ниже описано, что вошло в релиз, эндпоинт за эндпоинтом, с реальными именами событий, потоками аутентификации и поведением при сбоях.
Один API отправки для шести каналов
Ядро v1 — один эндпоинт. POST /v1/messages отправляет нормализованное текстовое сообщение через выбранный аккаунт провайдера. Вам не нужно изучать шесть SDK или шесть форматов полезной нагрузки — только один.
Специфика платформ никуда не делась, она переехала в структурированное поле provider_data. Нужно ответить на конкретное сообщение или задать parse mode в Telegram? Это живёт в provider_data (например, reply_to и parse_mode) без изменения формы запроса верхнего уровня. Типичный случай остаётся простым; специфичный для платформы — остаётся возможным.
Шесть поддерживаемых каналов: WhatsApp, Telegram, LINE, TikTok, Zalo и X. В API аккаунты провайдеров создаются с именами вроде telegram, whatsapp, twitter, line и zalo.
11 стандартных Webhook-событий
Вторая половина v1 — слой стандартных событий. Каждое сообщение от провайдера, каждое обновление статуса доставки и каждое событие жизненного цикла аккаунта преобразуется в одну стабильную JSON-форму. В этом релизе 11 стандартных событий, и ваш бэкенд обрабатывает их все через один обработчик.
Два, которые вы будете использовать чаще всего:
message.received— на подключённый аккаунт пришло входящее сообщениеmessage.status.updated— изменился статус доставки отправленного вами сообщения
События жизненного цикла аккаунта делают состояние подключения наблюдаемым, а не непрозрачным:
account.auth.required— аккаунту нужно действие входа (скан QR или код подтверждения)account.auth.succeeded— вход завершён;provider_account_refтеперь заполнен, событие несёт стандартные поля профиля (display_name,picture_url,region,status_message)account.started— рантайм аккаунта в сетиaccount.status.updated— статус аккаунта изменился
Событие message.received выглядит одинаково независимо от того, из какого из шести каналов оно пришло:
{
"event": "message.received",
"account_id": "acct_8Q2vK",
"provider": "whatsapp",
"from": "+6591234567",
"text": "Здравствуйте, мой заказ готов?",
"timestamp": 1749254400,
"message_id": "wamid.HBgLNTU..."
}
Замените whatsapp на line или zalo — и ваша логика маршрутизации не изменится ни на строку. В этом и весь смысл стандартного слоя.
Подключение аккаунта: потоки QR и кода
Подключение аккаунта в v1 — отдельный поток, спроектированный так, что состояние аутентификации — это то, за чем ваш Webhook может наблюдать, а не то, что нужно нянчить вручную.
Вы создаёте аккаунт через POST на эндпоинт аккаунтов, выбирая auth_mode, соответствующий стилю подключения:
{
"provider": "whatsapp",
"auth_mode": "code",
"provider_data": { "phone": "+6591234567" }
}
Для потоков на основе кода номер телефона в формате E.164 передаётся через provider_data.phone. Он сохраняется на аккаунте и автоматически воспроизводится для последующих действий аутентификации, так что повторно отправлять его не нужно. Создание дублирующей идентичности провайдера возвращает чистый 409 duplicate_provider_account вместо тихого создания второго аккаунта.
Для потоков на основе QR учётные данные приходят асинхронно через ваш Webhook:
- WhatsApp — вызовите
/auth/qr/start, чтобы начать сессию устройства. QR-токен приходит на Webhook как событиеaccount.auth.required(auth_payload.qr_code— это сырой токен, который ваш UI должен отрендерить в виде QR-изображения), а также доступен синхронно через/auth/qr/checkдля опроса. После сканирования приходитaccount.auth.succeededс заполненнымprovider_account_ref, затемaccount.started. - LINE — URL QR и PIN приходят асинхронно. Слушайте
account.auth.requiredили опрашивайте/auth/session, чтобы прочитатьauth_payload.url(изображение QR) иauth_payload.pin.
URL Webhook внедряется автоматически при настройке аккаунта — переходы состояния аутентификации и события входа приходят на тот же эндпоинт, что и входящие сообщения. Один Webhook, все события.
Как только приходит account.auth.succeeded, POST /v1/accounts/{account_id}/runtime/start выводит аккаунт в сеть (no-op, если рантайм уже запущен).
Управляющий слой Webhook
Webhook-эндпоинты в v1 — полноценные настраиваемые объекты, а не одно поле URL, спрятанное в настройках.
Создавая приёмник Webhook, вы точно выбираете, какие события он получает. subscribed_events принимает стандартные имена событий (такие как message.received, account.status.updated) или ["*"] для подписки на всё. Неизвестные имена событий отклоняются при записи, а не падают тихо позже.
Подпись встроена. Укажите signing_secret — и каждая доставка подписывается HMAC-SHA256, чтобы ваш эндпоинт мог проверить подлинность. Оставьте пустым — и подпись явно отключается: это осознанный выбор, а не случайность.
Поведение повторов настраиваете вы. retry_policy.max_attempts — неотрицательное целое; 0 полностью отключает повторы, нецелые значения отклоняются. Повторную доставку берёт на себя платформа; вашему эндпоинту нужно лишь ответить.
Надёжность, удерживающая турбулентность в слое платформы
Продакшен-релиз требует продакшен-настроек по умолчанию, и v1 поставляется с ними. Входящая доставка проходит через очередь с лимитами скорости, повторами, идемпотентностью и изоляцией сбоев, поэтому турбулентность на стороне провайдера остаётся внутри слоя платформы, а не каскадом обрушивается на ваше приложение.
Состояние рантайма аккаунта тоже нормализовано. runtime_status принимает одно из восьми стандартных для платформы значений — unknown, starting, running, stopping, stopped, reconnecting, disconnected, error — а специфичные для провайдера метки отображаются в этот набор ещё до того, как вы их увидите. Вы пишете один автомат состояний, а не шесть.
Для аккаунтов, которым нужна географическая маршрутизация, необязательный объект proxy_config сохраняется вместе с аккаунтом и применяется автоматически.
Что значит этот релиз
Готовность v1 к продакшену — это обязательство, а не просто номер версии. Эндпоинт отправки, 11 стандартных событий, потоки аутентификации и управляющий слой Webhook — это стабильная поверхность, поверх которой можно строить продукт. Смысл UnifyPort всегда был в том, чтобы командам не приходилось переписывать одну и ту же интеграцию шесть раз; v1 — версия, в которой эта поверхность перестаёт двигаться.
Если вы читали другие наши статьи о приёме сообщений без трения официального API — приём входящих WhatsApp без официального API, приём сообщений LINE без официального аккаунта или сравнение стоимости WhatsApp и Telegram — то это тот самый API, на котором работают эти пути.
С чего начать: создайте API-ключ, подключите первый аккаунт с auth_mode, подходящим каналу, зарегистрируйте Webhook-эндпоинт с signing_secret и подпишитесь на message.received. В рамках той же сессии нормализованное входящее событие уже будет приходить на ваш бэкенд. Дальше каждый новый канал — это тот же поток, а не очередной интеграционный проект.