← Все статьи
Руководство

Inbound-интеграция UnifyPort: начинайте с Webhook

Если вы строите inbound-интеграцию для мессенджеров, первым production-компонентом должен быть webhook receiver, а не подключение аккаунта. У UnifyPort нет универсального REST API для чтения истории сообщений и нет гарантированного replay для пропущенных payload. Поэтому webhook — это ваш durable intake layer: создайте POST /v1/webhook-endpoints, включите signing_secret, подпишитесь на message.received или [*], сохраните событие и только затем отправляйте его в CRM, AI workflow или support queue.

Ключевые выводы

  • Зарегистрируйте webhook до подключения production messaging account.
  • Используйте signing_secret, чтобы доставки содержали X-Device-Timestamp и X-Device-Signature.
  • Сохраняйте стандартный event envelope до медленных downstream-задач.
  • Для inbox только под inbound начните с message.received и проверяйте data.message.direction === "inbound".
  • Разделяйте фильтрацию событий, проверку подписи, retry handling и бизнес-маршрутизацию.

Почему webhook должен быть первым

Сообщение клиента может прийти раньше, чем CRM, AI agent или shared inbox будут готовы. Если receiver не зарегистрирован, нельзя рассчитывать, что вы надежно восстановите это сообщение через history API. В Quickstart UnifyPort webhook регистрируется до авторизации аккаунта именно по этой причине.

Эта статья дополняет два существующих материала: Webhook HMAC replay protection объясняет timestamp freshness и idempotency, а UnifyPort webhook event filters помогает выбрать subscribed_events или wildcard. Здесь мы собираем их в порядок первого внедрения.

Шаг 1: создайте signed endpoint

Реальный маршрут API — POST /v1/webhook-endpoints. Для focused inbound inbox начните с message.received; для общего collector всех public standard events используйте [*].

curl -X POST https://api.unifyport.ai/v1/webhook-endpoints \
  -H "X-Api-Key: $UNIFYPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PUBLIC_WEBHOOK_URL\",
    \"status\": \"active\",
    \"subscribed_events\": [\"message.received\"],
    \"signing_secret\": \"$WEBHOOK_SIGNING_SECRET\",
    \"retry_policy\": { \"max_attempts\": 3 }
  }"

retry_policy.max_attempts — это число повторных попыток после initial delivery. Документированное значение по умолчанию — 3, допустимый диапазон — от 0 до 5. При внедрении сверяйтесь с Create webhook endpoint.

Шаг 2: проверьте raw request body

Когда signing включен, UnifyPort отправляет X-Device-Signature. Это hex HMAC-SHA256 от точной строки:

<X-Device-Timestamp>.<raw request body>

Receiver должен проверять raw bytes до JSON parsing или повторной сериализации. В Node.js для этого подходят crypto.createHmac() и crypto.timingSafeEqual(); официальная документация Node.js указывает, что буферы для timingSafeEqual() должны иметь одинаковую длину.

import crypto from 'node:crypto';
import express from 'express';

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

app.post('/webhooks/unifyport', express.raw({ type: 'application/json' }), async (req, res) => {
  const timestamp = req.get('X-Device-Timestamp') ?? '';
  const signature = req.get('X-Device-Signature') ?? '';

  const expected = crypto.createHmac('sha256', signingSecret)
    .update(timestamp + '.')
    .update(req.body)
    .digest('hex');

  const valid = /^[0-9a-f]{64}$/i.test(signature) &&
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

  if (!valid) return res.sendStatus(401);
  const event = JSON.parse(req.body.toString('utf8'));
  await inbox.insertIfAbsent(event.id, event);
  return res.sendStatus(202);
});

Для production добавьте freshness window для timestamp, durable deduplication по event ID и acknowledgement, рассчитанный на retries. Подробности — в Webhook delivery and signature verification.

Шаг 3: сохраните стандартный event envelope

message.received имеет одинаковую верхнеуровневую форму для разных providers:

{
  "id": "evt_2f9c1a4b7e",
  "type": "message.received",
  "provider": "telegram",
  "account_id": "acc_8c21d0",
  "occurred_at": "2026-06-08T12:34:56Z",
  "data": {
    "conversation": { "id": "5005", "type": "user", "title": "Jordan Lee" },
    "sender": { "id": "4004", "name": "Jordan Lee", "type": "user" },
    "message": {
      "id": "3003",
      "text": "Order A1234 has shipped?",
      "direction": "inbound",
      "sent_at": "2026-06-08T12:34:55Z"
    }
  }
}

Сохраняйте минимум id, type, provider, account_id, occurred_at, data.conversation.id, data.sender.id и data.message.id. Если после edge вы используете n8n, посмотрите n8n WhatsApp AI agent tutorial: workflow должен получать уже доверенное событие, а не быть первой границей безопасности.

Ограничения и компромиссы

Unofficial interface полезен, когда команда хочет принимать inbound messages из обычных или уже существующих аккаунтов. Если вам нужны официальная сертификация, platform-specific business features или гарантии политики конкретного provider, выбирайте официальный API этой платформы. Также message.received может описывать не только inbound, но и outbound-наблюдение, поэтому inbox pipeline обязан проверять data.message.direction.

FAQ

На какое событие подписаться сначала?

Для inbound inbox используйте message.received. [*] подходит только для общего collector, который умеет хранить и маршрутизировать все public standard events.

Достаточно ли HMAC для защиты от replay и дублей?

Нет. HMAC проверяет целостность и знание shared secret. Добавьте freshness window по timestamp и durable deduplication по event ID.

Можно ли вернуть 2xx до завершения CRM-записи?

Да, если событие уже принято в durable inbox или queue. CRM, AI и уведомления лучше выполнять асинхронно.

Следующий шаг

Откройте Create webhook endpoint, зарегистрируйте receiver, затем настройте проверку и acknowledgement по webhook delivery guide до подключения production accounts.

Sources

Official sources checked on 2026-08-26:

UnifyPort API

Превратите интеграцию сообщений в стабильный продуктовый pipeline.

Начните с отправки через единый API, затем возвращайте входящие сообщения в бизнес-систему стандартными событиями.