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

API v2 (бета)

Вебхуки

Webhook endpoint — это URL на вашем сервере, который WbizTool вызывает, когда с сообщением что-то происходит: оно отправлено, не отправлено, отменено или истекло. Вы узнаёте об этом сразу, без опроса, а каждый запрос подписан, поэтому можно убедиться, что он пришёл от WbizTool.

ОперацияEndpointОбласть доступа
Добавление endpointPOST /api/v2/webhooksmessages:read
Список endpointGET /api/v2/webhooksmessages:read
Получение endpointGET /api/v2/webhooks/{id}messages:read
Удаление endpointDELETE /api/v2/webhooks/{id}messages:read
Замена секрета подписиPOST /api/v2/webhooks/{id}/rotate-secretmessages:read
Отправка тестового событияPOST /api/v2/webhooks/{id}/testmessages:read

Endpoint принадлежат рабочему пространству и получают события по всем его сообщениям, откуда бы они ни были отправлены: через API, из панели, кампаниями, напоминаниями или интеграциями. Поэтому ключ, ограниченный некоторыми номерами, не может ими управлять: каждый вызов возвращает 403 number_not_allowed.

События#

ТипКогда
message.sentСообщение ушло с вашего номера.
message.failedСообщение не удалось отправить; причина — в error.message.
message.cancelledОжидающее сообщение отменено: через API, в панели или потому, что его номер или кампания были удалены.
message.expiredСообщение не было отправлено до своего expires_at.
pingЗапрошенное вами тестовое событие.

События для номеров (подключён, вышел из аккаунта) и для входящих сообщений появятся позже. Галочки «доставлено» и «прочитано» событий не отправляют; чтобы их увидеть, получите сообщение.

Добавление endpoint#

POSThttps://wbiztool.com/api/v2/webhooks

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

Тело запроса

urlstringобязательно

Ваш endpoint: публичный адрес https://, до 500 символов. Адреса http://, частные и локальные адреса (например, localhost или 192.168.x.x) отклоняются.

eventsarray of stringsнеобязательно

Типы событий, которые он получает: любые из message.sent, message.failed, message.cancelled и message.expired. По умолчанию — все четыре. ping приходит всегда, когда вы его запрашиваете.

descriptionstringнеобязательно

Заметка для себя, до 100 символов, например Order system.

В рабочем пространстве может быть до 5 endpoint. Ответ — 201 с endpoint и его secret подписи, который показывается только этот раз. Сохраните его там, где его сможет прочитать ваш обработчик, например в переменной окружения. Дальнейшие ответы показывают только secret_last4; если вы потеряете секрет, замените его.

curl -X POST https://wbiztool.com/api/v2/webhooks \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/wbiztool/events",
    "events": ["message.sent", "message.failed"],
    "description": "Order system"
  }'

Ответ (201):

{
  "id": 41,
  "url": "https://example.com/wbiztool/events",
  "description": "Order system",
  "events": ["message.sent", "message.failed"],
  "secret_last4": "9c1e",
  "active": true,
  "disabled_reason": null,
  "created_at": "2026-10-18T11:20:05.733Z",
  "last_delivery": null,
  "secret": "3f0b…9c1e"
}

Настоящий secret состоит из 64 шестнадцатеричных символов. Повтор этого запроса с тем же Idempotency-Key не добавляет второй endpoint, а в его ответе секрета нет.

Ошибки при добавлении endpoint#

HTTPКодКогда
400validation_failedurl отсутствует или слишком длинный, events пуст или содержит неизвестный тип, или поле неизвестно
403webhook_limit_reachedВ рабочем пространстве уже 5 endpoint
403number_not_allowedКлюч ограничен некоторыми номерами
422invalid_webhook_urlurl — не публичный адрес https://

Список endpoint#

GEThttps://wbiztool.com/api/v2/webhooks

Endpoint рабочего пространства, которые получают события, сначала самые старые, одним списком data.

curl https://wbiztool.com/api/v2/webhooks \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

В список не входят endpoint, которые перестали работать. Владельцы тоже видят endpoint и могут их удалять на странице Настройки → API-ключи в разделе Адреса вебхуков.

Получение endpoint#

GEThttps://wbiztool.com/api/v2/webhooks/{id}

Один endpoint. last_delivery показывает, как прошла его последняя доставка. Endpoint, которого не существует или который удалён, возвращает 404 webhook_not_found; переставший работать показывается с active: false.

Удаление endpoint#

DELETEhttps://wbiztool.com/api/v2/webhooks/{id}

Ему больше ничего не отправляется, включая ещё ожидающие повторы. Ответ — {"id": 41, "deleted": true}.

Замена секрета подписи#

POSThttps://wbiztool.com/api/v2/webhooks/{id}/rotate-secret

Создаёт для endpoint новый секрет. Ответ — 200 с endpoint и его новым secret, который показывается только этот раз. Старый секрет сразу перестаёт действовать: события, отправленные после этого, подписываются новым, включая повторы более ранних событий. Сразу обновите свой обработчик.

curl -X POST https://wbiztool.com/api/v2/webhooks/41/rotate-secret \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

Отправка тестового события#

POSThttps://wbiztool.com/api/v2/webhooks/{id}/test

Ставит в очередь событие ping для этого endpoint, подписанное, как любое событие, чтобы вы могли проверить свой обработчик. Ответ — 202:

{ "event_id": "evt_8a2f4c1d9b7e6a5f4c3b2a19", "type": "ping", "queued": true }

Ваш endpoint получает:

{
  "id": "evt_8a2f4c1d9b7e6a5f4c3b2a19",
  "type": "ping",
  "created_at": "2026-10-18T11:21:40.002Z",
  "data": { "webhook_id": 41 }
}

Содержимое события#

Каждое событие — это POST с телом JSON:

{
  "id": "evt_c41d7e2a9f3b8c6d5e4f3a21",
  "type": "message.sent",
  "created_at": "2026-10-18T10:15:09.912Z",
  "data": {
    "message": {
      "id": 9817263,
      "status": "sent",
      "from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
      "to": { "phone": "+919876543210", "contact_id": 991 },
      "text": "Hi Asha, your order #1042 is ready.",
      "media": null,
      "send_at": null,
      "expires_at": null,
      "created_at": "2026-10-18T10:15:02.311Z",
      "sent_at": "2026-10-18T10:15:09.870Z",
      "error": null
    }
  }
}
ПолеОписание
idID события: evt_ и 24 символа. При каждом повторе у события тот же ID.
typeОдин из типов событий.
created_atКогда произошло событие.
data.messageДля событий message.*: Message в том виде, каким оно было тогда. media.url в нём работает не меньше 26 часов.
data.webhook_idДля ping: ID endpoint.

Заголовки:

ЗаголовокЗначение
Content-Typeapplication/json
User-AgentWbizTool-Webhooks/2
WbizTool-Event-Idid события, одинаковый при каждом повторе
WbizTool-TimestampКогда отправлена эта попытка, в секундах Unix, например 1792310409
WbizTool-Signaturev1= и шестнадцатеричный HMAC-SHA256 от <timestamp>.<raw body>, вычисленный секретом endpoint

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

Проверяйте каждый запрос, прежде чем ему доверять: вычислите подпись от необработанного тела (до того, как ваш фреймворк разберёт JSON), сравните её с заголовком за постоянное время и отклоняйте метки времени, расходящиеся больше чем на 5 минут, чтобы старый запрос нельзя было отправить повторно. Это та же схема, что у подписей вебхуков API v1, только с собственным секретом endpoint.

Затем используйте WbizTool-Event-Id, чтобы отбрасывать повторы: одно и то же событие может прийти больше одного раза, например когда ваш ответ потерялся и мы попробовали снова.

import hashlib, hmac, json, os, time

SECRET = os.environ["WBIZTOOL_WEBHOOK_SECRET"]

def verify(secret: str, body: bytes, headers) -> bool:
    ts, sig = headers.get("WbizTool-Timestamp", ""), headers.get("WbizTool-Signature", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
        return False
    mac = "v1=" + hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(mac, sig)

# Flask
from flask import Flask, request

app = Flask(__name__)
seen = set()  # use your database in production

@app.post("/wbiztool/events")
def events():
    body = request.get_data()  # the raw bytes
    if not verify(SECRET, body, request.headers):
        return "", 401
    event_id = request.headers["WbizTool-Event-Id"]
    if event_id in seen:
        return "", 200  # a repeat: already handled
    seen.add(event_id)
    event = json.loads(body)
    if event["type"] == "message.failed":
        message = event["data"]["message"]
        print("Failed:", message["id"], message["error"]["message"])
    return "", 200

В Django передавайте request.body и request.headers.

Отвечайте 2xx быстро, а медленную работу выполняйте потом (например, в очереди).

Повторные попытки#

  • Ответьте любым 2xx в течение 10 секунд. Всё остальное — неудача: другой код состояния (включая 4xx), отсутствие ответа в течение 10 секунд или отсутствие соединения в течение 3 секунд. Перенаправления выполняются, не больше 3, и каждое должно вести на публичный адрес.
  • Неудачная доставка повторяется через 1, 5 и 15 минут, затем через 1, 2, 4, 8 и 8 часов: 9 попыток примерно за 23 часа. После последней это событие отбрасывается.
  • У повтора то же тело и тот же WbizTool-Event-Id, но новые WbizTool-Timestamp и подпись.
  • Порядок не гарантируется. Повторённое message.sent может прийти после более позднего события. Когда порядок важен, используйте status сообщения или получите сообщение.

last_delivery у endpoint показывает, как прошла последняя доставка: state (pending, delivered или failed), status_code, которым ответил ваш сервер, и когда было создано событие.

Когда endpoint перестаёт работать#

Endpoint перестаёт получать события в одном из этих случаев. Он остаётся в GET /webhooks с active: false и disabled_reason, чтобы вы видели причину; его по-прежнему можно прочитать и удалить, но нельзя протестировать или выдать ему новый секрет (404).

  • Он не работает 24 часа. Если за 24 часа ему ничего не было доставлено, а доставки продолжали завершаться неудачей, он отключается, а его ожидающие повторы отбрасываются. На странице «Настройки → API-ключи» он тогда показан как Отключён. Исправьте свой сервер, а затем добавьте endpoint снова.
  • Ключ, который его создал, отозван или истёк. Отзыв ключа останавливает всё, что он настроил. Добавьте endpoint снова другим ключом.
  • Он удалён через Удаление endpoint или на странице «Настройки → API-ключи».

Переставшие работать endpoint не учитываются в лимите 5.

Объект webhook endpoint#

ПолеТипОписание
idintegerID endpoint.
urlstringКуда отправляются события.
descriptionstringВаша заметка; "", если её нет.
eventsarrayТипы событий, которые он получает.
secretstringСекрет подписи: только в ответах на Добавление endpoint и Замену секрета подписи.
secret_last4stringПоследние 4 символа секрета, чтобы понять, какой из них у вас.
activebooleanfalse, когда он больше не получает события, — см. Когда endpoint перестаёт работать.
disabled_reasonstring or nullПочему он перестал работать (неудачи в течение 24 часов или ключ, который его создал, отозван или истёк); null, пока он активен.
created_atstringКогда он был добавлен.
last_deliveryobject or nullПоследняя попытка доставки: state, status_code (или null, если ваш сервер не ответил) и created_at. null до первой.

Связанные материалы#