Добрать пропущенное

Подписки. После регистрации вебхука у ключа появляется подписка на каждую его линию. GET /subscriptions/ показывает их: subscription_id, channel_id, state (active, paused, revoked) и watermark — номер последнего события в этой подписке. Каждая доставка приходит с заголовками X-Wahub-Subscription-ID и X-Wahub-Sequence: сохраняйте последний обработанный sequence по каждой подписке.

Догнать пропущенное. Если сервис лежал дольше, чем длятся повторы, или вы нашли дыру в sequence, читайте GET /subscriptions/<subscription_id>/events/?after_sequence=<последний обработанный>&limit=100 (limit до 500). В ответе deliveries по возрастанию sequence: delivery_id, event_id, sequence и body — тот же JSON, что приходил на вебхук. Передавайте next_cursor как after_sequence, пока has_more не станет false. Чтение не подтверждает доставку и не отменяет повторы.

curl "https://dialogs.tehprof.kz/api/v1/gw/subscriptions/0b6f…/events/?after_sequence=120&limit=100" \
  -H "Authorization: Bearer gw_xxx"

200 {
  "subscription_id": "0b6f…", "channel_id": "32",
  "state": "active", "ack_mode": "legacy_2xx", "watermark": 124,
  "deliveries": [
    { "delivery_id": "9c1e…", "event_id": "5a7d…", "sequence": 121,
      "body": { "messages": [ { "event": "message.created", "message_id": "8841" } ] },
      "acked_at": null, "stop_reason": "" }
  ],
  "next_cursor": 124,
  "has_more": false
}

Повторить доставку. POST /deliveries/<delivery_id>/replay/ заново отправляет неудавшуюся доставку с тем же delivery_id — ваша защита от дублей сработает как обычно. Ответ 202. Если доставка не в состоянии «не удалась» или доступа к линии уже нет — 409 replay_unavailable.

Пауза и отключение. PATCH /subscriptions/<subscription_id>/ с { "state": "paused" } приостанавливает доставку по линии: события копятся и уйдут после { "state": "active" }. { "state": "revoked" } отключает подписку окончательно; чтобы снова получать события линии, создайте новую: POST /subscriptions/grant/ с { "channel_id": 32 }. ack_mode: legacy_2xx — доставка принята по любому ответу 2xx; receipt_v1 — только по ответу 200 с JSON { "delivery_id": …, "body_sha256": … }, где body_sha256 — sha256 сырого тела в hex.