Гайд по webhook
Webhook guide

PlanetDomains webhook guide

Webhook настраивается из бота и отправляет все поддерживаемые доменные события пользователя, даже если изменение пришло не из самой API.

Обзор

HTTPS only

Webhook настраивается из бота. Успехом считается любой ответ 2xx.

События

v1
domain.registered
Отправляется после успешной регистрации.
domain.renewed
Отправляется после успешного продления.
domain.blocked
Отправляется, когда мониторинг переводит домен в blocked state.
domain.unblocked
Отправляется, когда blocked-сигнал снова снимается.

Модель доставки

Outbox + retry

Non-2xx переводит событие через повторы: 30s, 2m, 10m, 1h, 6h, затем failed.

30s
2m
10m
1h
6h

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

HMAC-SHA256

PlanetDomains подписывает каждый payload по схеме timestamp + "." + raw_body.

X-Planet-Event
Имя события.
X-Planet-Event-Id
Уникальный id доставки.
X-Planet-Timestamp
UNIX timestamp строкой.
X-Planet-Signature
Hex digest вычисленного HMAC.

API истории доставок

GET /api/v1/webhook/deliveries

Этот endpoint помогает быстро посмотреть последние попытки webhook по вашему аккаунту: тип события, номер попытки, статус, код ответа и последнюю ошибку доставки.

curl -H "Authorization: Bearer pd_xxxxxxxxxxxxxxxxx" \
  "__BASE_URL__/api/v1/webhook/deliveries?limit=10"
Ответ истории доставок
{
  "status": true,
  "result": {
    "limit": 10,
    "count": 2,
    "items": [
      {"event_key": "evt_renew_001", "event_type": "domain.renewed", "attempt_number": 1, "status": "delivered", "status_code": 200, "error": null},
      {"event_key": "evt_block_002", "event_type": "domain.blocked", "attempt_number": 2, "status": "retrying", "status_code": 500, "error": "upstream timeout"}
    ]
  }
}

Примеры

Headers, payload, verify
Webhook payload
{
  "event": "domain.renewed",
  "domain": "planet-project.click",
  "client_ref": "deal-42",
  "external_ref": "invoice-77",
  "occurred_at": "2026-05-15T12:00:00Z"
}
Python
import hmac
import hashlib

signed = f"{timestamp}.{raw_body.decode()}".encode()
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
assert hmac.compare_digest(expected, signature)
Node.js
import crypto from "node:crypto";

const signed = `${timestamp}.${rawBody}`;
const expected = crypto.createHmac("sha256", secret).update(signed).digest("hex");
if (expected !== signature) throw new Error("invalid signature");
PHP
$signed = $timestamp . "." . $rawBody;
$expected = hash_hmac("sha256", $signed, $secret);
if (!hash_equals($expected, $signature)) {
    throw new RuntimeException("invalid signature");
}