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

# Update a thread

`PATCH /v1/email/threads/{thread_id}`

## Request

- Base URL: `https://us1.platform.bird.com`
- URL: `https://us1.platform.bird.com/v1/email/threads/{thread_id}`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `bird_session`

Applies label changes to a conversation, and links or unlinks a contact. Adding `spam` files the conversation, and its received messages, as spam. Adding `archive` files it away without deleting it. Adding `inbox`, or removing `spam`, `blocked`, or `archive`, returns it to the inbox, and its unread count recomputes to match. An archived conversation returns to the inbox by itself when a new message arrives that isn't spam or blocked; a junk reply or an outbound send leaves it archived. To block a sender going forward, add a receive rule instead. Any field you leave out stays unchanged.

## Headers

- `Idempotency-Key` string
- `X-Workspace-Id` string
- `X-Organization-Id` string

## Request body

- EmailThreadUpdateRequest: Changes to apply to a thread. Omitted fields are left unchanged.
  - `labels` EmailLabelsUpdate: Label changes to apply. Labels in `add` are applied and labels in `remove` are taken off; other labels are left untouched. Adding a label that is already present, or removing one that is not, has no effect. System labels express state changes. On a conversation, adding `spam` files it as spam. Adding `archive` files it away without deleting it. Adding `inbox`, or removing `spam`, `blocked`, or `archive`, returns it to the inbox. Removing `unread` marks all retained received messages as read in one call. On a message, adding or removing `unread` flips read state. Adding or removing `trash` moves it to or out of the trash. The API rejects changes that contradict this model. A request cannot add more than one placement label. It cannot add `blocked`, because blocking a sender is a receive-rule decision. Removing `inbox` requires adding a destination. A conversation cannot add `trash` or `unread`; removing `unread` is the mark-all-read shortcut, and `trash` uses the `DELETE` verb. A message cannot use placement labels; move its conversation instead. A sent message cannot use `unread`. Custom labels are 1-64 characters with no commas, control characters, or leading or trailing whitespace. System label names and a small reserved set (`all`, `archived`, `deleted`, `draft`, `drafts`, `flagged`, `important`, `junk`, `muted`, `none`, `outbox`, `pinned`, `read`, `scheduled`, `snoozed`, `starred`) cannot be used as custom labels, in any casing. A conversation or message has at most 20 labels, system labels included.
    - `add` string[]: Labels to apply.
    - `remove` string[]: Labels to take off.
  - `contact_id` string

## Response `200`

The updated thread.

- EmailThread: A conversation in a mailbox. It groups every message in both directions, the mail the mailbox received and the replies it sent, and it holds the conversation's read state, labels, and participant list. A message is retained until it is trashed or ages past the mailbox's retention tier. Only retained messages count toward the totals below.
  - `id` string, required
  - `mailbox_id` string, required
  - `channel` string, required: Channel this conversation lives on. Always `email`.
  - `contact_id` string, required
  - `subject` string, nullable, required: Subject of the conversation, taken from its first message. Null when that message had no subject.
  - `participants` string[], required: Addresses that appear on the retained messages in this conversation, including the mailbox's own address.
  - `message_count` integer, required: Number of retained messages in this conversation, both directions.
  - `unread_count` integer, required: Number of retained received messages that are still unread. Spam and blocked mail is not counted.
  - `last_message_at` string, date-time, required: When the most recent retained message in this conversation was received or sent.
  - `last_direction` 'inbound' | 'outbound', required: Direction of the most recent message: `inbound` for a received message, `outbound` for a sent one.
  - `labels` string[], required: Labels on this conversation. Exactly one system placement label is always present, set by the message that started the conversation: - `inbox`: The conversation is in the inbox. - `archive`: The conversation was filed away and is done for now. - `spam`: The conversation's opening message is filed in Spam. - `blocked`: The conversation's opening message was rejected by the mailbox's receive policy or rules. Move a conversation by updating its labels. Add `spam` to file it as spam, add `archive` to clean it out of the inbox, and add `inbox`, or remove `spam`, `blocked`, or `archive`, to bring it back. An archived conversation returns to the inbox by itself when a new message arrives. Custom labels share the same list, and a conversation has at most 20 labels in total.
  - `created_at` string, date-time, required: When the thread was created.
  - `updated_at` string, date-time, required: When the thread last changed.
  - `highlights` EmailThreadHighlights: Matched search fragments for a thread, one array per field the query matched, with the matched terms wrapped in `**`. A field is present only when the query matched it, so the keys that are present tell you which fields produced the hit. Returned only on thread search results.
    - `subject` string[]: Matched fragments from the conversation's subject.
    - `text` string[]: Matched fragments from a message's body text.

## Other responses

- `400`: Bad request
- `401`: Authentication required
- `403`: Insufficient permissions
- `404`: Resource not found
- `410`: The resource existed but is no longer available.
- `422`: The request has invalid field values, violates a business rule, or carries a query parameter the endpoint does not declare. Field validation errors use `type: validation_error` and include the affected fields in `details`. Business-rule errors identify the failed rule in `type`.
- `429`: Rate limit exceeded
- `500`: Internal server error
- `503`: The service is temporarily unavailable. If `Retry-After` is present, wait for that delay before retrying; otherwise, retry with exponential backoff. Reuse the same idempotency key and request when retrying a mutation.

---

[API](https://skmtc.dev/messagebird/apis/bird-api.md) · [All operations](https://skmtc.dev/messagebird/apis/bird-api/llms.txt) · [OpenAPI document](https://skmtc.dev/messagebird/apis/bird-api/revisions/6dfce1179799?raw)
