Threads

A thread is an email conversation: a subject and the messages exchanged under it. Carom imports threads from every mailbox connected to your account, and a thread that reached several of your team’s mailboxes appears once, listing each mailbox it came through. Use this resource to find threads, read their messages, and keep track of which ones need attention.

Your key sees the threads your key’s user can see: those in mailboxes that user owns or has been given access to, and those shared with them. Read, flagged, resolved, and snoozed are kept per user, so marking a thread read through the API changes it for your key’s user and no one else.

#The thread object

Returned by List threads and Retrieve a thread. List responses leave messages empty and return tasks and comments as null; retrieving a single thread fills them in.

Attributes

  • idstring · uuid

    Unique identifier for the thread.

  • subjectstring · nullable
  • snippetstring · nullable

    A short plain-text excerpt of the thread.

  • headlinestring · nullable

    A one-sentence summary written by Carom. Null until Carom has summarized the thread.

  • summarystring · nullable

    A longer summary of the whole thread, written by Carom. Null until Carom has summarized the thread.

  • message_countinteger · nullable
  • has_attachmentsboolean · nullable
  • readboolean

    Whether your key’s user has read the thread. Change it with Mark a thread read.

  • flaggedboolean

    Whether your key’s user has flagged the thread.

  • resolvedboolean

    Whether your key’s user has marked the thread as dealt with. Resolved threads drop out of List open threads.

  • snooze_untilstring · date-time · nullable

    When your key’s user’s snooze on this thread ends. Null when the thread isn’t snoozed.

  • mailbox_idsarray of strings · uuid

    The mailboxes the thread came through.

  • inbox_sort_timestring · date-time · nullable

    When the thread last received a message. The inbox slice of List threads sorts by this.

  • first_sent_atstring · date-time · nullable
  • last_sent_atstring · date-time · nullable

    When the latest message was sent. The default sort for List threads.

  • participantsobject

    Every participant’s email address, mapped to the matching contact when one is visible to your key, otherwise to the display name from the message headers, or to null.

  • participant_namesobject

    Every participant’s email address, mapped to the display name from the message headers, or to null when the headers carried none.

  • messagesarray of objects · nullable

    The messages visible to your key, oldest first. Empty in list responses. A message that reached only mailboxes your key can’t access is left out even when the thread itself is visible.

    Show 10 child attributesHide child attributes
    • idstring · uuid
    • sent_atstring · date-time · nullable
    • from_email_addressstring · nullable
    • to_email_addressesarray of strings
    • cc_email_addressesarray of strings
    • participant_email_addressesarray of strings

      Everyone on the message: sender and all recipients.

    • snippetstring · nullable
    • summarystring · nullable

      Carom’s summary of this message.

    • attachmentsarray of objects · nullable

      Files attached to the message. Each links to a file you can download.

      Show 8 child attributesHide child attributes
      • idstring · uuid
      • file_idstring · uuid · nullable
      • fileobject · nullable

        The file’s id, name, file_name, extension, and description.

      • content_typestring · nullable
      • sizeinteger · nullable

        In bytes.

      • inlineboolean · nullable

        True for images embedded in the message body.

      • content_idstring · nullable

        The MIME Content-ID the HTML body uses to reference this attachment as cid:content_id.

      • decorativeboolean

        True for a signature logo, a tracking pixel, or an image that appears only in quoted earlier messages, rather than a file someone meant to send. List files leaves these out by default.

    • bodyobject · nullable

      The message content. Carom splits each body at the quote header of a reply, so you can show only what this message added.

      Show 8 child attributesHide child attributes
      • source_formatstring · nullable

        Whether the original body was HTML or plain text.

        htmlplain
      • sanitized_htmlstring · nullable

        The whole HTML body, including any quoted reply, with scripts and other unsafe markup removed. An inline image that matches one of this message’s attachments by content_id has its src set to /files/{file_id}/download?attachment_id={id}, a path on the API that needs your key; any other cid: reference is left unchanged. Null when source_format is plain.

      • new_plain_textstring · nullable

        The text this message added, above any quote header, as plain text.

      • new_htmlstring · nullable

        The HTML this message added, above any quote header, sanitized and with inline images resolved as in sanitized_html. Null when source_format is plain.

      • quoted_plain_textstring · nullable

        The earlier messages quoted below the quote header, as plain text.

      • quoted_htmlstring · nullable

        The quoted part, sanitized and with inline images resolved as in sanitized_html. Null when source_format is plain.

      • has_quote_headerboolean · nullable

        Whether Carom found a quote header, such as “On Tuesday, Priya wrote:”, to split the body at.

      • truncatedboolean

        True when the original body was too large for Carom to read in full. Every text and HTML field then holds only the beginning of the message.

  • tasksarray of tasks · nullable

    Tasks attached to the thread that are visible to your key. Null in list responses.

  • commentsarray of comments · nullable

    Your team’s internal comments on the thread. Null in list responses.

  • tagsarray of tags · nullable

    Tags applied to this thread.

  • sharesarray of shares · nullable

    Who this thread has been shared with, and how.

  • pending_messagesarray of objects

    Messages your key’s user sent from Carom that haven’t synced back from the provider yet, oldest first. Each is a draft with status sending or sent, shown in message form, and drops out once the sent copy arrives in the thread. Queued and failed drafts don’t appear here. Empty in list responses.

    Show 14 child attributesHide child attributes
    • idstring · uuid

      The draft’s id.

    • delivery_statusstring

      sending while Carom hands the message to the provider, sent once the provider has accepted it.

      sendingsent
    • thread_idstring · uuid · nullable
    • mailbox_idstring · uuid · nullable
    • from_email_addressstring · nullable
    • to_email_addressesarray of strings
    • cc_email_addressesarray of strings
    • bcc_email_addressesarray of strings
    • subjectstring · nullable
    • bodystring · nullable
    • body_htmlstring · nullable
    • rfc_idstring · nullable

      The message’s Message-ID header.

    • created_atstring · date-time · nullable
    • sent_atstring · date-time · nullable
The thread object
{
  "id": "7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57",
  "subject": "Q4 renewal terms",
  "snippet": "Thanks Dana. The 12-month term works for us if we can keep the current per-site rate.",
  "headline": "Wildgrove accepts a 12-month renewal at the current rate",
  "summary": "Dana proposed a 12-month renewal starting October 1. Priya agreed on the condition that the per-site rate stays the same and asked for the paperwork by September 15.",
  "message_count": 4,
  "has_attachments": true,
  "read": true,
  "flagged": true,
  "resolved": false,
  "snooze_until": null,
  "mailbox_ids": ["d4e5f6a7-b8c9-4d0e-9f1a-2b3c4d5e6f70"],
  "inbox_sort_time": "2026-09-04T21:17:09.332Z",
  "first_sent_at": "2026-09-01T15:42:30.734Z",
  "last_sent_at": "2026-09-04T21:17:09.332Z",
  "participants": {
    "priya@wildgrove.example": {
      "id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
      "name": "Priya Natarajan",
      …
    },
    "dana@harborline.example": "Dana Whitfield"
  },
  "participant_names": {
    "priya@wildgrove.example": "Priya Natarajan",
    "dana@harborline.example": "Dana Whitfield"
  },
  "messages": [
    {
      "id": "5a1e3c7b-9d2f-4e6a-8b0c-7f3d1e5a9c26",
      "sent_at": "2026-09-01T15:42:30.734Z",
      "from_email_address": "dana@harborline.example",
      "to_email_addresses": ["priya@wildgrove.example"],
      "summary": "Dana proposes a 12-month renewal starting October 1.",
      …
    }
  ],
  "tasks": [],
  "comments": [],
  "tags": [
    {
      "id": "0f1e2d3c-4b5a-4968-8776-655443322110",
      "name": "Customer",
      "color": "#66b185",
      …
    }
  ],
  "shares": [],
  "pending_messages": []
}
get/threads Read key

#List threads

Returns the threads visible to your key, 50 per page, most recently sent first. Narrow the list with a slice, a record it involves, text, state, dates, or tags, and page through the result with a cursor.

A contact_id, organization_id, or space_id that isn’t visible to your key returns record_not_found. A visible record with no email addresses returns an empty list.

Query parameters

  • slicestring

    A preset view, in terms of your key’s user. inbox sorts by when threads last received a message instead of last_sent_at. today keeps threads whose latest message was sent today, and workweek those sent since the start of this week, in that user’s time zone. unreplied keeps threads with no message sent from that user’s own email address. awaiting is the same as unreplied. snoozed keeps threads whose snooze hasn’t ended. pinned-contacts keeps threads involving a contact that user has pinned. shared keeps threads shared directly with that user. flagged, unread, unresolved, and has_attachment match the boolean filters of the same names.

    inboxtodayworkweekflaggedunreadunrepliedawaitinghas_attachmentunresolvedsnoozedpinned-contactsshared
  • scopestring

    personal keeps threads in your key’s user’s primary mailbox; shared keeps threads shared with that user or one of their groups. Omit for no scope filter.

    personalshared
  • mailbox_idstring · uuid

    Only threads that came through this mailbox.

  • contact_idstring · uuid

    Only threads involving one of this contact’s email addresses.

  • organization_idstring · uuid

    Only threads involving someone employed at this organization.

  • space_idstring · uuid

    Only threads that belong to this space, through its contacts and organizations or through its tags, depending on how the space is set up.

  • querystring

    Match against subjects and snippets. Up to 500 characters.

  • subjectstring

    Match against subjects only. Up to 500 characters.

  • participantstring

    An email address that must be on the thread. Matched exactly, ignoring case.

  • categorystring

    The provider’s classification of the thread. Gmail threads take their inbox category. Outlook threads are personal when Focused Inbox puts them in Focused, and update when it puts them in Other.

    personalpromotionupdateforum
  • unread, flagged, unresolved, has_attachmentboolean

    When true, keep only threads in that state for your key’s user. false is the same as omitting the parameter.

  • first_sent_beforestring · date-time

    ISO 8601. Only threads that started before this time.

  • last_sent_afterstring · date-time

    ISO 8601. Only threads with a message sent after this time.

  • tagsstring

    Comma-separated tag ids, at most 50.

  • tag_operatorstringdefault any

    Whether a thread must carry any of the given tags, or all of them.

    anyall
  • next_cursorstring

    Opaque token from the previous page’s page_info.next_cursor. Omit to start from the beginning. The inbox slice sorts differently from the others, so a cursor from an inbox page works only with inbox. See Pagination.

Returns

  • collectionobject

    A page of threads and the cursor to the next one.

    Show 4 child attributesHide child attributes
    • recordsarray of threads

      Up to 50 threads, newest first.

    • page_infopage info

      Where this page sits in the full list. Pass next_cursor back to fetch the next page while has_more_after is true.

    • slice_keystring · nullable

      The slice you asked for, echoed back.

    • filtersobject · nullable

      The filters that were applied, echoed back.

Errors

  • 400invalid_requestA parameter is malformed, for example an unknown slice, an id that isn’t a UUID, or a date that isn’t ISO 8601.
  • 400invalid_cursorThe cursor is unreadable, or came from another list or sort.
  • 400unsupported_cursor_directionYou sent prev_cursor. This list pages forward only.
  • 404record_not_foundcontact_id, organization_id, or space_id names a record that isn’t visible to your key.
get/threads
curl "https://api.carom.io/threads?slice=inbox&unread=true" \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "collection": {
    "records": [
      {
        "id": "2f8d4b61-9c0a-4e37-b5d2-8a1c6e9f3b04",
        "subject": "Site walkthrough on the 22nd",
        "read": false,
        "inbox_sort_time": "2026-09-18T16:05:44.192Z",
        "messages": [],
        "tasks": null,
        …
      },
      {
        "id": "e4a7c1d9-3f52-4b8e-a0c6-5d9b2f7e1a38",
        "subject": "Invoice 2026-0914 from Tallis Freight",
        "read": false,
        "inbox_sort_time": "2026-09-18T09:31:02.012Z",
        "messages": [],
        "tasks": null,
        …
      }
    ],
    "page_info": {
      "limit": 50,
      "next_cursor": "c8Kq2vTnR4wLm7ZpX1dHsF9b",
      "prev_cursor": null,
      "has_more_after": true,
      "has_more_before": false
    },
    "slice_key": "inbox",
    "filters": {
      "unread": true
    }
  }
}
get/threads/open Read key

#List open threads

Returns the threads that still need your key’s user’s attention: every thread visible to your key that received a message in the last 14 days and that user hasn’t resolved, including snoozed threads. They come in three groups: unread, read and flagged, and the rest. Returns every open thread in one response; the list isn’t paginated.

Entries are a shorter form of the thread object, without messages, participants, tasks, comments, tags, or shares. Order within a group isn’t guaranteed; sort by inbox_sort_time if you need a stable order.

Returns

  • inboxobject
    Show 3 child attributesHide child attributes
    • unreadarray of objects

      Threads your key’s user hasn’t read.

    • flaggedarray of objects

      Threads that user has read and flagged.

    • otherarray of objects

      Threads that user has read and not flagged.

Each entry has these attributes of the thread object: id, subject, snippet, headline, summary, message_count, has_attachments, read, flagged, resolved, snooze_until, mailbox_ids, inbox_sort_time, first_sent_at, and last_sent_at. It also has these:

  • categorystring · nullable

    As on the category filter of List threads.

    personalpromotionupdateforum
  • sender_email_addressesarray of strings

    Everyone who has sent a message in the thread.

  • participant_email_addressesarray of strings

    Everyone on the thread.

  • participant_namesobject

    Every participant’s email address, mapped to the display name from the message headers, or to null when the headers carried none.

get/threads/open
curl https://api.carom.io/threads/open \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "inbox": {
    "unread": [
      {
        "id": "2f8d4b61-9c0a-4e37-b5d2-8a1c6e9f3b04",
        "subject": "Site walkthrough on the 22nd",
        "read": false,
        "flagged": false,
        "category": "personal",
        "sender_email_addresses": ["priya@wildgrove.example"],
        "inbox_sort_time": "2026-09-18T16:05:44.192Z",
        …
      }
    ],
    "flagged": [
      {
        "id": "7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57",
        "subject": "Q4 renewal terms",
        "read": true,
        "flagged": true,
        …
      }
    ],
    "other": []
  }
}
get/threads/{id} Read key

#Retrieve a thread

Returns a single thread with its messages, tasks, comments, and your key’s user’s pending sent messages. If some message bodies haven’t been downloaded yet, Carom fetches them from the provider before responding, so the first retrieval of an older thread can take longer.

Retrieving a thread doesn’t mark it read; read shows whether your key’s user has read it. To mark it read, use Mark a thread read.

Path parameters

  • idstring · uuidrequired

    The thread’s id.

Returns

The thread object, wrapped in thread.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
get/threads/{id}
curl https://api.carom.io/threads/7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57 \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "thread": {
    "id": "7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57",
    "subject": "Q4 renewal terms",
    "read": true,
    …
    "messages": [
      …
      {
        "id": "b8d2f6a0-4c1e-4a9b-9e3d-2c7f5a1b8e64",
        "sent_at": "2026-09-04T21:17:09.332Z",
        "from_email_address": "priya@wildgrove.example",
        "to_email_addresses": ["dana@harborline.example"],
        "cc_email_addresses": [],
        "snippet": "Thanks Dana. The 12-month term works for us if we can keep the current per-site rate.",
        "attachments": [
          {
            "id": "3e9b7d15-2a4c-4f6e-8d1b-9c5a3e7f2b40",
            "file_id": "91c4e8a2-6d3b-4e7f-a5c9-0b2d4f6e8a13",
            "file": {
              "id": "91c4e8a2-6d3b-4e7f-a5c9-0b2d4f6e8a13",
              "name": "Wildgrove site list",
              "file_name": "wildgrove-sites-2026.xlsx",
              "extension": "xlsx",
              "description": null
            },
            "content_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "size": 48213,
            "inline": false,
            "content_id": null,
            "decorative": false,
            …
          }
        ],
        "body": {
          "source_format": "html",
          "new_plain_text": "Thanks Dana. The 12-month term works for us if we can keep the current per-site rate. Updated site list attached.",
          "has_quote_header": true,
          "truncated": false,
          …
        }
      }
    ],
    "tasks": [
      {
        "id": "e7f8a9b0-c1d2-4e3f-8a4b-5c6d7e8f9a01",
        "description": "Send the Q4 renewal proposal",
        "due": "2026-09-15",
        …
      }
    ],
    "comments": [],
    "pending_messages": []
  }
}
get/threads/count Read key

#Count threads

Counts the threads that List threads would return for the same slice and filters, without fetching them. Counting stops at cap when you give one, which keeps the call fast on large mailboxes.

Query parameters

  • slice, scope, mailbox_id, contact_id, organization_id, space_id, query, subject, participant, category, unread, flagged, unresolved, has_attachment, first_sent_before, last_sent_after, tags, tag_operator

    As on List threads.

  • capinteger

    Stop counting at this many. When the cap is reached, total equals cap and exact is false.

Returns

  • Show 4 child attributesHide child attributes
    • totalinteger
    • exactboolean

      False when counting stopped at cap.

    • cappedboolean
    • capinteger · nullable

      The cap that applied, or null.

Errors

  • 400invalid_requestA parameter is malformed, for example an unknown slice or an id that isn’t a UUID.
  • 404record_not_foundcontact_id, organization_id, or space_id names a record that isn’t visible to your key.
get/threads/count
curl "https://api.carom.io/threads/count?unread=true&cap=500" \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{
  "count": {
    "total": 37,
    "exact": true,
    "capped": false,
    "cap": 500
  }
}
post/threads/{thread_id}/flag Write key

#Flag a thread

Flags the thread for your key’s user. Flagging a thread that is already flagged succeeds and changes nothing.

If your key’s user owns a mailbox the thread came through and that mailbox has label_sync on, Carom also flags the thread at the provider (a star, in Gmail) shortly after the request returns.

Path parameters

  • thread_idstring · uuidrequired

Returns

The ok object, {"ok": "ok"}.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
post/threads/{thread_id}/flag
curl -X POST https://api.carom.io/threads/7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57/flag \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{ "ok": "ok" }
delete/threads/{thread_id}/flag Write key

#Unflag a thread

Removes your key’s user’s flag from the thread. Unflagging a thread that isn’t flagged succeeds and changes nothing. With label_sync on, Carom removes the flag at the provider as well.

Path parameters

  • thread_idstring · uuidrequired

Returns

An empty response with status 204.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
delete/threads/{thread_id}/flag
curl -X DELETE https://api.carom.io/threads/7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57/flag \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response204
No content
post/threads/{thread_id}/read Write key

#Mark a thread read

Marks the thread read for your key’s user. If your key’s user owns a mailbox the thread came through and that mailbox has label_sync on, Carom also marks it read at the provider, shortly after the request returns.

Path parameters

  • thread_idstring · uuidrequired

Returns

The ok object, {"ok": "ok"}.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
post/threads/{thread_id}/read
curl -X POST https://api.carom.io/threads/2f8d4b61-9c0a-4e37-b5d2-8a1c6e9f3b04/read \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{ "ok": "ok" }
delete/threads/{thread_id}/read Write key

#Mark a thread unread

Marks the thread unread for your key’s user, and at the provider when label_sync applies.

Path parameters

  • thread_idstring · uuidrequired

Returns

An empty response with status 204.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
delete/threads/{thread_id}/read
curl -X DELETE https://api.carom.io/threads/2f8d4b61-9c0a-4e37-b5d2-8a1c6e9f3b04/read \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response204
No content
post/threads/{thread_id}/resolution Write key

#Resolve a thread

Marks the thread as dealt with for your key’s user. A resolved thread leaves List open threads and the unresolved filter of List threads. Resolution is kept in Carom only; nothing changes at the provider.

Path parameters

  • thread_idstring · uuidrequired

Returns

The ok object, {"ok": "ok"}.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
post/threads/{thread_id}/resolution
curl -X POST https://api.carom.io/threads/7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57/resolution \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response200
{ "ok": "ok" }
delete/threads/{thread_id}/resolution Write key

#Reopen a thread

Removes your key’s user’s resolution from the thread, so it counts as open again.

Path parameters

  • thread_idstring · uuidrequired

Returns

An empty response with status 204.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
delete/threads/{thread_id}/resolution
curl -X DELETE https://api.carom.io/threads/7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57/resolution \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response204
No content
post/threads/{thread_id}/snooze Write key

#Snooze a thread

Snoozes the thread for your key’s user until a given time. The thread shows the time as snooze_until and appears in the snoozed slice of List threads until then. Snoozing doesn’t remove the thread from other lists. Snoozing a thread that is already snoozed replaces the old time.

Path parameters

  • thread_idstring · uuidrequired

Request body application/json

  • snooze_untilstringrequired

    An ISO 8601 timestamp, or one of the shortcuts below, which use your key’s user’s time zone. soon is three hours from now, on the hour; tonight is 19:00 today, or halfway between now and midnight when it’s already 17:00 or later; morning is 8:00 tomorrow; weekend is 8:00 on the coming Saturday; week is 8:00 next Monday; month is 8:00 on the same date next month. Send a timestamp when the exact time matters.

    soontonightmorningweekendweekmonth

Returns

  • threadobject
    Show 1 child attributeHide child attributes
    • snooze_untilstring · date-time

      When the snooze ends. A timestamp you sent is echoed as you sent it.

Errors

  • 400invalid_requestsnooze_until is missing or empty.
  • 404record_not_foundNo thread with that id is visible to your key.
post/threads/{thread_id}/snooze
curl https://api.carom.io/threads/7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57/snooze \
  -H "Authorization: Bearer $CAROM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "snooze_until": "2026-09-22T15:00:00.000Z" }'
Response200
{
  "thread": {
    "snooze_until": "2026-09-22T15:00:00.000Z"
  }
}
delete/threads/{thread_id}/snooze Write key

#Unsnooze a thread

Ends your key’s user’s snooze on the thread now. Unsnoozing a thread that isn’t snoozed succeeds and changes nothing.

Path parameters

  • thread_idstring · uuidrequired

Returns

An empty response with status 204.

Errors

  • 404record_not_foundNo thread with that id is visible to your key.
delete/threads/{thread_id}/snooze
curl -X DELETE https://api.carom.io/threads/7c2e9a14-5b3d-4f8e-9a61-3d0b8e2f4c57/snooze \
  -H "Authorization: Bearer $CAROM_API_KEY"
Response204
No content