Permissions

Control what your API keys can access with granular permissions.

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 and inbox-scoped 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

PermissionDescription
inbox_readRead inbox details
inbox_createCreate new inboxes
inbox_updateUpdate inbox settings
inbox_deleteDelete inboxes

Messages

PermissionDescription
message_readRead messages
message_sendSend messages
message_updateUpdate message labels
message_deleteDelete messages

Threads

Threads are groupings of messages and have no permissions of their own. Every thread operation is governed by the equivalent message permission:

OperationRequired permission
List, get, or search threadsmessage_read
Update thread labelsmessage_update
Delete a threadmessage_delete

There is no thread_read or thread_delete permission. Granting message_delete on a key also lets that key delete whole threads. To create a key that can read and label messages but cannot delete anything, leave message_delete unset or false.

Label Visibility

PermissionDescription
label_spam_readAccess messages labeled as spam
label_blocked_readAccess messages labeled as blocked
label_unauthenticated_readAccess messages labeled as unauthenticated
label_trash_readAccess 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 and WebSockets. An API key without label_spam_read cannot create a webhook or WebSocket subscription for message.received.spam events, and the same applies to label_blocked_read for message.received.blocked and label_unauthenticated_read for message.received.unauthenticated. label_trash_read has no corresponding event type, so it gates reads only.

Drafts

PermissionDescription
draft_readRead drafts
draft_createCreate drafts
draft_updateUpdate drafts
draft_deleteDelete drafts
draft_sendSend drafts

Webhooks

PermissionDescription
webhook_readRead webhook configurations
webhook_createCreate webhooks
webhook_updateUpdate webhooks
webhook_deleteDelete webhooks

Domains

PermissionDescription
domain_readRead domain details
domain_createCreate domains
domain_updateUpdate domains
domain_deleteDelete domains

Lists

PermissionDescription
list_entry_readRead list entries
list_entry_createCreate list entries
list_entry_deleteDelete list entries

Metrics

PermissionDescription
metrics_readRead metrics

API Keys

PermissionDescription
api_key_readRead API keys
api_key_createCreate API keys
api_key_updateUpdate API keys
api_key_deleteDelete API keys

Pods

PermissionDescription
pod_readRead pods
pod_createCreate pods
pod_deleteDelete pods

Code Examples

Read-only key

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

1from agentmail import AgentMail
2
3client = AgentMail(api_key="YOUR_API_KEY")
4
5key = client.api_keys.create(
6 name="read-only-agent",
7 permissions={
8 "inbox_read": True,
9 "message_read": True,
10 "draft_read": True,
11 "webhook_read": True,
12 "domain_read": True,
13 "list_entry_read": True,
14 "metrics_read": True,
15 "api_key_read": True,
16 "pod_read": True,
17 "label_spam_read": True,
18 "label_blocked_read": True,
19 "label_unauthenticated_read": True,
20 "label_trash_read": True,
21 }
22)
23
24print(key.api_key)

No-spam key

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

1key = client.api_keys.create(
2 name="clean-inbox-agent",
3 permissions={
4 "inbox_read": True,
5 "inbox_create": True,
6 "inbox_update": True,
7 "inbox_delete": True,
8 "message_read": True,
9 "message_send": True,
10 "message_update": True,
11 "message_delete": True,
12 "label_spam_read": False,
13 "label_blocked_read": False,
14 "label_unauthenticated_read": False,
15 "label_trash_read": False,
16 "draft_read": True,
17 "draft_create": True,
18 "draft_update": True,
19 "draft_delete": True,
20 "draft_send": True,
21 "webhook_read": True,
22 "webhook_create": True,
23 "webhook_update": True,
24 "webhook_delete": True,
25 "domain_read": True,
26 "domain_create": True,
27 "domain_update": True,
28 "domain_delete": True,
29 "list_entry_read": True,
30 "list_entry_create": True,
31 "list_entry_delete": True,
32 "metrics_read": True,
33 "api_key_read": True,
34 "api_key_create": True,
35 "api_key_update": True,
36 "api_key_delete": True,
37 "pod_read": True,
38 "pod_create": True,
39 "pod_delete": True,
40 }
41)

Copy for Cursor / Claude

Copy one of the blocks below into Cursor or Claude for complete Permissions API knowledge in one shot.

1"""
2AgentMail Permissions — copy into Cursor/Claude.
3
4Permissions are a whitelist on API keys. No `permissions` field = full access.
5When `permissions` is set, only `True` values are granted; omitted or `False` = denied.
6Permissions intersect with scope (pod/inbox). A restricted key cannot create a more privileged child key.
7
8Permission fields (all optional<bool>, resource_action format):
9 Inboxes: inbox_read, inbox_create, inbox_update, inbox_delete
10 Messages: message_read, message_send, message_update, message_delete
11 Label visibility: label_spam_read, label_blocked_read, label_unauthenticated_read, label_trash_read
12 Drafts: draft_read, draft_create, draft_update, draft_delete, draft_send
13 Webhooks: webhook_read, webhook_create, webhook_update, webhook_delete
14 Domains: domain_read, domain_create, domain_update, domain_delete
15 Lists: list_entry_read, list_entry_create, list_entry_delete
16 Metrics: metrics_read
17 API Keys: api_key_read, api_key_create, api_key_update, api_key_delete
18 Pods: pod_read, pod_create, pod_delete
19
20Threads have no permissions of their own: thread reads use message_read,
21thread label updates use message_update, and thread deletes use message_delete.
22
23API: api_keys.create(name, permissions={...})
24"""
25from agentmail import AgentMail
26
27client = AgentMail(api_key="YOUR_API_KEY")
28
29# read-only key
30key = client.api_keys.create(
31 name="read-only",
32 permissions={"inbox_read": True, "message_read": True}
33)
34print(key.api_key)

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 or inbox-scoped 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, label_unauthenticated_read, and label_trash_read to false on agent-facing keys. This prevents agents from seeing or processing unwanted email, keeping their context clean.