API: rules

List, create, change, test, run and delete rules, and read their run history.

Updated Oct 11, 2026

Rules over the API use exactly the same options and checks as the app. Read Rules reference first; this page shows how those options look as JSON.

Abilities: read to list, view, test and read history. rules to create, change, delete and run.

The rule object

{
  "id": 12,
  "name": "Patch Tuesday",
  "enabled": true,
  "description": "Every Tuesday at 2:00 AM, on all sites, apply minor and patch plugin and theme updates (backup first) except woocommerce, skipping ones that need a license. Email me only if something needs me.",
  "trigger": { "type": "schedule", "every": "weekly", "time": "02:00", "day_of_week": 2, "day_of_month": 1 },
  "scope": { "type": "all" },
  "conditions": {
    "update_level": "minor",
    "include": [],
    "exclude": ["woocommerce"],
    "skip_needs_license": true,
    "window_start": "",
    "window_end": ""
  },
  "actions": {
    "backup": false,
    "updates": { "plugins": true, "themes": true, "core": false },
    "notify": false,
    "webhook": false,
    "report": { "enabled": false, "period": "last_month", "send_to": "client" }
  },
  "notify": "problems",
  "next_run_at": "2026-10-13T06:00:00+00:00",
  "last_run_at": null,
  "paused_reason": null
}
Field Values
trigger.type schedule or event
trigger.every daily, weekly, monthly, quarterly (schedule; quarterly runs in Jan, Apr, Jul, Oct on day_of_month)
trigger.time HH:MM, 24-hour, in the account’s timezone (schedule)
trigger.day_of_week 0 (Sunday) to 6. Weekly only.
trigger.day_of_month 1 to 28. Monthly only.
trigger.event backup.failed, update.failed, outside.any, outside.plugin_installed, outside.plugin_removed, outside.admin_added, outside.core_updated, site.disconnected, site.down, site.up, ssl.expiring, performance.dropped, security.found, visual.changed
trigger.times 1 to 10. Failures in a row, for backup.failed.
scope.type all, client (with client_id), sites (with site_ids)
conditions.update_level patch, minor (default), any
conditions.include / exclude Arrays of plugin or theme names, folders or slugs. Up to 50.
conditions.window_start / window_end HH:MM or empty
actions At least one of backup, updates.*, notify, webhook, report.enabled must be true. report.period: last_month, last_7, last_30, last_quarter, this_month. report.send_to: client, me, both, none.
notify always, problems (default), never
next_run_at Read only. Null for event rules and switched-off rules.
paused_reason Read only. Set when the rule paused itself after 3 failed runs.

List and view

GET /rules

GET /rules/{id}

Create

POST /rules

curl -X POST https://app.wpforeman.com/api/v1/rules \
  -H "Authorization: Bearer $WPF_TOKEN" -H "Content-Type: application/json" \
  -d '{
    "name": "Client installed a plugin",
    "trigger": { "type": "event", "event": "outside.plugin_installed" },
    "scope": { "type": "client", "client_id": 4 },
    "actions": { "backup": true, "notify": true }
  }'

Answers 201 with the rule. Anything you leave out gets the app’s default. Validation errors answer 422 with the field names, for example actions: “Pick at least one thing for the rule to do.”

Change

PATCH /rules/{id}

Send only what changes. Objects are merged; lists (include, exclude, site_ids) are replaced. Send "enabled": false to pause, true to switch back on (this also clears paused_reason).

{ "conditions": { "exclude": ["woocommerce", "elementor"] } }

Test

POST /rules/{id}/test

What the rule would do on each site right now. Changes nothing.

{ "data": [
  { "site": "Acme Plumbing", "would": ["Back up, then update Akismet 5.3.1 → 5.3.2"], "skip": null },
  { "site": "Old Shop", "would": [], "skip": "Not connected" }
] }

Run now

POST /rules/{id}/run

Answers 202 and runs the rule on all its sites. 409 if the rule is switched off.

History

GET /rules/{id}/runs

{ "data": [ {
    "id": 88, "trigger": "Scheduled run", "status": "problems",
    "sites": [
      { "site_id": 3, "name": "Acme Plumbing", "did": ["Backing up, then updating Akismet 5.3.1 → 5.3.2"] },
      { "site_id": 9, "name": "Old Shop", "did": [], "skipped": "Not connected" }
    ],
    "started_at": "2026-10-13T06:00:04+00:00", "finished_at": "2026-10-13T06:00:09+00:00"
  } ],
  "meta": { "page": 1, "last_page": 1, "total": 1 } }

status is running, done, problems or failed. Paginated with page and per_page.

Delete

DELETE /rules/{id}

Answers 204. Log entries the rule made are kept.

To hear about runs as they finish, subscribe a webhook to rule.ran and tick Send the rule.ran webhook on the rule ("actions": {"webhook": true}). See Webhooks.

Was this helpful?