---
title: "Update a thread"
method: PATCH
path: "/v1/threads/{id}"
tags: ["Threads"]
---

# Update a thread

`PATCH /v1/threads/{id}`

## Request

- Base URL: `https://api.mails.ai`
- URL: `https://api.mails.ai/v1/threads/{id}`
- Auth: HTTP bearer

**Requires scope:** `manage` or `inbox` (`inbox` only in a signed-in dashboard session; no API key or app can hold it). Changes `read`, `folder`, `status`, `labels` and `label_ids`; emits `thread.updated` when something changed. `folder: "archive"` and `status: "archived"` move together, and moving an archived thread anywhere else reopens it. `folder: "sent"` is a 422: a thread is filed there while every message in it is one the agent sent. So is `status: "archived"` with any folder but archive. A test key cannot move a thread holding live mail to trash (403 `live_mode_required`).

## Path parameters

- `id` string, required

## Request body

- UpdateThreadRequest
  - `labels` string[]: Label names, up to 50, each at most 64 characters. Replaces the thread's labels. Any such name works; a name that matches a label object picks up its id and colour.
  - `label_ids` string[]: Label object ids (`lbl_…`). Replaces the thread's labels with those labels' names. Sent together with `labels`, the thread gets both.
  - `status` 'open' | 'closed' | 'archived': "archived" also files the thread in archive; "open" or "closed" on an archived thread moves it back to the inbox.
  - `read` boolean: Mark the thread read (true) or unread (false).
  - `folder` 'inbox' | 'archive' | 'spam' | 'trash': Move the thread to inbox, archive, spam or trash. archive also sets status "archived", and moving an archived thread anywhere else reopens it. sent cannot be chosen (422): a thread is filed there while every message in it is one you sent. A thread in trash is deleted for good 30 days after it was moved there.

## Response `200`

The updated thread (no messages array).

- Thread
  - `id` string, required: Thread id (`thrd_…`).
  - `agent_id` string, required: Id (`agt_…`) of the agent the thread belongs to; a thread holds one agent's mail only.
  - `subject` string: The subject of the thread's first message, without one leading `Re:`, `Fwd:` or `Fw:`. Empty when that message had no subject.
  - `root_message_id` string: Id of the message that started the thread: `msg_…` for one the agent sent, `rcv_…` for one it received.
  - `last_message_id` string: Id of the message that joined the thread most recently (`msg_…` or `rcv_…`).
  - `last_message_at` string, date-time: When the latest message joined the thread. The thread list is ordered by it, newest first.
  - `message_count` integer, required: How many messages have joined the thread, sent and received.
  - `participants` string[]: Every address the thread has involved, in lower case and without repeats: the agent's own, the senders of received mail and the recipients of sent mail.
  - `labels` string[]: Label names, up to 50, each at most 64 characters. Any such name works; names that match a label object also appear in `label_ids`.
  - `label_ids` string[], required: Ids (`lbl_…`) of the label objects whose names are on this thread.
  - `status` 'open' | 'closed' | 'archived', required: `open` (every new thread), `closed` or `archived`, changed with PATCH. `archived` goes with folder `archive`, and only an `open` thread takes in new mail matched by its subject (mail from someone already in the thread).
  - `read` boolean, required: False once new mail arrives; set it with PATCH.
  - `folder` 'inbox' | 'archive' | 'spam' | 'trash' | 'sent', required: `inbox`, `archive`, `spam`, `trash` or `sent`. `archive` goes with status `archived`. `sent` holds a thread whose messages are all ones the agent sent, until a reply moves it to the inbox. Threads in trash are deleted for good 30 days after they were trashed.
  - `trashed_at` string, date-time: When the thread was moved to trash. Present only while it is there.
  - `test_mode` boolean, required: True when the thread holds no live mail: every message in it was sent with a test key (`mk_test_…`) or delivered through `POST /v1/test/inbound`. A thread with any live message is live. Its `thread.*` events carry the same `test_mode`, and `GET /v1/threads` lists a key's own mode unless `mode` says otherwise.
  - `created_at` string, date-time, required: When the thread was created, with its first message.
  - `updated_at` string, date-time: When the thread last changed: a message joined it, or its read state, folder, status or labels changed.

## Other responses

- `400`: Invalid request — malformed JSON or a field failed validation. Also `feature_not_enabled` when this server has a feature switched off (custom domains before they are available).
- `401`: Missing or invalid API key.
- `403`: The API key lacks the required scope (`insufficient_scope`), or the token belongs to an app connected by sign-in and this operation is closed to connected apps (`connected_app_not_allowed`).
- `404`: Resource not found in this workspace, or the agent a send names is archived (`agent_archived`).
- `422`: Unprocessable — agent paused, recipient suppressed, a recipient at test.mails.ai other than reply@test.mails.ai (`unknown_test_address`), or abuse guard.
- `500`: Internal server error.

---

[API](https://skmtc.dev/mails/apis/mails-ai-api.md) · [All operations](https://skmtc.dev/mails/apis/mails-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mails/apis/mails-ai-api/revisions/4d4930a8c33b?raw)
