Threads
Manage email conversations - list, read, reply, schedule follow-ups, archive, trash, and permanently delete threads.
A thread groups all messages in a single email conversation. Every outbound send and inbound message belongs to a thread. Use threads to read conversations, reply to contacts, update status, and manage lifecycle (archive, trash, delete).
Endpoints
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/agent/threads | read | List threads |
| GET | /v1/agent/threads/:id | read | Get thread with messages |
| PATCH | /v1/agent/threads/:id | admin | Update thread |
| POST | /v1/agent/threads/archive | manage | Archive threads |
| POST | /v1/agent/threads/unarchive | manage | Unarchive threads |
| POST | /v1/agent/threads/trash | manage | Move threads to trash |
| POST | /v1/agent/threads/restore | manage | Restore threads from trash |
| DELETE | /v1/agent/threads/:id/permanent | manage | Permanently delete a thread |
| POST | /v1/agent/outbound/schedule-followup | automation | Schedule a follow-up (Outbound) |
All endpoints require Bearer authentication. The scope column shows the minimum API key scope required.
List threads
GET https://api.molted.email/v1/agent/threadscurl "https://api.molted.email/v1/agent/threads?tenantId=TENANT_ID&status=open&direction=inbound&limit=25" \
-H "Authorization: Bearer YOUR_API_KEY"Query parameters
| Parameter | Type | Description |
|---|---|---|
tenantId | string | Your tenant ID |
mailboxId | string | Filter by mailbox |
status | string | Filter by status: open, waiting, resolved, escalated |
direction | string | Filter by direction: inbound, outbound |
view | string | Filter by view: active (default), archived, trashed |
contactEmail | string | Filter by contact email address |
limit | integer | Max results, 1-50 (default 25) |
offset | integer | Pagination offset |
Response
{
"items": [
{
"id": "thr_abc123",
"tenantId": "tenant_abc123",
"mailboxId": "mbx_abc123",
"status": "open",
"direction": "inbound",
"contactEmail": "alice@example.com",
"subject": "Re: Invoice question",
"lastMessageAt": "2026-03-01T12:00:00Z",
"createdAt": "2026-02-28T10:00:00Z"
}
],
"totalCount": 42
}Unlike most list endpoints (which return a bare array), threads list returns a paginated wrapper. Iterate over items and use totalCount with limit/offset to drive pagination.
CLI
molted threads list --status open --direction inbound --limit 10
molted threads list --contact alice@example.com
molted threads list --view archivedGet a thread
Returns the thread and all of its messages in chronological order.
GET https://api.molted.email/v1/agent/threads/:idcurl "https://api.molted.email/v1/agent/threads/thr_abc123?tenantId=TENANT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"Query parameters
| Parameter | Type | Description |
|---|---|---|
tenantId | string | Your tenant ID |
includeQuarantined | boolean | Include held/quarantined messages. Requires operator scope. |
Response
{
"thread": {
"id": "thr_abc123",
"status": "open",
"direction": "inbound",
"contactEmail": "alice@example.com",
"subject": "Re: Invoice question",
"mailboxId": "mbx_abc123"
},
"messages": [
{
"id": "msg_abc123",
"threadId": "thr_abc123",
"direction": "inbound",
"fromEmail": "alice@example.com",
"toEmail": "support@yourdomain.com",
"subject": "Invoice question",
"bodyText": "Hi, I have a question about my invoice...",
"createdAt": "2026-02-28T10:00:00Z"
}
]
}Pass includeQuarantined=true to include messages that are held for approval (requires operator scope).
CLI
molted threads get thr_abc123Update a thread
Update the status, assigned agent, or metadata on a thread.
PATCH https://api.molted.email/v1/agent/threads/:idcurl -X PATCH "https://api.molted.email/v1/agent/threads/thr_abc123?tenantId=TENANT_ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "resolved" }'Request body
| Field | Type | Description |
|---|---|---|
status | string | Thread status: open, waiting, resolved, escalated |
assignedAgentId | string | Assign the thread to a specific agent |
metadata | object | Arbitrary key-value metadata |
CLI
molted threads update thr_abc123 --status resolved
molted threads update thr_abc123 --status escalated --assigned-agent-id agt_abcThread lifecycle
Threads move through three storage states: active, archived, and trashed. Only trashed threads can be permanently deleted.
active --> archive --> active (unarchive)
active --> trash --> active (restore)
trashed --> [permanent delete]Bulk operations accept up to 100 thread IDs per call. If none of the provided IDs match existing threads (or threads in the expected state), the API returns 404 Not Found with an error message.
Archive
Move threads out of the active view without deleting them.
POST https://api.molted.email/v1/agent/threads/archive{ "threadIds": ["thr_abc123", "thr_def456"] }{ "archived": 2 }Unarchive
Move archived threads back to the active view.
POST https://api.molted.email/v1/agent/threads/unarchive{ "threadIds": ["thr_abc123"] }Trash
Move threads to the trash. Trashed threads are retained for recovery but excluded from normal views.
POST https://api.molted.email/v1/agent/threads/trash{ "threadIds": ["thr_abc123"] }Restore
Restore trashed threads to the active view.
POST https://api.molted.email/v1/agent/threads/restore{ "threadIds": ["thr_abc123"] }Permanent delete
Permanently removes a thread and all of its messages. The thread must be trashed first.
DELETE https://api.molted.email/v1/agent/threads/:id/permanentcurl -X DELETE "https://api.molted.email/v1/agent/threads/thr_abc123/permanent?tenantId=TENANT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"{ "deleted": true }CLI
molted threads archive thr_abc123 thr_def456
molted threads unarchive thr_abc123
molted threads trash thr_abc123
molted threads restore thr_abc123
molted threads delete thr_abc123 # must be trashed firstThread statuses
| Status | Description |
|---|---|
open | Active conversation, no action taken |
waiting | Waiting for a reply from the contact |
resolved | Conversation is complete |
escalated | Handed off for human or senior agent review |
Replying to a thread
Use the outbound reply endpoint to send a reply within a thread, or use the threads reply CLI shorthand:
# Shorthand with plain text body
molted threads reply thr_abc123 --body "Thanks for reaching out!"
# With a specific template
molted threads reply thr_abc123 --template-id follow-up \
--payload '{"name": "Alice"}' --dedupe-key "reply-alice-2"See Outbound for full send and reply API documentation.
Schedule a follow-up
Schedule a follow-up email that sends automatically if the contact does not reply within a specified delay. Follow-ups are tied to a specific send via its requestId, not a thread ID.
The requestId is returned in the response when you send an email. Save it if you plan to schedule a follow-up later:
# Send an email and note the requestId in the response
molted send --to alice@example.com --template welcome \
--dedupe-key "welcome-alice-1" --payload '{"name": "Alice"}'
# Response: { "status": "sent", "requestId": "req_abc123", "threadId": "thr_abc123" }
# Use the requestId (not the threadId) to schedule a follow-up
molted threads followup req_abc123 \
--contact-email alice@example.com \
--delay-hours 72 --cancel-on-replyThe threads followup command takes a requestId (from the send response), not a threadId. Follow-ups are tied to a specific outbound message, not the thread as a whole. Save the requestId from the send response if you plan to schedule a follow-up.
CLI
# Schedule a follow-up 72 hours after initial send, cancel if they reply
molted threads followup req_abc123 \
--contact-email alice@example.com \
--delay-hours 72 \
--cancel-on-reply
# Schedule a 30-minute follow-up
molted threads followup req_abc123 \
--contact-email alice@example.com \
--delay-minutes 30
# With trigger conditions (only send if contact has not converted)
molted threads followup req_abc123 \
--contact-email alice@example.com \
--delay-hours 24 \
--trigger-conditions '{"field":"outcome.converted","op":"eq","value":false}'Options
| Flag | Type | Required | Description |
|---|---|---|---|
--contact-email | string | Yes | Contact email address. |
--delay-hours | number | Yes (unless --delay-minutes) | Delay in hours before the follow-up sends. |
--delay-minutes | number | Yes (unless --delay-hours) | Delay in minutes before the follow-up sends. |
--cancel-on-reply | flag | No | Cancel the follow-up if the contact replies first. |
--trigger-conditions | JSON | No | Additional trigger conditions as JSON. |
You must provide exactly one of --delay-hours or --delay-minutes, not both.
API
POST https://api.molted.email/v1/agent/outbound/schedule-followupSee Outbound - Schedule followup for the full API reference, request body, and response format.