Discord firewall rules as code with the RestoreCord API

Verification rules decide who gets into your server. Keeping them in a repository and syncing them through the API turns every change into a reviewed, reversible commit.

Short answer

Create a key with only SERVER_FIREWALL, store each rule as JSON with a targetType, operator, targetValue and an actions array, then POST new rules, PUT changed ones and DELETE removed ones against /api/v3/servers/{serverId}/firewall/rules. Toggle a rule with PATCH instead of deleting it.

Why manage the firewall from Git

The RestoreCord firewall runs on every verification, so a single careless rule can lock out your own staff or wave a raid straight in. Dashboard edits leave no review trail. A rules file in a repository gets a pull request, a reviewer and a commit you can revert, and one sync script can apply the same baseline to every server you run.

Anatomy of a rule

A rule matches one condition field and then applies an actions array. The array holds exactly one decision, ALLOW, BLOCK, REQUIRE_PASSWORD or BYPASS_ALL, plus up to five distinct GIVE_ROLE effects:

rules/staff-access.jsonjson
{
  "name": "Staff access",
  "targetType": "USERNAME",
  "operator": "CONTAINS",
  "targetValue": "/^staff[-_].+/i",
  "actions": [
    { "type": "ALLOW" },
    { "type": "GIVE_ROLE", "roleId": "123456789012345678" }
  ]
}
Condition fieldOperatorsValue
USERNAME, DOMAINIS, IS_NOT, CONTAINS, NOT_CONTAINSLiteral text or a regex pattern
ROLE, GUILDCONTAINS, NOT_CONTAINSDiscord role or server ID (GUILD needs Business or higher)
USER, IPIS, IS_NOTDiscord user ID or IPv4 address
IP_RANGEIS, IS_NOTIPv4 CIDR range, where IS means inside it
COUNTRY, CONTINENTIS, IS_NOTOne or more supported codes
ASNIS, IS_NOTNumeric ASN, with or without the AS prefix

BLOCK cannot carry GIVE_ROLE effects, and REQUIRE_PASSWORD needs an active firewall password first. Validate both in CI so a bad file fails the build instead of the sync.

A minimal sync loop

Every firewall route accepts a key with SERVER_FIREWALL. A sync script only needs four of them:

  1. GET /firewall/rules returns the live rules, their statistics and the passwords available to them.
  2. POST /firewall/rules creates each rule that exists in Git but not on the server.
  3. PUT /firewall/rules/{ruleId} updates rules whose JSON changed.
  4. DELETE /firewall/rules/{ruleId} removes rules deleted from the file.
sync-firewall.mjsjs
const base = "https://restorecord.com/api/v3/servers/" + process.env.SERVER_ID + "/firewall";
const headers = {
  Authorization: "Bearer " + process.env.RESTORECORD_KEY,
  "Content-Type": "application/json",
};

async function call(method, path, body) {
  const res = await fetch(base + path, { method, headers, body: body && JSON.stringify(body) });
  if (!res.ok) throw new Error(method + " " + path + ": " + res.status);
  return res.json();
}

export async function createMissing(desired, live) {
  const liveNames = new Set(live.map((r) => r.name));
  for (const rule of desired) {
    if (!liveNames.has(rule.name)) await call("POST", "/rules", rule);
  }
}

Responses include both the canonical actions array and legacy fields such as ruleType and assignedRoleId. Compare on actions so your diff stays stable.

Scheduling rule changes

Rules targeting TIME are rejected, so schedule changes from a cron job that toggles isActive with PATCH.

Temporary exceptions

For a single member stuck behind a rule, skip editing the file. POST /servers/{serverId}/bypass with a userId and a duration of 15m, 1h, 6h, 24h or 7d lets them through and then expires on its own.

Turn Discord bans into rules

On Premium, Business and Enterprise, GET /firewall/import-bans previews server bans that are not yet firewall rules, and a POST to the same path creates BLOCK rules for them. The bot needs the Discord Ban Members permission. Run it after a cleanup so banned accounts cannot verify their way back in.

After each sync, read GET /firewall/logs?limit=100 and verify once with a known staff account before you announce the change.

Pair this with a narrowly scoped key, stream firewall.block events into your mod tools, or head back to the developer home.

Put your firewall under version control

  1. Create a firewall-only key

    Grant SERVER_FIREWALL and nothing else, and allowlist the machine that runs your sync.

  2. Keep rules in a file

    Store each rule as JSON in your repository with targetType, operator, targetValue and actions.

  3. Diff against the live list

    GET the current rules, then create, update or delete only the ones that changed.

  4. Test with a staff account

    Verify with a known account after each sync and read the firewall logs before announcing the change.

Firewall API questions

Review firewall changes like code

One SERVER_FIREWALL key and a rules file give every server you run the same tested protection.