Skip to main content

Inboxes

Tags: communication, email, messaging

Email inbox and message thread management

Resources​

Request and response models used by the endpoints on this page.

InboxCreateRequest​

FieldTypeRequiredDescription
autoReplyEnabledBooleanWhether automatic email replies are sent after processing (default: True)
defaultWorkflowIdIntegerDefault workflow ID for creating assignments
directMemberIdIntegerThe inbox's owner: a human Member or Agent that answer_owner rules reach, and that answers a known sender when no rule does.
emailFooterStringInbox-specific email footer (HTML). Overrides the workspace-wide footer for mail sent from this inbox. Empty or omitted means inherit the workspace footer.
nameString✓Name for the inbox
orgDomainUuidStringOptional UUID of an OrgDomain (org-tier custom domain) to use for this inbox's email address. When set, the inbox's email is @. The domain must be in this workspace's org and have a verified email config. When omitted, the inbox uses the default platform domain (gravityrail.net / gr-staging.net) and the address is _<workspace.slug>@.
receiveNonMemberEmailsBooleanWhether 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)
recipientStringRecipient address ('sender' or any email address) (default: sender)
routingRulesArray<RoutingRuleWrite> | nullAt most 50 rules for each of the four routing channels.
rulesInboxRulesConfig | nullSecurity rules for email filtering
slugString✓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​

FieldTypeRequiredDescription
itemsArray<InboxResponse>✓
totalInteger✓

Example:

{
"items": [],
"total": 0
}

InboxResponse​

FieldTypeRequiredDescription
autoReplyEnabledBoolean✓
createdAtDateTime✓
defaultWorkflowIdInteger
directMemberIdInteger
effectiveEmailFooterString
emailAddressEmailStr✓
emailCountInteger
emailFooterString
generatedEmailAddressString
idInteger✓
nameString✓
ownerIdInteger✓
receiveNonMemberEmailsBoolean✓
recipientString
routingMode<enum RoutingMode✓
routingRulesArray<RoutingRuleResponse>✓
rulesDict
slugString
unreadCountInteger
updatedAtDateTime✓
uuidString✓

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​

FieldTypeRequiredDescription
fieldLiteral['sender', 'sender_ip']✓
operatorLiteral['contains', 'equals', 'ends_with', 'regex', 'ip_in_range']✓
valueString✓

Example:

{
"field": "sender",
"operator": "contains",
"value": "string"
}

InboxRulesConfig​

FieldTypeRequiredDescription
allowModeLiteral['all', 'none', 'rules']Allow mode: all, none, or rules (default: all)
allowRulesArray<InboxRule> | nullList of allow rules
denyModeLiteral['all', 'none', 'rules']Deny mode: all, none, or rules (default: none)
denyRulesArray<InboxRule> | nullList of deny rules
rateLimitAllowlistArray<RateLimitAllowlistEntry> | nullSenders that bypass rate limiting for this inbox
rateLimitEnabledBooleanOverride system rate limiting (None = use system default)
rateLimitOverrideRateLimitOverride | nullCustom rate limit values for this inbox

Example:

{
"allowMode": "all",
"denyMode": "none"
}

InboxUpdateRequest​

FieldTypeRequiredDescription
autoReplyEnabledBooleanWhether automatic email replies are sent after processing. Omit to leave unchanged.
defaultWorkflowIdIntegerFallback 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.
directMemberIdIntegerThe 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.
emailFooterStringInbox-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.
nameStringName for the inbox. Omit to leave unchanged.
orgDomainUuidStringOptional 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 @. The domain must be in this workspace's org and have a verified email config. Omitting this field leaves the inbox's hosting domain unchanged.
receiveNonMemberEmailsBooleanWhether 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.
recipientStringRecipient address ('sender' or any email address). Omit to leave unchanged; send null to clear the override so replies go back to the sender.
routingRulesArray<RoutingRuleWrite> | nullAt most 50 rules for each of the four routing channels.
rulesInboxRulesConfig | nullSecurity rules for email filtering. Omit to leave unchanged; send null to clear the filtering config.
slugStringSlug for generating templated email address. Omit to leave unchanged. Lowercase letters, digits, and hyphens only.

Example:

{}

RateLimitAllowlistEntry​

FieldTypeRequiredDescription
reasonString
senderString✓

Example:

{
"sender": "string"
}

RateLimitOverride​

FieldTypeRequiredDescription
enabledBoolean
perHourInteger
perMinuteInteger

Example:

{}

RoutingCustomWindow​

FieldTypeRequiredDescription
dayLiteral['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']✓
enabledBoolean✓
endString
startString

Example:

{
"day": "monday",
"enabled": false
}

RoutingRuleResponse​

FieldTypeRequiredDescription
actionParamsDict[str, Any]✓
actionType<enum RoutingActionType✓
audience<enum RoutingAudience✓
callerMemberFilterIdInteger✓
channel<enum RoutingChannel✓
createdAtDateTime✓
idInteger✓
inboxIdInteger✓
orderInteger✓
phoneNumberIdInteger✓
scheduleRoutingSchedule✓
templateUuidString✓
updatedAtDateTime✓
uuidString✓

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​

FieldTypeRequiredDescription
actionParamsDict[str, Any]
actionType<enum RoutingActionType✓
audience<enum RoutingAudienceDefault: anyone
callerMemberFilterIdInteger
channel<enum RoutingChannel✓
scheduleRoutingSchedule
templateUuidString
uuidString

Example:

{
"channel": null,
"audience": "anyone",
"actionType": null
}

RoutingSchedule​

FieldTypeRequiredDescription
kind<enum RoutingTimeWindowDefault: always
windowsArray<RoutingCustomWindow> | null

Example:

{
"kind": "always"
}

Endpoints​

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:

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:

Response: See InboxResponse