Inbox
The inbox provides conversation thread management and direct message retrieval. An inbox item represents a conversation thread between a user and a contact on a specific platform, tracking unread count, archive state, and per-user pin state.
All endpoints require authentication via the X-API-Key header. See Authentication.
Conversation thread model
Each inbox item is uniquely identified by a combination of userId + contactId + platform. Inbox items are created and updated automatically when direct messages are sent or received — there is no explicit create endpoint.
Each inbox item tracks:
unreadCount— number of unread messages in the thread.unreadFixed— whether the thread was manually marked unread by the user who owns the inbox. It keeps the thread in theunreadview afterunreadCountreaches 0. No API key endpoint sets it; it is raised from the Stacked app.archived— whether the thread is archived.isPinned— a per-user map (Record<userId, boolean>). Each user has independent pin state on the same inbox item.
Type filters
The type query parameter on inbox items determines the view:
| Type | Description |
|---|---|
unread | Items with unreadCount greater than 0 or unreadFixed set (not archived). |
inbound | Items with at least one inbound message (not archived). |
outbound | Items with only outbound messages (not archived). |
archived | Archived items. |
pinned | Items pinned by the current user. |
List inbox channels
GET /inboxes
Returns available inbox channels for the authenticated user based on their configuration.
Channel types:
stacked-sms— users with a stacked phone configured.twitter— users with Twitter DMs enabled.web-chat— if web-chat is configured for the org.
Example request
Response
List inbox items
GET /inboxes/items
Returns conversation threads with populated contact, user, and message data.
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
userId | string | — | Required. User ID to fetch inbox items for. |
platform | string | — | Filter by platform. |
type | string | — | unread, inbound, outbound, archived, or pinned. |
search | string | — | Case-insensitive search on contact name. |
page | number | 0 | 0-indexed. |
perPage | number | 25 | Items per page. |
Example request
Response
Find an inbox item
GET /inboxes/items/find
Finds a specific inbox item by user, contact, and platform.
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
userId | string | — | Required. User ID. |
contactId | string | — | Required. Contact ID. |
platform | string | — | Platform. |
Example request
Response
Mark inbox item as read
POST /inboxes/items/mark-read
Sets the unreadCount to 0 for an inbox item.
An API key acts as a dedicated API user belonging to the organization, not as the person who created the key, and reaches every inbox in that organization. That API user never owns an inbox itself, so unreadFixed is never cleared: only unreadCount is zeroed, and a thread its owner marked unread stays in their unread view.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes | Inbox item ID. |
Example request
Response
Errors
| Status | Message | Cause |
|---|---|---|
| 400 | Validation error | Invalid ObjectId format. |
| 404 | Not found | Inbox item not found in your org. |
Archive or unarchive an inbox item
POST /inboxes/items/archive
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes | Inbox item ID. |
value | boolean | Yes | true to archive, false to unarchive. |
Example request
Response
Errors
| Status | Message | Cause |
|---|---|---|
| 400 | Validation error | Invalid ObjectId or value not boolean. |
| 404 | Not found | Inbox item not found in your org. |
Pin or unpin an inbox item
POST /inboxes/items/pin
Pin state is per-user — each user has independent pin state on the same inbox item. Returns the updated inbox item with full lookups.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes | Inbox item ID. |
value | boolean | Yes | true to pin, false to unpin. |
Example request
Response
Errors
| Status | Message | Cause |
|---|---|---|
| 400 | Validation error | Invalid ObjectId or value not boolean. |
| 404 | Not found | Inbox item not found in your org. |
Get conversation messages
GET /inboxes/conversations
Returns direct messages for a conversation between a user and a contact, sorted by timestamp descending (newest first).
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
userId | string | — | Required. User ID. |
contactId | string | — | Required. Contact ID. |
platform | string or string[] | — | Single platform or array of platforms. |
page | number | 0 | 0-indexed. |
perPage | number | 30 | Messages per page. |
Example request
Response
Response envelope
All endpoints use the standard envelope:
Error responses:
data is null for a general failure, such as a database error or an upstream timeout. When the request is rejected because of a specific field, data carries the field(s) at fault instead:
Each issue carries a path (the dotted path into the request body) and a message. A label is added when the path is not self-describing, which today means custom fields only, for example "path": "fields.68b0a1f39c2e4d0012ab77e5", "label": "Class Year". issues is an array, but treat it as holding at most one entry: validation stops at the first failure.