Firewall API

The OophiCloud Firewall API lets external platforms programmatically manage UFW (Uncomplicated Firewall) rules on the host server. Use it to automate IP allowlisting, block malicious sources, or integrate firewall control into your own orchestration pipelines.

Base URLhttps://<your-server>
API prefix/api/v1
AuthBearer token (API key)
FormatJSON request & response
TLSRequired in production
All /api/v1/firewall/* endpoints require a valid API key in the Authorization header. Keys are issued by a server admin through the Admin UI or the admin API.

Authentication

Every request must include your API key as a Bearer token in the Authorization header.

Authorization: Bearer oophi_a1b2c3d4e5f6...
API keys are shown only once at creation time. Store yours in a secret manager (e.g. AWS Secrets Manager, Vault, GitHub Actions secrets). If lost, revoke the key and generate a new one.

Key lifecycle

ActionEndpointAuth required
Create keyPOST /api/admin/api-keysAdmin session
List keysGET /api/admin/api-keysAdmin session
Revoke keyDELETE /api/admin/api-keys/:idAdmin session

Admin-session endpoints require a logged-in admin browser session (cookie), not an API key. They are intended for use through the Admin UI or internal tooling only.

Issuing API Keys

An admin must create a key before any external system can call the Firewall API.

Create a key

POST /api/admin/api-keys
Content-Type: application/json

{
  "name": "my-integration"
}

Response — the raw key is returned only here:

{
  "id":        "a3f8e1c2d4b6",
  "name":      "my-integration",
  "key":       "oophi_a1b2c3d4e5f6...",
  "createdAt": "2026-05-11T00:00:00.000Z"
}

List keys

GET /api/admin/api-keys

Returns all keys with status. The raw key value is never returned after creation.

{
  "keys": [
    {
      "id":         "a3f8e1c2d4b6",
      "name":       "my-integration",
      "prefix":     "oophi_a1b2c3...",
      "createdBy":  "admin",
      "createdAt":  "2026-05-11T00:00:00.000Z",
      "lastUsed":   "2026-05-11T01:23:45.000Z",
      "revokedAt":  null
    }
  ]
}

Revoke a key

DELETE /api/admin/api-keys/a3f8e1c2d4b6
{ "success": true, "message": "API key \"my-integration\" revoked" }

Error Codes

HTTP statusMeaning
200Success
201Rule created / key created
400Bad request — invalid or missing parameters
401Missing or invalid API key
500UFW command failed — check server logs

All error bodies follow the shape:

{ "error": "Human-readable description" }

List Firewall Rules

GET /api/v1/firewall/rules Bearer key

Returns all active UFW rules as structured JSON.

Request

No body or query parameters required.

Response 200

{
  "rules": [
    {
      "number":    1,
      "to":        "22/tcp",
      "action":    "ALLOW",
      "direction": "IN",
      "from":      "Anywhere"
    },
    {
      "number":    2,
      "to":        "Anywhere",
      "action":    "DENY",
      "direction": "IN",
      "from":      "203.0.113.45"
    }
  ]
}

Add a Firewall Rule

POST /api/v1/firewall/rules Bearer key

Creates a new UFW allow or deny rule. You may specify an IP, a port, or both.

Request body

FieldTypeRequiredDescription
action string required "allow" or "deny"
ip string optional* IPv4 address or CIDR block (e.g. "1.2.3.4" or "10.0.0.0/8")
port number optional* TCP/UDP port (1–65535)

* At least one of ip or port must be supplied.

Examples

Block a single IP:

{
  "action": "deny",
  "ip":     "203.0.113.45"
}

Allow a CIDR range on port 443:

{
  "action": "allow",
  "ip":     "10.0.0.0/8",
  "port":   443
}

Open a port for everyone:

{
  "action": "allow",
  "port":   8080
}

Response 201

{ "success": true, "output": "Rule added" }

Delete a Firewall Rule

DELETE /api/v1/firewall/rules/:number Bearer key

Removes a UFW rule by its rule number. Use List Rules to get the current number of each rule.

Rule numbers shift after every deletion. Always call List Rules immediately before deleting to confirm the correct number.

Path parameter

ParameterTypeDescription
numberinteger ≥ 1Rule number from GET /api/v1/firewall/rules

Response 200

{ "success": true, "output": "Deleting:" }

cURL Examples

List rules

curl -s https://your-server/api/v1/firewall/rules \
  -H "Authorization: Bearer oophi_YOUR_KEY" | jq .

Block an IP

curl -s -X POST https://your-server/api/v1/firewall/rules \
  -H "Authorization: Bearer oophi_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"deny","ip":"203.0.113.45"}'

Delete rule #3

curl -s -X DELETE https://your-server/api/v1/firewall/rules/3 \
  -H "Authorization: Bearer oophi_YOUR_KEY"

JavaScript / Node.js

Drop-in SDK class that works in Node.js and modern browsers.

class OophiFirewall {
  constructor(baseUrl, apiKey) {
    this.base = baseUrl.replace(/\/$/, '');
    this.headers = {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type':  'application/json'
    };
  }

  async #req(method, path, body) {
    const r = await fetch(`${this.base}${path}`, {
      method,
      headers: this.headers,
      body: body ? JSON.stringify(body) : undefined
    });
    const json = await r.json();
    if (!r.ok) throw new Error(json.error || r.statusText);
    return json;
  }

  /** Returns an array of rule objects */
  listRules() {
    return this.#req('GET', '/api/v1/firewall/rules')
      .then(d => d.rules);
  }

  /** action: "allow"|"deny", ip?: string, port?: number */
  addRule(action, ip, port) {
    return this.#req('POST', '/api/v1/firewall/rules', { action, ip, port });
  }

  /** Remove a rule by its number (from listRules) */
  deleteRule(number) {
    return this.#req('DELETE', `/api/v1/firewall/rules/${number}`);
  }
}

// Usage
const fw = new OophiFirewall('https://your-server', 'oophi_YOUR_KEY');

// Block a bad actor
await fw.addRule('deny', '203.0.113.45');

// List and then delete the first deny rule
const rules = await fw.listRules();
const target = rules.find(r => r.action === 'DENY' && r.from === '203.0.113.45');
if (target) await fw.deleteRule(target.number);

Python

Using the standard requests library (install with pip install requests).

import requests

class OophiFirewall:
    def __init__(self, base_url: str, api_key: str):
        self.base = base_url.rstrip("/")
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type":  "application/json",
        })

    def _req(self, method, path, **kwargs):
        r = self.session.request(method, self.base + path, **kwargs)
        r.raise_for_status()
        return r.json()

    def list_rules(self):
        """Returns list of rule dicts."""
        return self._req("GET", "/api/v1/firewall/rules")["rules"]

    def add_rule(self, action: str, ip: str = None, port: int = None):
        """action: 'allow' or 'deny'"""
        body = {"action": action}
        if ip:   body["ip"]   = ip
        if port: body["port"] = port
        return self._req("POST", "/api/v1/firewall/rules", json=body)

    def delete_rule(self, number: int):
        return self._req("DELETE", f"/api/v1/firewall/rules/{number}")


# Usage
fw = OophiFirewall("https://your-server", "oophi_YOUR_KEY")

# Block a range
fw.add_rule("deny", ip="198.51.100.0/24")

# Clean up: find and remove the rule
rules = fw.list_rules()
for rule in rules:
    if rule["from"] == "198.51.100.0/24" and rule["action"] == "DENY":
        fw.delete_rule(rule["number"])
        break