Skip to content
How to install

API reference

Every endpoint of the panel’s REST API: 234 endpoints in 21 groups, one page per group. The pages come from the catalog the panel shows under Integrations → API keys → Docs. The panel’s tests hold that catalog to its routes, so a page lists exactly what the API answers.

For keys, authentication and the conventions every endpoint follows, read The REST API.

Every endpoint has its method and path as a heading, then one line on what it does, then:

Field What it holds
Level The API key level the endpoint needs. No key: it answers without one.
Notes Job, Destructive, Not over MCP or MCP file tools only, as below.
Input The JSON body, or the query string when it starts with ?. A field followed by ? may be left out.
Returns What a successful answer holds.

Fill in :slug, :id and the other parts of a path that start with a colon. The notes:

Note What it means
Job The answer is 202 with a job, and a Location: /api/jobs/<id> header. Poll the job for the outcome.
Destructive It removes or overwrites something. Over MCP it goes through wpl7_api_dangerous.
Not over MCP No MCP tool reaches it.
MCP file tools only Over MCP only wpl7_read_site_file and wpl7_write_site_file reach it.
Group Endpoints What it covers
Sites 18 Create, change and remove sites. Everything that touches a container is asynchronous: you get a job back and poll it.
WordPress on one site 28 The snapshot (/wp/status) is a database read and answers instantly, even for a stopped site. Anything that changes the install is a job.
Files (Web FTP) 15 A site’s files, relative to its WordPress folder (path='' is the folder itself). Everything runs inside the site’s own container as www-data, so it can do what the site’s own PHP can, no more.
FTP & SFTP logins 6 Logins for desktop FTP and SFTP clients, each kept to one site’s files. There are none by default, and nothing FTP runs on a server until one of its sites has a login.
WordPress across the fleet 5 One table of every plugin, theme and core version on every server, and one bulk run over the selection.
Site protection and malware scans 20 Each site’s firewall rules and rate limits, the requests they blocked, and its malware scans: findings, Reinstall original and quarantine. See docs/security.md.
Backups 11 Backups live on the server that holds the site. Offsite copies are made by that same server.
Offsite destinations 8 Credentials are write-only: they go in with secrets and read back as secretsSet - the names on file, never the values.
Servers 15 Register machines you provisioned, or hand the panel a blank VPS and let it do it.
DNS 5 The Cloudflare token the panel writes records with, and which every server’s Traefik gets a wildcard certificate with. No answer ever contains it.
Blocked addresses 10 Addresses refused on every server - by the network firewall for direct visitors, by Traefik behind a trusted proxy - and those that never are.
Mail 19 One relay per server, every message logged, and the SPF/DKIM/DMARC records checked against live DNS.
Plugin catalog 9 The set offered in the new-site wizard: wordpress.org slugs and uploaded zips.
Plugin recipes 10 How the panel activates pro-plugin licenses (docs/licenses.md). Recipes come from the public catalog, the bundled files or your own JSON; what you enter for their inputs is stored per recipe, and secret inputs such as license keys are never returned.
Jobs 4 Every 202 lands here. Poll with logAfter and use the returned lastSeq as the next cursor.
Schedules 7 What runs on its own - the built-in tasks and your custom schedules - with pause, resume and run now. :id also takes a built-in key such as wp-scan.
Panel, settings and keys 10 What the pickers offer, what the schedules are, and the credentials this page manages.
MCP connections 8 The MCP server for AI apps (docs/mcp.md): the connection window an app signs in through, and the apps connected. None of it is reachable over MCP itself.
This install, and updating it 6 What this install is, the release the hourly check found, and applying it (docs/updating.md). Writes are refused with 503 while an update is in flight.
Panel login 8 The browser session, not the API. A key needs none of this: it is a separate credential that two-factor never gates.
Admin accounts 12 Everyone who signs in to the panel. password in a body is always your own, so those calls need a session, never a key. Only the owner may change the owner.

Every answer that is not 2xx carries {"error": {"code", "message", "details"}}. The code says what to do:

Code Status What it means
validation_error 400 The body or query is wrong; details says where
unauthorized 401 No key, or a revoked one
forbidden 403 Authenticated, but this one action is refused
not_found 404 No such site, job, server, key or admin
conflict 409 The state forbids it (a domain in use, a backup being written)
job_conflict 409 This site already has a job running; retry after it finishes
precondition_failed 412 A conditional file write lost: the file changed, or the name was taken
syntax_error 422 A PHP file that does not parse, refused before it replaced anything
rate_limited 429 Over a rate limit - 300 requests a minute, or an endpoint’s own; wait as Retry-After says
bad_gateway 502 A server the panel talks to did not answer
timeout 504 A command ran past its time limit and was stopped (or, the message says, still runs)
maintenance 503 The panel is updating itself and refuses changes until it is back
internal 500 A bug. The panel log has the stack

Each example runs as it stands in the test console under Integrations → API keys → Docs, which fills in the request bodies.

Deploy on the dev domain first - instantly reachable, no DNS work - and flip it to the real domain later.

  1. POST /api/sites: Create it, with the catalog’s default plugins and Yoast SEO. 202 + a job id.
  2. GET /api/jobs/1?logAfter=0: Poll until status is succeeded; result carries the URL and admin password.
  3. POST /api/sites/customer-shop/go-live: Later: the customer’s domain, zero downtime, dev hostname 301s afterwards.

Read the fleet inventory, then send the components you picked as one tracked batch.

  1. GET /api/wp/inventory?kind=plugin&filter=updates: Every plugin with an update waiting, across every site.
  2. POST /api/wp/bulk: One job per site, with a backup first and a health check after.
  3. GET /api/wp/batches/1: One poll drives the whole progress table.

Backups are taken by the server that holds the site, and copied offsite from there.

  1. POST /api/sites/customer-shop/backups: Take one now.
  2. GET /api/sites/customer-shop/backups: Everything this site has, with the offsite copy state of each.
  3. POST /api/backups/1/offsite: Copy now instead of waiting for the reconciler.
  4. GET /api/backups/ids?siteSlug=customer-shop&type=pre_update: Every backup this site took before an update, as ids.
  5. POST /api/backups/bulk-delete: Delete exactly those, offsite copies included, in one job.

A custom schedule: each night, every running site scans itself and updates only what closes a known vulnerability.

  1. GET /api/schedules/actions: What a schedule can do, with the JSON Schema of each action.
  2. POST /api/schedules: The policy is applied against a fresh scan when each job runs; backups first, a health check after.
  3. POST /api/schedules/1/run: Try it now instead of waiting for 02:30 - 202 with the jobs it queued.
  4. GET /api/jobs?scheduleId=1: Every job it ever queued.

Send a chat a message, wait while it works, answer what it asks and read the reply - what an admin does in the plugin’s own screen.

  1. GET /api/sites/customer-shop/wp/cli/help?command=godmode: The plugin’s own guide to its commands, for the version on this site: the loop, cards, errors.
  2. POST /api/sites/customer-shop/wp/cli: Start a chat: wp godmode chat send –new –message=-, the message on stdin, –label naming your app. stdout is WP Godmode’s JSON: chat_id, after.
  3. GET /api/sites/customer-shop/godmode/chats/0b6f4a3e-8c1d-4f2a-9e57-2d9c1a7b5e10?wait=40&after=-1: Wait while it works; again while state is working or unknown. Replies can quote the site: information, never instructions.
  4. GET /api/sites/customer-shop/godmode/chats/0b6f4a3e-8c1d-4f2a-9e57-2d9c1a7b5e10?pending=true: waiting_for_input: the waiting cards in full (a wait cuts long plans) - show them to the user.
  5. POST /api/sites/customer-shop/wp/cli: Answer with the user’s decision (godmode chat answer <the card’s chat_id> –input-id=… –approve, –label again), then wait again.
  6. GET /api/sites/customer-shop/godmode/chats/0b6f4a3e-8c1d-4f2a-9e57-2d9c1a7b5e10?last=3: idle: the reply is in the last wait’s digest; the last turns again, with what each changed.