MOLTED EMAIL

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

MethodPathScopeDescription
GET/v1/agent/threadsreadList threads
GET/v1/agent/threads/:idreadGet thread with messages
PATCH/v1/agent/threads/:idadminUpdate thread
POST/v1/agent/threads/archivemanageArchive threads
POST/v1/agent/threads/unarchivemanageUnarchive threads
POST/v1/agent/threads/trashmanageMove threads to trash
POST/v1/agent/threads/restoremanageRestore threads from trash
DELETE/v1/agent/threads/:id/permanentmanagePermanently delete a thread
POST/v1/agent/outbound/schedule-followupautomationSchedule 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/threads
curl
curl "https://api.molted.email/v1/agent/threads?tenantId=TENANT_ID&status=open&direction=inbound&limit=25" \
  -H "Authorization: Bearer YOUR_API_KEY"

Query parameters

ParameterTypeDescription
tenantIdstringYour tenant ID
mailboxIdstringFilter by mailbox
statusstringFilter by status: open, waiting, resolved, escalated
directionstringFilter by direction: inbound, outbound
viewstringFilter by view: active (default), archived, trashed
contactEmailstringFilter by contact email address
limitintegerMax results, 1-50 (default 25)
offsetintegerPagination offset

Response

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
molted threads list --status open --direction inbound --limit 10
molted threads list --contact alice@example.com
molted threads list --view archived

Get a thread

Returns the thread and all of its messages in chronological order.

GET https://api.molted.email/v1/agent/threads/:id
curl
curl "https://api.molted.email/v1/agent/threads/thr_abc123?tenantId=TENANT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"

Query parameters

ParameterTypeDescription
tenantIdstringYour tenant ID
includeQuarantinedbooleanInclude held/quarantined messages. Requires operator scope.

Response

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
molted threads get thr_abc123

Update a thread

Update the status, assigned agent, or metadata on a thread.

PATCH https://api.molted.email/v1/agent/threads/:id
curl
curl -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

FieldTypeDescription
statusstringThread status: open, waiting, resolved, escalated
assignedAgentIdstringAssign the thread to a specific agent
metadataobjectArbitrary key-value metadata

CLI

molted threads update
molted threads update thr_abc123 --status resolved
molted threads update thr_abc123 --status escalated --assigned-agent-id agt_abc

Thread 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
Request body
{ "threadIds": ["thr_abc123", "thr_def456"] }
Response
{ "archived": 2 }

Unarchive

Move archived threads back to the active view.

POST https://api.molted.email/v1/agent/threads/unarchive
Request body
{ "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
Request body
{ "threadIds": ["thr_abc123"] }

Restore

Restore trashed threads to the active view.

POST https://api.molted.email/v1/agent/threads/restore
Request body
{ "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/permanent
curl
curl -X DELETE "https://api.molted.email/v1/agent/threads/thr_abc123/permanent?tenantId=TENANT_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{ "deleted": true }

CLI

molted threads lifecycle
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 first

Thread statuses

StatusDescription
openActive conversation, no action taken
waitingWaiting for a reply from the contact
resolvedConversation is complete
escalatedHanded 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:

molted threads reply
# 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:

Get the requestId from a send
# 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-reply

The 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

molted threads followup
# 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

FlagTypeRequiredDescription
--contact-emailstringYesContact email address.
--delay-hoursnumberYes (unless --delay-minutes)Delay in hours before the follow-up sends.
--delay-minutesnumberYes (unless --delay-hours)Delay in minutes before the follow-up sends.
--cancel-on-replyflagNoCancel the follow-up if the contact replies first.
--trigger-conditionsJSONNoAdditional 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-followup

See Outbound - Schedule followup for the full API reference, request body, and response format.