Webhooks

Get a signed POST when backups, restores and updates finish or fail, or when a site disconnects.

Updated Oct 11, 2026

Webhooks let WP Foreman tell your other tools when something happens. Point one at Zapier or Make to post into Slack, open a ticket, or text you when a backup fails.

Add a webhook

  1. In the app, open Settings › Webhooks.
  2. Paste the https:// URL that should receive events and pick the events.
  3. Click Add webhook, then Send test to check it arrives.

Every webhook has a signing secret (starts with whsec_) so you can check deliveries really came from WP Foreman.

Events

Event When data contains
backup.succeeded A backup finished site, backup
backup.failed A backup failed site, backup (with error)
restore.succeeded A restore or clone finished site, restore
restore.failed A restore or clone failed site, restore
update.succeeded A plugin, theme or WordPress change finished site, activity
update.failed A change failed, or only some items worked site, activity
site.disconnected Someone clicked Disconnect in WordPress site
site.changed Someone changed a site outside WP Foreman: a plugin or theme installed, deleted, activated, deactivated or switched, WordPress updated by hand, or a new administrator (plugin 0.7.0+; auto-updates aren’t sent) site, changes (each with type, title, by {name, email, login, roles}, context, ip, at)
site.down Uptime monitoring confirmed a site is down site, incident (reason, regions, started_at)
site.up A site is back up after an outage site, incident (with ended_at and seconds)
visual.changed A visual check found pages that look different from their last screenshots site, check (id, trigger: update, schedule or manual, activity_id, threshold), shots (each over the threshold: path, device, diff_pct)
security.found Known vulnerabilities were found on a site (new ones only) site, vulnerabilities (each: vulnerability_id, name, type, slug, installed_version, fixed_in, severity, title)
performance.dropped A site’s mobile speed score fell 10+ points below its usual site, strategy (mobile), score, usual, lcp_ms, checked_at
rule.ran A rule with Send the rule.ran webhook ticked finished a run rule {id, name, description}, trigger, status (done, problems, failed), sites (each with site_id, name, did, and skipped or error when there was one)
* Everything, including events added later

Safety backups taken before restores and updates send backup events too, with trigger set to pre-restore or pre-update.

What a delivery looks like

POST /your/endpoint
Content-Type: application/json
User-Agent: WPForeman-Webhooks/1.0
X-WPF-Event: backup.failed
X-WPF-Delivery: 8f0e1c1a-2a9b-4b3c-9d61-0d3f6f1f7b9e
X-WPF-Signature: t=1791234567,v1=5d1c…e9

{
  "id": "8f0e1c1a-2a9b-4b3c-9d61-0d3f6f1f7b9e",
  "event": "backup.failed",
  "created_at": "2026-10-05T05:41:12+00:00",
  "data": {
    "site": { "id": 12, "name": "Shop", "url": "https://shop.example", "client": { "id": 3, "name": "Acme" } },
    "backup": { "id": 481, "status": "failed", "trigger": "scheduled", "error": "The site answered 503: Service Unavailable", … }
  }
}

The backup, restore and activity objects are the same as in the API.

Verify the signature

X-WPF-Signature is t=<unix time>,v1=<hex HMAC-SHA256>, signed over <t>.<raw body> with your signing secret. Reject deliveries older than five minutes.

// PHP
[$t, $sig] = sscanf($_SERVER['HTTP_X_WPF_SIGNATURE'], 't=%d,v1=%s');
$body = file_get_contents('php://input');
$ok = abs(time() - $t) < 300
   && hash_equals(hash_hmac('sha256', $t . '.' . $body, $secret), $sig);
// Node.js (Express: use express.raw() so you get the exact body)
const crypto = require('crypto');
const [, t, sig] = req.get('X-WPF-Signature').match(/^t=(\d+),v1=([a-f0-9]+)$/);
const expected = crypto.createHmac('sha256', secret).update(`${t}.${req.body}`).digest('hex');
const ok = Math.abs(Date.now() / 1000 - t) < 300 &&
  crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));

Retries

  • Answer with any 2xx within 15 seconds to confirm the delivery.
  • If your endpoint is down, times out, or answers 5xx or 429, WP Foreman tries again after 1 minute, 5 minutes, 30 minutes and 2 hours. Other 4xx answers aren’t retried.
  • Use id (also in X-WPF-Delivery) to ignore duplicates.
  • After 20 failed deliveries in a row the webhook is switched off. Fix it, then click Turn on.
  • Recent deliveries on the Webhooks page shows what was sent and how your endpoint answered.

For safety, webhook URLs must use https:// and can’t point at private or local network addresses.

Subscribe over the API (Zapier, Make)

Tools that manage their own subscriptions can use a token with the webhooks ability:

GET /webhooks

POST /webhooks

DELETE /webhooks/{id}

curl -X POST https://app.wpforeman.com/api/v1/webhooks \
  -H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
  -d '{"url":"https://hooks.zapier.com/…","events":["backup.failed","update.failed"]}'

The response includes the secret. It’s only returned when the webhook is created.

Slack: Slack’s own “incoming webhook” URLs expect a different format. Send WP Foreman’s webhook to Zapier or Make and have it post a message to Slack, e.g. “⚠️ Backup failed on {{site.name}}: {{backup.error}}”.

Was this helpful?