Вебхуки
Укажите URL и секрет вебхука в настройках интеграции в дашборде и включите доставку. Cloud API использует один адрес для всех событий. История доставки доступна в дашборде. Секрет вебхука отличается от API-ключа.
Формат
События приходят HTTP POST с Content-Type: application/json и X-Webhook-Signature:
{
"event": "order.completed",
"timestamp": "2026-09-28T12:00:00.000Z",
"data": {
"order_id": 401,
"status": "completed",
"amount_usd": "5.0000",
"currency": "USD",
"vm_id": 101,
"rental_id": null,
"error_code": null,
"error_message": null,
"order_type": "vm_purchase",
"api_user_id": "customer-123"
}
}
event — тип события, timestamp — время создания конверта в UTC. data зависит от события. События ресурсов также содержат числовой data.event_id и data.created_at исходного события; у событий заказов этих двух полей нет. Некоторые поля необязательны и отсутствуют, если их не было в исходном событии.
События заказов
| Событие | Значение |
|---|---|
order.completed | Оплаченное действие завершено; покупка дедика зарезервирована, но ещё не выдана |
order.failed | Ошибка заказа; проверьте причину и транзакции |
order.refunded | Сумма возвращена на баланс интеграции |
order.review | Неопределённый или частичный результат, требующий выяснения |
Все четыре используют поля примера выше: order_id, order_type, api_user_id, status, amount_usd, currency, допускающие null vm_id, rental_id, error_code, error_message. vm_id возвращается только для завершённого заказа. ipv4_renewal дополнительно содержит ip_id и paid_until. Завершённая покупка VPS может содержать guest_initialization; если результата нет, значение — null.
Типы заказов: vm_purchase, vm_renewal, vm_resize, traffic_purchase, ipv4_purchase, ipv4_renewal, dedicated_purchase, dedicated_renewal. При возврате передаётся исходная положительная сумма заказа; отличайте возврат от покупки по event/status.
События VPS
Общие поля: event_id, created_at, vm_id; при наличии — api_user_id, order_id, operation_id. В таблице перечислены дополнительные поля. Создание содержит ips с объектами только из address. Удаление содержит held_ips по формату результата удаления VPS. События ошибок включают публичные error_code и error_message.
| Событие | Значение | Дополнительные поля data |
|---|---|---|
vm.rescue.enabled | Rescue включён | status, rescue |
vm.rescue.enable_failed | Ошибка включения Rescue | requires_review, error_code, error_message |
vm.rescue.disabled | Загрузка обычной ОС восстановлена | status, rescue |
vm.rescue.disable_failed | Ошибка выхода из Rescue | requires_review, error_code, error_message |
vm.reinstalled | ОС переустановлена | os, hostname, wipe_extra_disks, status, guest_initialization |
vm.reinstall_failed | Ошибка переустановки ОС | requires_review, error_code, error_message |
vm.password.changed | Пароль изменён | login, password_changed, status |
vm.password.change_failed | Ошибка смены пароля | requires_review, error_code, error_message |
vm.created | VPS создан | status, hostname, smtp_blocked, paid_until, ips, guest_initialization |
vm.creation_failed | Ошибка создания VPS | status, requires_review, error_code, error_message |
vm.resized | Ресурсы тарифа изменены | status, cpu_cores, cpu_percent, ram_mb, disk_gb, traffic_limit_bytes, resources_applied, traffic_applied |
vm.resize_failed | Ошибка либо частичное применение тарифа | requires_review, status, cpu_cores, cpu_percent, ram_mb, disk_gb, traffic_limit_bytes, resources_applied, traffic_applied, error_code, error_message |
vm.renewed | VPS продлён | paid_until, resume_pending, auto_start |
vm.traffic.topped_up | Трафик докуплен | period_id, quota_revision, additional_bytes, total_additional_bytes, remaining_bytes |
vm.traffic.updated | Квота трафика изменена | period_id, quota_revision, previous_limit_bytes, traffic_limit_bytes, remaining_bytes |
vm.ip.attached | IPv4 назначен | status, ip_id, detached_ip_id, keep_ip, addresses, guest_configuration_required |
vm.ip.attach_failed | Ошибка назначения IPv4 | requires_review, error_code, error_message |
vm.ip.replaced | Получен результат замены IP | status, ip_id, detached_ip_id, keep_ip, addresses, guest_configuration_required |
vm.ip.replace_failed | Ошибка замены IP | requires_review, error_code, error_message |
vm.ip.detached | IPv4 снят | status, ip_id, detached_ip_id, keep_ip, addresses, guest_configuration_required |
vm.ip.detach_failed | Ошибка снятия IPv4 | requires_review, error_code, error_message |
vm.power.changed | Команда питания выполнена | action, status, uptime |
vm.power.failed | Ошибка команды питания | action, requires_review, error_code, error_message |
vm.deleted | VPS удалён | status, keep_ips, reason, paid_until, held_ips |
vm.delete_failed | Ошибка удаления VPS | requires_review, error_code, error_message |
vm.expiring | Скоро окончание оплаты | paid_until, hours_before, delete_after |
vm.deleting_soon | За час до удаления VPS | paid_until, hours_before, delete_after, reason |
vm.suspended | VPS приостановлен | status, reason, paid_until, delete_after |
vm.resumed | VPS восстановлен | status, reason, paid_until, auto_started |
vm.traffic.low | Трафик заканчивается | period_id, quota_revision, starts_at, ends_at, included_bytes, additional_bytes, outgoing_bytes, overage_bytes, remaining_bytes |
vm.traffic.exhausted | Трафик исчерпан | period_id, quota_revision, starts_at, ends_at, included_bytes, additional_bytes, outgoing_bytes, overage_bytes, remaining_bytes |
vm.shaping.changed | Ограничение скорости изменено | previous_reason, reason, limit_mbps, bandwidth_limited_until |
Результат инициализации и Rescue
vm.created, vm.reinstalled и завершённый заказ покупки VPS передают guest_initialization отдельно от результата создания ресурса:
{
"guest_initialization": {
"status": "failed",
"error_code": "cloud_init_failed"
}
}
Возможные статусы: succeeded с error_code=null, failed с cloud_init_failed или unknown с guest_initialization_timeout после 15 минут ожидания. Пользовательская инициализация может завершиться с ошибкой или остаться неподтверждённой, а работающий VPS — сохраниться с завершённой покупкой. Это не ошибка создания и не автоматический возврат оплаты. В событии ресурса поле отсутствует, если результата нет.
Успешные события Rescue содержат вложенное состояние:
{
"event": "vm.rescue.enabled",
"timestamp": "2026-09-28T12:00:00.000Z",
"data": {
"event_id": 701,
"created_at": "2026-09-28T12:00:00Z",
"vm_id": 101,
"api_user_id": "customer-123",
"operation_id": 501,
"status": "running",
"rescue": {
"active": true,
"access": "ssh",
"requires_review": false,
"operation_id": 501,
"operation_status": "succeeded"
}
}
}
При выходе rescue.active=false; VPS может остаться stopped, если срок оплаты истёк или он приостановлен. active означает сохранённый контекст Rescue, а не гарантию доступности SSH. access принимает ssh, console или null. События ошибок передают requires_review, error_code и error_message; актуальное состояние смотрите в деталях VPS и операции.
Пароли, содержимое cloud-init, stdout и stderr в этих вебхуках не передаются. Правила запросов описаны в разделе Cloud-init и Rescue.
События IPv4
Общие поля при наличии: event_id, created_at, ip_id, address, family, vm_id, api_user_id, paid_until. У сохранённого адреса vm_id=null. Дополнительные поля:
| Событие | Значение | Дополнительные поля data |
|---|---|---|
ip.expiring | Срок оплаты IPv4 заканчивается | hours_before, delete_after |
ip.releasing_soon | За час до освобождения IPv4 | hours_before, delete_after, reason |
ip.suspended | IPv4 приостановлен | reason, delete_after |
ip.resumed | IPv4 восстановлен | reason |
ip.released | IPv4 освобождён | reason |
События аренды дедиков
Общие поля при наличии: event_id, created_at, rental_id, plan_id, order_id, api_user_id, status, issued_at, paid_until, overdue_at, finished_at. Доступы не передаются вебхуком: получите детали аренды после dedicated.issued. Дополнительные поля:
| Событие | Значение | Дополнительные поля data |
|---|---|---|
dedicated.preparing | Аренда зарезервирована и готовится | — |
dedicated.issued | Выделенный сервер выдан | — |
dedicated.expiring | Оплата аренды заканчивается | hours_before |
dedicated.overdue | Оплата аренды истекла | release_after |
dedicated.releasing_soon | За час до освобождения аренды | hours_before, release_after, reason |
dedicated.renewed | Аренда продлена | — |
dedicated.released | Аренда освобождена или отменена; проверьте reason | reason |
dedicated.completed | Очистка аренды завершена | — |
Значения полей и последние предупреждения
- Даты (
created_at,paid_until,starts_at,ends_at,delete_after,release_after,bandwidth_limited_until) передаются в UTC; необязательные даты могут быть null. Счётчики байт — целые числа.limit_mbps— ограничение скорости в Мбит/с либо null. statusописывает ресурс, а не доставку.reason— причина перехода, напримерpayment_expired. Не используйте одну причину как идентификатор события.hours_before— интервал предупреждения.delete_after— дедлайн удаления VPS/освобождения IPv4,release_after— дедлайн аренды дедика.resources_applied/traffic_appliedпоказывают применённые части смены тарифа.requires_review=trueозначает, что результат требует выяснения перед новой командой.period_idиquota_revisionопределяют период трафика и ревизию квоты.additional_bytes— добавленный/текущий объём в зависимости от события,total_additional_bytes— общий объём после докупки.remaining_bytes— оставшаяся квота.guest_configuration_required=trueозначает, что нужно проверить сеть внутри ОС клиента.addressesсодержит итоговые адреса;keep_ip/keep_ips— выбор сохранения. Итоговое состояние уточняйте в деталях VPS/IP.resume_pending,auto_startиauto_startedописывают восстановление после оплаты. Успешное продление не обязательно означает, что VPS уже запущен.
vm.deleting_soon, ip.releasing_soon и dedicated.releasing_soon предупреждают за час до удаления/освобождения после 24 часов ожидания оплаты. Они передаются и при выключенном автопродлении либо недостаточном балансе. При включённом автопродлении Cloud API делает последнюю попытку оплаты. Предупреждение всё равно содержит исходный дедлайн; результат смотрите по событиям продления или состоянию ресурса.
Пример последнего предупреждения VPS:
{
"event": "vm.deleting_soon",
"timestamp": "2026-09-29T11:00:00.000Z",
"data": {
"event_id": 701,
"created_at": "2026-09-29T11:00:00+00:00",
"vm_id": 101,
"api_user_id": "customer-123",
"paid_until": "2026-09-28T12:00:00+00:00",
"hours_before": 1,
"delete_after": "2026-09-29T12:00:00+00:00",
"reason": "payment_expired"
}
}
Проверка подписи
X-Webhook-Signature — HMAC-SHA256 от точных исходных байт тела запроса, в виде hex-строки нижнего регистра, с секретом вебхука интеграции. Сам секрет не передаётся. Проверяйте исходные байты до разбора JSON; повторная сериализация меняет данные подписи.
const crypto = require('node:crypto');
function verifySignature(rawBody, secret, signature) {
if (typeof signature !== 'string' || !/^[a-f0-9]{64}$/.test(signature)) {
return false;
}
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest();
return crypto.timingSafeEqual(expected, Buffer.from(signature, 'hex'));
}
rawBody должен быть исходным Buffer вашего HTTP-сервера до JSON-middleware.
Подтверждение, повторы и доставка
- Проверьте подпись и сохраните событие.
- Примените его один раз: для ресурсов используйте интеграцию и
data.event_id; для результатов заказов — интеграцию,data.order_idиevent. - После приёма верните HTTP 200 или 201. Тело ответа не требуется. Другие коды, включая 202 и 204, не подтверждают доставку.
Таймаут HTTP — 10 секунд. После принятия сервисом доставки неуспешная отправка повторяется до 10 попыток, с задержками после предыдущей ошибки:
| Попытка | Задержка |
|---|---|
| 1 | Сразу |
| 2 | 60 секунд |
| 3 | 120 секунд |
| 4 | 300 секунд |
| 5 | 600 секунд |
| 6 | 900 секунд |
| 7 | 1800 секунд |
| 8 | 3600 секунд |
| 9 | 7200 секунд |
| 10 | 7200 секунд |
Порядок доставки не гарантирован. Позднее предупреждение не должно затирать новый оплаченный срок в вашем биллинге. При противоречащих событиях перечитайте состояние. Результат заказа и событие ресурса могут описывать одно действие; не выдавайте услугу и не зачисляйте возврат дважды.
Вебхук не гарантирует получение каждого результата. При отсутствии события запросите заказ, VPS, аренду или IP. История доставки находится в дашборде; отдельного публичного маршрута истории нет. Поддержка события вроде vm.ip.replaced не означает наличие соответствующего публичного маршрута замены: используйте опубликованный каталог маршрутов.