Using the PortWall API: examples for common tasks

PortWall's management API lets scripts do what the console does. Create a key on the console's API Keys page, send it in the X-Api-Key header to http://127.0.0.1:5000/api on the server, and use the examples here to check protection, list sites, change a site's mode, block or allowlist addresses, export attacks and back up the configuration.

What the API is for

The PortWall API lets a script do what you do in the console: check that protection is working, list your sites, switch a site between watching and blocking, block or allowlist addresses, export attacks and back up the configuration. It is the same API the console itself uses. Every endpoint, with the role it needs and every field it takes and returns, is in the API reference.

Every example on this page was run against a PortWall server before it was published. The examples use PowerShell, which every Windows server has; curl works too.

Where the API answers

  • On Windows, the API answers only on the server itself, at http://127.0.0.1:5000/api/. Run your scripts on the PortWall server, for example from Task Scheduler. Nothing outside the server can reach it.
  • On the Linux appliance, scripts on the appliance use the same address. From another machine, use the console's address, https://<appliance address>:9443/api/. The console's certificate is self-signed, so the script must trust it: compare its fingerprint with the one the appliance shows on its screen.

Getting a key

  1. In the console, open API Keys.
  2. Give the key a name that says what it is for (for example nightly-backup), and pick a role:
    • Viewer reads everything and changes nothing. Use it for monitoring and reports.
    • Admin can also change settings, block addresses and export the configuration.
  3. Click Create key and copy the key straight away. It is shown once only.

Use one key per script, so you can revoke one without breaking the others. See API keys for scripts and integrations for revoking and rotating keys.

Starting a script

Every example below starts from these two lines. Replace the key with yours:

$api = 'http://127.0.0.1:5000/api'
$headers = @{ 'X-Api-Key' = 'pwk_your_key_here' }

Run the examples in Windows PowerShell or PowerShell 7. Keep the key out of shared scripts: read it from a file only Administrators can open, for example $headers = @{ 'X-Api-Key' = (Get-Content C:\scripts\portwall-key.txt -Raw).Trim() }.

In Windows PowerShell, put a list the API returns into a variable before you pipe it, as the examples do. Piping Invoke-RestMethod straight into Select-Object passes the whole list as one item.

Check that protection is working

Needs a Viewer key.

$status = Invoke-RestMethod "$api/protection-status" -Headers $headers
$status.allHealthy
$status.summary
$status.problems
$status.features | Select-Object name, enabled, enforcing, severity

allHealthy is True when every protection that is turned on is enforcing. summary says the same in a sentence, for example 11 protections enabled and enforcing. problems lists anything that is on but not working, with the fix. These are the same checks as the Overview's Protection status cards, so a monitoring system can alert on allHealthy being False.

Check the licence

Needs a Viewer key.

$licence = Invoke-RestMethod "$api/license" -Headers $headers
$licence | Select-Object state, tier, enforcementActive

state is Licensed, Grace or Unlicensed; enforcementActive is False when blocking is disarmed. See Licences, editions and licence states.

List your sites and their modes

Needs a Viewer key.

$sites = Invoke-RestMethod "$api/sites/all" -Headers $headers
$sites | Select-Object siteName, mode

mode is one of:

Value In the console
Off Off
DetectionOnly Detection only: attacks are logged, nothing is blocked
On Blocking

Switch a site to blocking

Needs an Admin key. This puts one or more sites in a mode and waits until the change is in force:

$body = @{ mode = 'On'; sites = @('shop.example.com') } | ConvertTo-Json
$result = Invoke-RestMethod "$api/sites/mode" -Method Post -Headers $headers -ContentType 'application/json' -Body $body
if ($result.applying) {
    do {
        Start-Sleep -Seconds 2
        $apply = Invoke-RestMethod "$api/config-apply/status" -Headers $headers
    } while ($apply.completed -lt $result.applySeq)
    $apply.outcome
}

Use the site names from the list above. The reply says how many sites changed; when nothing needed changing it does not apply anything, and the script skips the wait. The change is applied in the background, usually within seconds, and outcome is applied when it is in force. Use DetectionOnly to go back to watching. The change is recorded in the audit log, as a change made in the console would be.

Block an address

Needs an Admin key. To block an address for a while, give the minutes:

$body = @{ ip = '203.0.113.50'; ttlMinutes = 60; reason = 'scraping the price list' } | ConvertTo-Json
Invoke-RestMethod "$api/blocks" -Method Post -Headers $headers -ContentType 'application/json' -Body $body

To block it until you remove the block yourself:

$body = @{ ip = '203.0.113.51'; permanent = $true; reason = 'repeat offender' } | ConvertTo-Json
Invoke-RestMethod "$api/blocks" -Method Post -Headers $headers -ContentType 'application/json' -Body $body

To see what is blocked, and to remove a block:

$blocks = Invoke-RestMethod "$api/blocks" -Headers $headers
$blocks | Select-Object ip, reason, expiresAt, country
Invoke-RestMethod "$api/blocks/203.0.113.50" -Method Delete -Headers $headers

A block takes effect within moments. An address on the allowlist cannot be blocked: the API answers 409. A permanent block shows an empty expiresAt.

Allowlist an address or range

Needs an Admin key.

$body = @{ ipOrCidr = '198.51.100.0/24'; scope = 'Both'; reason = 'head office' } | ConvertTo-Json
Invoke-RestMethod "$api/allowlist" -Method Post -Headers $headers -ContentType 'application/json' -Body $body

scope is Waf (never blocked by the WAF or by blocks), Feeds (never blocked by threat-intelligence feeds) or Both. To list the allowlist, and to remove an entry:

$allowed = Invoke-RestMethod "$api/allowlist" -Headers $headers
$allowed | Select-Object ipOrCidr, scope, reason
Invoke-RestMethod "$api/allowlist/198.51.100.0/24" -Method Delete -Headers $headers

See Allowlist and outbound (egress) control.

Export recent attacks to a spreadsheet

Needs a Viewer key. The attack feed comes 200 entries at a time, newest first. This saves the latest 1,000 to a CSV file:

$all = @(); $skip = 0
do {
    $page = Invoke-RestMethod "$api/events?skip=$skip&take=200" -Headers $headers
    $all += $page.items
    $skip += 200
} while ($page.hasMore -and $skip -lt 1000)
$all | Select-Object timestamp, source, country, site, kind, anomalyScore, ruleIds |
    Export-Csv C:\scripts\portwall-attacks.csv -NoTypeInformation

total in each page is the number of attacks recorded. To find the attacks from one address or on one site, add q: "$api/events?q=203.0.113.50&take=200". It matches the address, the site name, the kind of attack and the rule ID.

Fetch only the attacks since a time

Needs a Viewer key. Add since, a time in UTC, to get only the attacks at or after it. This fetches the last 24 hours:

$since = (Get-Date).ToUniversalTime().AddHours(-24).ToString('yyyy-MM-ddTHH:mm:ssZ')
$recent = Invoke-RestMethod "$api/events?since=$since&take=200" -Headers $headers
$recent.total
$recent.items | Select-Object timestamp, source, site, kind

total counts only the attacks since that time, and skip pages through them as above. A script that runs every hour can save the newest timestamp it saw and pass it as since next time. Because since includes attacks at exactly that time, the last attack of the previous run comes back once more: skip the attacks whose timestamp is the one you saved.

Back up the configuration every night

Needs an Admin key. This saves the whole configuration, the same file as Download backup on the Backup & Restore page:

New-Item -ItemType Directory -Force C:\portwall-backups | Out-Null
Invoke-WebRequest "$api/config/export" -Headers $headers -UseBasicParsing `
    -OutFile "C:\portwall-backups\portwall-config-$(Get-Date -Format yyyy-MM-dd).json"

Save it as a script and run it daily from Task Scheduler. Keep the backups somewhere only Administrators can read, and copy them off the server too. See Back up, restore and move PortWall for restoring.

With curl

curl works too (it is built into Windows Server 2019 and later). These are for Command Prompt, or a Linux shell on the appliance; in PowerShell, use the examples above (PowerShell's own curl is a different command, and it passes quotes inside JSON to curl.exe differently):

curl -H "X-Api-Key: pwk_your_key_here" http://127.0.0.1:5000/api/protection-status
curl -X POST -H "X-Api-Key: pwk_your_key_here" -H "Content-Type: application/json" -d "{\"ip\":\"203.0.113.50\",\"ttlMinutes\":60}" http://127.0.0.1:5000/api/blocks

Errors you may see

Answer Meaning
401 The key is missing, wrong or revoked.
403 The key's role cannot do this (a Viewer key trying a change), or the request came from an address the console does not accept.
400 Something in the request is not valid, for example an address that is not an IP address. The reply says what.
404 The site, entry or address is not there.
409 The change conflicts with something, for example blocking an allowlisted address.

With a 400 or 409, the reply is JSON with one field, error, that says what went wrong and what to change, for example {"error": "Invalid IP address."}. A 404 often has no text at all. In PowerShell, read the reply like this:

try {
    $body = @{ ip = 'not-an-address'; ttlMinutes = 60 } | ConvertTo-Json
    Invoke-RestMethod "$api/blocks" -Method Post -Headers $headers -ContentType 'application/json' -Body $body
} catch {
    $reply = $_.ErrorDetails.Message
    if (-not $reply) {
        # Windows PowerShell 5.1 leaves the reply in the response itself
        $reply = (New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())).ReadToEnd()
    }
    [int]$_.Exception.Response.StatusCode
    ($reply | ConvertFrom-Json).error
}

This prints 400 and Invalid IP address. It works in Windows PowerShell 5.1 and in PowerShell 7.

The full API reference

The API reference lists every endpoint scripts can use: what it does, the role it needs, and every field it takes and returns. It also covers the tenant API, for hosting providers whose customers manage their own sites. For something the API cannot do yet, write to [email protected] with what you want to automate.

Updated 2026-10-27Something unclear or missing? Tell us.