# Manage Site Rules with the xCloud Public API and MCP

> Create, update and delete header and redirect Site Rules from the xCloud Public API or an MCP agent, with the same config test and rollback as the dashboard.

You can now create, update and delete **Site Rules** (custom response headers and redirects) from the xCloud Public API or from an AI agent connected to xCloud MCP. Every change goes through the same steps as the dashboard: xCloud writes the rule and tests the web server config. If the web server rejects the new config, xCloud undoes the change and your site keeps its previous config. This guide is for developers and agencies who manage rules across many sites from scripts, CI or an agent.

## What the API and MCP can do

The API covers the full life of a rule except testing and reordering. Use the [dashboard guide](/docs/how-to-create-and-manage-site-rules/) for those two.

| Task | Public API | MCP operation | Compact executor |
|---|---|---|---|
| List a site's rules | `GET /sites/{uuid}/web-rules` | `sites.webRules` | `xcloud_execute_read` |
| Create a rule | `POST /sites/{uuid}/web-rules` | `sites.webRules.store` | `xcloud_execute_destructive` |
| Update a rule | `PUT /sites/{uuid}/web-rules/{rule_uuid}` | `sites.webRules.update` | `xcloud_execute_destructive` |
| Delete a rule | `DELETE /sites/{uuid}/web-rules/{rule_uuid}` | `sites.webRules.destroy` | `xcloud_execute_destructive` |
| Test a rule without saving | Dashboard only | Not available | Not available |
| Change rule order | Dashboard only | Not available | Not available |

Create, update and delete change the live web server config straight away. The response tells you the result directly; there is nothing to poll.

## Prerequisites
- A WordPress site on an Nginx or OpenLiteSpeed server. Other site types and stacks are refused with `403`.
- A paid xCloud plan. Site Rules are not available on the free plan.
- A team role that can manage Site Rules on that site.
- For the Public API: a token with `read:sites` and `write:sites`. Follow [How to access the xCloud API](/docs/how-to-access-the-xcloud-api/).
- For xCloud MCP: a client connected with write access. Follow [How to connect xCloud MCP to your AI agent](/docs/how-to-connect-xcloud-mcp-to-ai-agent/).
- The site's web server config regeneration must be on for create and update (see [Troubleshooting](#troubleshooting)).

## Rule fields

Each rule has a `rule_type` (`header` or `redirect`) and a `config` object. You set `rule_type` only when you create a rule.

**Header rules** (up to 10 per site):

| Field | Values |
|---|---|
| `action` | `set` adds or replaces the header, `unset` removes it |
| `header_name` | Letters, digits and hyphens, starting with a letter. One rule per header name on a site. |
| `header_value` | Required for `set`. Up to 1024 characters (255 on OpenLiteSpeed), no line breaks or `<` `>`. |
| `always_apply` | Required for `set`. `true` also sends the header on error responses. |

**Redirect rules** (up to 25 per site):

| Field | Values |
|---|---|
| `source` | Path that starts with `/` or `^/` (a pattern) |
| `destination` | Path that starts with `/`, or a full `http://` or `https://` URL |
| `redirect_type` | `301` or `302`. OpenLiteSpeed also accepts `0` for an internal rewrite. |
| `keep_query_string` | `true` or `false` |
| `condition` | Optional: `type` (`host`, `uri`, `query_arg` or `device_code`), `operator` (`=`, `!=`, `~`, `!~`) and `value`. For `query_arg`, `value` is the parameter name only: letters, digits and underscores. |

None of the redirect text fields (source, destination, condition value) may contain `;`, `{`, `}` or line breaks. Two redirect rules with the same source and destination are refused.

## Manage rules through the Public API

### Step 1: Set the API variables

Set the base URL, your token and the site UUID in your shell:

```bash
export XCLOUD_API_BASE='https://app.xcloud.host/api/v1'
export XCLOUD_API_TOKEN='xc_live_xxxxxxxxxxxx'
export SITE_UUID='11111111-1111-4111-8111-111111111111'
```

Find the site UUID with `GET /sites`. If your token covers several teams, add the `X-Team-Id` header to pick one (see [multi-team API tokens](/docs/multi-team-api-tokens-and-mcp-access/)).

**Expected result:** your shell holds the values the next requests use. The token is not printed.

### Step 2: List the existing rules

Check what the site already has before you add anything:

```bash
curl --fail-with-body -sS \
  -H "Authorization: Bearer ${XCLOUD_API_TOKEN}" \
  -H 'Accept: application/json' \
  "${XCLOUD_API_BASE}/sites/${SITE_UUID}/web-rules"
```

**Expected result:** `data.items` lists each rule with its `uuid`, `rule_type`, `config` and `sort_order`, and `data.counts` shows how many headers and redirects exist. Compare the counts with the limits above.

### Step 3: Create a header rule

This example adds `X-Content-Type-Options: nosniff` to every response:

```bash
curl --fail-with-body -sS \
  -X POST \
  -H "Authorization: Bearer ${XCLOUD_API_TOKEN}" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  "${XCLOUD_API_BASE}/sites/${SITE_UUID}/web-rules" \
  --data '{
    "rule_type": "header",
    "config": {
      "action": "set",
      "header_name": "X-Content-Type-Options",
      "header_value": "nosniff",
      "always_apply": true
    }
  }'
```

**Expected result:** `201 Created` with `data.success: true` and the new rule in `data.rule`. Save `data.rule.uuid` if you plan to update or delete it later. The header is live as soon as the response arrives.

### Step 4: Create a redirect rule

This example sends `/old-page` to `/new-page` permanently and keeps the query string:

```bash
curl --fail-with-body -sS \
  -X POST \
  -H "Authorization: Bearer ${XCLOUD_API_TOKEN}" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  "${XCLOUD_API_BASE}/sites/${SITE_UUID}/web-rules" \
  --data '{
    "rule_type": "redirect",
    "config": {
      "source": "/old-page",
      "destination": "/new-page",
      "redirect_type": 301,
      "keep_query_string": true
    }
  }'
```

To redirect only on one hostname, add a condition such as `"condition": {"type": "host", "operator": "=", "value": "www.example.com"}`.

**Expected result:** `201 Created` with the rule in `data.rule`. Check it with `curl -I https://example.com/old-page`, which should show `301` and the new location.

### Step 5: Update a rule

Send the complete new `config` to the rule's UUID. The rule keeps its type, so do not send `rule_type`:

```bash
export RULE_UUID='22222222-2222-4222-8222-222222222222'

curl --fail-with-body -sS \
  -X PUT \
  -H "Authorization: Bearer ${XCLOUD_API_TOKEN}" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  "${XCLOUD_API_BASE}/sites/${SITE_UUID}/web-rules/${RULE_UUID}" \
  --data '{
    "config": {
      "source": "/old-page",
      "destination": "/new-page",
      "redirect_type": 302,
      "keep_query_string": true
    }
  }'
```

**Expected result:** `200 OK` with `data.success: true` and the updated rule. If the config test fails, the rule goes back to its previous values.

### Step 6: Delete a rule

```bash
curl --fail-with-body -sS \
  -X DELETE \
  -H "Authorization: Bearer ${XCLOUD_API_TOKEN}" \
  -H 'Accept: application/json' \
  "${XCLOUD_API_BASE}/sites/${SITE_UUID}/web-rules/${RULE_UUID}"
```

**Expected result:** `200 OK` with `data.success: true` and `data.rule: null`. The rule is removed from the live config. Deleting works even when config regeneration is off, the same as in the dashboard.

## Manage rules through xCloud MCP

MCP uses the same contract as the Public API. Connect your client to `https://app.xcloud.host/mcp`, or `https://app.xcloud.host/mcp?profile=compact` when your client limits the number of tools.

### Step 1: Ask the agent to read the current rules

Start with a read so the agent knows what exists:

```text
List the Site Rules on my site example.com in xCloud. Show each rule's type, settings and UUID. Do not change anything yet.
```

The agent should find the site, call `xcloud_agent_search` to locate the operation, then run `sites.webRules` through `xcloud_execute_read`.

**Expected result:** the agent shows each header and redirect rule and the current counts.

### Step 2: Approve the exact change

Describe the rule you want and ask to see the request first:

```text
Add a header rule to example.com that sets Referrer-Policy to strict-origin-when-cross-origin on every response. Show me the exact rule before you send it.
```

After you approve, the agent runs `sites.webRules.store` (or `.update` / `.destroy`) through `xcloud_execute_destructive` with `confirm: true`. These operations change the live server config, so a well-behaved agent never sets `confirm` without your approval.

**Expected result:** the agent reports `success: true` and the rule's UUID, or reports the refusal code and what to do next.

## Troubleshooting

Refusals carry a stable `errors.code` and `errors.next_actions`. Branch on those, not on the message text.

| Response | Cause | Fix |
|---|---|---|
| `422` `site_rule_config_test_failed`, next action `review_site_rule_config` | The web server rejected the new config. xCloud rolled the change back and the site is unaffected. | Check the header value or redirect pattern and send a corrected rule. |
| `422` `site_rules_regeneration_disabled`, next action `enable_site_rules_regeneration` | Config regeneration is turned off for this site, so create and update are blocked. | Open the site, go to **Nginx and Security** (**Security** on OpenLiteSpeed) and turn off **Disable Nginx Config Regeneration** (**Disable OpenLiteSpeed Config Regeneration**). See [config regeneration failures](/docs/how-to-troubleshoot-nginx-configuration-regeneration-failures-with-xcloud/). |
| `403` `site_rules_plan_required`, next action `upgrade_site_rules_plan` | The team is on the free plan. | Upgrade to a paid plan. |
| `403` "Site Rules require WordPress." or "require Nginx or OpenLiteSpeed." | The site type or server stack is not supported. | Use a WordPress site on an Nginx or OpenLiteSpeed server. |
| `403` without a code | The token lacks `write:sites`, or your team role cannot manage Site Rules. | Add the scope to the token or ask a team admin for the permission. |
| `422` "Maximum 10 header rules per site." or "Maximum 25 redirect rules per site." | The site is at its rule limit. | Delete or combine rules first. |
| `422` validation error on `config.*` | A field is missing, too long, a duplicate, or uses a blocked character. | Read `errors` for the field name and fix that value. |
| `404` | The site or rule UUID does not exist in the selected team, or the rule belongs to another site. | Re-list the rules and use the UUID from `data.items`. |

## Frequently asked questions

### What happens if a new rule breaks the web server config?

xCloud tests the config before it keeps the change. If the test fails, xCloud removes the new rule or restores the old one, your site keeps serving with its previous config, and the API returns 422 with errors.code set to site_rule_config_test_failed.

### Can I test or reorder Site Rules through the API?

Not yet. The API can list, create, update and delete rules. Testing a rule without saving it and changing rule order are only available in the dashboard.

### Which MCP tool creates, updates or deletes a rule?

Use the operations sites.webRules.store (create), sites.webRules.update (update) and sites.webRules.destroy (delete). On the compact profile, run them through xcloud_execute_destructive with confirm set to true after you approve the exact rule. To list rules, run sites.webRules through xcloud_execute_read.

### Can I change the rule type of an existing rule?

No. An update keeps the rule's stored type and only replaces its config. To turn a header rule into a redirect, delete it and create a new redirect rule.

## Next steps
- Manage the same rules in the dashboard, including **Test Rule** and ordering: [How to create and manage Site Rules](/docs/how-to-create-and-manage-site-rules/).
- Review the full [xCloud Public API reference](https://app.xcloud.host/api/v1/docs).
- Create and scope a token with [How to access the xCloud API](/docs/how-to-access-the-xcloud-api/).
- Connect an AI client with [How to connect xCloud MCP to your AI agent](/docs/how-to-connect-xcloud-mcp-to-ai-agent/).
- Deploy sites the same way with [Git deploy via the API and MCP](/docs/deploy-git-projects-with-xcloud-public-api-and-mcp/).

If you run into any issues with Site Rules through the API or MCP, feel free to reach out to our [support team](/docs/access-built-in-support-portal-in-xcloud/) with the site UUID and the error code you received.
