Permissions reference

Complete reference for the 26 workspace and 4 agency API permissions available in SenditCold.

SenditCold 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 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

PermissionBitValueCategoryDescription
READ_EMAILS01readView email accounts and settings
READ_CAMPAIGNS12readView campaigns and sequences
READ_CONTACTS24readView contact lists, segments, notes, and activities
READ_UNIBOX38readAccess unified inbox
READ_ANALYTICS416readView analytics and statistics
WRITE_EMAILS532writeModify email account settings
WRITE_CAMPAIGNS664writeCreate and modify campaigns and sequences
WRITE_CONTACTS7128writeCreate and modify contacts, segments, notes, activities
WRITE_UNIBOX8256writeMark emails as read/unread and send replies
BULK_CONTACTS9512bulkBulk import/export/delete contacts
BULK_CAMPAIGNS101024bulkBulk campaign operations
REALTIME_SUBSCRIBE112048specialSubscribe to realtime events
WEBHOOKS124096specialManage webhook endpoints
API_KEYS138192specialCreate and manage API keys
SEND_CAMPAIGNS1416384writeStart and stop campaigns (sends real mail)
READ_TEMPLATES1532768readView reply templates
WRITE_TEMPLATES1665536writeCreate and modify reply templates
READ_CRM17131072readView pipelines, deals, and CRM tasks
WRITE_CRM18262144writeCreate and modify pipelines, deals, CRM tasks
READ_AUDIT_LOGS19524288readView organization audit logs
INTEGRATIONS201048576specialConnect and manage third-party integrations
WARMUP_ROUTING212097152specialManage warmup routing rules
AI_AGENT224194304specialRun the AI assistant and MCP tools
AI_RESEARCH238388608specialRun AI contact research
CONNECT_EMAILS2416777216specialConnect mailboxes and create sign-in links (Partnership plan)
MANAGE_REPORTS2533554432writeCreate, share and schedule client reports
AGENCY_READ2667108864agencyView the agency, its staff, clients, overview, inbox and brand
AGENCY_MANAGE_CLIENTS27134217728agencyCreate, attach, cap and detach client workspaces
AGENCY_READ_USAGE28268435456agencyView the shared send pool and AI balance
AGENCY_TRANSFER_AI29536870912agencyMove AI balance from the agency into a client workspace

Bits 26 to 29 exist only on agency API keys. A workspace key or OAuth app never holds them, and POST /api-keys refuses them as unknown bits.

AI_AGENT gates the web and playbook tools (search_web, fetch_url, load_skill) on /v1/mcp and /ai/tools; every other tool there checks its own scope. It also gates the AI skills endpoints for keys; creating, editing or deleting a playbook with a key further needs the member who created the key to hold manage_settings.

CONNECT_EMAILS is the only scope that lets a key hand SenditCold a mailbox password: it gates the mailbox connect routes, which take SMTP/IMAP credentials, mint Google and Microsoft sign-in links and save the workspace's own OAuth apps. Those routes also refuse a workspace that is not on the Partnership plan with 403 partnership_plan_required. It is left out of the Full access preset, and an OAuth app can never be granted it.

MANAGE_REPORTS covers creating and editing client reports, minting and revoking their public links and setting their email schedules. A report link shows analytics to anyone who holds it, so this is separate from READ_ANALYTICS, which is all that listing, reading and previewing a report takes.

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. An inbox placement test sends real mail from a real mailbox too, so starting or cancelling one, and scheduling a campaign's placement monitor, takes SEND_CAMPAIGNS, while reading results takes READ_ANALYTICS.

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, mailbox connect, and self-service key management. Grant individually.

Agency

The agency's own endpoints under /v1/agency/:agencyId. Only an agency API key carries these, and it carries them alongside the workspace bits it uses in each client workspace.

Agency permissionEndpoints
AGENCY_READGET /agency, GET /agency/plans, GET /agency/:agencyId, its staff, clients, overview and brand; with READ_UNIBOX also the cross-client inbox
AGENCY_MANAGE_CLIENTSCreate, attach, update (send and AI caps) and detach clients
AGENCY_READ_USAGEGET /agency/:agencyId/usage and GET /agency/:agencyId/ai-balance
AGENCY_TRANSFER_AIPOST /agency/:agencyId/clients/:orgId/ai-balance

An agency key never holds API_KEYS, REALTIME_SUBSCRIBE or CONNECT_EMAILS: it manages no workspace keys, opens no realtime socket and takes no mailbox credentials.

What a role can delegate

An API key or an OAuth grant acts for a member of the workspace, so it never holds a permission that member's role does not cover. Each API permission maps to the team role permission it needs; the workspace owner covers every one.

API permissionMember needs
READ_EMAILS, READ_CAMPAIGNS, READ_TEMPLATESview_campaigns
READ_CONTACTS, READ_CRMview_contacts
READ_UNIBOX, WRITE_UNIBOXaccess_unibox
READ_ANALYTICS, READ_AUDIT_LOGSview_analytics
WRITE_EMAILS, CONNECT_EMAILSmanage_emails
WRITE_CAMPAIGNS, WRITE_TEMPLATES, BULK_CAMPAIGNSmanage_campaigns
WRITE_CONTACTS, WRITE_CRM, BULK_CONTACTSmanage_contacts
SEND_CAMPAIGNSsend_campaigns
WEBHOOKS, WARMUP_ROUTINGmanage_settings
API_KEYSmanage_api_keys
INTEGRATIONSuse_integrations
AI_AGENTuse_ai
AI_RESEARCHview_contacts and use_ai
MANAGE_REPORTSview_analytics and manage_campaigns
REALTIME_SUBSCRIBEany member

An agency key acts for the agency owner or admin who created it, through the membership the agency gives them in each client workspace (Admin), so the same table bounds it there. The agency bits need that person to still be an owner or admin of the agency.

Where it applies:

  • Creating or editing an API key from the dashboard refuses a permission outside the member's role with 403 api_key_permissions_exceed_caller.
  • Creating or editing an API key with an API key keeps the result inside the calling key: no permission it lacks, and when the calling key is limited to some mailboxes or IP addresses, the new or edited key must be limited to a subset of them. The same 403 api_key_permissions_exceed_caller answers otherwise.
  • An OAuth grant carries only the requested scopes the approving member's role covers, re-checked against the member's current role on every request. See OAuth scopes. API_KEYS and CONNECT_EMAILS are never granted to an OAuth app, and OAuth tokens cannot create, edit, revoke or delete API keys (403 oauth_token_not_allowed).
  • A member restricted to selected resources holds view_campaigns, view_analytics and access_unibox from any role, and manage_campaigns and send_campaigns only from a role that lets clients act. A key or grant acting for them is limited to the API permissions those cover, to the routes their scope allows, and to their grants (which routes); access_unibox covers inbox writes only through a role that lets clients act. A key's own mailbox allowlist still applies on top. Restricted members cannot create keys.

Preset combinations

Both presets are returned by GET /api-keys/permissions for convenience. The same response carries grantable, the mask the caller may put on a key (its role's reach, or the calling key's own permissions), and app_scopes, the mask an OAuth app may request.

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 (50331647)

Every workspace permission except CONNECT_EMAILS, which is granted by hand:

((1 << 26) - 1) & ~16777216 = 50331647

Agency key presets

GET /agency/:agencyId/api-keys/permissions returns the bits an agency key may hold, grouped as workspace and agency, with two presets:

  • Read only (336232479): the workspace read set plus AGENCY_READ and AGENCY_READ_USAGE, 688159 | 67108864 | 268435456.
  • Full access (1056954367): every bit an agency key may hold, which is every workspace bit except API_KEYS, REALTIME_SUBSCRIBE and CONNECT_EMAILS (50321407) plus the four agency bits (1006632960).

Working with bitmasks

Combining

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

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

Checking

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 33554431. POST /agency/:agencyId/api-keys does the same against 536860671 and answers 400 invalid_agency_key_permissions.

Common permission sets

Monitoring integration

For dashboards and reporting:

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

CRM sync

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)

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

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,
  CONNECT_EMAILS: 16777216,
  MANAGE_REPORTS: 33554432,
  // Agency API keys only
  AGENCY_READ: 67108864,
  AGENCY_MANAGE_CLIENTS: 134217728,
  AGENCY_READ_USAGE: 268435456,
  AGENCY_TRANSFER_AI: 536870912,
} as const;
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
    CONNECT_EMAILS = 16777216
    MANAGE_REPORTS = 33554432
    # Agency API keys only
    AGENCY_READ = 67108864
    AGENCY_MANAGE_CLIENTS = 134217728
    AGENCY_READ_USAGE = 268435456
    AGENCY_TRANSFER_AI = 536870912
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
    APIPermConnectEmails                        // 16777216
    APIPermManageReports                        // 33554432
    // Agency API keys only
    APIPermAgencyRead                           // 67108864
    APIPermAgencyManageClients                  // 134217728
    APIPermAgencyReadUsage                      // 268435456
    APIPermAgencyTransferAI                     // 536870912
)

See also

On this page