Перейти к содержимому
ChatVendor ChatVendor

Вебхуки

Узнавайте о событиях сразу, вместо того чтобы опрашивать API.

Зарегистрируйте эндпоинт в разделе Разработчик → Вебхуки (или POST /api/v1/webhooks), выберите события и проверяйте заголовок X-ChatVendor-Signature при каждой доставке. Неудачные доставки повторяются с задержкой.

Webhook'и

Узнавайте о событиях: события, payload, подпись, повторы.

Base URL: https://chatvendor.net/api/v1 · каждый ответ {"success": true, "data": …}

GET /webhooks List webhook endpoints

Право: webhooks:manage

Ответ 200 · Webhook[]

id stringurl stringevents string: message.queued | message.sent | message.delivered | message.failed | device.online | device.offline | chat.message | chat.message.edited | chat.message.deleted | chat.action | chat.reaction | chat.operator_requested | lead.new | lead.updated | scenario.done | scenario.failed | scenario.cancelled | channel.connected | channel.disconnected | channel.revoked | bot.callback | bot.inline_query | bot.inline_chosen | bot.precheckout | bot.shipping | bot.join_request | bot.stopped | bot.reaction | bot.business_message | bot.paid_media | bot.payment | call.incoming | call.ended | call.group | secret.chat | contact.referral | contact.link_click | contact.updated | comment.new | order.created | order.paid | order.expired | order.updated | booking.created | booking.confirmed | booking.cancelled[]enabled boolean

curl https://chatvendor.net/api/v1/webhooks \
  -H "Authorization: Bearer cv_live_xxxxxxxxxxxx"
POST /webhooks Create a webhook endpoint

Право: webhooks:manage

Тело запроса (application/json)

urlstring (uri)обязательно
eventsstring: message.queued | message.sent | message.delivered | message.failed | device.online | device.offline | chat.message | chat.message.edited | chat.message.deleted | chat.action | chat.reaction | chat.operator_requested | lead.new | lead.updated | scenario.done | scenario.failed | scenario.cancelled | channel.connected | channel.disconnected | channel.revoked | bot.callback | bot.inline_query | bot.inline_chosen | bot.precheckout | bot.shipping | bot.join_request | bot.stopped | bot.reaction | bot.business_message | bot.paid_media | bot.payment | call.incoming | call.ended | call.group | secret.chat | contact.referral | contact.link_click | contact.updated | comment.new | order.created | order.paid | order.expired | order.updated | booking.created | booking.confirmed | booking.cancelled[]обязательно

Ответ 201 · Webhook

id stringurl stringevents string: message.queued | message.sent | message.delivered | message.failed | device.online | device.offline | chat.message | chat.message.edited | chat.message.deleted | chat.action | chat.reaction | chat.operator_requested | lead.new | lead.updated | scenario.done | scenario.failed | scenario.cancelled | channel.connected | channel.disconnected | channel.revoked | bot.callback | bot.inline_query | bot.inline_chosen | bot.precheckout | bot.shipping | bot.join_request | bot.stopped | bot.reaction | bot.business_message | bot.paid_media | bot.payment | call.incoming | call.ended | call.group | secret.chat | contact.referral | contact.link_click | contact.updated | comment.new | order.created | order.paid | order.expired | order.updated | booking.created | booking.confirmed | booking.cancelled[]enabled boolean

curl -X POST https://chatvendor.net/api/v1/webhooks \
  -H "Authorization: Bearer cv_live_xxxxxxxxxxxx"
  -H "Content-Type: application/json" \
  -d '{"url":"…","events":[]}'
PATCH /webhooks/{webhook} Update a webhook endpoint

Право: webhooks:manage

Параметры

webhookpath · stringобязательно

Webhook public id

Ответ 200 · Webhook

id stringurl stringevents string: message.queued | message.sent | message.delivered | message.failed | device.online | device.offline | chat.message | chat.message.edited | chat.message.deleted | chat.action | chat.reaction | chat.operator_requested | lead.new | lead.updated | scenario.done | scenario.failed | scenario.cancelled | channel.connected | channel.disconnected | channel.revoked | bot.callback | bot.inline_query | bot.inline_chosen | bot.precheckout | bot.shipping | bot.join_request | bot.stopped | bot.reaction | bot.business_message | bot.paid_media | bot.payment | call.incoming | call.ended | call.group | secret.chat | contact.referral | contact.link_click | contact.updated | comment.new | order.created | order.paid | order.expired | order.updated | booking.created | booking.confirmed | booking.cancelled[]enabled boolean

curl -X PATCH https://chatvendor.net/api/v1/webhooks/{webhook} \
  -H "Authorization: Bearer cv_live_xxxxxxxxxxxx"
DELETE /webhooks/{webhook} Delete a webhook endpoint

Право: webhooks:manage

Параметры

webhookpath · stringобязательно

Webhook public id

Ответ 204

Deleted

curl -X DELETE https://chatvendor.net/api/v1/webhooks/{webhook} \
  -H "Authorization: Bearer cv_live_xxxxxxxxxxxx"

Узнавайте о событиях вместо опроса. Добавьте endpoint в Developer → Webhooks или через API выше с ключом webhooks:manage. У каждого endpoint есть секрет; каждая доставка подписана.

События

События мессенджера: chat.message, chat.message.edited, chat.message.deleted, chat.action, chat.operator_requested, lead.new, lead.updated, scenario.done|failed|cancelled, channel.connected|disconnected|revoked. В payload — channel_id и данные события.

message.queuedСообщение в очереди
message.sentСообщение отправлено
message.deliveredСообщение доставлено
message.failedОшибка отправки
device.onlineУстройство вышло на связь
device.offlineУстройство пропало со связи
chat.messageЧат: новое сообщение
chat.message.editedЧат: сообщение изменено
chat.message.deletedЧат: сообщение удалено
chat.actionЧат: событие группы
chat.reactionЧат: изменились реакции
chat.operator_requestedЧат: запрошен оператор
lead.newЛид: новый
lead.updatedЛид: обновлён
scenario.doneСценарий: завершён
scenario.failedСценарий: ошибка
scenario.cancelledСценарий: отменён
channel.connectedСеть подключена
channel.disconnectedСеть отключена
channel.revokedСессия сети отозвана
bot.callbackБот: нажата кнопка
bot.inline_queryБот: inline-запрос
bot.inline_chosenБот: выбран inline-результат
bot.precheckoutБот: pre-checkout запрос
bot.shippingБот: запрос доставки
bot.join_requestБот: заявка на вступление
bot.stoppedБот: пользователь заблокировал/разблокировал бота
bot.reactionБот: реакция
bot.business_messageБот: бизнес-сообщение
bot.paid_mediaБот: куплено платное медиа
bot.paymentБот: инвойс оплачен
call.incomingЗвонок: входящий
call.endedЗвонок: завершён
call.groupЗвонок: изменился голосовой чат
secret.chatСекретный чат: запрошен / принят / отклонён
contact.referralКонтакт: новый реферал
contact.link_clickКонтакт: клик по ссылке
contact.updatedКонтакт: изменились теги/переменные
comment.newInstagram: новый комментарий
order.createdЗаказ: создан
order.paidЗаказ: оплачен
order.expiredЗаказ: подписка истекла
order.updatedЗаказ: статус доставки изменился
booking.createdЗапись: создана
booking.confirmedЗапись: подтверждена
booking.cancelledЗапись: отменена

Payload

POST https://example.com/webhooks/sms
Content-Type: application/json
X-SMS-Event: message.delivered
X-SMS-Event-Id: evt_01k…
X-SMS-Delivery-Attempt: 1
X-SMS-Signature: t=1754825400,v1=8f3a…

{
  "event_id": "evt_01k…",
  "event": "message.delivered",
  "timestamp": "2026-08-11T09:30:00+00:00",
  "data": {
    "id": "msg_01k…",
    "status": "delivered",
    "to": "+998901234567",
    "segments": 1,
    "client_reference": "order_4389",
    "delivered_at": "2026-08-11T09:29:58+00:00"
  }
}

Проверка подписи

Compute HMAC SHA-256 over "{timestamp}.{raw body}" with your endpoint's secret. Sign the raw body — re-encoding the JSON first will change the bytes and the signature will not match. The timestamp is inside the signed string, which is what stops a captured payload being replayed later.

// PHP
$raw = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_SMS_SIGNATURE'] ?? '';

parse_str(strtr($header, ',', '&'), $parts);

if (abs(time() - (int) $parts['t']) > 300) {
    http_response_code(400);   // too old, treat as replay
    exit;
}

$expected = hash_hmac('sha256', $parts['t'] . '.' . $raw, $secret);

if (! hash_equals($expected, $parts['v1'])) {
    http_response_code(401);
    exit;
}
// Node.js (express, raw body required)
app.post('/webhooks/sms', express.raw({ type: 'application/json' }), (req, res) => {
  const parts = Object.fromEntries(
    req.get('X-SMS-Signature').split(',').map((p) => p.split('=')),
  );

  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(`${parts.t}.${req.body}`)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))) {
    return res.sendStatus(401);
  }

  res.sendStatus(200);   // acknowledge fast, process afterwards
});

Повторы

Any 2xx counts as delivered. Anything else is retried 1 min, 5 min, 30 min, 2 h after the first attempt. An endpoint that fails 20 times in a row is disabled automatically — re-enable it once it is fixed.

Every event carries a unique event_id. A retry reuses it, so store the ones you have processed and ignore repeats — a delivery that timed out on your side may still have been received.

Reply quickly. We wait 10 seconds; do the real work after responding, not before.

Callback на сообщение

Passing callback_url on a send delivers that message's events to that URL as well. Those are not signed — there is no shared secret behind a one-off URL — so treat them as a hint and confirm with GET /api/v1/messages/{id} before acting on anything that matters.