Assign, close, tag and file conversations
These endpoints change who owns a conversation and where it sits. They never send mail. All of them require the write:emails scope.
Addressing conversations
Every endpoint on this page takes the same two fields:
| Field | Description |
|---|---|
threadKey | One conversation |
threadKeys | Up to 500 conversations |
Each key can be a threadKey or the ID of any message in the conversation. Keys that match nothing in this workspace come back in notFound and nothing is written for them. If none of the keys match, the call returns 404.
Acting as a teammate
An API key belongs to the workspace, not to a person. Where the app records who did something (who closed a conversation, who assigned it, who wrote a comment), pass asUserId with the ID of an active user in this workspace. Without it, the workspace owner is recorded. Get user IDs from GET /api/v1/inbox/assignees.
The response
Assign, status, spam, trash and tags return the state of each conversation after the change:
{
"affected": 1,
"notFound": ["not-a-real-key"],
"threads": [
{
"threadKey": "18c2f0a9b1d4e5f6",
"state": "OPEN",
"assignee": { "id": "cmq1user0alk34567891", "name": "Rita Cole" },
"closedAt": null,
"spam": false,
"trashed": false,
"tags": [{ "id": "cmq7tag00alk34567890", "name": "Pricing", "color": null }]
}
]
}Archive and snooze return { "affected": 1, "notFound": [] }.
Assign
POST /api/v1/inbox/threads/assign
{ "threadKeys": ["18c2f0a9b1d4e5f6"], "assigneeUserId": "cmq1user0alk34567891", "asUserId": "cmq1user0alk34567890" }| Body | Effect |
|---|---|
assigneeUserId: "<user id>" | Assign to that person. They must be an active user in this workspace |
assigneeUserId: null | Back to Unassigned |
auto: true | Round-robin: the person assigned least recently, skipping anyone marked away |
The new owner gets one notification for the whole call, not one per conversation. asUserId is who that notification says assigned it.
Close or reopen
POST /api/v1/inbox/threads/status
{ "threadKey": "18c2f0a9b1d4e5f6", "status": "closed", "asUserId": "cmq1user0alk34567891" }status is closed or open. Closed is the team's shared "handled" state and stays closed when new mail arrives.
Spam
POST /api/v1/inbox/threads/spam with { "threadKeys": [...], "spam": true }. Pass false to mark as not spam. A conversation marked as spam appears only in the spam folder.
Trash
POST /api/v1/inbox/threads/trash with { "threadKeys": [...], "trashed": true }. Pass false to restore.
Trash is emptied on a schedule
Nothing is deleted by this call, and a trashed conversation can be restored. A retention cleanup removes trashed conversations after some time, the same as trash in the app.
Archive
POST /api/v1/inbox/threads/archive with { "threadKeys": [...], "archived": true }. Pass false to unarchive.
Archive takes a conversation out of the Inbox until the next reply arrives, which brings it back on its own. It does not close the conversation.
Snooze
POST /api/v1/inbox/threads/snooze
{ "threadKeys": ["18c2f0a9b1d4e5f6"], "until": "2026-10-01T13:00:00Z" }until must be in the future. Pass null to wake a snoozed conversation now. A reply that arrives before until brings the conversation back early.
Tags
POST /api/v1/inbox/threads/tags
{ "threadKeys": ["18c2f0a9b1d4e5f6"], "addTagNames": ["Pricing"], "removeTagIds": ["cmq7tag00alk34567891"] }| Field | Description |
|---|---|
addTagNames | Tag names. A name the workspace has not used yet is created |
addTagIds | Existing tag IDs in this workspace |
removeTagIds | Tag IDs to take off |
removeTagNames | Tag names to take off (exact match, case-insensitive) |
Pass at least one. Every tag ID and name is checked before anything is written, so one bad ID fails the whole call with 404 and leaves nothing half-tagged. Removing a tag never deletes the tag itself; contacts and deals may still use it.