## CC filters (`cc-filters`)

How matched requests are handled: rate limiting or a challenge (JS, slider, captcha and so on).

Authentication: User (some parameters admin only) · Docs: https://www-demo.kuxitong.com/en/docs/api/cc-filters

### GET `/api/v2/cc-filters`

List CC filters · Authentication: User (some parameters admin only)

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `page` | integer |  | Page number, starting from 1 Default: 1 |
| `page_size` | integer |  | Items per page Default: 20 |
| `sort` | string |  | Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id` |
| `tenant_id` | integer |  | Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data |
| `name` | string |  | Filter by name substring. |
| `owner` | string |  | platform = platform objects only; tenant = tenant objects only. Values: ["platform","tenant"] |

```sh
curl "https://panel.example.com/api/v2/cc-filters" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/cc-filters`

Create CC filter · Authentication: User (some parameters admin only)

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `count_key` | string |  | Who to count by (rate/challenge): ip = client IP (default, existing behavior); ja4 = TLS fingerprint only, regardless of IP — real visitors sharing the fingerprint are counted together, so it is allowed with the log action only (a rule item with ban/deny is rejected with 422); to punish use ip_ja4 = same IP and same fingerprint combined. Plaintext requests have no fingerprint, so ja4/ip_ja4 fall back to IP. Not used by url_auth (must be ip). Values: ["ip","ja4","ip_ja4"] |
| `des` | string |  | Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object). |
| `kind` | string |  | Challenge type (required for challenge): js/redirect/slide/captcha/click/delay_jump/rotate/cookie; not used for rate. |
| `max` | integer | Yes | Requests allowed within the window. |
| `mode` | string |  | Required for url_auth: signing scheme. a = ?<sign_arg>=md5(key+path+timestamp)&<time_arg>=timestamp; b = ?<sign_arg>=timestamp-random-uid-md5(path-timestamp-random-uid-key). Values: ["a","b"] |
| `name` | string | Yes | Name |
| `per_uri_max` | integer |  | rate: per-URI limit; 0 = unlimited. |
| `sign_arg` | string |  | Required for url_auth: name of the signature query parameter (letters, digits, underscore, hyphen). |
| `sign_use_max` | integer |  | url_auth: how many times the same signature may be used; 0 = unlimited. |
| `time_arg` | string |  | Required for url_auth with mode=a: name of the timestamp query parameter; not used with mode=b. |
| `ttl_s` | integer |  | Required for url_auth (1 to 2592000): maximum difference in seconds between the signed timestamp and the current time. |
| `type` | string | Yes | rate = request rate; challenge = challenge (the type is given by kind); url_auth = URL signature check (the signing key is the site's config.url_auth_salt). Values: ["rate","challenge","url_auth"] |
| `window_s` | integer | Yes | Counting window in seconds. |

```sh
curl -X POST "https://panel.example.com/api/v2/cc-filters" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"max":20,"name":"rate-5-20","per_uri_max":10,"type":"rate","window_s":5}'
```

### GET `/api/v2/cc-filters/{id}`

Get CC filter · Authentication: User (some parameters admin only)

```sh
curl "https://panel.example.com/api/v2/cc-filters/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/cc-filters/{id}`

Update CC filter · Authentication: User (some parameters admin only)

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `count_key` | string |  | Who to count by (rate/challenge): ip = client IP (default, existing behavior); ja4 = TLS fingerprint only, regardless of IP — real visitors sharing the fingerprint are counted together, so it is allowed with the log action only (a rule item with ban/deny is rejected with 422); to punish use ip_ja4 = same IP and same fingerprint combined. Plaintext requests have no fingerprint, so ja4/ip_ja4 fall back to IP. Not used by url_auth (must be ip). Values: ["ip","ja4","ip_ja4"] |
| `des` | string |  | Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object). |
| `kind` | string |  | Challenge type (required for challenge): js/redirect/slide/captcha/click/delay_jump/rotate/cookie; not used for rate. |
| `max` | integer | Yes | Requests allowed within the window. |
| `mode` | string |  | Required for url_auth: signing scheme. a = ?<sign_arg>=md5(key+path+timestamp)&<time_arg>=timestamp; b = ?<sign_arg>=timestamp-random-uid-md5(path-timestamp-random-uid-key). Values: ["a","b"] |
| `name` | string | Yes | Name |
| `per_uri_max` | integer |  | rate: per-URI limit; 0 = unlimited. |
| `sign_arg` | string |  | Required for url_auth: name of the signature query parameter (letters, digits, underscore, hyphen). |
| `sign_use_max` | integer |  | url_auth: how many times the same signature may be used; 0 = unlimited. |
| `time_arg` | string |  | Required for url_auth with mode=a: name of the timestamp query parameter; not used with mode=b. |
| `ttl_s` | integer |  | Required for url_auth (1 to 2592000): maximum difference in seconds between the signed timestamp and the current time. |
| `type` | string | Yes | rate = request rate; challenge = challenge (the type is given by kind); url_auth = URL signature check (the signing key is the site's config.url_auth_salt). Values: ["rate","challenge","url_auth"] |
| `window_s` | integer | Yes | Counting window in seconds. |

```sh
curl -X PUT "https://panel.example.com/api/v2/cc-filters/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"max":20,"name":"rate-5-20","per_uri_max":10,"type":"rate","window_s":5}'
```

### DELETE `/api/v2/cc-filters/{id}`

Delete CC filter · Authentication: User (some parameters admin only)

```sh
curl -X DELETE "https://panel.example.com/api/v2/cc-filters/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

CC filters object:

| Field | Type | Required | Description |
|---|---|---|---|
| `builtin` | boolean |  | Built-in object; cannot be deleted. (read-only) |
| `count_key` | string |  | Who to count by (rate/challenge): ip = client IP (default, existing behavior); ja4 = TLS fingerprint only, regardless of IP — real visitors sharing the fingerprint are counted together, so it is allowed with the log action only (a rule item with ban/deny is rejected with 422); to punish use ip_ja4 = same IP and same fingerprint combined. Plaintext requests have no fingerprint, so ja4/ip_ja4 fall back to IP. Not used by url_auth (must be ip). Values: ["ip","ja4","ip_ja4"] |
| `created_at` | string |  | Created at (read-only) |
| `des` | string |  | Remark; empty if omitted (omitting it on update also clears it, since the update replaces the whole object). |
| `id` | integer |  | Record ID (read-only) |
| `kind` | string |  | Challenge type (required for challenge): js/redirect/slide/captcha/click/delay_jump/rotate/cookie; not used for rate. |
| `max` | integer |  | Requests allowed within the window. |
| `mode` | string |  | Required for url_auth: signing scheme. a = ?<sign_arg>=md5(key+path+timestamp)&<time_arg>=timestamp; b = ?<sign_arg>=timestamp-random-uid-md5(path-timestamp-random-uid-key). Values: ["a","b"] |
| `name` | string |  | Name |
| `per_uri_max` | integer |  | rate: per-URI limit; 0 = unlimited. |
| `sign_arg` | string |  | Required for url_auth: name of the signature query parameter (letters, digits, underscore, hyphen). |
| `sign_use_max` | integer |  | url_auth: how many times the same signature may be used; 0 = unlimited. |
| `tenant_id` | integer |  | Owning tenant; null = platform object (built-in or created by an admin, read-only for tenants). (read-only) |
| `time_arg` | string |  | Required for url_auth with mode=a: name of the timestamp query parameter; not used with mode=b. |
| `ttl_s` | integer |  | Required for url_auth (1 to 2592000): maximum difference in seconds between the signed timestamp and the current time. |
| `type` | string |  | rate = request rate; challenge = challenge (the type is given by kind); url_auth = URL signature check (the signing key is the site's config.url_auth_salt). Values: ["rate","challenge","url_auth"] |
| `updated_at` | string |  | Updated at (read-only) |
| `window_s` | integer |  | Counting window in seconds. |
