# WAF (ModSecurity)

<a id="get-api-v1-accounts-username-waf-audit-log"></a>
#### `GET /api/v1/accounts/{username}/waf/audit-log`

*ModSecurity audit log (account-scope)*

The newest audit entries whose Host header names one of the account's own domains.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |

**Query parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `limit` | integer | no | minimum=1; maximum=1000 |
| `offset` | integer | no | minimum=0 |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_list_WafAuditLogEntry__` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": [
    {
      "action": "...",
      "client_ip": "...",
      "host": "...",
      "request_uri": "...",
      "rule_id": "...",
      "rule_message": "...",
      "severity": "...",
      "timestamp": "..."
    }
  ],
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/accounts/{username}/waf/audit-log
```

---

<a id="get-api-v1-accounts-username-waf-rules"></a>
#### `GET /api/v1/accounts/{username}/waf/rules`

*List the account's rule exclusions*

The rules excluded for this account's vhosts, each with its optional URI scope.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_list_WafRuleExclusionEntry__` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": [
    {
      "description": "...",
      "rule_id": "...",
      "uri": "..."
    }
  ],
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/accounts/{username}/waf/rules
```

---

<a id="post-api-v1-accounts-username-waf-rules-exclude"></a>
#### `POST /api/v1/accounts/{username}/waf/rules/exclude`

*Exclude a CRS rule for one account*

Add an account-scope exclusion — the named rule no longer triggers for this account's vhosts (or for the given URI only). The rule must be in the loaded rule set; an exclusion already present is answered without a write. Answers 409 FEATURE_DISABLED while modsecurity.per_account_overrides is off.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |

**Body fields:**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `description` | string | no | — |
| `rule_id` | integer | yes | minimum=900000.0; maximum=999999.0 |
| `uri` | string | no | — |

**Request body example:**

```json
{
  "description": "string",
  "rule_id": 900000.0,
  "uri": "string"
}
```

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_WafAccountStatus_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "rule_exclusions": [
      "..."
    ],
    "username": "alice",
    "waf_enabled": false
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X POST \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  -H "Content-Type: application/json" \
  -d @body.json \
  https://your-server:2000/api/v1/accounts/{username}/waf/rules/exclude
```

---

<a id="delete-api-v1-accounts-username-waf-rules-exclude-rule-id"></a>
#### `DELETE /api/v1/accounts/{username}/waf/rules/exclude/{rule_id}`

*Remove rule exclusion*

Removes the exclusion of the rule without a URI scope, or — with `uri` — the exclusion scoped to that URI. The rule resumes triggering for the account. Answers 409 FEATURE_DISABLED while modsecurity.per_account_overrides is off.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |
| `rule_id` | integer | yes | — |

**Query parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `uri` | string | no | — |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_WafAccountStatus_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "rule_exclusions": [
      "..."
    ],
    "username": "alice",
    "waf_enabled": false
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X DELETE \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/accounts/{username}/waf/rules/exclude/{rule_id}
```

---

<a id="get-api-v1-accounts-username-waf-status"></a>
#### `GET /api/v1/accounts/{username}/waf/status`

*ModSecurity per-account status*

Account-scope: WAF on/off flag + the account's rule exclusions. An account that does not exist answers 404.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_WafAccountStatus_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "rule_exclusions": [
      "..."
    ],
    "username": "alice",
    "waf_enabled": false
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/accounts/{username}/waf/status
```

---

<a id="put-api-v1-accounts-username-waf-toggle"></a>
#### `PUT /api/v1/accounts/{username}/waf/toggle`

*Toggle ModSecurity for account*

Per-account override — bypass WAF entirely for the named account's vhosts. A change reloads the webserver; the state already in force is answered without a write. Answers 409 FEATURE_DISABLED while modsecurity.per_account_overrides is off.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |

**Body fields:**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `enabled` | boolean | yes | — |

**Request body example:**

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

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_WafAccountStatus_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "rule_exclusions": [
      "..."
    ],
    "username": "alice",
    "waf_enabled": false
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X PUT \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  -H "Content-Type: application/json" \
  -d @body.json \
  https://your-server:2000/api/v1/accounts/{username}/waf/toggle
```

---

<a id="get-api-v1-waf-audit-log"></a>
#### `GET /api/v1/waf/audit-log`

*ModSecurity audit log (global)*

The newest entries of the ModSecurity audit log (the rotation copies and truncates the file, so the panel reads every entry since the last rotation): the client address, the host and URI asked for, the first rule that matched, and whether the request was blocked, detected (detection-only) or only logged.

**Query parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `limit` | integer | no | minimum=1; maximum=1000 |
| `offset` | integer | no | minimum=0 |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_list_WafAuditLogEntry__` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": [
    {
      "action": "...",
      "client_ip": "...",
      "host": "...",
      "request_uri": "...",
      "rule_id": "...",
      "rule_message": "...",
      "severity": "...",
      "timestamp": "..."
    }
  ],
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/waf/audit-log
```

---

<a id="put-api-v1-waf-config"></a>
#### `PUT /api/v1/waf/config`

*Update ModSecurity global config*

Patch engine mode, paranoia level, audit logging. The rendered files are tested before the values are persisted; a change reloads the webserver, a save that changes nothing does not.

**Body fields:**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `audit_log` | boolean | no | — |
| `crs_paranoia_level` | integer | no | — |
| `engine_mode` | string | no | — |

**Request body example:**

```json
{
  "audit_log": false,
  "crs_paranoia_level": 1.0,
  "engine_mode": "string"
}
```

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_WafGlobalStatus_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "active": false,
    "audit_log": false,
    "crs_paranoia_level": 1,
    "disabled_rules": 0,
    "engine_mode": "off",
    "installed": false,
    "owasp_crs": false,
    "rules_loaded": false,
    "total_rules": 0,
    "webserver": "",
    "webserver_supported": true
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X PUT \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  -H "Content-Type: application/json" \
  -d @body.json \
  https://your-server:2000/api/v1/waf/config
```

---

<a id="get-api-v1-waf-rules"></a>
#### `GET /api/v1/waf/rules`

*List CRS rules*

Every id-bearing rule of the loaded rule set with its message (where it carries one), file and enabled flag.

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_list_WafRuleEntry__` | Successful Response |

**Response example (200):**

```json
{
  "data": [
    {
      "description": "...",
      "enabled": "...",
      "file": "...",
      "rule_id": "..."
    }
  ],
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/waf/rules
```

---

<a id="put-api-v1-waf-rules-rule-id"></a>
#### `PUT /api/v1/waf/rules/{rule_id}`

*Toggle CRS rule*

Enable / disable a single rule by id; an id that is not in the loaded rule set answers 404. A change reloads the webserver, a toggle to the state already in force does not.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `rule_id` | integer | yes | — |

**Body fields:**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `enabled` | boolean | yes | — |

**Request body example:**

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

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_WafRuleEntry_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "description": "",
    "enabled": true,
    "file": "",
    "rule_id": 0
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X PUT \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  -H "Content-Type: application/json" \
  -d @body.json \
  https://your-server:2000/api/v1/waf/rules/{rule_id}
```

---

<a id="get-api-v1-waf-status"></a>
#### `GET /api/v1/waf/status`

*ModSecurity global status*

Engine state (DetectionOnly / On / Off), CRS version, paranoia level, request body limit.

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_WafGlobalStatus_` | Successful Response |

**Response example (200):**

```json
{
  "data": {
    "active": false,
    "audit_log": false,
    "crs_paranoia_level": 1,
    "disabled_rules": 0,
    "engine_mode": "off",
    "installed": false,
    "owasp_crs": false,
    "rules_loaded": false,
    "total_rules": 0,
    "webserver": "",
    "webserver_supported": true
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/waf/status
```

---

<a id="post-api-v1-waf-test"></a>
#### `POST /api/v1/waf/test`

*Test ModSecurity config*

Runs the webserver's configuration test over the rendered ModSecurity files (nginx -t, apachectl configtest); no request is sent. Answers 409 WAF_TEST_UNAVAILABLE on a webserver without such a test.

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `MessageResponse` | Successful Response |

**Response example (200):**

```json
{
  "message": "string",
  "status": "success"
}
```

**cURL example:**

```bash
curl -X POST \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/waf/test
```

---
