Webhook guide
PlanetDomains webhook guide
Webhook is configured from the bot and sends all supported domain events for the user, even when the change did not come from the API itself.
Overview
HTTPS only
Webhook is configured from the bot. Delivery succeeds on any 2xx response.
Events
v1
domain.registered
Triggered after a successful registration.
domain.renewed
Triggered after a successful renewal.
domain.blocked
Triggered when monitoring moves the domain into blocked state.
domain.unblocked
Triggered when the blocked signal is cleared again.
Delivery model
Outbox + retry
Non-2xx responses move the event through retries: 30s, 2m, 10m, 1h, 6h, then failed.
30s
2m
10m
1h
6h
Signature verification
HMAC-SHA256
PlanetDomains signs every payload over timestamp + "." + raw_body.
X-Planet-Event
Event name.
X-Planet-Event-Id
Unique delivery id.
X-Planet-Timestamp
UNIX timestamp string.
X-Planet-Signature
Hex digest of the computed HMAC.
Delivery log API
GET /api/v1/webhook/deliveries
Use this endpoint to inspect the latest webhook attempts for your account: event type, attempt number, status, response code, and the last delivery error.
curl -H "Authorization: Bearer pd_xxxxxxxxxxxxxxxxx" \
"__BASE_URL__/api/v1/webhook/deliveries?limit=10"Delivery history response
{
"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"}
]
}
}Examples
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");
}