Documentation is English-only for now. The rest of the site follows your language.
Webhooks
Outgoing signed HTTP callbacks: pick events, receive an HMAC-signed JSON POST, verify the signature, and retry failed deliveries.
6 min read
Admin → Webhooks (/admin/webhooks, administrators). Register an endpoint with a name, an HTTPS URL, and the events it should receive. Justflows then POSTs a JSON body to that URL whenever one of those events fires. Endpoints, events, and the signing secret are managed through /api/webhooks.
Events
Twenty core events are available; a plugin can add its own through the webhook.eventTypes filter (see Hooks).
content.created/updated/published/unpublished/deletedmedia.uploaded/media.deleteduser.created/updated/deletedauth.login/auth.logoutplugin.installed/activated/deactivated/uninstalledtheme.installed/theme.activatedcore.updated
Signature
Each endpoint has a secret shown once on creation and re-issued by POST /api/webhooks/:id/rotate-secret (prefix whsec_). Every request carries X-Justflows-Signature: sha256=<hex>, an HMAC-SHA256 over <timestamp>.<body>. Recompute it with your secret and compare in constant time; reject old timestamps to stop replay.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(secret: string, header: string, timestamp: string, body: string) {
const expected = createHmac("sha256", secret)
.update(`${timestamp}.${body}`)
.digest("hex");
const got = header.replace(/^sha256=/, "");
return (
got.length === expected.length &&
timingSafeEqual(Buffer.from(got), Buffer.from(expected))
);
}Delivery and retries
- The payload is a JSON object with the event name and its data, capped at 256 KB. A plugin can reshape it through the
webhook.payloadfilter. - A background job drains the queue every minute. A non-2xx response or timeout is retried up to 5 times with backoff.
- Deliveries interrupted by a deploy or crash are re-queued on boot, so a callback is never stranded.
GET /api/webhooks/deliveries/historyreturns the last 100 attempts (event, status, response code, error).POST /api/webhooks/deliveries/:id/redeliverre-queues one.
Endpoint URLs are validated
The target URL is checked before it is saved: private, loopback, and link-local addresses are rejected so a webhook cannot be pointed at internal services.