Inkbox

> # Documentation index
> Fetch the complete documentation index at: https://inkbox.ai/sitemap.xml
> Use this file to discover all available pages before exploring further.

---

# Mailbox Contact Rules
description: Per-mailbox allow and block rules — the whitelist or blacklist applied to inbound email

---


# Mailbox Contact Rules

Per-mailbox allow/block rules for inbound email. The mailbox's `filter_mode` field decides how the rule list is interpreted:

- **`filter_mode: "whitelist"`** — only senders matching an `allow` rule can deliver mail
- **`filter_mode: "blacklist"`** — every sender can deliver except those matching a `block` rule

Set `filter_mode` on the mailbox itself via `PATCH /mailboxes/{email_address}` — see [Mailboxes](/docs/api/mail/mailboxes). The rules below are interpreted against that mode.

Rules match on either a full email address (`match_type: "exact_email"`) or a bare domain (`match_type: "domain"`). A rule with `status: "paused"` reserves the target slot without taking effect, so you can stage policy changes without losing the uniqueness claim.

**Auth.** List, get, and create accept admin API keys, claimed agent keys, and Clerk JWT; unclaimed (mid-signup) agent keys are rejected. `PATCH`, `DELETE`, and the org-wide list are admin + JWT only.

For the org-wide audit view, see [List org mail contact rules](#list-org-mail-contact-rules).

---

## List contact rules `GET`


List contact rules for a mailbox, newest first. Returns both active and paused rules.

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `email_address` | string | Mailbox email address |

### Query parameters

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `action` | string | — | Filter by `"allow"` or `"block"` |
| `match_type` | string | — | Filter by `"exact_email"` or `"domain"` |
| `limit` | integer | 50 | Max rules (1–200) |
| `offset` | integer | 0 | Offset for pagination |

### Response (200)

```json
[
    {
      "id": "r1a2b3c4-d5e6-7890-abcd-ef1234567890",
      "mailbox_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "action": "block",
      "match_type": "domain",
      "match_target": "spam.example",
      "status": "active",
      "created_at": "2026-04-21T12:30:00Z",
      "updated_at": "2026-04-21T12:30:00Z"
    }
]
```

### Code examples

**cURL**

```bash
curl -X GET "https://inkbox.ai/api/v1/mail/mailboxes/EMAIL_ADDRESS/contact-rules" \\
    -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const response = await fetch(
    `https://inkbox.ai/api/v1/mail/mailboxes/${emailAddress}/contact-rules`,
    { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const rules = await response.json();
```

**Python**

```python
import requests

response = requests.get(
    f"https://inkbox.ai/api/v1/mail/mailboxes/{email_address}/contact-rules",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
rules = response.json()
```

---

## Create contact rule `POST`


Create an allow or block rule on a mailbox.

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `email_address` | string | Mailbox email address |

### Request body

| Field | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `action` | string | Yes | `"allow"` or `"block"` |
| `match_type` | string | Yes | `"exact_email"` (full address) or `"domain"` (bare domain like `gmail.com`) |
| `match_target` | string | Yes | Value to match against. For `exact_email`: a full address with one `@` and at least one dot after it. For `domain`: a lowercase ASCII bare domain (no leading `*@`, no leading `@`, no trailing `.`). Max 320 chars. |

New rules always start with `status: "active"` — to pause a rule use [Update contact rule](#update-contact-rule).

### Request example

```json
{
    "action": "block",
    "match_type": "domain",
    "match_target": "spam.example"
}
```

### Response (201)

Returns the created rule.

### Error responses

| Status | Description |
| :--- | :--- |
| 409 | A non-deleted rule with the same `(match_type, match_target)` already exists. Response body contains `existing_rule_id`. |
| 422 | `match_target` invalid for the given `match_type` (e.g. glob pattern, non-ASCII domain, missing dot) |

### Code examples

**cURL**

```bash
curl -X POST "https://inkbox.ai/api/v1/mail/mailboxes/EMAIL_ADDRESS/contact-rules" \\
    -H "X-API-Key: YOUR_API_KEY" \\
    -H "Content-Type: application/json" \\
    -d '{"action": "block", "match_type": "domain", "match_target": "spam.example"}'
```

**JavaScript**

```javascript
const response = await fetch(
    `https://inkbox.ai/api/v1/mail/mailboxes/${emailAddress}/contact-rules`,
    {
        method: "POST",
        headers: {
            "X-API-Key": "YOUR_API_KEY",
            "Content-Type": "application/json",
        },
        body: JSON.stringify({
            action: "block",
            match_type: "domain",
            match_target: "spam.example",
        }),
    }
);
const rule = await response.json();
```

**Python**

```python
import requests

response = requests.post(
    f"https://inkbox.ai/api/v1/mail/mailboxes/{email_address}/contact-rules",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "action": "block",
        "match_type": "domain",
        "match_target": "spam.example",
    },
)
rule = response.json()
```

---

## Get contact rule `GET`


Fetch a single contact rule by ID.

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `email_address` | string | Mailbox email address |
| `rule_id` | UUID | Rule ID |

### Code examples

**cURL**

```bash
curl -X GET "https://inkbox.ai/api/v1/mail/mailboxes/EMAIL_ADDRESS/contact-rules/RULE_ID" \\
    -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const response = await fetch(
    `https://inkbox.ai/api/v1/mail/mailboxes/${emailAddress}/contact-rules/${ruleId}`,
    { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const rule = await response.json();
```

**Python**

```python
import requests

response = requests.get(
    f"https://inkbox.ai/api/v1/mail/mailboxes/{email_address}/contact-rules/{rule_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
rule = response.json()
```

---

## Update contact rule `PATCH`


Update a rule's `action` or `status`.

> **Auth:** admin API key or Clerk JWT only.

`match_type` and `match_target` are immutable — delete the rule and create a new one to change the target.

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `email_address` | string | Mailbox email address |
| `rule_id` | UUID | Rule ID |

### Request body

At least one of:

| Field | Type | Description |
| :--- | :--- | :--- |
| `action` | string | `"allow"` or `"block"` |
| `status` | string | `"active"` or `"paused"` (only these two values are accepted on PATCH; use DELETE to remove a rule) |

Sending `null` for either field is a client error (422) — omit the field to leave it unchanged.

### Code examples

**cURL**

```bash
curl -X PATCH "https://inkbox.ai/api/v1/mail/mailboxes/EMAIL_ADDRESS/contact-rules/RULE_ID" \\
    -H "X-API-Key: YOUR_API_KEY" \\
    -H "Content-Type: application/json" \\
    -d '{"status": "paused"}'
```

**JavaScript**

```javascript
const response = await fetch(
    `https://inkbox.ai/api/v1/mail/mailboxes/${emailAddress}/contact-rules/${ruleId}`,
    {
        method: "PATCH",
        headers: {
            "X-API-Key": "YOUR_API_KEY",
            "Content-Type": "application/json",
        },
        body: JSON.stringify({ status: "paused" }),
    }
);
const rule = await response.json();
```

**Python**

```python
import requests

response = requests.patch(
    f"https://inkbox.ai/api/v1/mail/mailboxes/{email_address}/contact-rules/{rule_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"status": "paused"},
)
rule = response.json()
```

---

## Delete contact rule `DELETE`


Delete a contact rule. Returns `204 No Content` on success.

> **Auth:** admin API key or Clerk JWT only.

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `email_address` | string | Mailbox email address |
| `rule_id` | UUID | Rule ID |

### Code examples

**cURL**

```bash
curl -X DELETE "https://inkbox.ai/api/v1/mail/mailboxes/EMAIL_ADDRESS/contact-rules/RULE_ID" \\
    -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
await fetch(
    `https://inkbox.ai/api/v1/mail/mailboxes/${emailAddress}/contact-rules/${ruleId}`,
    {
        method: "DELETE",
        headers: { "X-API-Key": "YOUR_API_KEY" },
    }
);
```

**Python**

```python
import requests

requests.delete(
    f"https://inkbox.ai/api/v1/mail/mailboxes/{email_address}/contact-rules/{rule_id}",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
```

---

## List org mail contact rules `GET`


Org-wide aggregate list of mail contact rules across every mailbox the caller can see. Intended for admin dashboards that render rules org-wide without fanning out one per-mailbox request per mailbox.

> **Auth:** admin API key or Clerk JWT only.

Results are ordered `created_at` descending, with `id` as a stable tiebreaker so pagination stays consistent when rules from different mailboxes share a microsecond.

### Query parameters

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `mailbox_id` | UUID | — | Narrow to a single mailbox; omit to list across every mailbox in the org |
| `action` | string | — | Filter by `"allow"` or `"block"` |
| `match_type` | string | — | Filter by `"exact_email"` or `"domain"` |
| `limit` | integer | 50 | Max rules (1–200) |
| `offset` | integer | 0 | Offset for pagination |

### Response (200)

Returns an array of [contact rule objects](#contact-rule-object) — same shape as the per-mailbox list.

### Code examples

**cURL**

```bash
curl -X GET "https://inkbox.ai/api/v1/mail/contact-rules?action=block&limit=100" \\
    -H "X-API-Key: YOUR_ADMIN_API_KEY"
```

**JavaScript**

```javascript
const response = await fetch(
    "https://inkbox.ai/api/v1/mail/contact-rules?action=block&limit=100",
    { headers: { "X-API-Key": "YOUR_ADMIN_API_KEY" } }
);
const rules = await response.json();
```

**Python**

```python
import requests

response = requests.get(
    "https://inkbox.ai/api/v1/mail/contact-rules",
    headers={"X-API-Key": "YOUR_ADMIN_API_KEY"},
    params={"action": "block", "limit": 100},
)
rules = response.json()
```

---

## Contact rule object

| Field | Type | Description |
| :--- | :--- | :--- |
| `id` | UUID | Unique rule identifier |
| `mailbox_id` | UUID | Owning mailbox |
| `action` | string | `"allow"` or `"block"` |
| `match_type` | string | `"exact_email"` or `"domain"` |
| `match_target` | string | Canonicalized match value |
| `status` | string | `"active"`, `"paused"`, or `"deleted"` |
| `created_at` | string | Creation timestamp (ISO 8601) |
| `updated_at` | string | Last-updated timestamp (ISO 8601) |

## Additional resources

- [Filtering guide](/docs/capabilities/filtering) — narrative walk-through of whitelist/blacklist semantics across mail and phone
- [Mailboxes](/docs/api/mail/mailboxes) — includes the `filter_mode` field that interprets these rules
- [Phone contact rules](/docs/api/phone/contact-rules) — the phone-side equivalent
