<Intro>

<EndpointHeader />

<Description>

Applies label changes to a conversation and links or unlinks a contact. System labels move the conversation: adding `spam` files it (and its received messages) as spam, adding `archive` files it away without deleting it, and adding `inbox` — or removing `spam`, `blocked`, or `archive` — returns it to the inbox; unread counts recompute to match. An archived conversation returns to the inbox by itself when a new message arrives. To block a sender going forward, add a receive rule instead. Omitted fields are left unchanged.

</Description>

</Intro>

<Payload kind="request">

<Field name="labels" type="object">

<Description>

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` or `archive`) returns it to the inbox, and removing `unread` marks all retained received messages as read in one call; on a message, adding or removing `unread` flips read state, and adding or removing `trash` moves it to or out of the trash. Changes that contradict this model are rejected: adding more than one placement label in one request, adding `blocked` (blocking a sender is a receive-rule decision), removing `inbox` without adding a destination, adding `trash` or `unread` to a conversation (removing `unread` is the mark-all-read shortcut; `trash` uses the DELETE verb), placement labels on a message (move its conversation instead), and `unread` on a sent message. 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 carries at most 20 labels, system labels included.

</Description>

<FieldChildren kind="request">

<Field name="add" type="array of string" prefix="labels.">

<Description>

Labels to apply.

</Description>

</Field>

<Field name="remove" type="array of string" prefix="labels.">

<Description>

Labels to take off.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="contact_id" type="nullable string">

<Description>

Contact to link this conversation to, or null to unlink the current contact.

</Description>

</Field>

</Payload>

<Payload kind="response">

<Field name="id" type="string" required>

<Description>

Thread ID.

</Description>

</Field>

<Field name="mailbox_id" type="string" required>

<Description>

Mailbox this conversation belongs to.

</Description>

</Field>

<Field name="channel" type="string" required>

<Description>

Channel this conversation lives on. Always `email`.

</Description>

</Field>

<Field name="contact_id" type="nullable string" required>

<Description>

Contact linked to this conversation, or null when none is linked.

</Description>

</Field>

<Field name="subject" type="nullable string" required>

<Description>

Subject of the conversation, taken from its first message. Null when that message had no subject.

</Description>

</Field>

<Field name="participants" type="array of string" required>

<Description>

Addresses that appear on the retained messages in this conversation, including the mailbox's own address.

</Description>

</Field>

<Field name="message_count" type="integer" required>

<Description>

Number of retained messages in this conversation, both directions.

</Description>

</Field>

<Field name="unread_count" type="integer" required>

<Description>

Number of retained received messages that are still unread. Spam and blocked mail is not counted.

</Description>

</Field>

<Field name="last_message_at" type="string" required>

<Description>

When the most recent retained message in this conversation was received or sent.

</Description>

</Field>

<Field name="last_direction" type="string" required>

<Description>

Direction of the most recent message — `inbound` for a received message, `outbound` for a sent one.

</Description>

<Description>

Possible values: `inbound`, `outbound`

</Description>

</Field>

<Field name="labels" type="array of string" required>

<Description>

Labels on this conversation. Exactly one system placement label is always present — `inbox`, `archive` (filed away, done for now), `spam` (the opening message failed sender authentication), or `blocked` (rejected by the mailbox's receive policy or rules) — set by the message that started the conversation. 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; a conversation carries at most 20.

</Description>

</Field>

<Field name="created_at" type="string" required>

<Description>

When the thread was created.

</Description>

</Field>

<Field name="updated_at" type="string" required>

<Description>

When the thread last changed.

</Description>

</Field>

<Field name="highlights" type="object">

<Description>

Matched search fragments, keyed by the field that matched. Returned only by thread search; omitted when listing threads.

</Description>

<FieldChildren kind="response">

<Field name="subject" type="array of string" prefix="highlights.">

<Description>

Matched fragments from the conversation's subject.

</Description>

</Field>

<Field name="text" type="array of string" prefix="highlights.">

<Description>

Matched fragments from a message's body text.

</Description>

</Field>

</FieldChildren>

</Field>

</Payload>