Permission Catalog
Permissions are strings evaluated against a member’s role and enforced by the API on every request.
Tenant Permissions
These permissions are held by tenant members. All are scoped to the tenant identified in the JWT tenant_id claim — a user cannot hold tenant A’s tenant:notifications:audit:read and use it to read tenant B’s audit log.
Settings & Administration
| Permission | Self-scoped? | Allows |
|---|---|---|
tenant:settings:read | No | Read tenant name, slug, tier, status, features map, region |
tenant:settings:write | No | Update name, slug (transactional slug swap), feature flags |
tenant:members:read | No | List all members with their roles and last-seen timestamps |
tenant:members:invite | No | Create, list, and revoke pending invites |
tenant:members:remove | No | Remove any member except the owner |
tenant:members:role:write | No | Change a member’s role (cannot promote to or demote the owner role) |
tenant:grants:read | No | Read the grant row for all members |
tenant:grants:write | No | Create, update, or delete a member’s grant |
tenant:keys:read | No | List all API keys in the tenant (metadata only, no plaintext) |
tenant:keys:read:self | Yes | List own API keys only |
tenant:keys:write | No | Create and revoke any API key in the tenant (members restricted to own keys by enforcement in handler) |
tenant:billing:read | No | Read subscription status, usage summary, invoice list |
tenant:billing:write | No | Change the payment method; cancel the subscription (owner only enforced in handler) |
tenant:gdpr:read | No | Request the tenant’s GDPR right-to-access export and read the presigned download URL |
tenant:transfer:owner | No | Transfer tenant ownership to another member. Current owner only, enforced in handler. |
tenant:delete | No | Soft-delete the tenant. Current owner only, enforced in handler. |
tenant:features:read | No | Read the tenant feature-flag map |
tenant:features:write | No | Enable or disable a tenant feature flag. Disabling preserves data. |
Integrations
| Permission | Allows |
|---|---|
tenant:integrations:hubspot:connect | Connect a new HubSpot integration or reconnect after token expiry |
tenant:integrations:hubspot:disconnect | Disconnect the HubSpot integration and delete the stored credentials |
tenant:integrations:hubspot:read | Read the integration status, hub_id, granted scopes, and connected-at timestamp |
tenant:integrations:slack:read | Read the Slack integration status, connected workspace, and configured channels |
tenant:integrations:slack:write | Connect, configure channels, set routing rules, and disconnect the Slack integration |
tenant:integrations:apn:configure | Connect, configure catalog (Sandbox/Production), and disconnect APN |
tenant:integrations:apn:read | Read APN integration status, partner account ID, catalog, and sync statistics |
FlowState Domain
| Permission | Allows |
|---|---|
tenant:hubspot:read | Call HubSpot CRM and reporting APIs using the tenant’s stored credentials |
tenant:deals:analyze | Trigger a pipeline refresh run; invoke AI deal analysis |
tenant:deals:read | Read precomputed deal snapshots, pipeline summaries, and deal details |
tenant:deals:reanalyze | Force a per-deal reanalysis, bypassing the TTL cache |
tenant:goals:read | Read annual revenue and deal-count goals and rep quotas |
tenant:goals:write | Set annual goals and per-rep quota targets |
tenant:win-loss:read | Read win/loss aggregations and trend analyses |
tenant:win-loss:trigger | Start a win/loss batch (up to 48 month-analysis workers). Rate-limited to one run per tenant per 15 minutes |
tenant:slack:test | Send a test message to the tenant’s configured Slack channel |
tenant:apn:read | Read APN sync state for all deals; list opportunities; read conflicts and errors |
tenant:apn:sync:trigger | Trigger manual syncs; retry failed syncs; resolve conflicts; accept/reject engagement invitations |
tenant:marketplace:offers:read | Read Marketplace private offers, their draft changesets and release status |
tenant:marketplace:offers:write | Create and amend DRAFT private offers. A released offer’s commercial terms can never be changed |
tenant:marketplace:offers:release | Release a draft private offer to the buyer. Irreversible — kept separate from write for that reason |
tenant:mcp:invoke | Invoke any tenant-scoped MCP tool. Required in addition to the tool’s own permission. |
Notifications
| Permission | Self-scoped? | Allows |
|---|---|---|
tenant:notifications:read | No | View which members in this tenant are subscribed to which notification categories. Admin view. |
tenant:notifications:read:self | Yes | Read own global and per-tenant notification preferences |
tenant:notifications:write:self | Yes | Update own notification preferences (enable/disable categories, per-tenant overrides) |
tenant:notifications:audit:read | No | Read the per-tenant notification send log (category, ses_message_id, status, timestamp) |
Self-Scoped Permissions
Permissions marked “self-scoped” (*:self) enforce that a member can only exercise them on their own resources:
tenant:keys:read:self— member can list their own keys but not others’.tenant:notifications:read:self— member can read their own prefs but not another member’s.tenant:notifications:write:self— member can update their own prefs only.
The :self scoping is enforced by verifying the resource belongs to the requesting member. The presence of the :self permission never grants access to another member’s resources.
Admins and owners hold the non-self-scoped variants which implicitly cover self-access as well.