Message labels
Discover message tags, update them in batches, and combine required or excluded labels.
Read as Markdown ↗Labels are ordinary, case-sensitive tags on individual received or sent messages. Guests and registered accounts can label their own mail. Agents sharing an account see the same labels. No separate label-creation request is needed.
Message lists and details return a labels array, empty when there are no labels. Received messages can be labeled in any processing state; sent copies can be labeled in any sending state. Labels are not sent to recipients or added to original MIME.
Add or remove labels
Use the endpoint for the message copy you want to organize:
PATCH /v1/messages/{message_id}for received mail.PATCH /v1/sent/{message_id}for a saved outgoing message.
Both require bearer authentication and Content-Type: application/json. The JSON body is limited to 20 KiB.
{"add_labels":["receipts","needs-review"],"remove_labels":["handled"]}| Field | Contract |
|---|---|
add_labels | Optional array of at most 32 label strings to add. Existing labels are unchanged. |
remove_labels | Optional array of at most 32 label strings to remove. Absent labels are ignored. |
At least one array must contain a label. Unknown fields are rejected. Duplicate names within an array are ignored. A name cannot appear in both arrays after trimming.
Names must contain 1–128 UTF-8 bytes after trimming surrounding whitespace, with no control characters or malformed Unicode. Case is preserved: Receipts and receipts are different tags. Labels are a set; do not rely on their order.
A successful update returns 200 with the resulting labels:
{"id":"22222222-2222-4222-8222-222222222222","labels":["needs-review","receipts"]}Additions and removals apply together without replacing unrelated labels. Repeating the same update does not duplicate labels. Concurrent changes to different labels are preserved; opposite changes to the same label follow write order. Labels are not a work-claiming lock.
Invalid changes return 400 invalid_labels. Missing, deleted, or other-account messages return 404. Label updates do not require sending or deletion permission and consume no sending allowance.
Update several messages
Use PATCH /v1/messages/labels for received mail or PATCH /v1/sent/labels for outgoing copies. Authentication and label-change rules are the same as for individual updates. The body may contain up to 32 KiB of JSON:
{"message_ids":["22222222-2222-4222-8222-222222222222","33333333-3333-4333-8333-333333333333"],"add_labels":["handled"],"remove_labels":["needs-review"]}Supply 1–100 message IDs in message_ids; duplicate IDs are updated once. Only message_ids, add_labels, and remove_labels are accepted. The same additions and removals apply to every target. IDs can belong to different inboxes owned by the account, but received and sent copies must use their respective endpoint.
The request is atomic: if any target is missing, deleted, or inaccessible, the response is a generic 404 and no labels change. Invalid ID arrays return 400 invalid_message_ids. Success returns 200 with one result per distinct ID in request order:
{"messages":[{"id":"22222222-2222-4222-8222-222222222222","labels":["handled"]},{"id":"33333333-3333-4333-8333-333333333333","labels":["handled"]}]}Select explicit IDs before updating; this endpoint does not accept a filter. Larger jobs require separate batches, each atomic on its own. If a response is lost, the whole batch may have applied. Inspect current labels before retrying when other agents may be changing the same tags.
Filter messages
Received lists, received counts, and sent lists accept the same label filters:
| Parameter | Matches |
|---|---|
labels_all | Every listed label must be present. |
labels_any | At least one listed label must be present. |
labels_none | None of the listed labels may be present. Unlabeled messages qualify. |
Supplied groups combine with AND. Each group accepts up to 32 names; names are trimmed and deduplicated using the ordinary label rules. Matching is exact and case-sensitive, not substring matching. Contradictory conditions simply match no messages.
In HTTP, repeat the group parameter for each name and URL-encode each value. Do not use comma-separated lists: a comma is part of a label name.
GET /v1/inboxes/INBOX_ID/messages?labels_all=project-x&labels_any=needs-reply&labels_any=waiting&labels_none=done
GET /v1/inboxes/INBOX_ID/messages/count?labels_none=handled
GET /v1/inboxes/INBOX_ID/sent?labels_all=project-x&labels_all=reportConnected tools list_messages, count_messages, and list_sent use arrays for the three groups. For one required tag, pass labels_all: ["receipts"], or use ?labels_all=receipts in HTTP. Empty arrays impose no condition; in HTTP, omit unused groups rather than supplying an empty value.
Follow next_cursor with the same inbox and normalized filters. Name order, duplicate names, and surrounding whitespace do not change a filter. Changing or removing a condition requires starting without a cursor. Labels can change between pages, so results are a live view rather than a snapshot.
Discover labels
GET /v1/inboxes/{inbox_id}/labels lists names currently used on undeleted received and sent copies in an owned, undeleted inbox. It requires bearer authentication and is available to guests through connected tools as list_labels.
Optional prefix restricts names by a literal, case-sensitive prefix, trimmed using label-name rules. Empty or omitted means all names; supply it at most once. limit is 1–100, default 20. Results are ordered by name using case-sensitive binary order, not locale-specific collation. Continue with cursor and the same inbox and prefix.
{"labels":[{"name":"receipts","received_count":12,"sent_count":2}],"next_cursor":null}Counts describe messages, not conversations, and include all processing and sending states. A name disappears when no undeleted message uses it. There is no separate label registry or rename operation. Results and counts can change while you paginate.
Label while sending
Message submission accepts optional labels, an array of at most 32 names using the same rules. They apply to the saved sent copy, including rejected or unknown attempts, not to replies or received copies.
Initial labels are part of the send's idempotency input. Name order and duplicates do not matter; omitted and empty arrays are equivalent. Retry with the original initial labels even if you later edit the saved message's tags. A replay returns the current labels without reapplying the originals.
Label behavior
Names such as read, unread, trash, and approved-to-send are just tags. They do not mark mail as read, hide or delete messages, authorize sending, or trigger processing. Cherami does not automatically apply labels.
Threads do not own labels and cannot be filtered or updated by label. Individual messages returned within a conversation retain their own labels. A reply does not inherit its parent's labels.