# MCP tool reference

The 85 tools the PBN.LTD MCP server (`https://app.pbn.ltd/mcp`) offers, in the order `tools/list` returns them. Each one is the same operation as the REST endpoint named beside it (paths relative to `https://app.pbn.ltd/api/v1`), with the same permission, the same limits and the same audit trail - see the [API reference](https://app.pbn.ltd/api/docs) for the full description of what each field means.

A connection only sees the tools its permissions allow. "Kind" is the behaviour annotation the tool carries: **read** never changes anything, **write** does, and **DESTRUCTIVE** replaces or deletes something that cannot be brought back.

## All tools

| Tool | What it does | Permission | Kind |
|---|---|---|---|
| [account_limits](https://app.pbn.ltd/api/docs/mcp-tools#account-limits) | Site slots (plan + extra-site add-ons), subscription state and paid-until date, the default per-site limits, every paused (frozen) site with the re… | `account:read` | read |
| [account_me](https://app.pbn.ltd/api/docs/mcp-tools#account-me) | The account and the key making the call. The cheapest call there is: use it to test a key. | `account:read` | read |
| [account_usage_refresh](https://app.pbn.ltd/api/docs/mcp-tools#account-usage-refresh) | Starts a fresh disk / database / file-count measurement for the account's sites - the usage tab's "Check now", for many sites at once. It returns a… | `account:write` | write |
| [meta_limits](https://app.pbn.ltd/api/docs/mcp-tools#meta-limits) | The rate limits and size limits that apply to the key making the call. `overridden` is true when support has raised or lowered a limit for this key… | `kb:read` | read |
| [billing_invoice_pdf](https://app.pbn.ltd/api/docs/mcp-tools#billing-invoice-pdf) | The PDF of an invoice or credit note of this account (Content-Type application/pdf). | `billing:read` | read |
| [billing_invoices](https://app.pbn.ltd/api/docs/mcp-tools#billing-invoices) | Every payment and refund of the account, newest first. `document` is the invoice / credit note when one has been issued; download it with GET /bill… | `billing:read` | read |
| [billing_summary](https://app.pbn.ltd/api/docs/mcp-tools#billing-summary) | Subscription (state, plan, paid-until date, days left, payment method), unpaid state with the date sites are removed if it stays unpaid, site slots… | `billing:read` | read |
| [sites_create](https://app.pbn.ltd/api/docs/mcp-tools#sites-create) | Creates a site exactly as the Add new site form does - same validation, same slot limit, same checks - for every type: WordPress, Static HTML, PHP… | `sites:write` | write |
| [sites_create_options](https://app.pbn.ltd/api/docs/mcp-tools#sites-create-options) | The fields the Create site form accepts for this account right now, with their choices (site types, CDNs, PHP versions, templates, blueprints, grou… | `sites:write` | read |
| [sites_delete](https://app.pbn.ltd/api/docs/mcp-tools#sites-delete) | Deletes the site for good (files, database, DNS zone, CDN), exactly like Delete site in the panel. Refused while the site is busy or paused for non… | `sites:delete` | DESTRUCTIVE |
| [sites_edit_options](https://app.pbn.ltd/api/docs/mcp-tools#sites-edit-options) | The fields the Edit site form offers for THIS site right now (they depend on type, CDN and state), with choices and current values. | `sites:write` | read |
| [sites_get](https://app.pbn.ltd/api/docs/mcp-tools#sites-get) | Everything the site page shows: state, URL, settings, why it is paused (freeze.reasons), nameserver status (current vs required, pointed, autopilot… | `sites:read` | read |
| [sites_list](https://app.pbn.ltd/api/docs/mcp-tools#sites-list) | The same search, filters and order as the sites list in the panel. `total` is the number of matching sites. A key restricted to some sites only see… | `sites:read` | read |
| [sites_update](https://app.pbn.ltd/api/docs/mcp-tools#sites-update) | Change any setting the Edit site form offers: name, domain, PHP version, HTTPS, www, group, admin e-mail, login URL, auto-updates, mailbox. Send on… | `sites:write` | write |
| [cleaner_get](https://app.pbn.ltd/api/docs/mcp-tools#cleaner-get) | Site Cleaner for this site: whether the add-on is active, the last scan (what can be removed and how much it saves), the running job, recent jobs (… | `sites:read` | read |
| [cleaner_run](https://app.pbn.ltd/api/docs/mcp-tools#cleaner-run) | Runs Site Cleaner. `scan` lists unused plugins/themes, junk files and database clutter (free). `clean` removes the selected items after taking a ba… | `sites:write` | write |
| [cleaner_schedule](https://app.pbn.ltd/api/docs/mcp-tools#cleaner-schedule) | Sets automatic cleaning for the site (needs the add-on to actually clean). | `sites:write` | write |
| [health_get](https://app.pbn.ltd/api/docs/mcp-tools#health-get) | The online badge (online / offline / slow / paused... with the reason) and, for application sites, the last integrity check (V1 config lines, admin… | `sites:read` | read |
| [health_integrity_check](https://app.pbn.ltd/api/docs/mcp-tools#health-integrity-check) | Checks the application now (WordPress, Joomla, Drupal, PrestaShop, OpenCart, Grav, MediaWiki): V1's config lines, the site URL, the admin account,… | `sites:write` | write |
| [health_recheck](https://app.pbn.ltd/api/docs/mcp-tools#health-recheck) | Probes the home page again now (same probe and recording as the platform's monitor) and asks the server why if it fails. Asynchronous: follow the j… | `sites:write` | write |
| [health_repair](https://app.pbn.ltd/api/docs/mcp-tools#health-repair) | "Repair site": checks, repairs everything repairable (backups first, on the server), checks again. You get an e-mail listing what was repaired. | `sites:write` | write |
| [sites_admin_login](https://app.pbn.ltd/api/docs/mcp-tools#sites-admin-login) | A single-use login link to the site's admin (WordPress wp-admin, Joomla, Drupal, PrestaShop, OpenCart, Grav, MediaWiki), valid for 60 seconds - the… | `sites:login` | write |
| [sites_php_version](https://app.pbn.ltd/api/docs/mcp-tools#sites-php-version) | Shortcut for PATCH /sites/{site_id} with php_version. The web server is reconfigured in the background (a job is returned). | `sites:write` | write |
| [sites_purge_cache](https://app.pbn.ltd/api/docs/mcp-tools#sites-purge-cache) | Clears the CDN cache of both hostnames (as Purge CDN cache in the panel). The site must be live. | `sites:write` | write |
| [sites_reinstall](https://app.pbn.ltd/api/docs/mcp-tools#sites-reinstall) | Installs the site again from scratch (as Reinstall in the panel) - the current files and database are replaced. Refused while the site is busy, swi… | `sites:write` | DESTRUCTIVE |
| [sites_temp_unfreeze](https://app.pbn.ltd/api/docs/mcp-tools#sites-temp-unfreeze) | A site paused ONLY for a usage limit (disk / database / files) comes back for 30 minutes so you can clean it up (3 times per site per day). At the… | `sites:write` | write |
| [sites_usage](https://app.pbn.ltd/api/docs/mcp-tools#sites-usage) | The Usage & add-ons tab: disk, database and file-count use against the limits (plan + add-ons), what is over, CDN bandwidth for metered CDNs, and t… | `sites:read` | read |
| [sites_usage_refresh](https://app.pbn.ltd/api/docs/mcp-tools#sites-usage-refresh) | Starts a fresh measurement of disk, database and files (the usage tab's "Check now"). Returns the current figures with busy=true; poll GET /sites/{… | `sites:write` | write |
| [dns_create](https://app.pbn.ltd/api/docs/mcp-tools#dns-create) | Adds a record with the panel's own validation. It is published to the site's DNS provider within a minute or two (follow the job); your records are… | `dns:write` | write |
| [dns_delete](https://app.pbn.ltd/api/docs/mcp-tools#dns-delete) | Deletes a record; it is removed at the DNS provider within a minute or two. | `dns:write` | write |
| [dns_list](https://app.pbn.ltd/api/docs/mcp-tools#dns-list) | The site's own DNS records (the DNS records tab), and the publishing state: the DNS provider, when the records were last published and any record t… | `dns:read` | read |
| [dns_update](https://app.pbn.ltd/api/docs/mcp-tools#dns-update) | Changes a record; send only the fields that change. | `dns:write` | write |
| [sites_nameservers](https://app.pbn.ltd/api/docs/mcp-tools#sites-nameservers) | The nameservers the domain must use (required), what it uses now (current, checked daily), whether it is pointed, whether the DNS zone expired at t… | `dns:read` | read |
| [backups_create](https://app.pbn.ltd/api/docs/mcp-tools#backups-create) | Takes a full backup (files + database) now, as Create backup in the panel. Follow the job until the backup is Ok. | `backups:write` | write |
| [backups_delete](https://app.pbn.ltd/api/docs/mcp-tools#backups-delete) | Deletes a backup. A backup that a blueprint uses cannot be deleted. | `backups:write` | DESTRUCTIVE |
| [backups_download](https://app.pbn.ltd/api/docs/mcp-tools#backups-download) | A temporary link to download the backup archive (tar.gz) - valid about 4 hours. | `backups:read` | read |
| [backups_get](https://app.pbn.ltd/api/docs/mcp-tools#backups-get) | One backup of the site. | `backups:read` | read |
| [backups_list](https://app.pbn.ltd/api/docs/mcp-tools#backups-list) | The site's backups, newest first (automatic daily ones, manual ones and uploaded ones). | `backups:read` | read |
| [backups_restore](https://app.pbn.ltd/api/docs/mcp-tools#backups-restore) | Replaces the site's files and database with the backup (as Restore in the panel). Refused while the site is busy, switched off or the plan has expi… | `backups:write` | DESTRUCTIVE |
| [files_delete](https://app.pbn.ltd/api/docs/mcp-tools#files-delete) | Deletes a file, or a folder (with recursive=true when it is not empty). There is no undo - take a backup first for anything important. | `files:write` | DESTRUCTIVE |
| [files_list](https://app.pbn.ltd/api/docs/mcp-tools#files-list) | Folders first, then files; up to 5,000 entries. Symbolic links are listed (type "link") but never followed. Available under the same rule as the Fi… | `files:read` | read |
| [files_mkdir](https://app.pbn.ltd/api/docs/mcp-tools#files-mkdir) | Creates a folder (and any missing parent folders). | `files:write` | write |
| [files_move](https://app.pbn.ltd/api/docs/mcp-tools#files-move) | Renames or moves a file or folder inside the site folder. | `files:write` | write |
| [files_read](https://app.pbn.ltd/api/docs/mcp-tools#files-read) | Returns a file of up to 5 MB (the limit is in GET /limits). Use encoding=raw to stream the bytes directly. | `files:read` | read |
| [files_stat](https://app.pbn.ltd/api/docs/mcp-tools#files-stat) | Type, size, modification time and mode of one path. | `files:read` | read |
| [files_write](https://app.pbn.ltd/api/docs/mcp-tools#files-write) | Writes a file of up to 25 MB atomically (a temporary file renamed into place), owned by the site's web server user. Refuses to write through symbol… | `files:write` | write |
| [logs_access](https://app.pbn.ltd/api/docs/mcp-tools#logs-access) | Requests that reached the web server for this site's hostnames, newest last. The client IP is the visitor as the CDN reported it. 30 fetches per 10… | `logs:read` | read |
| [logs_errors](https://app.pbn.ltd/api/docs/mcp-tools#logs-errors) | Recent PHP and web server errors of THIS site (the Error log tab): last 7 days, grouped, sanitised (paths shown relative to the site folder, secret… | `logs:read` | read |
| [tickets_create](https://app.pbn.ltd/api/docs/mcp-tools#tickets-create) | Opens a ticket (support is e-mailed as for a panel ticket). The ticket limits apply: at most 2 open tickets at a time (409 ticket_limit). | `tickets:write` | write |
| [tickets_get](https://app.pbn.ltd/api/docs/mcp-tools#tickets-get) | A ticket with every public message (yours and support's). can_reply says if you may add a message now (ticket limits: one message before support an… | `tickets:read` | read |
| [tickets_list](https://app.pbn.ltd/api/docs/mcp-tools#tickets-list) | Your tickets, newest first. | `tickets:read` | read |
| [tickets_queues](https://app.pbn.ltd/api/docs/mcp-tools#tickets-queues) | The categories (queues) a ticket can be opened in. | `tickets:read` | read |
| [tickets_reply](https://app.pbn.ltd/api/docs/mcp-tools#tickets-reply) | Adds your message to the ticket (support is notified). One message until support answers. | `tickets:write` | write |
| [kb_article](https://app.pbn.ltd/api/docs/mcp-tools#kb-article) | One article as plain text and as sanitised HTML, with related articles. | `kb:read` | read |
| [kb_search](https://app.pbn.ltd/api/docs/mcp-tools#kb-search) | The dashboard's knowledge-base search (keyword + meaning). Every key may use it. | `kb:read` | read |
| [sites_kb_suggestions](https://app.pbn.ltd/api/docs/mcp-tools#sites-kb-suggestions) | Knowledge-base articles that fit what is going on with this site right now (why it is paused, nameservers not pointed, offline...), with app and pu… | `sites:read` | read |
| [jobs_get](https://app.pbn.ltd/api/docs/mcp-tools#jobs-get) | The live status of a job: running, succeeded or failed, with a message. Poll every few seconds (it counts against the rate limit like any call). | `account:read` | read |
| [jobs_list](https://app.pbn.ltd/api/docs/mcp-tools#jobs-list) | Jobs the API started for this account, newest first. | `account:read` | read |
| [campaigns_get](https://app.pbn.ltd/api/docs/mcp-tools#campaigns-get) | One campaign with its last ten runs. | `content:read` | read |
| [campaigns_list](https://app.pbn.ltd/api/docs/mcp-tools#campaigns-list) | The AI auto-posting campaigns on the account: what they write, when they run next and how many articles they have made. | `content:read` | read |
| [campaigns_status](https://app.pbn.ltd/api/docs/mcp-tools#campaigns-status) | Pauses a campaign or starts it again. A campaign paused by our staff or by a problem with an AI key cannot be resumed from here - fix the cause first. | `content:write` | write |
| [campaigns_write_now](https://app.pbn.ltd/api/docs/mcp-tools#campaigns-write-now) | Asks a campaign to write and publish now, the same as the "Write now" button. Returns the run; follow it with runs.get. | `content:write` | write |
| [content_create](https://app.pbn.ltd/api/docs/mcp-tools#content-create) | Writes the post and puts it on the site. Works for every site type: WordPress, Joomla, Drupal, PrestaShop, OpenCart, Grav and MediaWiki get a nativ… | `content:write` | write |
| [content_get](https://app.pbn.ltd/api/docs/mcp-tools#content-get) | One post in full, with its text and the history of what happened to it. | `content:read` | read |
| [content_list](https://app.pbn.ltd/api/docs/mcp-tools#content-list) | The latest posts the site itself reports, and every post this account has written for it through PBN.LTD (including ones still being written or wai… | `content:read` | read |
| [content_media](https://app.pbn.ltd/api/docs/mcp-tools#content-media) | Puts a picture or file on the site and gives back the address to use in a post. On WordPress it goes into the media library; on every other site ty… | `content:write` | write |
| [content_options](https://app.pbn.ltd/api/docs/mcp-tools#content-options) | Before writing anything, ask this: it says how a post appears on this site type, which fields it supports (featured picture, categories, tags, auth… | `content:read` | read |
| [content_queue](https://app.pbn.ltd/api/docs/mcp-tools#content-queue) | Every post on the account that is queued, being written, waiting for approval, scheduled, publishing, published, failed or cancelled - newest first… | `content:read` | read |
| [content_remove](https://app.pbn.ltd/api/docs/mcp-tools#content-remove) | Removes a published post from the site, or cancels one that has not gone out yet. There is no undo. | `content:write` | DESTRUCTIVE |
| [content_update](https://app.pbn.ltd/api/docs/mcp-tools#content-update) | Changes a post that has not gone out yet. A post that is already on the site cannot be edited from here - remove it and write a new one. | `content:write` | write |
| [runs_get](https://app.pbn.ltd/api/docs/mcp-tools#runs-get) | One run of a campaign and every article in it. | `content:read` | read |
| [code_check](https://app.pbn.ltd/api/docs/mcp-tools#code-check) | Runs PHP's own syntax check over a file or every .php file in a folder, in the exact PHP version the site runs. Do this before switching a plugin o… | `sites:read` | read |
| [extsites_deploy](https://app.pbn.ltd/api/docs/mcp-tools#extsites-deploy) | Publishes the site to its provider again, or rolls it back to a deploy that is already there. This replaces what is live at that provider. No files… | `sites:write` | DESTRUCTIVE |
| [extsites_history](https://app.pbn.ltd/api/docs/mcp-tools#extsites-history) | The recent deploys of one external site, newest first - what to pass to a rollback. | `sites:read` | read |
| [extsites_list](https://app.pbn.ltd/api/docs/mcp-tools#extsites-list) | The sites this account publishes to outside PBN.LTD (GitHub Pages, Cloudflare Pages, Netlify, Vercel and the rest), with their address and the stat… | `sites:read` | read |
| [files_upload_archive](https://app.pbn.ltd/api/docs/mcp-tools#files-upload-archive) | Unpacks a zip of a built website (or a plugin or theme) into the site. Every file goes through the same path a single upload uses, so the same rule… | `files:write` | write |
| [plugins_delete](https://app.pbn.ltd/api/docs/mcp-tools#plugins-delete) | Switches a plugin off and deletes its files. There is no undo; the plugin's own data in the database is removed the way the plugin asks for. | `sites:write` | DESTRUCTIVE |
| [plugins_install](https://app.pbn.ltd/api/docs/mcp-tools#plugins-install) | Installs a plugin on a WordPress site, from wordpress.org or from a zip you send. A plugin that is on our blocked list is refused. Activating a plu… | `sites:write` | DESTRUCTIVE |
| [plugins_list](https://app.pbn.ltd/api/docs/mcp-tools#plugins-list) | Every plugin installed on a WordPress site, whether it is active, its version and whether an update is waiting. | `sites:read` | read |
| [plugins_state](https://app.pbn.ltd/api/docs/mcp-tools#plugins-state) | Activates or deactivates a plugin. Activating can take a site down, so check it with sites.verify afterwards; deactivating is how you put it back. | `sites:write` | DESTRUCTIVE |
| [sites_set_home](https://app.pbn.ltd/api/docs/mcp-tools#sites-set-home) | Makes a page the front page of the site. On WordPress this sets the site's own "front page" setting; on the other site types the file you name is c… | `sites:write` | DESTRUCTIVE |
| [sites_verify](https://app.pbn.ltd/api/docs/mcp-tools#sites-verify) | Fetches a page of the site and says exactly what came back: the HTTP status, how long it took, its size, its title and any redirect. The page is al… | `sites:read` | read |
| [themes_activate](https://app.pbn.ltd/api/docs/mcp-tools#themes-activate) | Switches the site to another theme. This changes how every page looks at once - check the site with sites.verify straight after, and switch back if… | `sites:write` | DESTRUCTIVE |
| [themes_list](https://app.pbn.ltd/api/docs/mcp-tools#themes-list) | Every theme on a WordPress site and which one is in use. | `sites:read` | read |
| [jobs_wait](https://app.pbn.ltd/api/docs/mcp-tools#jobs-wait) | Waits for a job started by another tool (site create, backup, restore, delete, reinstall, DNS publish) and returns it once it has succeeded or fail… | `account:read` | read |


## Account

The account behind the key: profile, plan, site slots, limits and usage.

### `account_limits`

**Plan, slots, limits and frozen sites** · read-only · permission `account:read` · REST equivalent `GET /account/limits`

Site slots (plan + extra-site add-ons), subscription state and paid-until date, the default per-site limits, every paused (frozen) site with the reason(s) it is paused, and the add-ons on the account. Needs the `account:read` permission.

Takes no arguments.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "account_limits",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Account](https://app.pbn.ltd/api/docs/reference/account#account-limits). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `account_me`

**Who am I** · read-only · permission `account:read` · REST equivalent `GET /me`

The account and the key making the call. The cheapest call there is: use it to test a key. Needs the `account:read` permission.

Takes no arguments.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "account_me",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Account](https://app.pbn.ltd/api/docs/reference/account#account-me). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `account_usage_refresh`

**Measure usage of the whole account now** · write · permission `account:write` · REST equivalent `POST /account/limits/refresh`

Starts a fresh disk / database / file-count measurement for the account's sites - the usage tab's "Check now", for many sites at once. It returns at once: each site is reported as started, busy, throttled (the panel's own per-site cooldown and per-account budget apply unchanged) or skipped with the reason. Poll GET /account/limits or GET /sites/{site_id}/usage for the new figures a few seconds later. Needs the `account:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_ids` | array | no | Only these sites (default: every installed site of the account, newest first). |
| `max_sites` | integer | no | How many sites to start a measurement for in this call (1-100). Default: `25`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "account_usage_refresh",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Account](https://app.pbn.ltd/api/docs/reference/account#account-usage_refresh). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `meta_limits`

**API limits for this key** · read-only · permission `kb:read` · REST equivalent `GET /limits`

The rate limits and size limits that apply to the key making the call. `overridden` is true when support has raised or lowered a limit for this key or for the whole account. Needs the `kb:read` permission.

Takes no arguments.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "meta_limits",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Account](https://app.pbn.ltd/api/docs/reference/account#meta-limits). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Billing

Subscription, payment due, invoices and invoice PDFs, add-ons.

### `billing_invoice_pdf`

**Download an invoice PDF** · read-only · permission `billing:read` · REST equivalent `GET /billing/invoices/{number}.pdf`

The PDF of an invoice or credit note of this account (Content-Type application/pdf). Needs the `billing:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `number` | string | yes | Invoice number, e.g. PBN-2026-001234. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "billing_invoice_pdf",
    "arguments": {
      "number": "PBN-2026-001234"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Billing](https://app.pbn.ltd/api/docs/reference/billing#billing-invoice_pdf). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `billing_invoices`

**Payments and invoices** · read-only · permission `billing:read` · REST equivalent `GET /billing/invoices`

Every payment and refund of the account, newest first. `document` is the invoice / credit note when one has been issued; download it with GET /billing/invoices/{number}.pdf. Needs the `billing:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `limit` | integer | no | Items per page (1-200). Default: `50`. |
| `cursor` | string | no | The next_cursor value of the previous page. Omit for the first page. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "billing_invoices",
    "arguments": {
      "limit": 10
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Billing](https://app.pbn.ltd/api/docs/reference/billing#billing-invoices). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `billing_summary`

**Billing overview** · read-only · permission `billing:read` · REST equivalent `GET /billing`

Subscription (state, plan, paid-until date, days left, payment method), unpaid state with the date sites are removed if it stays unpaid, site slots, add-ons, VAT treatment and the panel links. Needs the `billing:read` permission.

Takes no arguments.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "billing_summary",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Billing](https://app.pbn.ltd/api/docs/reference/billing#billing-summary). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Sites

Every site type: list, search, create, change, delete; status, nameservers, CDN, SEO.

### `sites_create`

**Create a site (any type)** · write · permission `sites:write` · REST equivalent `POST /sites`

Creates a site exactly as the Add new site form does - same validation, same slot limit, same checks - for every type: WordPress, Static HTML, PHP hosting, Joomla, Drupal, PrestaShop, OpenCart, Grav and MediaWiki. A WordPress site also needs title, subtitle, login_url and feedback_email; no other type does - GET /sites/options?type=... lists exactly what the type you are creating requires. Installation runs in the background: follow the returned job (GET /jobs/{job_id}) or the site state. Once installed, point the domain at nameservers.required from GET /sites/{site_id}. Needs the `sites:write` permission. Starts a job that finishes later: the answer carries `job.id` - wait for it with `jobs_wait` or poll `jobs_get`.

| Argument | Type | Required | Description |
|---|---|---|---|
| `type` | string (one of: Wordpress, Static HTML, PHP hosting, Joomla, Drupal, PrestaShop, OpenCart, Grav, MediaWiki) | yes | Site type. |
| `name` | string | yes | A unique short name (letters, digits, dashes). |
| `domain` | string | yes | The domain (or subdomain of one of your sites). |
| `cdn` | string | no | CDN (see GET /sites/options for the choices open to you). |
| `php_version` | string | no | PHP version value, e.g. "PHP 8.3" (see GET /sites/options). |
| `use_https` | boolean | no | Serve over HTTPS. |
| `use_www` | boolean | no | Use www. as the primary host. |
| `title` | string | no | Site title (WordPress and the ready-installed applications). REQUIRED when type is Wordpress. |
| `subtitle` | string | no | Tagline. REQUIRED when type is Wordpress; ignored for other types. |
| `admin_email` | string | no | Administrator e-mail (WordPress and the applications). |
| `feedback_email` | string | no | Contact-form e-mail address, where the site's contact form sends its messages. REQUIRED when type is Wordpress; ignored for other types. |
| `login_url` | string | no | WordPress login path (default wp-login.php). REQUIRED when type is Wordpress. |
| `template_id` | integer | no | WordPress template id (omit for random). |
| `blueprint_id` | integer | no | Deploy from one of your blueprints (WordPress). |
| `group_id` | integer | no | Put the site in this group. |
| `create_mailbox` | boolean | no | Create an e-mail account for the domain. |
| `autoupdate_wordpress` | boolean | no | Auto-update WordPress core and plugins. |
| `form_fields` | object | no | Any other Create site form field by its form name (see form_field in GET /sites/options), e.g. the WordPress theme/plugin pickers. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_create",
    "arguments": {
      "type": "Wordpress",
      "name": "myblog",
      "domain": "myblog-example.com",
      "cdn": "Cloudflare",
      "use_https": true,
      "title": "My blog",
      "subtitle": "Notes from the workshop",
      "admin_email": "you@example.com",
      "feedback_email": "you@example.com"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Sites](https://app.pbn.ltd/api/docs/reference/sites#sites-create). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_create_options`

**Fields and choices for a new site** · read-only · permission `sites:write` · REST equivalent `GET /sites/options`

The fields the Create site form accepts for this account right now, with their choices (site types, CDNs, PHP versions, templates, blueprints, groups...) and defaults. Build a create screen from it; every field name here is accepted by POST /sites (unknown ones go in form_fields). `required` is the answer FOR THE TYPE in the response's `type` - a WordPress site also needs title, subtitle, login_url and feedback_email, no other type does. `required_for_types` on each field and the `required_by_type` map give the whole picture in one call. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `type` | string (one of: Wordpress, Static HTML, PHP hosting, Joomla, Drupal, PrestaShop, OpenCart, Grav, MediaWiki) | no | Describe the form for this site type. Which fields are REQUIRED depends on the type, so name the type you are going to create. Default: the form's own default type. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_create_options",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Sites](https://app.pbn.ltd/api/docs/reference/sites#sites-create_options). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_delete`

**Delete a site** · **destructive** · permission `sites:delete` · REST equivalent `DELETE /sites/{site_id}`

Deletes the site for good (files, database, DNS zone, CDN), exactly like Delete site in the panel. Refused while the site is busy or paused for non-payment/malware, while it has subdomain sites, or while a blueprint is being made from it. Runs in the background: a job is returned. Needs the `sites:delete` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_delete",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Sites](https://app.pbn.ltd/api/docs/reference/sites#sites-delete). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_edit_options`

**Fields and choices to edit a site** · read-only · permission `sites:write` · REST equivalent `GET /sites/{site_id}/options`

The fields the Edit site form offers for THIS site right now (they depend on type, CDN and state), with choices and current values. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_edit_options",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Sites](https://app.pbn.ltd/api/docs/reference/sites#sites-edit_options). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_get`

**Get one site** · read-only · permission `sites:read` · REST equivalent `GET /sites/{site_id}`

Everything the site page shows: state, URL, settings, why it is paused (freeze.reasons), nameserver status (current vs required, pointed, autopilot), CDN, SEO, indexation, platform, online status and what can be done with it right now (capabilities). Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_get",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Sites](https://app.pbn.ltd/api/docs/reference/sites#sites-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_list`

**List and search sites** · read-only · permission `sites:read` · REST equivalent `GET /sites`

The same search, filters and order as the sites list in the panel. `total` is the number of matching sites. A key restricted to some sites only sees those. Needs the `sites:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `search` | string | no | Part of the domain or name (www. is ignored). |
| `state` | string (one of: ok, waiting, activating, working, error, frozen, notinstalled) | no | ok = live, waiting = waiting for DNS, activating = activating CDN, working = being installed/changed, error, frozen = paused, notinstalled. |
| `type` | string (one of: Wordpress, Static HTML, PHP hosting, Joomla, Drupal, PrestaShop, OpenCart, Grav, MediaWiki, mismatch) | no | Site type; "mismatch" = the files run a different platform than the site type. |
| `group` | string | no | Group id, or "none" for sites in no group. |
| `cdn` | string | no | CDN name, e.g. Cloudflare, BunnyCDN, KeyCDN, CDN77.COM, Gcore, CloudFront. |
| `php_version` | string | no | PHP version value, e.g. "PHP 8.3". |
| `indexed` | string (one of: yes, no, pending) | no | Google indexation state. |
| `online` | string (one of: online, offline) | no | The online badge: offline = a confirmed problem. |
| `sort` | string (one of: newest, oldest, name, name_desc, domain, domain_desc) | no | Order of the list. Default: `newest`. |
| `limit` | integer | no | Items per page (1-200). Default: `50`. |
| `cursor` | string | no | The next_cursor value of the previous page. Omit for the first page. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_list",
    "arguments": {
      "search": "blog",
      "state": "ok",
      "limit": 20
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Sites](https://app.pbn.ltd/api/docs/reference/sites#sites-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_update`

**Change site settings** · write · permission `sites:write` · REST equivalent `PATCH /sites/{site_id}`

Change any setting the Edit site form offers: name, domain, PHP version, HTTPS, www, group, admin e-mail, login URL, auto-updates, mailbox. Send only what changes. Changes that touch the server (domain, PHP, HTTPS/www) run in the background: a job is returned then. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `name` | string | no | A unique short name (letters, digits, dashes). |
| `domain` | string | no | The domain (or subdomain of one of your sites). |
| `php_version` | string | no | PHP version value, e.g. "PHP 8.3" (see GET /sites/options). |
| `use_https` | boolean | no | Serve over HTTPS. |
| `use_www` | boolean | no | Use www. as the primary host. |
| `admin_email` | string | no | Administrator e-mail (WordPress and the applications). |
| `login_url` | string | no | WordPress login path (default wp-login.php). REQUIRED when type is Wordpress. |
| `group_id` | integer | no | Put the site in this group. |
| `create_mailbox` | boolean | no | Create an e-mail account for the domain. |
| `autoupdate_wordpress` | boolean | no | Auto-update WordPress core and plugins. |
| `form_fields` | object | no | Any other Create site form field by its form name (see form_field in GET /sites/options), e.g. the WordPress theme/plugin pickers. |
| `ssl_mode` | string (one of: full, flexible) | no | Cloudflare SSL mode (only offered when the site has its own address records). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_update",
    "arguments": {
      "site_id": 123,
      "php_version": "PHP 8.3",
      "use_www": true
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Sites](https://app.pbn.ltd/api/docs/reference/sites#sites-update). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Site tools

Cache purge, one-click admin login, reinstall, health checks, Site Cleaner, usage.

### `cleaner_get`

**Site Cleaner status** · read-only · permission `sites:read` · REST equivalent `GET /sites/{site_id}/cleaner`

Site Cleaner for this site: whether the add-on is active, the last scan (what can be removed and how much it saves), the running job, recent jobs (with undo_available) and the schedule. Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "cleaner_get",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#cleaner-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `cleaner_run`

**Scan, clean or undo** · write · permission `sites:write` · REST equivalent `POST /sites/{site_id}/cleaner/{action}`

Runs Site Cleaner. `scan` lists unused plugins/themes, junk files and database clutter (free). `clean` removes the selected items after taking a backup and checks the site afterwards - it needs the Site Cleaner add-on (402 addon_required otherwise). `undo` puts a clean back from its backup. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `action` | string (one of: scan, clean, undo) | yes | scan (free) / clean (needs the Site Cleaner add-on) / undo a clean. |
| `items` | array | no | clean: ids from last_scan.items to remove (omit = the default selection). |
| `job_id` | integer | no | undo: the id of the clean job to undo. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "cleaner_run",
    "arguments": {
      "site_id": 123,
      "action": "scan"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#cleaner-run). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `cleaner_schedule`

**Automatic cleaning** · write · permission `sites:write` · REST equivalent `PUT /sites/{site_id}/cleaner/schedule`

Sets automatic cleaning for the site (needs the add-on to actually clean). Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `schedule` | string (one of: off, daily, weekly, monthly) | yes | How often Site Cleaner runs by itself. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "cleaner_schedule",
    "arguments": {
      "site_id": 123,
      "schedule": "weekly"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#cleaner-schedule). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `health_get`

**Health status** · read-only · permission `sites:read` · REST equivalent `GET /sites/{site_id}/health`

The online badge (online / offline / slow / paused... with the reason) and, for application sites, the last integrity check (V1 config lines, admin account, login health, core files). Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "health_get",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#health-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `health_integrity_check`

**Integrity check now** · write · permission `sites:write` · REST equivalent `POST /sites/{site_id}/health/integrity-check`

Checks the application now (WordPress, Joomla, Drupal, PrestaShop, OpenCart, Grav, MediaWiki): V1's config lines, the site URL, the admin account, one-click login health and core file checksums. Changes nothing. Takes a few seconds. Needs the `sites:write` permission. This can take up to a minute.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "health_integrity_check",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#health-integrity_check). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `health_recheck`

**Re-check if the site is up** · write · permission `sites:write` · REST equivalent `POST /sites/{site_id}/health/recheck`

Probes the home page again now (same probe and recording as the platform's monitor) and asks the server why if it fails. Asynchronous: follow the job; its result has the outcome. At most 10 an hour. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "health_recheck",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#health-recheck). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `health_repair`

**Repair the site** · write · permission `sites:write` · REST equivalent `POST /sites/{site_id}/health/repair`

"Repair site": checks, repairs everything repairable (backups first, on the server), checks again. You get an e-mail listing what was repaired. Needs the `sites:write` permission. This can take up to a minute.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "health_repair",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#health-repair). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_admin_login`

**One-click admin login link** · write · permission `sites:login` · REST equivalent `POST /sites/{site_id}/admin-login`

A single-use login link to the site's admin (WordPress wp-admin, Joomla, Drupal, PrestaShop, OpenCart, Grav, MediaWiki), valid for 60 seconds - the panel's one-click login. Open it in a browser; do not store it. Not for Static HTML / PHP hosting sites. Needs the `sites:login` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_admin_login",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#sites-admin_login). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_php_version`

**Change the PHP version** · write · permission `sites:write` · REST equivalent `PUT /sites/{site_id}/php-version`

Shortcut for PATCH /sites/{site_id} with php_version. The web server is reconfigured in the background (a job is returned). Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `php_version` | string | yes | e.g. "PHP 8.3" (see GET /sites/{site_id}/options) |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_php_version",
    "arguments": {
      "site_id": 123,
      "php_version": "PHP 8.3"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#sites-php_version). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_purge_cache`

**Purge the CDN cache** · write · permission `sites:write` · REST equivalent `POST /sites/{site_id}/purge-cache`

Clears the CDN cache of both hostnames (as Purge CDN cache in the panel). The site must be live. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_purge_cache",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#sites-purge_cache). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_reinstall`

**Reinstall from scratch** · **destructive** · permission `sites:write` · REST equivalent `POST /sites/{site_id}/reinstall`

Installs the site again from scratch (as Reinstall in the panel) - the current files and database are replaced. Refused while the site is busy, switched off or being deleted. Needs the `sites:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `confirm` | boolean | yes | Must be true: this action overwrites the site. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_reinstall",
    "arguments": {
      "site_id": 123,
      "confirm": true
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#sites-reinstall). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_temp_unfreeze`

**Switch a paused site on for cleanup** · write · permission `sites:write` · REST equivalent `POST /sites/{site_id}/temporary-unfreeze`

A site paused ONLY for a usage limit (disk / database / files) comes back for 30 minutes so you can clean it up (3 times per site per day). At the end it is paused again only if still over the limit. freeze.temporary_unfreeze in GET /sites/{site_id} says if it is available and why not. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_temp_unfreeze",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#sites-temp_unfreeze). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_usage`

**Disk, database and file usage** · read-only · permission `sites:read` · REST equivalent `GET /sites/{site_id}/usage`

The Usage & add-ons tab: disk, database and file-count use against the limits (plan + add-ons), what is over, CDN bandwidth for metered CDNs, and the add-ons on the site. Numbers are measured every few hours; POST /sites/{site_id}/usage/refresh measures now. Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_usage",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#sites-usage). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_usage_refresh`

**Measure usage now** · write · permission `sites:write` · REST equivalent `POST /sites/{site_id}/usage/refresh`

Starts a fresh measurement of disk, database and files (the usage tab's "Check now"). Returns the current figures with busy=true; poll GET /sites/{site_id}/usage until busy is false (seconds). Same throttles as the panel: one measurement per site every few minutes. Needs the `sites:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_usage_refresh",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Site tools](https://app.pbn.ltd/api/docs/reference/site-tools#sites-usage_refresh). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## DNS records

The site's own DNS records (A, AAAA, CNAME, TXT, MX, SRV, CAA, NS).

### `dns_create`

**Add a DNS record** · write · permission `dns:write` · REST equivalent `POST /sites/{site_id}/dns`

Adds a record with the panel's own validation. It is published to the site's DNS provider within a minute or two (follow the job); your records are never overwritten by the platform. Needs the `dns:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `type` | string (one of: A, AAAA, CNAME, TXT, MX, SRV, CAA, NS) | yes | Record type. |
| `name` | string | yes | "@" for the domain itself, or a name like blog, shop.eu, _dmarc, _sip._tcp. |
| `value` | string | yes | IPv4 (A), IPv6 (AAAA), host name (CNAME, MX, SRV target, NS), text (TXT) or CA domain (CAA). |
| `priority` | integer | no | MX and SRV. |
| `weight` | integer | no | SRV. |
| `port` | integer | no | SRV. |
| `caa_flags` | integer (one of: 0, 128) | no | CAA: 0 or 128 (critical). |
| `caa_tag` | string (one of: issue, issuewild, iodef) | no | CAA tag. |
| `proxied` | boolean | no | Cloudflare only, A/AAAA/CNAME: proxy through the CDN (off = DNS only). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "dns_create",
    "arguments": {
      "site_id": 123,
      "type": "TXT",
      "name": "@",
      "value": "google-site-verification=abc123"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [DNS records](https://app.pbn.ltd/api/docs/reference/dns#dns-create). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `dns_delete`

**Delete a DNS record** · write · permission `dns:write` · REST equivalent `DELETE /sites/{site_id}/dns/{record_id}`

Deletes a record; it is removed at the DNS provider within a minute or two. Needs the `dns:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `record_id` | integer | yes | The DNS record id. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "dns_delete",
    "arguments": {
      "site_id": 123,
      "record_id": 5501
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [DNS records](https://app.pbn.ltd/api/docs/reference/dns#dns-delete). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `dns_list`

**List DNS records** · read-only · permission `dns:read` · REST equivalent `GET /sites/{site_id}/dns`

The site's own DNS records (the DNS records tab), and the publishing state: the DNS provider, when the records were last published and any record the provider refused (with its error). Records the platform manages for the CDN are not listed and are never changed through this API. Needs the `dns:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "dns_list",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [DNS records](https://app.pbn.ltd/api/docs/reference/dns#dns-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `dns_update`

**Change a DNS record** · write · permission `dns:write` · REST equivalent `PATCH /sites/{site_id}/dns/{record_id}`

Changes a record; send only the fields that change. Needs the `dns:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `record_id` | integer | yes | The DNS record id. |
| `type` | string (one of: A, AAAA, CNAME, TXT, MX, SRV, CAA, NS) | no | Record type. |
| `name` | string | no | "@" for the domain itself, or a name like blog, shop.eu, _dmarc, _sip._tcp. |
| `value` | string | no | IPv4 (A), IPv6 (AAAA), host name (CNAME, MX, SRV target, NS), text (TXT) or CA domain (CAA). |
| `priority` | integer | no | MX and SRV. |
| `weight` | integer | no | SRV. |
| `port` | integer | no | SRV. |
| `caa_flags` | integer (one of: 0, 128) | no | CAA: 0 or 128 (critical). |
| `caa_tag` | string (one of: issue, issuewild, iodef) | no | CAA tag. |
| `proxied` | boolean | no | Cloudflare only, A/AAAA/CNAME: proxy through the CDN (off = DNS only). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "dns_update",
    "arguments": {
      "site_id": 123,
      "record_id": 5501,
      "value": "google-site-verification=xyz789"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [DNS records](https://app.pbn.ltd/api/docs/reference/dns#dns-update). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_nameservers`

**Nameserver status** · read-only · permission `dns:read` · REST equivalent `GET /sites/{site_id}/nameservers`

The nameservers the domain must use (required), what it uses now (current, checked daily), whether it is pointed, whether the DNS zone expired at the provider (zone_expired: re-create it from the site page), and the registrar autopilot status when a registrar connection sets them for you. Needs the `dns:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_nameservers",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [DNS records](https://app.pbn.ltd/api/docs/reference/dns#sites-nameservers). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Backups

List, create, download and restore backups.

### `backups_create`

**Create a backup now** · write · permission `backups:write` · REST equivalent `POST /sites/{site_id}/backups`

Takes a full backup (files + database) now, as Create backup in the panel. Follow the job until the backup is Ok. Needs the `backups:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "backups_create",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Backups](https://app.pbn.ltd/api/docs/reference/backups#backups-create). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `backups_delete`

**Delete a backup** · **destructive** · permission `backups:write` · REST equivalent `DELETE /sites/{site_id}/backups/{backup_id}`

Deletes a backup. A backup that a blueprint uses cannot be deleted. Needs the `backups:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `backup_id` | integer | yes | The backup id. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "backups_delete",
    "arguments": {
      "site_id": 123,
      "backup_id": 88001
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Backups](https://app.pbn.ltd/api/docs/reference/backups#backups-delete). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `backups_download`

**Download link** · read-only · permission `backups:read` · REST equivalent `POST /sites/{site_id}/backups/{backup_id}/download-link`

A temporary link to download the backup archive (tar.gz) - valid about 4 hours. Needs the `backups:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `backup_id` | integer | yes | The backup id. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "backups_download",
    "arguments": {
      "site_id": 123,
      "backup_id": 88001
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Backups](https://app.pbn.ltd/api/docs/reference/backups#backups-download). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `backups_get`

**Get one backup** · read-only · permission `backups:read` · REST equivalent `GET /sites/{site_id}/backups/{backup_id}`

One backup of the site. Needs the `backups:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `backup_id` | integer | yes | The backup id. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "backups_get",
    "arguments": {
      "site_id": 123,
      "backup_id": 88001
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Backups](https://app.pbn.ltd/api/docs/reference/backups#backups-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `backups_list`

**List backups** · read-only · permission `backups:read` · REST equivalent `GET /sites/{site_id}/backups`

The site's backups, newest first (automatic daily ones, manual ones and uploaded ones). Needs the `backups:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `state` | string (one of: Pending, Creating, Ok, Error, Storing) | no | Only backups in this state. |
| `limit` | integer | no | Items per page (1-200). Default: `50`. |
| `cursor` | string | no | The next_cursor value of the previous page. Omit for the first page. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "backups_list",
    "arguments": {
      "site_id": 123,
      "limit": 10
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Backups](https://app.pbn.ltd/api/docs/reference/backups#backups-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `backups_restore`

**Restore a backup** · **destructive** · permission `backups:write` · REST equivalent `POST /sites/{site_id}/backups/{backup_id}/restore`

Replaces the site's files and database with the backup (as Restore in the panel). Refused while the site is busy, switched off or the plan has expired. Follow the job. Needs the `backups:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `backup_id` | integer | yes | The backup id. |
| `confirm` | boolean | yes | Must be true: this action overwrites the site. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "backups_restore",
    "arguments": {
      "site_id": 123,
      "backup_id": 88001,
      "confirm": true
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Backups](https://app.pbn.ltd/api/docs/reference/backups#backups-restore). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Files

Browse, read, upload, rename and delete the files of a site.

### `files_delete`

**Delete a file or folder** · **destructive** · permission `files:write` · REST equivalent `DELETE /sites/{site_id}/files`

Deletes a file, or a folder (with recursive=true when it is not empty). There is no undo - take a backup first for anything important. Needs the `files:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | yes | Path relative to the site folder, e.g. "wp-content/uploads" ("" or "/" = the site folder). |
| `recursive` | boolean | no | Required to delete a folder that is not empty. Default: `False`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_delete",
    "arguments": {
      "site_id": 123,
      "path": "hello.txt"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Files](https://app.pbn.ltd/api/docs/reference/files#files-delete). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `files_list`

**List a folder** · read-only · permission `files:read` · REST equivalent `GET /sites/{site_id}/files`

Folders first, then files; up to 5,000 entries. Symbolic links are listed (type "link") but never followed. Available under the same rule as the File Manager: the site is installed, the plan is active and the site is not suspended. Needs the `files:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | no | Folder path relative to the site folder (default: the site folder itself). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_list",
    "arguments": {
      "site_id": 123,
      "path": "wp-content"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Files](https://app.pbn.ltd/api/docs/reference/files#files-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `files_mkdir`

**Create a folder** · write · permission `files:write` · REST equivalent `POST /sites/{site_id}/files/folders`

Creates a folder (and any missing parent folders). Needs the `files:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | yes | The new folder path. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_mkdir",
    "arguments": {
      "site_id": 123,
      "path": "wp-content/uploads/reports"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Files](https://app.pbn.ltd/api/docs/reference/files#files-mkdir). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `files_move`

**Rename or move** · write · permission `files:write` · REST equivalent `POST /sites/{site_id}/files/move`

Renames or moves a file or folder inside the site folder. Needs the `files:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | yes | What to move. |
| `to` | string | yes | The new path. |
| `overwrite` | boolean | no | Replace an existing file at the destination. Default: `False`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_move",
    "arguments": {
      "site_id": 123,
      "path": "hello.txt",
      "to": "old/hello.txt"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Files](https://app.pbn.ltd/api/docs/reference/files#files-move). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `files_read`

**Read (download) a file** · read-only · permission `files:read` · REST equivalent `GET /sites/{site_id}/files/content`

Returns a file of up to 5 MB (the limit is in GET /limits). Use encoding=raw to stream the bytes directly. Needs the `files:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | yes | Path relative to the site folder, e.g. "wp-content/uploads" ("" or "/" = the site folder). |
| `encoding` | string (one of: base64, text, raw) | no | base64 (JSON, any file), text (JSON, UTF-8 files) or raw (the bytes themselves, with a Content-Type). Default: `base64`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_read",
    "arguments": {
      "site_id": 123,
      "path": "robots.txt",
      "encoding": "text"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Files](https://app.pbn.ltd/api/docs/reference/files#files-read). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `files_stat`

**File or folder details** · read-only · permission `files:read` · REST equivalent `GET /sites/{site_id}/files/stat`

Type, size, modification time and mode of one path. Needs the `files:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | yes | Path relative to the site folder, e.g. "wp-content/uploads" ("" or "/" = the site folder). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_stat",
    "arguments": {
      "site_id": 123,
      "path": "index.php"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Files](https://app.pbn.ltd/api/docs/reference/files#files-stat). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `files_write`

**Upload (write) a file** · write · permission `files:write` · REST equivalent `PUT /sites/{site_id}/files/content`

Writes a file of up to 25 MB atomically (a temporary file renamed into place), owned by the site's web server user. Refuses to write through symbolic links and into folders the platform manages. Needs the `files:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | yes | Where to write it, relative to the site folder. |
| `content` | string | no | Text content (UTF-8). Or use content_base64. |
| `content_base64` | string | no | The file, base64-encoded. Or send the raw bytes as the request body (Content-Type application/octet-stream) or a multipart form with a "file" field. |
| `overwrite` | boolean | no | Replace an existing file. Default: `False`. |
| `mkdirs` | boolean | no | Create missing folders. Default: `True`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_write",
    "arguments": {
      "site_id": 123,
      "path": "hello.txt",
      "overwrite": "true",
      "content": "Hello world\n"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Files](https://app.pbn.ltd/api/docs/reference/files#files-write). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Logs

Error log and access log of a site.

### `logs_access`

**Access log** · read-only · permission `logs:read` · REST equivalent `GET /sites/{site_id}/logs/access`

Requests that reached the web server for this site's hostnames, newest last. The client IP is the visitor as the CDN reported it. 30 fetches per 10 minutes per account. Needs the `logs:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `hours` | integer | no | How far back to look. Default: `1`. |
| `lines` | integer | no | At most this many (the newest) lines. Default: `200`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "logs_access",
    "arguments": {
      "site_id": 123,
      "hours": 1,
      "lines": 100
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Logs](https://app.pbn.ltd/api/docs/reference/logs#logs-access). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `logs_errors`

**Error log** · read-only · permission `logs:read` · REST equivalent `GET /sites/{site_id}/logs/errors`

Recent PHP and web server errors of THIS site (the Error log tab): last 7 days, grouped, sanitised (paths shown relative to the site folder, secrets hidden). php_hint=true when the errors look like code written for an older PHP version. Cached 60 s; 20 fetches per 10 minutes per account. Needs the `logs:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "logs_errors",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Logs](https://app.pbn.ltd/api/docs/reference/logs#logs-errors). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Support tickets

Open support tickets and reply to them.

### `tickets_create`

**Open a ticket** · write · permission `tickets:write` · REST equivalent `POST /tickets`

Opens a ticket (support is e-mailed as for a panel ticket). The ticket limits apply: at most 2 open tickets at a time (409 ticket_limit). Needs the `tickets:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | Short summary. |
| `message` | string | yes | What happened, what you expected. |
| `queue` | string | no | Category slug (GET /tickets/queues). Default: `general-support-request`. |
| `priority` | string (one of: low, normal, high) | no | Priority. Default: `normal`. |
| `site_id` | integer | no | The site it is about (its domain is added to the ticket). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "tickets_create",
    "arguments": {
      "title": "Question about my site",
      "message": "How do I add a subdomain?",
      "queue": "general-support-request",
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Support tickets](https://app.pbn.ltd/api/docs/reference/tickets#tickets-create). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `tickets_get`

**Read a ticket** · read-only · permission `tickets:read` · REST equivalent `GET /tickets/{ticket_id}`

A ticket with every public message (yours and support's). can_reply says if you may add a message now (ticket limits: one message before support answers). Needs the `tickets:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `ticket_id` | integer | yes | The ticket id. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "tickets_get",
    "arguments": {
      "ticket_id": 4412
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Support tickets](https://app.pbn.ltd/api/docs/reference/tickets#tickets-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `tickets_list`

**List tickets** · read-only · permission `tickets:read` · REST equivalent `GET /tickets`

Your tickets, newest first. Needs the `tickets:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `status` | string (one of: open, closed) | no | Only open or only closed tickets. |
| `limit` | integer | no | Items per page (1-200). Default: `50`. |
| `cursor` | string | no | The next_cursor value of the previous page. Omit for the first page. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "tickets_list",
    "arguments": {
      "status": "open"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Support tickets](https://app.pbn.ltd/api/docs/reference/tickets#tickets-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `tickets_queues`

**Ticket categories** · read-only · permission `tickets:read` · REST equivalent `GET /tickets/queues`

The categories (queues) a ticket can be opened in. Needs the `tickets:read` permission.

Takes no arguments.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "tickets_queues",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Support tickets](https://app.pbn.ltd/api/docs/reference/tickets#tickets-queues). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `tickets_reply`

**Reply to a ticket** · write · permission `tickets:write` · REST equivalent `POST /tickets/{ticket_id}/messages`

Adds your message to the ticket (support is notified). One message until support answers. Needs the `tickets:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `ticket_id` | integer | yes | The ticket id. |
| `message` | string | yes | Your message. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "tickets_reply",
    "arguments": {
      "ticket_id": 4412,
      "message": "Thanks, that worked."
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Support tickets](https://app.pbn.ltd/api/docs/reference/tickets#tickets-reply). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Knowledge base

Search the knowledge base.

### `kb_article`

**Read an article** · read-only · permission `kb:read` · REST equivalent `GET /kb/articles/{slug}`

One article as plain text and as sanitised HTML, with related articles. Needs the `kb:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `slug` | string | yes | Article slug from a search result. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "kb_article",
    "arguments": {
      "slug": "change-nameservers"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Knowledge base](https://app.pbn.ltd/api/docs/reference/kb#kb-article). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `kb_search`

**Search the knowledge base** · read-only · permission `kb:read` · REST equivalent `GET /kb/search`

The dashboard's knowledge-base search (keyword + meaning). Every key may use it. Needs the `kb:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `q` | string | yes | What you are looking for, in plain words. |
| `limit` | integer | no | At most this many. Default: `8`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "kb_search",
    "arguments": {
      "q": "change nameservers"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Knowledge base](https://app.pbn.ltd/api/docs/reference/kb#kb-search). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_kb_suggestions`

**Help articles for this site** · read-only · permission `sites:read` · REST equivalent `GET /sites/{site_id}/help`

Knowledge-base articles that fit what is going on with this site right now (why it is paused, nameservers not pointed, offline...), with app and public links. Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_kb_suggestions",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Knowledge base](https://app.pbn.ltd/api/docs/reference/kb#sites-kb_suggestions). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Jobs

Progress of the long-running actions the API started.

### `jobs_get`

**Job status** · read-only · permission `account:read` · REST equivalent `GET /jobs/{job_id}`

The live status of a job: running, succeeded or failed, with a message. Poll every few seconds (it counts against the rate limit like any call). Needs the `account:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | The id returned as job.id. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "jobs_get",
    "arguments": {
      "job_id": "job_4f1c0a9e2b7d6c5a3e10"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Jobs](https://app.pbn.ltd/api/docs/reference/jobs#jobs-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `jobs_list`

**List jobs** · read-only · permission `account:read` · REST equivalent `GET /jobs`

Jobs the API started for this account, newest first. Needs the `account:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `status` | string (one of: running, succeeded, failed) | no | Only jobs in this state. |
| `site_id` | integer | no | Only jobs of this site. |
| `limit` | integer | no | Items per page (1-200). Default: `50`. |
| `cursor` | string | no | The next_cursor value of the previous page. Omit for the first page. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "jobs_list",
    "arguments": {
      "status": "running"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Jobs](https://app.pbn.ltd/api/docs/reference/jobs#jobs-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `jobs_wait`

**Wait for a job to finish** · read-only · permission `account:read` · REST equivalent `GET /jobs/{job_id}, polled until it finishes`

Waits for a job started by another tool (site create, backup, restore, delete, reinstall, DNS publish) and returns it once it has succeeded or failed, or when the wait runs out. Use this instead of calling jobs_get in a loop. Needs the `account:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | The job id returned by the tool that started it (job_...). |
| `timeout_seconds` | integer | no | How long to wait before giving up and returning the job as it is. Default: `120`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "jobs_wait",
    "arguments": {
      "job_id": "job_4f1c0a9e2b7d6c5a3e10",
      "timeout_seconds": 120
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Jobs](https://app.pbn.ltd/api/docs/jobs). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Content and publishing

Posts, pages, pictures and the AI auto-posting campaigns, on every site type.

### `campaigns_get`

**Read one campaign** · read-only · permission `content:read` · REST equivalent `GET /campaigns/{campaign_id}`

One campaign with its last ten runs. Needs the `content:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | integer | yes | The campaign. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "campaigns_get",
    "arguments": {
      "campaign_id": 44
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#campaigns-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `campaigns_list`

**List auto-posting campaigns** · read-only · permission `content:read` · REST equivalent `GET /campaigns`

The AI auto-posting campaigns on the account: what they write, when they run next and how many articles they have made. Needs the `content:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `limit` | integer | no | How many to return. Default: `20`. |
| `cursor` | string | no | The next_cursor value of the previous page. |
| `status` | string (one of: active, paused, problem, finished) | no |  |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "campaigns_list",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#campaigns-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `campaigns_status`

**Pause or resume** · write · permission `content:write` · REST equivalent `PUT /campaigns/{campaign_id}/status`

Pauses a campaign or starts it again. A campaign paused by our staff or by a problem with an AI key cannot be resumed from here - fix the cause first. Needs the `content:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | integer | yes |  |
| `status` | string (one of: active, paused) | yes | "paused" stops it writing; "active" starts it again. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "campaigns_status",
    "arguments": {
      "campaign_id": 44,
      "status": "paused"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#campaigns-status). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `campaigns_write_now`

**Write one now** · write · permission `content:write` · REST equivalent `POST /campaigns/{campaign_id}/write-now`

Asks a campaign to write and publish now, the same as the "Write now" button. Returns the run; follow it with runs.get. Needs the `content:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | integer | yes |  |
| `site_ids` | array | no | Only these sites of the campaign (default: all of them). |
| `count` | integer | no | Articles per site. Default: `1`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "campaigns_write_now",
    "arguments": {
      "campaign_id": 44,
      "count": 1
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#campaigns-write_now). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_create`

**Publish a post or page** · write · permission `content:write` · REST equivalent `POST /sites/{site_id}/content`

Writes the post and puts it on the site. Works for every site type: WordPress, Joomla, Drupal, PrestaShop, OpenCart, Grav and MediaWiki get a native post/article/page, and Static HTML and PHP hosting sites get a page built in the look of their own pages, with a blog index and sitemap.xml kept up to date. The answer carries a job - wait for it and then read the post to get its address. Needs the `content:write` permission. Starts a job that finishes later: the answer carries `job.id` - wait for it with `jobs_wait` or poll `jobs_get`.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `title` | string | yes | The title of the post. |
| `body_html` | string | no | The text as HTML. Or send body_markdown. |
| `body_markdown` | string | no | The text as Markdown (headings, lists, links, bold, code, quotes). |
| `status` | string (one of: publish, draft) | no | "draft" only on site types that have drafts (see content.options). Default: `publish`. |
| `category` | string | no | Category id or name, on site types that have them. |
| `author` | string | no | Author id, on site types that have authors. |
| `tags` | array | no | Tags for the post. |
| `slug` | string | no | The address of the post; one is made from the title when you leave it out. |
| `publish_at` | string | no | ISO date and time to publish it (default: now). |
| `featured_image_base64` | string | no | The main picture, base64. It leads the post and becomes the featured image on site types that have one. |
| `images_base64` | array | no | More pictures, base64; they are placed in the text. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_create",
    "arguments": {
      "site_id": 123,
      "title": "Five ways to speed up your shop",
      "body_markdown": "## Why speed matters\n\nA faster shop sells more.",
      "status": "publish",
      "tags": [
        "speed",
        "shop"
      ]
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-create). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_get`

**Read one post** · read-only · permission `content:read` · REST equivalent `GET /sites/{site_id}/content/{post_id}`

One post in full, with its text and the history of what happened to it. Needs the `content:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `post_id` | integer | yes | The post id this API gave you when it was created. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_get",
    "arguments": {
      "site_id": 123,
      "post_id": 90210
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_list`

**Posts on this site** · read-only · permission `content:read` · REST equivalent `GET /sites/{site_id}/content`

The latest posts the site itself reports, and every post this account has written for it through PBN.LTD (including ones still being written or waiting to go out). Needs the `content:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `limit` | integer | no | How many to return. Default: `20`. |
| `state` | string (one of: queued, writing, images, review, ready, publishing, done, failed, cancelled) | no | Only posts in this state. |
| `on_site` | boolean | no | Also ask the site itself for its latest posts (slower). Default: `True`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_list",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_media`

**Upload a picture or file** · write · permission `content:write` · REST equivalent `POST /sites/{site_id}/content/media`

Puts a picture or file on the site and gives back the address to use in a post. On WordPress it goes into the media library; on every other site type it goes into the site's own files. Needs the `content:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `name` | string | yes | The file name, e.g. "hero.jpg". |
| `content_base64` | string | yes | The file itself, base64. |
| `alt` | string | no | Alt text (WordPress media library). |
| `folder` | string | no | Where to put it on site types with no media library. Default: `assets`. |
| `overwrite` | boolean | no | Replace a file of the same name. Default: `False`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_media",
    "arguments": {
      "site_id": 123,
      "name": "hero.jpg",
      "content_base64": "iVBORw0KGgo=",
      "alt": "The shop front"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-media). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_options`

**What a post on this site can have** · read-only · permission `content:read` · REST equivalent `GET /sites/{site_id}/content/options`

Before writing anything, ask this: it says how a post appears on this site type, which fields it supports (featured picture, categories, tags, author, drafts) and the real categories and authors the site has. Site types with no drafts publish straight away - the answer says so. Needs the `content:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_options",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-options). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_queue`

**Everything being written or published** · read-only · permission `content:read` · REST equivalent `GET /content/queue`

Every post on the account that is queued, being written, waiting for approval, scheduled, publishing, published, failed or cancelled - newest first, across all sites. Needs the `content:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `limit` | integer | no | How many to return. Default: `20`. |
| `cursor` | string | no | The next_cursor value of the previous page. |
| `state` | string (one of: queued, writing, images, review, ready, publishing, done, failed, cancelled) | no | Only posts in this state. |
| `site_id` | integer | no | Only this site. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_queue",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-queue). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_remove`

**Take a post off the site** · **destructive** · permission `content:write` · REST equivalent `DELETE /sites/{site_id}/content/{post_id}`

Removes a published post from the site, or cancels one that has not gone out yet. There is no undo. Needs the `content:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `post_id` | integer | yes | The post id this API gave you when it was created. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_remove",
    "arguments": {
      "site_id": 123,
      "post_id": 90210
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-remove). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `content_update`

**Change a post** · write · permission `content:write` · REST equivalent `PATCH /sites/{site_id}/content/{post_id}`

Changes a post that has not gone out yet. A post that is already on the site cannot be edited from here - remove it and write a new one. Needs the `content:write` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `post_id` | integer | yes | The post id this API gave you when it was created. |
| `title` | string | no | A new title. |
| `body_html` | string | no | New text as HTML. |
| `body_markdown` | string | no | New text as Markdown. |
| `tags` | array | no | Replace the tags. |
| `status` | string (one of: publish, draft) | no |  |
| `publish_at` | string | no | Move when it goes out. |
| `approve` | boolean | no | Approve a post that is waiting for approval. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "content_update",
    "arguments": {
      "site_id": 123,
      "post_id": 90210,
      "title": "Five ways to speed up your shop (updated)"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#content-update). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `runs_get`

**How a run is going** · read-only · permission `content:read` · REST equivalent `GET /runs/{run_id}`

One run of a campaign and every article in it. Needs the `content:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `run_id` | integer | yes | The run. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "runs_get",
    "arguments": {
      "run_id": 7782
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Content and publishing](https://app.pbn.ltd/api/docs/reference/content#runs-get). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.


## Building, plugins and themes

Upload a built site, set the home page, install and test plugins and themes, and the sites you publish to other hosts.

### `code_check`

**Check PHP code for errors** · read-only · permission `sites:read` · REST equivalent `POST /sites/{site_id}/code-check`

Runs PHP's own syntax check over a file or every .php file in a folder, in the exact PHP version the site runs. Do this before switching a plugin or theme on - a syntax error there takes the whole site down. Needs the `sites:read` permission. This can take up to a minute.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | yes | A file or folder in the site, e.g. "wp-content/plugins/my-plugin". |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "code_check",
    "arguments": {
      "site_id": 123,
      "path": "wp-content/plugins/my-plugin"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#code-check). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `extsites_deploy`

**Deploy again or roll back** · **destructive** · permission `sites:write` · REST equivalent `POST /external-sites/{ext_site_id}/deploy`

Publishes the site to its provider again, or rolls it back to a deploy that is already there. This replaces what is live at that provider. No files travel through this call - to publish new files, put them on the PBN.LTD site first (files.write or files.upload_archive) and then redeploy. Needs the `sites:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `ext_site_id` | integer | yes |  |
| `kind` | string (one of: redeploy, rollback) | no | Build and publish again, or go back to an earlier deploy. Default: `redeploy`. |
| `rollback_to` | string | no | The deploy to go back to (see extsites.history). Needed for a rollback. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "extsites_deploy",
    "arguments": {
      "ext_site_id": 9,
      "kind": "redeploy"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#extsites-deploy). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `extsites_history`

**Deploys of an external site** · read-only · permission `sites:read` · REST equivalent `GET /external-sites/{ext_site_id}/deployments`

The recent deploys of one external site, newest first - what to pass to a rollback. Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `ext_site_id` | integer | yes |  |
| `limit` | integer | no |  Default: `25`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "extsites_history",
    "arguments": {
      "ext_site_id": 9
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#extsites-history). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `extsites_list`

**Sites on third-party hosts** · read-only · permission `sites:read` · REST equivalent `GET /external-sites`

The sites this account publishes to outside PBN.LTD (GitHub Pages, Cloudflare Pages, Netlify, Vercel and the rest), with their address and the state of the last deploy. Connecting a provider and adding a site stay in the panel, because they need your own provider credentials. Needs the `sites:read` permission. Paginated: pass `cursor` from `next_cursor` to read the next page.

| Argument | Type | Required | Description |
|---|---|---|---|
| `limit` | integer | no | How many to return. Default: `20`. |
| `cursor` | string | no | The next_cursor value of the previous page. |
| `provider` | string | no | Only this provider. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "extsites_list",
    "arguments": {}
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#extsites-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `files_upload_archive`

**Upload a built site (zip)** · write · permission `files:write` · REST equivalent `POST /sites/{site_id}/files/archive`

Unpacks a zip of a built website (or a plugin or theme) into the site. Every file goes through the same path a single upload uses, so the same rules hold for each one: inside the site folder only, symbolic links are never followed and the platform's own folders are refused. Up to 60 files and 25 MB in one call - send a bigger site in parts. Needs the `files:write` permission. This can take up to a minute.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `zip_base64` | string | yes | The .zip file, base64. |
| `path` | string | no | Folder inside the site to unpack into (default: the site root). |
| `strip_top_folder` | boolean | no | Drop the single top folder the zip may have ("mysite/index.html" -> "index.html"). Default: `False`. |
| `overwrite` | boolean | no | Replace files that already exist. Default: `False`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "files_upload_archive",
    "arguments": {
      "site_id": 123,
      "zip_base64": "UEsDBAoAAAAAA...",
      "path": "",
      "strip_top_folder": true,
      "overwrite": true
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#files-upload_archive). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `plugins_delete`

**Remove a plugin** · **destructive** · permission `sites:write` · REST equivalent `DELETE /sites/{site_id}/plugins/{slug}`

Switches a plugin off and deletes its files. There is no undo; the plugin's own data in the database is removed the way the plugin asks for. Needs the `sites:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `slug` | string | yes | The plugin folder name. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "plugins_delete",
    "arguments": {
      "site_id": 123,
      "slug": "my-plugin"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#plugins-delete). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `plugins_install`

**Install a plugin** · **destructive** · permission `sites:write` · REST equivalent `POST /sites/{site_id}/plugins`

Installs a plugin on a WordPress site, from wordpress.org or from a zip you send. A plugin that is on our blocked list is refused. Activating a plugin can break a site: install first, then activate, then check the site with sites.verify and read the error log. Needs the `sites:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it. This can take up to a minute.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `slug` | string | no | A wordpress.org plugin slug, e.g. "classic-editor". |
| `zip_base64` | string | no | Or your own plugin as a .zip file, base64. |
| `activate` | boolean | no | Switch it on straight away. Test the site afterwards with sites.verify. Default: `False`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "plugins_install",
    "arguments": {
      "site_id": 123,
      "slug": "classic-editor",
      "activate": false
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#plugins-install). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `plugins_list`

**Plugins on this site** · read-only · permission `sites:read` · REST equivalent `GET /sites/{site_id}/plugins`

Every plugin installed on a WordPress site, whether it is active, its version and whether an update is waiting. Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "plugins_list",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#plugins-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `plugins_state`

**Switch a plugin on or off** · **destructive** · permission `sites:write` · REST equivalent `POST /sites/{site_id}/plugins/{slug}/{action}`

Activates or deactivates a plugin. Activating can take a site down, so check it with sites.verify afterwards; deactivating is how you put it back. Needs the `sites:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `slug` | string | yes | The plugin folder name. |
| `action` | string (one of: activate, deactivate) | yes | What to do. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "plugins_state",
    "arguments": {
      "site_id": 123,
      "slug": "my-plugin",
      "action": "activate"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#plugins-state). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_set_home`

**Set the home page** · **destructive** · permission `sites:write` · REST equivalent `POST /sites/{site_id}/home-page`

Makes a page the front page of the site. On WordPress this sets the site's own "front page" setting; on the other site types the file you name is copied over index.html (or index.php), which replaces what is there now. Needs the `sites:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `page` | string | yes | WordPress: the page id or its exact title. Other site types: the file to use, e.g. "home.html". |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_set_home",
    "arguments": {
      "site_id": 123,
      "page": "home.html"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#sites-set_home). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `sites_verify`

**Fetch a page and check it** · read-only · permission `sites:read` · REST equivalent `POST /sites/{site_id}/verify`

Fetches a page of the site and says exactly what came back: the HTTP status, how long it took, its size, its title and any redirect. The page is always fetched on the site's own server (so it works even before the domain points at us) and, when the address allows it, from the internet as well. The newest PHP errors are read at the same time. This is the honest test after changing anything - a plugin, a theme, a file or a setting. Needs the `sites:read` permission. This can take up to a minute.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `path` | string | no | The page to fetch, e.g. "/about". Default: `/`. |
| `public` | boolean | no | Also try the page from the internet. Default: `True`. |
| `errors` | boolean | no | Also read the PHP error log afterwards. Default: `True`. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "sites_verify",
    "arguments": {
      "site_id": 123,
      "path": "/"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#sites-verify). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `themes_activate`

**Use this theme** · **destructive** · permission `sites:write` · REST equivalent `POST /sites/{site_id}/themes/{slug}/activate`

Switches the site to another theme. This changes how every page looks at once - check the site with sites.verify straight after, and switch back if it is wrong. Needs the `sites:write` permission. DESTRUCTIVE: this cannot be undone. Confirm with the user before calling it.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |
| `slug` | string | yes | The theme folder name. |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "themes_activate",
    "arguments": {
      "site_id": 123,
      "slug": "twentytwentyfive"
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#themes-activate). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.

### `themes_list`

**Themes on this site** · read-only · permission `sites:read` · REST equivalent `GET /sites/{site_id}/themes`

Every theme on a WordPress site and which one is in use. Needs the `sites:read` permission.

| Argument | Type | Required | Description |
|---|---|---|---|
| `site_id` | integer | yes | The site id (see GET /sites). |

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "themes_list",
    "arguments": {
      "site_id": 123
    }
  }
}
```

The answer carries the same data as the REST call, as `structuredContent`, with an example of every field in [Building, plugins and themes](https://app.pbn.ltd/api/docs/reference/devtools#themes-list). The exact JSON Schema the answer is validated against is the tool's own `outputSchema` in `tools/list`.
