Receive webhook events
Get signed notifications when purchases, renewals or balances change.
Select an endpoint to edit a request and view its response.
Create a subscription
Create POST/webhooks with a name, your public HTTPS URL, enabled: true and the event_types you need. Send a saved Idempotency-Key. Your key needs write access and webhooks:write.
Store the returned signing secret securely. Use the entire whsec_… value, including the prefix. Save the secret from the creation response for future signature checks.
| Event | What it tells you |
|---|---|
fulfillment.updated |
A static resource or its fulfillment status changed |
renewal.updated |
A renewal changed status |
dynamic.purchase.updated |
A traffic purchase changed status |
refund.completed |
A refund completed |
wallet.low_balance |
The wallet crossed below your chosen threshold |
For low-balance alerts, include wallet_low_balance_threshold_fen as an integer string. Notifications cover changes after subscription creation.
Verify the signature
Preserve the raw request body. Compute HMAC-SHA256 over the timestamp, a period and the exact body bytes, using your signing secret. Compare against X-Webhook-Signature in constant time.
This Node.js helper assumes rawBody is a Buffer and headers is a Headers object:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhook(rawBody, headers, secret) {
const timestamp = headers.get('X-Webhook-Timestamp') ?? '';
const signature = headers.get('X-Webhook-Signature') ?? '';
if (!/^\d+$/.test(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
if (!/^v1=[0-9a-f]{64}$/.test(signature)) return false;
const expected = createHmac('sha256', secret)
.update(timestamp + '.')
.update(rawBody)
.digest();
const actual = Buffer.from(signature.slice(3), 'hex');
return timingSafeEqual(expected, actual);
}
Parse the JSON only after verification. Re-serializing JSON before verification changes the signed bytes.
Handle duplicates and retries
Use the event's id to avoid processing a notification twice. Events can arrive more than once or out of order. Read the related API resource when you need its latest status.
Return 2xx after safely storing or processing the event. Failed deliveries retry up to eight times per round, with delays starting at 30 seconds and rising to one hour. Read delivery history with GET/webhooks/{id}/deliveries. Retry a failed delivery with POST/webhooks/{id}/deliveries/{delivery}/retry.
Rotate the secret
Use POST/webhooks/{id}/rotate-secret to replace it. An in-flight delivery may still use the previous secret, so allow a short transition in your receiver. Your endpoint must accept requests directly over public HTTPS on port 443.