What the Webhooks integration does
Build on DokLocker: read and update documentation from your own scripts, tools and AI assistants.
Setting it up
An admin adds a webhook under Admin › Integrations › Webhooks: an address, and the events to send (or all of them). DokLocker POSTs one JSON request per event:
{"id": "evt_8812", "event": "record.updated", "occurred_at": "2026-10-30T14:02:11+00:00",
"workspace": "Bogus IT",
"object": {"type": "record", "id": 431, "name": "ACME-FW01", "url": "https://doklocker.example.com/configurations/431/"},
"client": {"id": 12, "name": "Acme Inc"},
"changes": {"WAN IP": {"before": "203.0.113.4", "after": "203.0.113.9"}, "Admin password": {"before": "(changed)", "after": "(changed)"}},
"by": {"email": "[email protected]", "via": "web"}}
Events are client, site, contact, record, note, file, photo, link, domain, certificate, article, checklist and rack, each .created, .updated or .deleted, plus password.viewed and info_request.submitted. Send a test sends a ping event. Passwords are never sent: a changed password only shows as "(changed)". Changes made by integration syncs aren't sent one by one.
Every request has these headers:
X-DokLocker-Event: the event name.X-DokLocker-Delivery: a delivery id. A retried delivery keeps its id, so you can skip ones you've already handled.X-DokLocker-Signature:t=<unix time>,v1=<signature>, where the signature is the hex HMAC-SHA256 of<t>.<raw body>with the webhook's signing secret (shown on its page).
Checking the signature in Python:
import hashlib, hmac, time
def is_from_doklocker(secret, header, body):
parts = dict(p.split("=", 1) for p in header.split(","))
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - int(parts["t"])) < 300
And in Node.js:
const crypto = require("crypto");
function isFromDokLocker(secret, header, rawBody) {
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.`).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1)) && Math.abs(Date.now() / 1000 - parts.t) < 300;
}
Answer with any 2xx status within 15 seconds. Anything else is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 12 hours. A webhook that fails 20 times in a row is switched off, and your admins get a "sync failed" alert. Each webhook's page shows its last 50 deliveries.
On the hosted service, webhooks must use https:// and can't point to private network addresses.
Included in every plan
Every integration is included at no extra cost, on the hosted service and self-hosted. Connect it under Admin › Integrations, click Test, and the first sync starts straight away.