Skip to content

Firewall (CSF)

ConfigServer Security & Firewall management: allow/deny lists, temporary blocks, profiles, country blocks.

All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.

Endpoint count: 32

Endpoints

Method Path Handler Guards
POST /api/firewall/allow firewallAllow RequirePermission(db, "firewall_management")
DELETE /api/firewall/allow/*ip firewallRemoveAllow RequirePermission(db, "firewall_management")
GET /api/firewall/cloudflare cloudflareStatus RequirePermission(db, "firewall_management")
POST /api/firewall/cloudflare cloudflareOnly RequirePermission(db, "firewall_management")
GET /api/firewall/countries firewallCountries RequirePermission(db, "firewall_management")
POST /api/firewall/countries/block firewallCountryBlock RequirePermission(db, "firewall_management")
GET /api/firewall/countries/list firewallCountryList RequirePermission(db, "firewall_management")
POST /api/firewall/deny firewallDeny RequirePermission(db, "firewall_management")
DELETE /api/firewall/deny/*ip firewallRemoveDeny RequirePermission(db, "firewall_management")
POST /api/firewall/disable firewallDisable RequirePermission(db, "firewall_management")
POST /api/firewall/enable firewallEnable RequirePermission(db, "firewall_management")
POST /api/firewall/export firewallExport RequirePermission(db, "firewall_management")
GET /api/firewall/geoip firewallGeoIP RequirePermission(db, "firewall_management")
POST /api/firewall/import firewallImport RequirePermission(db, "firewall_management")
GET /api/firewall/ipinfo firewallIPInfo RequirePermission(db, "firewall_management")
GET /api/firewall/logs firewallLogs RequirePermission(db, "firewall_management")
POST /api/firewall/port/close firewallClosePort RequirePermission(db, "firewall_management")
POST /api/firewall/port/open firewallOpenPort RequirePermission(db, "firewall_management")
GET /api/firewall/portinfo firewallPortInfo RequirePermission(db, "firewall_management")
GET /api/firewall/ports firewallPorts RequirePermission(db, "firewall_management")
POST /api/firewall/restart firewallRestart RequirePermission(db, "firewall_management")
GET /api/firewall/rules firewallRules RequirePermission(db, "firewall_management")
GET /api/firewall/settings firewallGetSettings RequirePermission(db, "firewall_management")
PATCH /api/firewall/settings firewallUpdateSettings RequirePermission(db, "firewall_management")
POST /api/firewall/settings firewallUpdateSetting RequirePermission(db, "firewall_management")
GET /api/firewall/status firewallStatus RequirePermission(db, "firewall_management")
GET /api/firewall/superaccess firewallSuperAccess RequirePermission(db, "firewall_management")
POST /api/firewall/superaccess firewallAddSuperAccess RequirePermission(db, "firewall_management")
DELETE /api/firewall/superaccess/:ip firewallRemoveSuperAccess RequirePermission(db, "firewall_management")
GET /api/firewall/temp firewallTempList RequirePermission(db, "firewall_management")
DELETE /api/firewall/temp/:ip firewallRemoveTemp RequirePermission(db, "firewall_management")
POST /api/firewall/tempdeny firewallTempDeny RequirePermission(db, "firewall_management")

Source

Handlers for this section live in api/routes/handlers_*.go in the StarkOne source. Each handler binds its request body with gin.ShouldBindJSON(&req) and responds with the standard envelope:

{ "data": { ... } }

On error:

{ "error": { "code": "string", "message": "string" } }

Reference

POST /api/firewall/allow

Adds an IP address to the CSF allow list (csf.allow) with an optional comment.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "ip": "string (required)", "comment": "string (optional)" }
Field Type Required Description
ip string yes IP address (or CIDR) to allow.
comment string no Free-text note stored alongside the rule.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding (e.g. missing ip).
400 firewall_error CSF rejected the allow operation.

Side effects

  • Calls firewall.Allow(ip, comment), which writes the IP into the CSF allow list and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/allow \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ip": "203.0.113.10", "comment": "office"}'

DELETE /api/firewall/allow/*ip

Removes an IP address from the CSF allow list.

Guards: RequirePermission(db, "firewall_management")

Path parameters

Name Type Description
ip string The IP to remove. Captured as a wildcard (*ip); the handler strips the leading /.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 firewall_error CSF rejected the removal.

Side effects

  • Calls firewall.RemoveAllow(ip), which deletes the matching entry from the CSF allow list and reloads CSF.

Example

curl -X DELETE https://panel.example.com:2087/api/firewall/allow/203.0.113.10 \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/cloudflare

Returns whether Cloudflare-only mode (restricting ports 80/443 to Cloudflare IP ranges) is enabled.

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { "enabled": false } }

Example

curl https://panel.example.com:2087/api/firewall/cloudflare \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/cloudflare

Enables or disables Cloudflare-only mode for HTTP/HTTPS ports.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "enabled": true }
Field Type Required Description
enabled boolean yes true enables Cloudflare-only mode, false disables it. Note: the field carries binding:"required", so a literal false value fails binding validation.

Response - 200 OK

{ "data": { "success": true, "enabled": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding.
500 firewall_error Enabling/disabling Cloudflare-only mode failed.

Side effects

  • Calls firewall.EnableCloudflareOnly() or firewall.DisableCloudflareOnly(), which adjust CSF rules for ports 80/443 and reload CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/cloudflare \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'

GET /api/firewall/countries

Returns the firewall's country-block configuration as provided by firewall.GetCountries().

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { } }

The exact shape is determined by firewall.GetCountries(); it is returned verbatim inside data.

Example

curl https://panel.example.com:2087/api/firewall/countries \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/countries/block

Adds or removes a list of countries from the CSF CC_DENY country-block list.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "countries": ["CN", "RU"], "deny": true }
Field Type Required Description
countries array of string yes ISO country codes to block or unblock.
deny boolean no true to add the countries to CC_DENY, false to remove them.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding (e.g. missing countries).
500 firewall_error Updating the country-deny list failed.

Side effects

  • Calls firewall.SetCountryDeny(countries, deny), which edits CSF CC_DENY configuration and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/countries/block \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"countries": ["CN", "RU"], "deny": true}'

GET /api/firewall/countries/list

Returns all countries with their current block status as provided by firewall.GetCountryList().

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": [ ] }

The exact shape is determined by firewall.GetCountryList(); it is returned verbatim inside data.

Example

curl https://panel.example.com:2087/api/firewall/countries/list \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/deny

Adds an IP address to the CSF deny list (csf.deny) with an optional comment.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "ip": "string (required)", "comment": "string (optional)" }
Field Type Required Description
ip string yes IP address (or CIDR) to deny.
comment string no Free-text note stored alongside the rule.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding (e.g. missing ip).
400 firewall_error CSF rejected the deny operation.

Side effects

  • Calls firewall.Deny(ip, comment), which writes the IP into the CSF deny list and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/deny \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ip": "203.0.113.20", "comment": "abuse"}'

DELETE /api/firewall/deny/*ip

Removes an IP address from the CSF deny list.

Guards: RequirePermission(db, "firewall_management")

Path parameters

Name Type Description
ip string The IP to remove. Captured as a wildcard (*ip); the handler strips the leading /.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 firewall_error CSF rejected the removal.

Side effects

  • Calls firewall.RemoveDeny(ip), which deletes the matching entry from the CSF deny list and reloads CSF.

Example

curl -X DELETE https://panel.example.com:2087/api/firewall/deny/203.0.113.20 \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/disable

Disables the CSF firewall.

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
500 firewall_error Disabling CSF failed.

Side effects

  • Calls firewall.Disable(), which disables CSF (equivalent to csf -x).

Example

curl -X POST https://panel.example.com:2087/api/firewall/disable \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/enable

Enables the CSF firewall.

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
500 firewall_error Enabling CSF failed.

Side effects

  • Calls firewall.Enable(), which enables CSF (equivalent to csf -e).

Example

curl -X POST https://panel.example.com:2087/api/firewall/enable \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/export

Reads a fixed set of CSF configuration files from /etc/csf/ and returns their contents keyed by filename. Despite the POST method, no request body is read.

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { "csf.conf": "...", "csf.allow": "...", "csf.deny": "..." } }

data is a map of filename to file contents. Only files that exist and are readable are included. The candidate files are: csf.conf, csf.allow, csf.deny, csf.ignore, csf.pignore, csf.blocklists, csf.dyndns, csf.fignore, csf.rignore, csf.signore, csf.suignore, csf.mignore, csf.logfiles, csf.syslogfiles, csf.uidignore, csf.dirwatch, csfpre.sh, csfpost.sh.

Side effects

  • Reads files under /etc/csf/. No writes.

Example

curl -X POST https://panel.example.com:2087/api/firewall/export \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/geoip

Proxies ip-api.com to perform a GeoIP lookup for the supplied IP and streams the upstream JSON back to the caller.

Guards: RequirePermission(db, "firewall_management")

Query parameters

Name Type Optional Description
ip string no The IPv4 or IPv6 address to look up.

Response - 200 OK

The upstream ip-api.com JSON is streamed through unchanged (the upstream status code is proxied; the content type is always set to application/json). It contains fields country, countryCode, city, isp, org, proxy, hosting. This response is NOT wrapped in the data envelope.

{ "country": "United States", "countryCode": "US", "city": "Ashburn", "isp": "Example ISP", "org": "Example Org", "proxy": false, "hosting": true }

Errors

Status Code Meaning
400 bad_request ip query param missing.
502 lookup_failed The request to ip-api.com failed.

Side effects

  • Makes an outbound HTTP request to http://ip-api.com/json/<ip> (5s timeout).

Example

curl "https://panel.example.com:2087/api/firewall/geoip?ip=203.0.113.30" \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/import

Imports CSF configuration files: disables CSF, writes the supplied known CSF files into /etc/csf/, re-enables and restarts CSF.

Guards: RequirePermission(db, "firewall_management")

Request body

The body is a JSON object mapping filename to file contents. It may be wrapped in a data key, or be a flat map at the top level (both accepted).

{ "data": { "csf.allow": "203.0.113.10\n", "csf.deny": "203.0.113.20\n" } }
Field Type Required Description
data object no Map of filename to contents. If absent, the top-level object is used as the map directly.

Only filenames starting with csf. plus csfpre.sh and csfpost.sh are written; entries with empty/non-string values are skipped.

Response - 200 OK

{ "data": { "message": "Imported 2 files, CSF restarted" } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding.

Side effects

  • Runs csf -x (disable), writes accepted files to /etc/csf/<filename> (mode 0644), chmod +x on csfpre.sh and csfpost.sh, then csf -e (enable) and csf -r (restart).

Example

curl -X POST https://panel.example.com:2087/api/firewall/import \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": {"csf.allow": "203.0.113.10\n"}}'

GET /api/firewall/ipinfo

Returns detailed information about an IP as provided by firewall.GetIPInfo().

Guards: RequirePermission(db, "firewall_management")

Query parameters

Name Type Optional Description
ip string no The IP address to inspect.

Response - 200 OK

{ "data": { } }

The exact shape is determined by firewall.GetIPInfo(ip); it is returned verbatim inside data.

Errors

Status Code Meaning
400 bad_request ip query param missing.

Example

curl "https://panel.example.com:2087/api/firewall/ipinfo?ip=203.0.113.30" \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/logs

Returns recent firewall attack logs, newest first, limited by the limit query parameter.

Guards: RequirePermission(db, "firewall_management")

Query parameters

Name Type Optional Description
limit integer yes Max number of log entries. Defaults to 100; values outside 1-1000 are coerced back to 100.

Response - 200 OK

{ "data": [ ] }

data is an array of firewall.AttackLog entries (empty array when there are none).

Example

curl "https://panel.example.com:2087/api/firewall/logs?limit=50" \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/port/close

Closes a single port for a given protocol and direction in the firewall.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "port": 8080, "protocol": "tcp", "direction": "in" }
Field Type Required Description
port integer yes Port number, 1-65535.
protocol string yes tcp or udp.
direction string yes in or out.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding (e.g. invalid port, protocol, or direction).
500 firewall_error Closing the port failed.

Side effects

  • Calls firewall.ClosePort(port, protocol, direction), which edits CSF port configuration and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/port/close \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"port": 8080, "protocol": "tcp", "direction": "in"}'

POST /api/firewall/port/open

Opens a port or port range for a given protocol and direction in the firewall.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "port": 8080, "port_range": "40000:40100", "protocol": "tcp", "direction": "in" }
Field Type Required Description
port integer no Single port (legacy). Used only when port_range is empty and port > 0.
port_range string no Port range such as "40000:40100". Takes precedence over port.
protocol string yes tcp or udp.
direction string yes in or out.

At least one of port or port_range must be provided.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Body failed JSON binding, or neither port nor port_range supplied.
500 firewall_error Opening the port/range failed.

Side effects

  • Calls firewall.OpenPortRange(portStr, protocol, direction), which edits CSF port configuration and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/port/open \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"port_range": "40000:40100", "protocol": "tcp", "direction": "in"}'

GET /api/firewall/portinfo

Returns information about a specific port as provided by firewall.GetPortInfo().

Guards: RequirePermission(db, "firewall_management")

Query parameters

Name Type Optional Description
port integer no Port number, 1-65535.

Response - 200 OK

{ "data": { } }

The exact shape is determined by firewall.GetPortInfo(port); it is returned verbatim inside data.

Errors

Status Code Meaning
400 bad_request port query param missing, non-numeric, or outside 1-65535.

Example

curl "https://panel.example.com:2087/api/firewall/portinfo?port=443" \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/ports

Returns the list of firewall-configured ports as provided by firewall.GetPorts().

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { "ports": [ ] } }

The value of ports is determined by firewall.GetPorts().

Example

curl https://panel.example.com:2087/api/firewall/ports \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/restart

Restarts the CSF firewall.

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
500 firewall_error Restarting CSF failed.

Side effects

  • Calls firewall.Restart(), which restarts/reloads CSF (equivalent to csf -r).

Example

curl -X POST https://panel.example.com:2087/api/firewall/restart \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/rules

Returns the current allow and deny lists.

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { "allow": [ ], "deny": [ ] } }

allow comes from firewall.GetAllowList() and deny from firewall.GetDenyList().

Example

curl https://panel.example.com:2087/api/firewall/rules \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/settings

Returns the current CSF settings as provided by firewall.GetSettings().

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { } }

The exact shape is determined by firewall.GetSettings(); it is returned verbatim inside data.

Example

curl https://panel.example.com:2087/api/firewall/settings \
  -H "Authorization: Bearer $TOKEN"

PATCH /api/firewall/settings

Updates multiple CSF settings at once from a flat key/value map.

Guards: RequirePermission(db, "firewall_management")

Request body

A flat JSON object of setting key to string value.

{ "TCP_IN": "20,21,22,80,443", "DENY_IP_LIMIT": "200" }
Field Type Required Description
(any key) string n/a CSF setting name mapped to its new string value. The body binds as map[string]string.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding (not a string map).
500 firewall_error Applying the settings failed.

Side effects

  • Calls firewall.UpdateMultipleSettings(map), which writes the settings to CSF configuration and reloads CSF.

Example

curl -X PATCH https://panel.example.com:2087/api/firewall/settings \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"TCP_IN": "20,21,22,80,443"}'

POST /api/firewall/settings

Updates a single CSF setting by key and value.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "key": "TCP_IN", "value": "20,21,22,80,443" }
Field Type Required Description
key string yes CSF setting name. Must be non-empty.
value string no New value for the setting; may be an empty string.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Body failed JSON binding, or key is empty.
400 firewall_error Applying the setting failed.

Side effects

  • Calls firewall.UpdateSetting(key, value), which writes the setting to CSF configuration and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/settings \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"key": "TCP_IN", "value": "20,21,22,80,443"}'

GET /api/firewall/status

Returns the overall firewall status as provided by firewall.GetStatus().

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": { } }

The exact shape is determined by firewall.GetStatus(); it is returned verbatim inside data.

Example

curl https://panel.example.com:2087/api/firewall/status \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/superaccess

Returns the list of super-access IPs (entries in csf.ignore) as provided by firewall.GetSuperAccessList().

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": [ ] }

The exact shape is determined by firewall.GetSuperAccessList(); it is returned verbatim inside data.

Example

curl https://panel.example.com:2087/api/firewall/superaccess \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/superaccess

Adds an IP to the super-access list (csf.ignore) with an optional comment.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "ip": "string (required)", "comment": "string (optional)" }
Field Type Required Description
ip string yes IP address to grant super access.
comment string no Free-text note stored alongside the entry.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding (e.g. missing ip).
500 firewall_error Adding the super-access entry failed.

Side effects

  • Calls firewall.AddSuperAccess(ip, comment), which writes the IP into csf.ignore and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/superaccess \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ip": "203.0.113.40", "comment": "admin"}'

DELETE /api/firewall/superaccess/:ip

Removes an IP from the super-access list (csf.ignore).

Guards: RequirePermission(db, "firewall_management")

Path parameters

Name Type Description
ip string The IP to remove from super access.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 firewall_error Removing the super-access entry failed.

Side effects

  • Calls firewall.RemoveSuperAccess(ip), which removes the IP from csf.ignore and reloads CSF.

Example

curl -X DELETE https://panel.example.com:2087/api/firewall/superaccess/203.0.113.40 \
  -H "Authorization: Bearer $TOKEN"

GET /api/firewall/temp

Returns the current temporary blocks as provided by firewall.GetTempList().

Guards: RequirePermission(db, "firewall_management")

Response - 200 OK

{ "data": [ ] }

The exact shape is determined by firewall.GetTempList(); it is returned verbatim inside data.

Example

curl https://panel.example.com:2087/api/firewall/temp \
  -H "Authorization: Bearer $TOKEN"

DELETE /api/firewall/temp/:ip

Removes a temporary block for the given IP.

Guards: RequirePermission(db, "firewall_management")

Path parameters

Name Type Description
ip string The IP whose temporary block should be removed.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 firewall_error Removing the temporary block failed.

Side effects

  • Calls firewall.RemoveTemp(ip), which removes the temporary block and reloads CSF.

Example

curl -X DELETE https://panel.example.com:2087/api/firewall/temp/203.0.113.50 \
  -H "Authorization: Bearer $TOKEN"

POST /api/firewall/tempdeny

Adds a temporary deny (time-limited block) for an IP.

Guards: RequirePermission(db, "firewall_management")

Request body

{ "ip": "string (required)", "seconds": 3600, "comment": "string (optional)" }
Field Type Required Description
ip string yes IP address to block temporarily.
seconds integer yes Duration of the block in seconds.
comment string no Free-text note stored alongside the block.

Response - 200 OK

{ "data": { "success": true } }

Errors

Status Code Meaning
400 bad_request Request body failed JSON binding (e.g. missing ip or seconds).
400 firewall_error CSF rejected the temporary deny.

Side effects

  • Calls firewall.TempDeny(ip, seconds, comment), which adds a temporary deny entry (equivalent to csf -td) and reloads CSF.

Example

curl -X POST https://panel.example.com:2087/api/firewall/tempdeny \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ip": "203.0.113.50", "seconds": 3600, "comment": "rate limit"}'