# Create a shield rule

> Allow, block, or reroute matching mail before it is stored.

`POST https://inboundr.net/api/v1/shield-rules`

Creates a [shield rule](/concepts/shield). New rules are appended **last** in the
evaluation order, so adding one can never change what your existing rules do —
move it up with [Reorder](/api-reference/shield-rules/update) once you've
confirmed it matches what you meant.

<ParamField body="name" type="string" required>
  Short label, up to 60 characters. Shown in the console and on every block
  record the rule produces.
</ParamField>
<ParamField body="action" type="string" required>
  One of `allow`, `block`, or `route`.

  - `allow` — deliver normally and stop. Put one above a broad `block` to carve
    out an exception.
  - `block` — **permanently drop the message.** It is never stored or
    delivered, and only an envelope record is kept
    (see [List blocks](/concepts/shield#reviewing-what-was-blocked)); the body
    cannot be recovered. It **does** still count against your monthly
    allotment — the message was received before any rule could look at it.
  - `route` — deliver to `endpointIds` *instead of* the address's own
    destinations.
</ParamField>
<ParamField body="conditions" type="array" required>
  1–8 conditions. **All of them must match** (AND). For "either/or", create two
  rules.

  <Expandable title="condition">
    <ParamField body="field" type="string" required>
      `from`, `from_domain`, `to`, `subject`, `body`, `has_attachment`,
      `attachment_name`, `attachment_type`, `spam_verdict`, `spf_verdict`,
      or `dkim_verdict`.
    </ParamField>
    <ParamField body="operator" type="string" required>
      `contains`, `not_contains`, `equals`, `starts_with`, `ends_with`,
      `is_true`, or `is_false`. Not every operator suits every field — see the
      table in [Shield](/concepts/shield#fields-and-operators).
    </ParamField>
    <ParamField body="value" type="string">
      Compared case-insensitively. Omit for `is_true` / `is_false`.
    </ParamField>
  </Expandable>
</ParamField>
<ParamField body="endpointIds" type="array">
  `route` only. At most one webhook and one email destination, the same
  fan-out limit addresses live under. An **empty** array quarantines: the
  message is stored and readable over the API, and delivered nowhere.
</ParamField>
<ParamField body="domainId" type="string">
  Limit the rule to one domain (`dom_…`). Omit both scope fields to apply it to
  every domain on the account.
</ParamField>
<ParamField body="addressId" type="string">
  Limit the rule to one address route (`addr_…`). Mutually exclusive with
  `domainId`.
</ParamField>

<ResponseExample>
```json 201
{
  "id": "gr_123",
  "name": "Drop flagged spam",
  "action": "block",
  "priority": 2,
  "enabled": true,
  "scope": "account",
  "domainId": null,
  "addressId": null,
  "conditions": [
    { "field": "spam_verdict", "operator": "equals", "value": "FAIL" }
  ],
  "endpointIds": [],
  "createdAt": "2026-07-20T10:00:00.000Z"
}
```
</ResponseExample>

<Warning>
  A `block` rule deletes mail. There is no quarantine folder to recover it from
  and no body to inspect afterwards — only the sender, recipient, and subject in
  the block log. Test a new rule as `route` with an empty `endpointIds` first if
  you want to see what it catches before it starts destroying anything.
</Warning>

<Note>
  Plans cap how many rules an account may hold (3 on Free, 200 on Scale). Over
  the cap, this returns `402`.
</Note>
