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.

---

# iMessage Contact Rules
description: Per-identity allow and block rules for inbound iMessage traffic

---


# iMessage Contact Rules

Per-identity allow/block rules for inbound iMessage traffic. Because there is no per-identity iMessage number — conversations ride a shared pool of lines — rules attach to the **agent identity** itself and are addressed by `agent_handle`. The identity's `imessage_filter_mode` field decides how the rule list is interpreted:

- **`imessage_filter_mode: "whitelist"`** — only numbers matching an `allow` rule can reach the agent
- **`imessage_filter_mode: "blacklist"`** — every number can reach the agent except those matching a `block` rule

Set `imessage_filter_mode` on the identity via `PATCH /identities/{agent_handle}` — see [Manage identities](/docs/api/identities/manage). Rules match on exact E.164 phone numbers only in v1 (`match_type: "exact_number"`); the field is wired in to stay forward-compatible when additional match types are added.

A rule with `status: "paused"` has no effect, but still counts as the rule for its number. Creating a duplicate returns 409.

When a number is blocked: inbound messages are stored but never delivered to the agent. No webhooks fire, identity-scoped keys never see them, and [admin API keys](/docs/api-keys) or the [Inkbox Console](https://inkbox.ai/console) can audit them with [`is_blocked=true`](/docs/api/imessage/messages#list-messages). Inbound tapbacks are not recorded, outbound sends and tapbacks to the number return `403`, and the [router](/docs/api/imessage/router) gives the blocked human the same generic response as for an unknown agent.

**Auth.** List, get, and create accept [admin API keys](/docs/api-keys) and claimed agent keys; unclaimed (mid-signup) agent keys are rejected. `PATCH`, `DELETE`, and the org-wide list require an admin-scoped API key, or you can manage them as a user in the [Inkbox Console](https://inkbox.ai/console).

---

## List contact rules `GET`


List contact rules for an agent identity, newest first.

An identity-scoped API key may only address its own identity's `agent_handle` — any other handle returns `403` (this applies to list, get, and create alike).

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agent_handle` | string | The identity's handle, with or without the leading `@` |

### Query parameters

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `action` | string | — | Filter by `"allow"` or `"block"` |
| `match_type` | string | — | Filter by match type (`"exact_number"` is the only value in v1) |
| `limit` | integer | 50 | 1–200 |
| `offset` | integer | 0 | Offset for pagination |

### Response (200)

```json
[
    {
      "id": "r1a2b3c4-d5e6-7890-abcd-ef1234567890",
      "agent_identity_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "action": "block",
      "match_type": "exact_number",
      "match_target": "+15555550999",
      "status": "active",
      "created_at": "2026-06-09T12:30:00Z",
      "updated_at": "2026-06-09T12:30:00Z"
    }
]
```

### Code examples

**cURL**

```bash
curl "https://inkbox.ai/api/v1/imessage/identities/my-agent/contact-rules" \\
    -H "X-API-Key: YOUR_API_KEY"
```

**Python**

```python
rules = inkbox.imessage_contact_rules.list("my-agent")
for rule in rules:
    print(rule.action, rule.match_target, rule.status)
```

**TypeScript**

```typescript
const rules = await inkbox.imessageContactRules.list("my-agent");
for (const rule of rules) {
    console.log(rule.action, rule.matchTarget, rule.status);
}
```

---

## Create contact rule `POST`


Add an allow or block rule for an agent identity. New rules are always created `active`; use [update](#update-contact-rule) to pause one.

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agent_handle` | string | The identity's handle |

### Request body

| Field | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `action` | string | Yes | `"allow"` or `"block"` |
| `match_target` | string | Yes | Phone number to match, normalized to E.164 |
| `match_type` | string | No | Defaults to `"exact_number"` (the only value in v1) |

### Request example

```json
{
    "action": "block",
    "match_target": "+15555550999"
}
```

### Response (201)

Returns the new rule. See [Contact rule object](#contact-rule-object).

### Error responses

| Status | Description |
| :--- | :--- |
| 403 | Identity-scoped key addressed a different identity's handle |
| 404 | Identity not found, or not visible to the caller |
| 409 | `rule_already_exists` — a rule with the same `(match_type, match_target)` already exists on this identity; the response includes `existing_rule_id` |
| 422 | Invalid `action`, `match_type`, or `match_target` |

### Code examples

**cURL**

```bash
curl -X POST "https://inkbox.ai/api/v1/imessage/identities/my-agent/contact-rules" \\
    -H "X-API-Key: YOUR_API_KEY" \\
    -H "Content-Type: application/json" \\
    -d '{"action": "block", "match_target": "+15555550999"}'
```

**Python**

```python
rule = inkbox.imessage_contact_rules.create(
    "my-agent",
    action="block",
    match_target="+15555550999",
)
```

**TypeScript**

```typescript
const rule = await inkbox.imessageContactRules.create("my-agent", {
    action: "block",
    matchTarget: "+15555550999",
});
```

---

## Get contact rule `GET`


Fetch a single rule by ID.

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agent_handle` | string | The identity's handle |
| `rule_id` | UUID | Rule ID |

### Response (200)

Returns the rule. See [Contact rule object](#contact-rule-object).

### Error responses

| Status | Description |
| :--- | :--- |
| 403 | Identity-scoped key addressed a different identity's handle |
| 404 | Rule not found, or it belongs to a different identity |

---

## Update contact rule `PATCH`


Change a rule's `action` or `status`. Requires an admin API key, or manage rules from the [Inkbox Console](https://inkbox.ai/console).

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agent_handle` | string | The identity's handle |
| `rule_id` | UUID | Rule ID |

### Request body

At least one field is required; fields you omit are left unchanged.

| Field | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `action` | string | No | `"allow"` or `"block"` |
| `status` | string | No | `"active"` or `"paused"` |

### Request example

```json
{
    "status": "paused"
}
```

### Response (200)

Returns the updated rule.

### Error responses

| Status | Description |
| :--- | :--- |
| 403 | Caller is not admin-scoped |
| 404 | Rule not found, or it belongs to a different identity |
| 422 | Empty body, or a field explicitly set to null |

---

## Delete contact rule `DELETE`


Delete a rule. Requires an admin API key, or manage rules from the [Inkbox Console](https://inkbox.ai/console).

### Path parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| `agent_handle` | string | The identity's handle |
| `rule_id` | UUID | Rule ID |

### Response (204)

No content.

### Error responses

| Status | Description |
| :--- | :--- |
| 403 | Caller is not admin-scoped |
| 404 | Rule not found, or it belongs to a different identity |

---

## List org iMessage contact rules `GET`


Org-wide aggregate list of iMessage contact rules across every identity. Requires an admin API key, or browse rules in the [Inkbox Console](https://inkbox.ai/console).

### Query parameters

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `agent_identity_id` | UUID | — | Narrow to one identity by ID |
| `action` | string | — | Filter by `"allow"` or `"block"` |
| `match_type` | string | — | Filter by match type (`"exact_number"` is the only value in v1) |
| `limit` | integer | 50 | 1–200 |
| `offset` | integer | 0 | Offset for pagination |

### Response (200)

Returns a `list[ContactRule]` ordered newest first.

### Code examples

**cURL**

```bash
curl "https://inkbox.ai/api/v1/imessage/contact-rules?action=block" \\
    -H "X-API-Key: YOUR_API_KEY"
```

**Python**

```python
rules = inkbox.imessage_contact_rules.list_all(action="block")
```

**TypeScript**

```typescript
const rules = await inkbox.imessageContactRules.listAll({ action: "block" });
```

---

## Contact rule object

| Field | Type | Description |
| :--- | :--- | :--- |
| `id` | string (UUID) | Rule ID |
| `agent_identity_id` | string (UUID) | The identity this rule protects |
| `action` | string | `"allow"` or `"block"` |
| `match_type` | string | `"exact_number"` (the only value in v1) |
| `match_target` | string | The matched phone number in E.164 format |
| `status` | string | `"active"` or `"paused"` |
| `created_at` | string (ISO 8601) | Creation timestamp |
| `updated_at` | string (ISO 8601) | Last update timestamp |

## Additional resources

- [iMessage guide — filtering](/docs/capabilities/imessage#filtering-who-can-reach-your-agent)
- [Manage identities](/docs/api/identities/manage) — set `imessage_filter_mode`
- [Phone contact rules](/docs/api/phone/contact-rules) — the per-number equivalent for calls and texts
