## What are Permissions?

`Permissions` let you restrict what an API key can do. By default, an API key has full access within its scope (organization, pod, or inbox). When you provide a `permissions` object, it acts as a **whitelist**: only the permissions you explicitly set to `true` are granted. Everything else is denied.

This gives you fine-grained control over which resources and operations each key can access, on top of the existing scope-based isolation provided by [pod-scoped](/content/pods/index.html) and [inbox-scoped](/content/docs/inboxes#inbox-scoped-api-keys/index.html) keys.

## How Permissions Work

### Whitelist model

When you create an API key with a `permissions` object, it switches from “full access” mode to “whitelist” mode:

- **No `permissions` field**: The key has full access within its scope. This is the default and is backward compatible with existing keys.
- **`permissions` present**: Only permissions set to `true` are allowed. Any permission that is omitted or set to `false` is denied.

##### Backward compatibility

Existing API keys without a `permissions` field continue to work exactly as before with full access. The whitelist only activates when you explicitly provide the `permissions` object.

### Intersection with scope

Permissions are intersected with the key’s scope. A key scoped to a single inbox cannot gain organization-level capabilities (like `inbox_create` or `domain_create`) even if those permissions are set to `true`. The effective permissions are always the intersection of what the scope allows and what the `permissions` object grants.

### Privilege escalation protection

A restricted API key cannot create a child key with more permissions than itself. When creating a new key, the child’s permissions are automatically constrained to the parent’s effective permissions. This prevents privilege escalation through key creation.

## Permissions Reference

### Inboxes

| Permission         | Description                  |
|--------------------|------------------------------|
| `inbox_read`       | Read inbox details           |
| `inbox_create`     | Create new inboxes           |
| `inbox_update`     | Update inbox settings         |
| `inbox_delete`     | Delete inboxes               |

### Threads

| Permission         | Description                  |
|--------------------|------------------------------|
| `thread_read`      | Read threads                 |
| `thread_delete`    | Delete threads               |

### Messages

| Permission         | Description                  |
|--------------------|------------------------------|
| `message_read`      | Read messages                |
| `message_send`      | Send messages                |
| `message_update`    | Update message labels        |

### Label Visibility

| Permission         | Description                  |
|--------------------|------------------------------|
| `label_spam_read`   | Access messages labeled as spam |
| `label_blocked_read`| Access messages labeled as blocked |
| `label_trash_read`  | Access messages labeled as trash |

When a label visibility permission is denied, items with that label are automatically excluded from list results and return “not found” on direct access. For example, setting `label_spam_read` to `false` means the key will never see spam messages in any listing or lookup.

##### Event subscriptions

Label visibility permissions also control whether an API key can subscribe to the corresponding event types on [webhooks](/content/docs/events/index.html) and [WebSockets](/content/docs/websockets/index.html). An API key without `label_spam_read` cannot create a webhook or WebSocket subscription for `message.received.spam` events, and an API key without `label_blocked_read` cannot subscribe to `message.received.blocked` events.

### Drafts

| Permission         | Description                  |
|--------------------|------------------------------|
| `draft_read`       | Read drafts                  |
| `draft_create`     | Create drafts                |
| `draft_update`     | Update drafts                |
| `draft_delete`     | Delete drafts                |
| `draft_send`       | Send drafts                  |

### Webhooks

| Permission         | Description                  |
|--------------------|------------------------------|
| `webhook_read`      | Read webhook configurations   |
| `webhook_create`    | Create webhooks              |
| `webhook_update`    | Update webhooks              |
| `webhook_delete`    | Delete webhooks              |

### Domains

| Permission         | Description                  |
|--------------------|------------------------------|
| `domain_read`      | Read domain details          |
| `domain_create`    | Create domains               |
| `domain_update`    | Update domains               |
| `domain_delete`    | Delete domains               |

### Lists

| Permission         | Description                  |
|--------------------|------------------------------|
| `list_entry_read`  | Read list entries            |
| `list_entry_create`| Create list entries          |
| `list_entry_delete`| Delete list entries          |

### Metrics

| Permission         | Description                  |
|--------------------|------------------------------|
| `metrics_read`     | Read metrics                 |

### API Keys

| Permission         | Description                  |
|--------------------|------------------------------|
| `api_key_read`     | Read API keys                |
| `api_key_create`   | Create API keys              |
| `api_key_delete`   | Delete API keys              |

### Pods

| Permission         | Description                  |
|--------------------|------------------------------|
| `pod_read`         | Read pods                    |
| `pod_create`       | Create pods                  |
| `pod_delete`       | Delete pods                  |

## Code Examples

### Read-only key

Create an API key that can read all resources but cannot create, update, or delete anything.

PythonTypeScriptCLI

```python
from agentmail import AgentMail

client = AgentMail(api_key="YOUR_API_KEY")

key = client.api_keys.create(
    name="read-only-agent",
    permissions={
        "inbox_read": True,
        "thread_read": True,
        "message_read": True,
        "draft_read": True,
        "webhook_read": True,
        "domain_read": True,
        "list_entry_read": True,
        "metrics_read": True,
        "api_key_read": True,
        "pod_read": True,
        "label_spam_read": True,
        "label_blocked_read": True,
        "label_trash_read": True,
    }
)

print(key.api_key)
```

### No-spam key

Create a key with full access but block visibility into spam, blocked, and trash content. This is useful for agent-facing keys where you want to prevent the agent from processing unwanted email.

PythonTypeScriptCLI

```python
key = client.api_keys.create(
    name="clean-inbox-agent",
    permissions={
        "inbox_read": True,
        "inbox_create": True,
        "inbox_update": True,
        "inbox_delete": True,
        "thread_read": True,
        "thread_delete": True,
        "message_read": True,
        "message_send": True,
        "message_update": True,
        "label_spam_read": False,
        "label_blocked_read": False,
        "label_trash_read": False,
        "draft_read": True,
        "draft_create": True,
        "draft_update": True,
        "draft_delete": True,
        "draft_send": True,
        "webhook_read": True,
        "webhook_create": True,
        "webhook_update": True,
        "webhook_delete": True,
        "domain_read": True,
        "domain_create": True,
        "domain_update": True,
        "domain_delete": True,
        "list_entry_read": True,
        "list_entry_create": True,
        "list_entry_delete": True,
        "metrics_read": True,
        "api_key_read": True,
        "api_key_create": True,
        "api_key_delete": True,
        "pod_read": True,
        "pod_create": True,
        "pod_delete": True,
    }
)
```

## Best Practices

- **Use the principle of least privilege.** Only grant the permissions your agent actually needs. A support agent that reads and replies to emails does not need `domain_create` or `inbox_delete`.
- **Combine with scopes for defense in depth.** Pair permissions with [pod-scoped](/content/docs/multi-tenancy#pod-scoped-keys/index.html) or [inbox-scoped](/content/docs/multi-tenancy#inbox-scoped-keys/index.html) keys. Scopes limit _which_ resources a key can see, while permissions limit _what_ it can do.
- **Filter unwanted content from agents.** Set `label_spam_read`, `label_blocked_read`, and `label_trash_read` to `false` on agent-facing keys. This prevents agents from seeing or processing unwanted email, keeping their context clean.
