Inboxes
Tags: communication, email, messaging
Email inbox and message thread management
Resources
Request and response models used by the endpoints on this page.
InboxCreateRequest
| Field | Type | Required | Description |
|---|---|---|---|
autoReplyEnabled | Boolean | Whether automatic email replies are sent after processing (default: True) | |
defaultWorkflowId | Integer | Default workflow ID for creating assignments | |
directMemberId | Integer | The inbox's owner: a human Member or Agent that answer_owner rules reach, and that answers a known sender when no rule does. | |
emailFooter | String | Inbox-specific email footer (HTML). Overrides the workspace-wide footer for mail sent from this inbox. Empty or omitted means inherit the workspace footer. | |
name | String | ✓ | Name for the inbox |
orgDomainUuid | String | Optional UUID of an OrgDomain (org-tier custom domain) to use for this inbox's email address. When set, the inbox's email is | |
receiveNonMemberEmails | Boolean | Whether mail from senders who are not workspace Members is stored. Stored-only: such mail is never processed by the AI, because anyone can email an open inbox. False (the default) keeps the historical behaviour of dropping it. (default: False) | |
recipient | String | Recipient address ('sender' or any email address) (default: sender) | |
routingRules | Array<RoutingRuleWrite> | null | At most 50 rules for each of the four routing channels. | |
rules | InboxRulesConfig | null | Security rules for email filtering | |
slug | String | ✓ | Slug for generating the templated email address. Must be unique per (slug, domain) pair within a workspace — the same slug can be reused on a different OrgDomain, but two inboxes on the same domain cannot share a slug. Lowercase letters, digits, and hyphens only (no underscore — that delimits workspace slug in platform addresses). |
Example:
{
"name": "string",
"slug": "string",
"autoReplyEnabled": true,
"receiveNonMemberEmails": false,
"recipient": "sender"
}
InboxListResponse
| Field | Type | Required | Description |
|---|---|---|---|
items | Array<InboxResponse> | ✓ | |
total | Integer | ✓ |
Example:
{
"items": [],
"total": 0
}
InboxResponse
| Field | Type | Required | Description |
|---|---|---|---|
autoReplyEnabled | Boolean | ✓ | |
createdAt | DateTime | ✓ | |
defaultWorkflowId | Integer | ||
directMemberId | Integer | ||
effectiveEmailFooter | String | ||
emailAddress | EmailStr | ✓ | |
emailCount | Integer | ||
emailFooter | String | ||
generatedEmailAddress | String | ||
id | Integer | ✓ | |
name | String | ✓ | |
ownerId | Integer | ✓ | |
receiveNonMemberEmails | Boolean | ✓ | |
recipient | String | ||
routingMode | <enum RoutingMode | ✓ | |
routingRules | Array<RoutingRuleResponse> | ✓ | |
rules | Dict | ||
slug | String | ||
unreadCount | Integer | ||
updatedAt | DateTime | ✓ | |
uuid | String | ✓ |
Example:
{
"id": 0,
"uuid": "string",
"emailAddress": "user@example.com",
"name": "string",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
"ownerId": 0,
"routingMode": null,
"autoReplyEnabled": false,
"receiveNonMemberEmails": false,
"routingRules": []
}
InboxRule
| Field | Type | Required | Description |
|---|---|---|---|
field | Literal['sender', 'sender_ip'] | ✓ | |
operator | Literal['contains', 'equals', 'ends_with', 'regex', 'ip_in_range'] | ✓ | |
value | String | ✓ |
Example:
{
"field": "sender",
"operator": "contains",
"value": "string"
}
InboxRulesConfig
| Field | Type | Required | Description |
|---|---|---|---|
allowMode | Literal['all', 'none', 'rules'] | Allow mode: all, none, or rules (default: all) | |
allowRules | Array<InboxRule> | null | List of allow rules | |
denyMode | Literal['all', 'none', 'rules'] | Deny mode: all, none, or rules (default: none) | |
denyRules | Array<InboxRule> | null | List of deny rules | |
rateLimitAllowlist | Array<RateLimitAllowlistEntry> | null | Senders that bypass rate limiting for this inbox | |
rateLimitEnabled | Boolean | Override system rate limiting (None = use system default) | |
rateLimitOverride | RateLimitOverride | null | Custom rate limit values for this inbox |
Example:
{
"allowMode": "all",
"denyMode": "none"
}
InboxUpdateRequest
| Field | Type | Required | Description |
|---|---|---|---|
autoReplyEnabled | Boolean | Whether automatic email replies are sent after processing. Omit to leave unchanged. | |
defaultWorkflowId | Integer | Fallback Workflow used only when no Routing Rule matches. This does not change a saved rule destination; edit routingRules to change that destination. Omit to leave unchanged; send null to clear the fallback. | |
directMemberId | Integer | The inbox's owner: a human Member or Agent that answer_owner rules reach, and that answers a known sender when no rule does. Omit to leave unchanged; send null to clear it. | |
emailFooter | String | Inbox-specific email footer (HTML). Overrides the workspace-wide footer for mail sent from this inbox. Send an empty string or null to clear the override and inherit the workspace footer again; omitting the field leaves it unchanged. | |
name | String | Name for the inbox. Omit to leave unchanged. | |
orgDomainUuid | String | Optional UUID of an OrgDomain (org-tier custom domain) to use for this inbox's email address. When set, the inbox's email is switched to | |
receiveNonMemberEmails | Boolean | Whether mail from senders who are not workspace Members is stored. Stored-only: such mail is never processed by the AI, because anyone can email an open inbox. False (the default) keeps the historical behaviour of dropping it. Omit to leave unchanged. | |
recipient | String | Recipient address ('sender' or any email address). Omit to leave unchanged; send null to clear the override so replies go back to the sender. | |
routingRules | Array<RoutingRuleWrite> | null | At most 50 rules for each of the four routing channels. | |
rules | InboxRulesConfig | null | Security rules for email filtering. Omit to leave unchanged; send null to clear the filtering config. | |
slug | String | Slug for generating templated email address. Omit to leave unchanged. Lowercase letters, digits, and hyphens only. |
Example:
{}
RateLimitAllowlistEntry
| Field | Type | Required | Description |
|---|---|---|---|
reason | String | ||
sender | String | ✓ |
Example:
{
"sender": "string"
}
RateLimitOverride
| Field | Type | Required | Description |
|---|---|---|---|
enabled | Boolean | ||
perHour | Integer | ||
perMinute | Integer |
Example:
{}
RoutingCustomWindow
| Field | Type | Required | Description |
|---|---|---|---|
day | Literal['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] | ✓ | |
enabled | Boolean | ✓ | |
end | String | ||
start | String |
Example:
{
"day": "monday",
"enabled": false
}
RoutingRuleResponse
| Field | Type | Required | Description |
|---|---|---|---|
actionParams | Dict[str, Any] | ✓ | |
actionType | <enum RoutingActionType | ✓ | |
audience | <enum RoutingAudience | ✓ | |
callerMemberFilterId | Integer | ✓ | |
channel | <enum RoutingChannel | ✓ | |
createdAt | DateTime | ✓ | |
id | Integer | ✓ | |
inboxId | Integer | ✓ | |
order | Integer | ✓ | |
phoneNumberId | Integer | ✓ | |
schedule | RoutingSchedule | ✓ | |
templateUuid | String | ✓ | |
updatedAt | DateTime | ✓ | |
uuid | String | ✓ |
Example:
{
"id": 0,
"uuid": "string",
"templateUuid": "string",
"channel": null,
"phoneNumberId": 0,
"inboxId": 0,
"order": 0,
"schedule": null,
"audience": null,
"callerMemberFilterId": 0,
"actionType": null,
"actionParams": {},
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
RoutingRuleWrite
| Field | Type | Required | Description |
|---|---|---|---|
actionParams | Dict[str, Any] | ||
actionType | <enum RoutingActionType | ✓ | |
audience | <enum RoutingAudience | Default: anyone | |
callerMemberFilterId | Integer | ||
channel | <enum RoutingChannel | ✓ | |
schedule | RoutingSchedule | ||
templateUuid | String | ||
uuid | String |
Example:
{
"channel": null,
"audience": "anyone",
"actionType": null
}
RoutingSchedule
| Field | Type | Required | Description |
|---|---|---|---|
kind | <enum RoutingTimeWindow | Default: always | |
windows | Array<RoutingCustomWindow> | null |
Example:
{
"kind": "always"
}
Endpoints
GET /api/v2/w/{workspace_uuid}/inboxes- ListPOST /api/v2/w/{workspace_uuid}/inboxes- CreateDELETE /api/v2/w/{workspace_uuid}/inboxes/{inbox_id}- Delete Inbox IdGET /api/v2/w/{workspace_uuid}/inboxes/{inbox_id}- Get Inbox IdPUT /api/v2/w/{workspace_uuid}/inboxes/{inbox_id}- Update Inbox Id
List
GET /api/v2/w/{workspace_uuid}/inboxes
Description:
List all inboxes that the current member has permissions to access.
The embedded routingRules need no scope beyond inboxes:read — a
routing rule is configuration and carries no PHI. Loading them costs ONE
extra query for the whole page (selectinload batches the collection by
parent id), not one per inbox.
Authorization: Requires inboxes:read scope
Response: See InboxListResponse
Create
POST /api/v2/w/{workspace_uuid}/inboxes
Description:
Create a new inbox for the current member.
Requires inboxes:write scope.
Sending routingRules sets the inbox's email-channel rules in the same
transaction; routing rules use the inbox's own permissions, so creating
the inbox covers them. Omitting it leaves the creation seed to apply. When
the address already has an inbox, the request returns that inbox, and
writing its routingRules requires admin access on it, as the update route
does.
Authorization: Requires inboxes:write scope
Parameters:
request- See InboxCreateRequest
Response: See InboxResponse
Delete Inbox Id
DELETE /api/v2/w/{workspace_uuid}/inboxes/{inbox_id}
Description:
Delete an inbox and its global mapping by ID or UUID. Requires INBOXES_ADMIN scope or being the owner.
Authorization: Requires inboxes:admin scope
Parameters:
inbox_id(String)
Get Inbox Id
GET /api/v2/w/{workspace_uuid}/inboxes/{inbox_id}
Description:
Get a specific inbox by ID or UUID.
The embedded routingRules need no scope beyond inboxes:read — a
routing rule is configuration and carries no PHI.
Authorization: Requires inboxes:read scope
Parameters:
inbox_id(String)
Response: See InboxResponse
Update Inbox Id
PUT /api/v2/w/{workspace_uuid}/inboxes/{inbox_id}
Description:
Update an existing inbox by ID or UUID. Requires INBOXES_WRITE scope and admin permission on the inbox.
Sending routingRules replaces this inbox's rules for the channels the
list names (channels it does not name are untouched) in the same
transaction as the update; routing rules use the inbox's own permissions,
so the admin permission this update requires covers them. Reading the
routingRules embed on the response takes the inbox's read access.
This is a partial update. Every field is optional and only the fields
the payload actually carried are applied, so flipping one flag does not
require echoing the inbox's other values back. Where a cleared state
exists, an explicit null clears the field; where it does not, an
explicit null is rejected rather than ignored. InboxUpdateRequest
holds the per-field table.
If orgDomainUuid is provided, the inbox's hosting domain is switched
to the referenced verified OrgDomain — the same ownership + email-config
validation used on create is applied, and the resulting email address
becomes <slug>@<domain>. Omitting the field leaves the hosting domain
unchanged (the inbox stays on whatever domain it was already on).
Authorization: Requires inboxes:write scope
Parameters:
request- See InboxUpdateRequestinbox_id(String)
Response: See InboxResponse