Webhook Event Streams
Receive signed HMAC-SHA256 HTTP POST notifications when crawls finish or ranking shifts occur.
Webhooks stream real-time events from the Four Systems engine directly into your application, Slack notifier, or n8n workflow.
Supported Events
| Event Name | Description |
|---|---|
audit.completed | Triggered when a scheduled or on-demand crawl finishes |
audit.failed | Triggered if an audit terminates with an error or DNS failure |
ranking.dropped | Triggered when a tracked query drops $>3$ positions |
ranking.climbed | Triggered when a query climbs into striking distance (positions 4–10) |
intervention.deployed | Triggered when an automated fix deploys via a CMS connector |
intervention.rolled_back | Triggered when an automated rollback restores prior state |
backlink.lost | Triggered when a high-authority referring domain disappears |
geo_score.changed | Triggered when AI engine brand sentiment or citation rate changes |
Register a Webhook
POST /api/v1/webhooksRequest Body
{
"url": "https://api.yourdomain.com/webhooks/hubseo",
"events": ["audit.completed", "ranking.dropped"],
"description": "Production Alert Pipeline"
}Response (201 Created)
{
"data": {
"id": "whk_01j7x5...",
"url": "https://api.yourdomain.com/webhooks/hubseo",
"events": ["audit.completed", "ranking.dropped"],
"secret": "whsec_aB1cD2eF3gH4...",
"is_active": true,
"created_at": "2026-09-14T16:00:00.000Z"
}
}Save Signing Secret
The secret token (whsec_...) is only returned once in the creation response.
Store it securely to verify signatures on incoming HTTP payloads.
Verifying Webhook Signatures
HubSEO computes an HMAC-SHA256 signature using your webhook's secret and sends it in the HubSEO-Signature header:
HubSEO-Signature: t=1726329600,v1=5d41402abc4b2a76b9719d911017c592
HubSEO-Event-ID: evt_01j7x6...
HubSEO-Event-Type: audit.completed
HubSEO-Timestamp: 1726329600Verification Example (Node.js)
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifySignature(
rawBody: string,
header: string,
secret: string,
toleranceSec = 300
): boolean {
const parts = Object.fromEntries(
header.split(",").map((p) => p.split("="))
);
const timestamp = parseInt(parts.t, 10);
const receivedSig = parts.v1;
if (isNaN(timestamp) || !receivedSig) return false;
// Prevent replay attacks (5 minute window)
if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > toleranceSec) {
return false;
}
const expectedSig = createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const a = Buffer.from(receivedSig, "hex");
const b = Buffer.from(expectedSig, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}Testing Webhooks
You can trigger an immediate diagnostic test ping from the Developer Portal at hubseo.dev/dashboard/developers or via API:
POST /api/v1/webhooks/{id}/pingHubSEO performs a live network dispatch to your endpoint, verifies HMAC delivery, and reports real round-trip latency measured via performance.now().
