---
title: Permissions reference
description: Complete reference for the 22 API permissions available in Warmbly.
---

Warmbly uses a bitmask system for API permissions. Each permission is one bit in a `uint64`, so a single integer can express any combination of the permissions below.

These same permissions are the [OAuth](/api/oauth/) scopes, lowercased: `READ_EMAILS` is the scope `read_emails`. An OAuth access token carries a bitmask of granted permissions and is checked through the identical gates as an API key.

## Permission values

| Permission | Bit | Value | Category | Description |
|------------|-----|-------|----------|-------------|
| `READ_EMAILS` | 0 | 1 | read | View email accounts and settings |
| `READ_CAMPAIGNS` | 1 | 2 | read | View campaigns and sequences |
| `READ_CONTACTS` | 2 | 4 | read | View contact lists, segments, notes, and activities |
| `READ_UNIBOX` | 3 | 8 | read | Access unified inbox |
| `READ_ANALYTICS` | 4 | 16 | read | View analytics and statistics |
| `WRITE_EMAILS` | 5 | 32 | write | Modify email account settings |
| `WRITE_CAMPAIGNS` | 6 | 64 | write | Create and modify campaigns and sequences |
| `WRITE_CONTACTS` | 7 | 128 | write | Create and modify contacts, segments, notes, activities |
| `WRITE_UNIBOX` | 8 | 256 | write | Mark emails as read/unread and send replies |
| `BULK_CONTACTS` | 9 | 512 | bulk | Bulk import/export/delete contacts |
| `BULK_CAMPAIGNS` | 10 | 1024 | bulk | Bulk campaign operations |
| `REALTIME_SUBSCRIBE` | 11 | 2048 | special | Subscribe to realtime events |
| `WEBHOOKS` | 12 | 4096 | special | Manage webhook endpoints |
| `API_KEYS` | 13 | 8192 | special | Create and manage API keys |
| `SEND_CAMPAIGNS` | 14 | 16384 | write | Start and stop campaigns (sends real mail) |
| `READ_TEMPLATES` | 15 | 32768 | read | View reply templates |
| `WRITE_TEMPLATES` | 16 | 65536 | write | Create and modify reply templates |
| `READ_CRM` | 17 | 131072 | read | View pipelines, deals, and CRM tasks |
| `WRITE_CRM` | 18 | 262144 | write | Create and modify pipelines, deals, CRM tasks |
| `READ_AUDIT_LOGS` | 19 | 524288 | read | View organization audit logs |
| `INTEGRATIONS` | 20 | 1048576 | special | Connect and manage third-party integrations |
| `WARMUP_ROUTING` | 21 | 2097152 | special | Manage warmup routing rules |
| `AI_AGENT` | 22 | 4194304 | special | Run the AI assistant and MCP tools |
| `AI_RESEARCH` | 23 | 8388608 | special | Run AI contact research |

`SEND_CAMPAIGNS` is intentionally separate from `WRITE_CAMPAIGNS`: editing a campaign draft and starting one that actually transmits mail are different blast radii, so a key can be granted the first without the second.

## Categories

### Read

Read-only data access. Safe for monitoring, reporting, BI sync.

### Write

Resource mutation, but no campaign starts. A key with the full write set can edit drafts but cannot turn on a campaign.

### Bulk

High-volume operations. These can touch large numbers of rows in a single request, so they're broken out from the per-record write permissions.

### Special

Realtime subscriptions, webhooks, integrations, warmup routing, AI assistant / MCP access, AI contact research, and self-service key management. Grant individually.

## Preset combinations

Both presets are returned by `GET /api-keys/permissions` for convenience.

### Read only (688159)

All read permissions combined:

```
READ_EMAILS | READ_CAMPAIGNS | READ_CONTACTS | READ_UNIBOX | READ_ANALYTICS
  | READ_TEMPLATES | READ_CRM | READ_AUDIT_LOGS
= 1 | 2 | 4 | 8 | 16 | 32768 | 131072 | 524288
= 688159
```

### Full access (16777215)

All 24 permissions:

```
(1 << 24) - 1 = 16777215
```

## Working with bitmasks

### Combining

```javascript
const READ_EMAILS = 1;
const READ_CAMPAIGNS = 2;
const SEND_CAMPAIGNS = 16384;

const permissions = READ_EMAILS | READ_CAMPAIGNS | SEND_CAMPAIGNS;
// 16387
```

### Checking

```javascript
function hasPermission(permissions, required) {
  return (permissions & required) === required;
}

hasPermission(16387, 16384); // true: SEND_CAMPAIGNS granted
hasPermission(16387, 64);    // false: WRITE_CAMPAIGNS missing
```

### Rejecting unknown bits

`POST /api-keys` rejects any request whose `permissions` field has bits outside the known set, so a stale client can't accidentally request a future permission. The current mask of valid bits is `4194303`.

## Common permission sets

### Monitoring integration

For dashboards and reporting:

```javascript
const MONITORING =
  READ_EMAILS |     // 1
  READ_CAMPAIGNS |  // 2
  READ_ANALYTICS;   // 16
// 19
```

### CRM sync

```javascript
const CRM_SYNC =
  READ_CONTACTS |   // 4
  WRITE_CONTACTS |  // 128
  BULK_CONTACTS |   // 512
  READ_CRM |        // 131072
  WRITE_CRM;        // 262144
// 393860
```

### Campaign automation (drafts only, no send)

```javascript
const CAMPAIGN_DRAFTS =
  READ_CAMPAIGNS |    // 2
  WRITE_CAMPAIGNS |   // 64
  READ_CONTACTS |     // 4
  READ_TEMPLATES |    // 32768
  WRITE_TEMPLATES;    // 65536
// 98374
```

### Campaign automation (with send)

Same as above, plus `SEND_CAMPAIGNS` (16384). Grant only when the integration genuinely needs to start campaigns.

## Permission constants

<Tabs defaultValue="javascript">

<TabsList>
  <LangTab lang="javascript" />
  <LangTab lang="python" />
  <LangTab lang="go" />
</TabsList>

<Tab value="javascript">

```typescript
export const Permissions = {
  READ_EMAILS: 1,
  READ_CAMPAIGNS: 2,
  READ_CONTACTS: 4,
  READ_UNIBOX: 8,
  READ_ANALYTICS: 16,
  WRITE_EMAILS: 32,
  WRITE_CAMPAIGNS: 64,
  WRITE_CONTACTS: 128,
  WRITE_UNIBOX: 256,
  BULK_CONTACTS: 512,
  BULK_CAMPAIGNS: 1024,
  REALTIME_SUBSCRIBE: 2048,
  WEBHOOKS: 4096,
  API_KEYS: 8192,
  SEND_CAMPAIGNS: 16384,
  READ_TEMPLATES: 32768,
  WRITE_TEMPLATES: 65536,
  READ_CRM: 131072,
  WRITE_CRM: 262144,
  READ_AUDIT_LOGS: 524288,
  INTEGRATIONS: 1048576,
  WARMUP_ROUTING: 2097152,
  AI_AGENT: 4194304,
  AI_RESEARCH: 8388608,
} as const;
```

</Tab>

<Tab value="python">

```python
class Permissions:
    READ_EMAILS = 1
    READ_CAMPAIGNS = 2
    READ_CONTACTS = 4
    READ_UNIBOX = 8
    READ_ANALYTICS = 16
    WRITE_EMAILS = 32
    WRITE_CAMPAIGNS = 64
    WRITE_CONTACTS = 128
    WRITE_UNIBOX = 256
    BULK_CONTACTS = 512
    BULK_CAMPAIGNS = 1024
    REALTIME_SUBSCRIBE = 2048
    WEBHOOKS = 4096
    API_KEYS = 8192
    SEND_CAMPAIGNS = 16384
    READ_TEMPLATES = 32768
    WRITE_TEMPLATES = 65536
    READ_CRM = 131072
    WRITE_CRM = 262144
    READ_AUDIT_LOGS = 524288
    INTEGRATIONS = 1048576
    WARMUP_ROUTING = 2097152
    AI_AGENT = 4194304
    AI_RESEARCH = 8388608
```

</Tab>

<Tab value="go">

```go
const (
    APIPermReadEmails        uint64 = 1 << iota // 1
    APIPermReadCampaigns                        // 2
    APIPermReadContacts                         // 4
    APIPermReadUnibox                           // 8
    APIPermReadAnalytics                        // 16
    APIPermWriteEmails                          // 32
    APIPermWriteCampaigns                       // 64
    APIPermWriteContacts                        // 128
    APIPermWriteUnibox                          // 256
    APIPermBulkContacts                         // 512
    APIPermBulkCampaigns                        // 1024
    APIPermRealtimeSubscribe                    // 2048
    APIPermWebhooks                             // 4096
    APIPermAPIKeys                              // 8192
    APIPermSendCampaigns                        // 16384
    APIPermReadTemplates                        // 32768
    APIPermWriteTemplates                       // 65536
    APIPermReadCRM                              // 131072
    APIPermWriteCRM                             // 262144
    APIPermReadAuditLogs                        // 524288
    APIPermIntegrations                         // 1048576
    APIPermWarmupRouting                        // 2097152
    APIPermAIAgent                              // 4194304
    APIPermAIResearch                           // 8388608
)
```

</Tab>

</Tabs>

## See also

- [Authentication](/api/authentication/)
- [Endpoints](/api/endpoints/)
- [Team & roles](/guides/team-roles/)
