| list_messagesA | List messages with filtering by date, conversation, folder, workspace, creator or language.
USE WHEN: The general-purpose message reader; full bodies incl. transcript and AI summary. Max date span 183 days. user_ids filters by SENDER — for messages exchanged WITH someone, pass conversation_id from list_conversations. Use presigned URLs as-is.
USE INSTEAD: get_recent_messages for a quick look at the latest few (hard-capped at 10, no paging). search_message_ids for filters this cannot express — notified state, mentions or labels.
FIRST: workspace_id comes from get_workspaces_basic_info (field id) — call it first if you don't have one.
EXAMPLE: {"workspace_id":"ws-abc","start_date":"2026-09-01T00:00:00Z","size":25}
RETURNS: {page, size, sort_direction, total, results_count, has_next_page, filters, results: [{id, transcript?, ai_summary?, audio_url?, creator_id, conversation_id?, duration_ms, reply_count, status, type, created_at, ...}]}. Page on has_next_page/total — do not guess.
NARROW: pass response_fields ["total","has_next_page","results.id","results.transcript","results.created_at"] unless you need more — the full payload is much larger. |
| get_messageA | Get one message by ID, optionally expanded with related records.
USE WHEN: You have a message ID. fields ADDS related data (conversation, creator, labels) — it does not narrow the response. Use response_fields to narrow.
USE INSTEAD: list_messages when you do not have an ID, or need several messages — it already returns full bodies, so fetching each one again is wasted.
FIRST: id comes from list_messages (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"msg-abc","fields":"creator"}
RETURNS: {message: {id, transcript?, ai_summary?, audio_url?, creator_id, duration_ms, status, type, attachments?, created_at, ...}}. |
| get_recent_messagesA | Get up to 10 of the most recent messages, each with its conversation, creator and labels.
USE WHEN: A quick "what just happened" glance. Pre-joined, so no follow-up calls for creator or conversation names.
USE INSTEAD: list_messages whenever you need more than 10, any date range, paging, or a filter other than conversation and language — this tool supports none of those.
EXAMPLE: {"conversation_id":"conv-abc"}
RETURNS: {results: [{message: {...}, conversation: {...}, creator: {...}, labels: [...]}]}. No total and no paging: the cap of 10 is the whole answer. |
| create_conversation_messageA | Post a message into an existing conversation, or reply in a thread.
USE WHEN: You have a conversation_id. Pass parent_id (a message ID) to reply as a thread. Either transcript or links is required — the schema marks neither individually, so both param descriptions say so.
USE INSTEAD: create_direct_message to reach people who are not already in a conversation. create_voicememo_message for a standalone memo.
FIRST: id comes from list_conversations (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"conv-abc","transcript":"Agreed, shipping Friday."}
RETURNS: {message: {id, link, transcript?, status, type, conversation_id, created_at, ...}}.
ERROR BAD_REQUEST: Neither transcript nor links was provided. — Pass at least one of them. |
| create_direct_messageA | Send a direct message to one or more people, by user ID or email.
USE WHEN: Reaching people outside an existing conversation. Address it with to.user_ids or to.emails. Requires transcript or links.
USE INSTEAD: create_conversation_message when a conversation already exists — a DM starts a separate thread rather than joining it.
FIRST: to.user_ids comes from search_users (field id) — call it first if you don't have one.
EXAMPLE: {"to":{"user_ids":["user-abc"]},"transcript":"Quick question about the deck."}
RETURNS: {message: {id, link, transcript?, status, conversation_id, created_at, ...}}.
ERROR BAD_REQUEST: A user ID is invalid, or neither transcript nor links was provided. — Resolve people with search_users — never pass a display name as a user ID — and include a transcript or links. |
| create_voicememo_messageA | Create a voice memo, either from text (spoken via text-to-speech) or from an audio file at a URL.
USE WHEN: Pass transcript (2-5000 chars) to have Carbon Voice speak the text, or an https audio_url to upload audio, which wins over transcript. File it with folder_id, whose type must match, or a workspace_id.
USE INSTEAD: create_conversation_message to post into an existing conversation, or create_direct_message to send to specific people. A voice memo is standalone and lives in a folder or workspace.
EXAMPLE: {"transcript":"Reminder to review the pricing deck before Friday."}
RETURNS: {message: {id, link, transcript?, audio_url?, duration_ms, status, type, created_at, ...}}. status is often processing at first.
ERROR INVALID_AUDIO_URL: audio_url is not https, unreachable, too large, timed out, embeds credentials, or resolves to a private address. — The message gives the reason. Use a public https URL, or pass transcript instead.
ERROR BAD_REQUEST: None of transcript, audio_url or links was provided, or the transcript is outside 2-5000 characters. — Provide one of the three, and keep the transcript within the length limits. |
| add_attachments_to_messageA | Attach one or more link URLs to an existing message.
USE WHEN: Adding external links to a message that already exists.
USE INSTEAD: create_message_share_link to share a Carbon Voice message outward — that produces a link, this consumes them.
FIRST: id comes from list_messages (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"msg-abc","links":["https://example.com/spec"]}
RETURNS: {...} confirmation with the resulting attachments. |
| get_userA | Get a user's full profile by ID — names, languages, voice settings, workspace roles.
USE WHEN: You already have a user ID and need complete details.
USE INSTEAD: search_user / search_users to FIND someone by email, phone or name. get_current_user for the caller — this tool needs an explicit ID and will not default to you.
FIRST: id comes from search_users (field id) — call it first if you don't have one.
EXAMPLE: {"id":"user-abc"}
RETURNS: {id, first_name, last_name?, languages, voice_gender, workspace_ids, workspace_roles, user_type, created_at, ...}.
NARROW: pass response_fields ["id","first_name","last_name","workspace_ids"] unless you need more — the full payload is much larger. |
| search_userA | Find a single user by email, phone or name.
USE WHEN: Resolving ONE person. Supply exactly one of email, phone or name. Name search only matches your own contacts.
USE INSTEAD: search_users for several people in one call — it takes arrays and saves a round trip per person. get_user when you already have the ID.
EXAMPLE: {"email":"someone@example.com"}
RETURNS: {id, full_name, first_name, last_name?, link, image_url?, languages?, ...}. Use id wherever another tool asks for a user ID.
ERROR NOT_FOUND: Nobody matched, or a name search hit a non-contact. — Try an email or phone instead of a name; name search is limited to your contacts. |
| search_usersA | Resolve several users at once by emails, phones, IDs or names.
USE WHEN: Turning a list of people into user IDs in one call — the right first step before any tool that takes user IDs. Name search only matches your contacts.
USE INSTEAD: search_user for a single lookup. get_user for a full profile once you have the ID.
EXAMPLE: {"names":["Brett"]}
RETURNS: Array of {id, full_name, first_name, last_name?, link, languages?, ...}. If a name returns more than one candidate, ask which person was meant rather than guessing.
NARROW: pass response_fields ["id","full_name"] unless you need more — the full payload is much larger. |
| get_current_userA | Get the calling user's own identity, workspaces and settings.
USE WHEN: Establishing who you are acting as, or finding the caller’s workspace IDs before a workspace-scoped call. Takes no arguments.
USE INSTEAD: get_user for somebody else (it requires an explicit ID). get_workspaces_basic_info if you only need workspace IDs and names — it is far smaller than this response.
EXAMPLE: {}
RETURNS: {success, user: {user_guid, first_name, last_name?, email_txt?, phone_txt?, workspace_guids, identities, entries, environments, lifecycle_events, notification_settings, settings, ...}, settings: {...}}. This payload is LARGE — several unbounded arrays and an open settings map.
NARROW: pass response_fields ["user.user_guid","user.first_name","user.email_txt","user.workspace_guids"] unless you need more — the full payload is much larger. |
| list_conversationsA | List your conversations from the last 6 months, optionally filtered by participants, type and name.
USE WHEN: Finding a conversation_id. Filter with user_ids plus match, types and name — YOUR DM with someone is user_ids: ["<their id>"], types: ["directMessage"]. You are always an implicit participant, so never pass your own ID. Filters AND together; if several match, ask which was meant.
USE INSTEAD: get_conversation when you already have an ID and want full detail — this returns only id, name, workspace_id and type.
EXAMPLE: {"user_ids":["user-abc"],"types":["directMessage"]}
RETURNS: {results_count, results: [{id, name, workspace_id, type}]} where type is directMessage | customerConversation | namedConversation | asyncMeeting. No paging: results_count is what is returned, after filtering. name adds unfiltered_count: rows the name was matched against, AFTER user_ids/types. ALWAYS check it before saying no such conversation exists. 0 of 47 means none matched that string (misspelt, or >6 months old); 0 of 0 means your other filters left nothing — not that the caller has none. Widen the filters or ask; never report it does not exist. |
| get_conversationA | Get one conversation by ID, with full metadata.
USE WHEN: You have a conversation_id and need its description, visibility, owner or workspace name.
USE INSTEAD: get_conversation_users for the participant list. list_messages with conversation_id for its messages — this returns neither.
FIRST: id comes from list_conversations (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"conv-abc"}
RETURNS: {id, name, description?, link, workspace_id, workspace_name, owner_id, type, visibility, ...}. |
| get_conversation_usersA | List the people in a conversation.
USE WHEN: Finding out who is in a conversation, or collecting participant user IDs.
USE INSTEAD: search_users to resolve people by name or email generally — this is scoped to one conversation.
FIRST: id comes from list_conversations (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"conv-abc"}
RETURNS: Array of user objects with id and profile fields.
NARROW: pass response_fields ["id","full_name"] unless you need more — the full payload is much larger. |
| summarize_conversationA | Summarize a conversation by running an AI Action over its recent messages.
USE WHEN: You want a conversation summarized and have a conversation_id. Message selection is handled for you — omit message_ids and the most recent messages are used.
USE INSTEAD: run_ai_action if you already know exactly which message_ids to process, or want a non-summary AI Action.
FIRST: prompt_id comes from list_ai_actions (field id) — call it first if you don't have one.
FIRST: conversation_id comes from list_conversations (field results[].id) — call it first if you don't have one.
EXAMPLE: {"conversation_id":"conv-abc","prompt_id":"prompt-abc","limit":50}
RETURNS: Same as run_ai_action: {id, prompt_id, message_ids, responses: [{language, text?, markdown?, ...}], ...}.
ERROR BAD_REQUEST: prompt_id is not a valid AI Action ID. — Call list_ai_actions to get valid prompt_id values. |
| get_root_foldersA | List the root folders of a workspace for a given folder type.
USE WHEN: Orienting in the folder tree, or finding a folder_id. type is required: voicememo or prerecorded. include_all_tree returns nested folders too.
USE INSTEAD: get_folder to inspect one folder. get_folder_with_messages when you want a folder’s messages rather than its structure.
EXAMPLE: {"type":"voicememo","workspace_id":"ws-abc"}
RETURNS: {type, workspace_id?, include_all_tree?, sort_by, sort_direction, results: [{id, name, parent_folder_id?, subfolder_ids?, total_nested_folders_count, total_nested_messages_count, ...}]}. Not paginated — this is the complete set.
NARROW: pass response_fields ["results.id","results.name","results.total_nested_messages_count"] unless you need more — the full payload is much larger. |
| create_folderA | Create a folder in a workspace, optionally nested under another.
USE WHEN: Organising memos. name, type and workspace_id are all required; add parent_folder_id to nest.
USE INSTEAD: move_folder to relocate a folder that already exists.
FIRST: workspace_id comes from get_workspaces_basic_info (field id) — call it first if you don't have one.
EXAMPLE: {"name":"Q4 planning","type":"voicememo","workspace_id":"ws-abc"}
RETURNS: The created folder, same shape as get_folder. |
| get_folderA | Get one folder's metadata and, optionally, its immediate subfolders.
USE WHEN: Inspecting a folder. Set include_first_level_tree: true to get subfolders. Both date AND direction are silently ignored unless you do — upstream only documented that caveat on date.
USE INSTEAD: get_folder_with_messages when you want the messages inside the folder — this returns structure and counts only.
FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"folder-abc","include_first_level_tree":true}
RETURNS: {id, name, type, workspace_id, parent_folder_id?, path?, subfolder_ids?, message_ids?, total_nested_folders_count, total_nested_messages_count, subfolders?, ...}. |
| get_folder_with_messagesA | Get a folder together with the messages stored directly in it.
USE WHEN: Reading a folder’s contents. Only messages at that folder’s own level are returned — nested folders are not walked.
USE INSTEAD: get_folder for structure and counts without message bodies. list_messages with folder_id when you need date filtering or paging, which this tool does not support.
FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"folder-abc"}
RETURNS: {folder: {...}, messages: [{...}]}.
NARROW: pass response_fields ["folder.id","folder.name","messages"] unless you need more — the full payload is much larger. |
| update_folder_nameA | Rename a folder.
USE WHEN: Changing only the name. name is the sole editable field here.
USE INSTEAD: move_folder to change where a folder sits in the tree.
FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"folder-abc","name":"Q4 planning (final)"}
RETURNS: The updated folder, same shape as get_folder. |
| delete_folderA | Permanently delete a folder, including every nested folder and all their messages.
USE WHEN: Only when the whole subtree should be destroyed. This cascades and cannot be undone.
USE INSTEAD: move_folder to get a folder out of the way, or move_message_to_folder to relocate its messages first. Check total_nested_messages_count via get_folder before calling — the cascade is easy to underestimate.
FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"folder-abc"}
RETURNS: Deletion confirmation. |
| move_folderA | Move a folder into another folder, or up to a workspace root.
USE WHEN: Relocating a folder. Pass folder_id for a new parent folder, or workspace_id to move it to the workspace root — one or the other, not both.
USE INSTEAD: update_folder_name to rename in place. move_message_to_folder for a single message rather than a folder.
FIRST: id comes from get_root_folders (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"folder-abc","folder_id":"folder-parent"}
RETURNS: The moved folder, same shape as get_folder.
ERROR BAD_REQUEST: Both folder_id and workspace_id were given, or neither, or the move would nest a folder inside itself. — Pass exactly one destination. |
| move_message_to_folderA | Move a message into a folder, or out to a workspace.
USE WHEN: Filing a memo. Only voicememo/prerecorded messages you created can be moved, and the message type must match the folder's type. Pass exactly one of folder_id or workspace_id.
USE INSTEAD: move_folder to relocate a whole folder. create_voicememo_message with folder_id to file a memo at creation time instead of moving it after.
FIRST: message_id comes from list_messages (field results[].id) — call it first if you don't have one.
EXAMPLE: {"message_id":"msg-abc","folder_id":"folder-abc"}
RETURNS: The updated message with its new placement.
ERROR BAD_REQUEST: The message type is not voicememo/prerecorded, it does not match the destination folder's type, or both/neither destination was given. — Check type via get_message and the folder type via get_folder; they must match. Pass exactly one destination. |
| get_workspaces_basic_infoA | List every workspace you belong to, as id and name only.
USE WHEN: The cheapest way to resolve a workspace name to an ID before a workspace-scoped call. Takes no arguments.
USE INSTEAD: get_current_user if you need more than ids and names — but note that response is much larger, so prefer this one when ids suffice.
EXAMPLE: {}
RETURNS: Array of {id, name}. Nothing else, and no paging. |
| list_ai_actionsA | List the AI Actions (Prompts) available to you — each has an id usable as prompt_id.
USE WHEN: Before calling run_ai_action or summarize_conversation, to find a prompt_id. Also to show the user which AI Actions exist. Filter by owner_type (user = your own, workspace = shared, system = Carbon Voice built-ins).
USE INSTEAD: get_ai_action_responses if you want results that were already generated rather than the list of available actions.
EXAMPLE: {"owner_type":"system"}
RETURNS: Array of {id, name, description?, prompt, owner_type, workspace_id?, response_format?, created_at, last_updated_at}. Use id as prompt_id elsewhere.
NARROW: pass response_fields ["id","name","description","owner_type"] unless you need more — the full payload is much larger. |
| run_ai_actionA | Run an AI Action (Prompt) against one or more specific messages.
USE WHEN: You have concrete message_ids and a prompt_id, and want the AI Action applied to exactly those messages.
USE INSTEAD: summarize_conversation if you want a whole conversation summarized and would otherwise have to list its messages yourself — it does that selection for you.
FIRST: prompt_id comes from list_ai_actions (field id) — call it first if you don't have one.
FIRST: message_ids comes from list_messages (field results[].id) — call it first if you don't have one.
EXAMPLE: {"prompt_id":"prompt-abc","message_ids":["msg-1","msg-2"],"language":"english"}
RETURNS: {id, prompt_id, message_ids, creator_id, channel_id?, workspace_id?, responses: [{language, text?, markdown?, html?, json?}], created_at}. The generated output is in responses[], one entry per language.
ERROR BAD_REQUEST: prompt_id or one of message_ids is not a valid ID. — Call list_ai_actions for valid prompt_id values and list_messages for valid message IDs; do not retry with the same IDs. |
| run_ai_action_for_shared_linkA | Run an AI Action (Prompt) against one or more shared messages, addressed by share link ID.
USE WHEN: You have share link IDs — from create_message_share_link, or a link someone gave you — and want an AI Action applied to the messages behind them.
USE INSTEAD: run_ai_action if you have the message IDs directly; going through a share link adds nothing when you already have access.
FIRST: share_link_ids comes from create_message_share_link (field id) — call it first if you don't have one.
FIRST: prompt_id comes from list_ai_actions (field id) — call it first if you don't have one.
EXAMPLE: {"prompt_id":"prompt-abc","share_link_ids":["share-abc"]}
RETURNS: {share_link_ids, responses: [{language, text?, markdown?, html?, json?}], ...}.
ERROR NOT_FOUND: A share link ID does not exist, or its access has been revoked or expired. — Create a fresh link with create_message_share_link, or verify the ID with get_message_share_link. |
| get_ai_action_responsesA | Retrieve AI Action results that were generated previously.
USE WHEN: You want existing output rather than a fresh run — e.g. showing what an AI Action already produced for a message or conversation. Combine prompt_id, message_id and channel_id to narrow.
USE INSTEAD: run_ai_action (or summarize_conversation) to generate new output; this tool only reads what already exists and returns an empty array if nothing has been generated.
EXAMPLE: {"channel_id":"conv-abc","limit":10}
RETURNS: Array of {id, prompt_id, creator_id, message_ids, channel_id?, workspace_id?, responses: [{language, text?, markdown?, html?, json?}], created_at}.
NARROW: pass response_fields ["id","prompt_id","responses"] unless you need more — the full payload is much larger. |
| create_message_share_linkA | Create a shareable link to an existing message (e.g. a voice memo), and get the URL back.
USE WHEN: share_type: "link" for a shareable URL; "forward" to attach the share onto another message (also needs message_id). Also how you get a share_link_ids value.
USE INSTEAD: add_attachments_to_message to attach an external URL to a message, rather than share a Carbon Voice message outward.
FIRST: shared_message_id comes from list_messages (field results[].id) — call it first if you don't have one.
EXAMPLE: {"shared_message_id":"msg-abc","share_type":"link","access_type":"public"}
RETURNS: {id, link, share_type, access_type, created_by, specified_access?, end_access_at?, revoked_at?, shared_message: {...}}. link is the URL to hand out; id is the share_link_ids value other tools take.
NARROW: pass response_fields ["id","link","share_type","access_type"] unless you need more — the full payload is much larger.
ERROR BAD_REQUEST: shared_message_id is invalid, or share_type is "forward" without message_id. — Confirm the ID with get_message; when forwarding, also pass message_id. |
| get_message_share_linkA | Look up an existing message share link by its ID, including the message behind it.
USE WHEN: You have a share link ID and want its URL, access settings, or whether it is still valid — check revoked_at and end_access_at before relying on it.
USE INSTEAD: create_message_share_link to make a new link; this only reads existing ones. get_message if you have the message ID and do not care about the share.
FIRST: share_link_id comes from create_message_share_link (field id) — call it first if you don't have one.
EXAMPLE: {"share_link_id":"share-abc"}
RETURNS: Same shape as create_message_share_link: {id, link, share_type, access_type, revoked_at?, end_access_at?, shared_message: {...}, ...}.
NARROW: pass response_fields ["id","link","revoked_at","end_access_at"] unless you need more — the full payload is much larger.
ERROR NOT_FOUND: No share link with that ID, or it is no longer accessible. — Create a new one with create_message_share_link; do not retry the same ID. |
| list_my_action_itemsA | List your action items across every conversation and folder: those assigned to you, PLUS unassigned ones you created.
USE WHEN: Answering "what do I owe / what is on my plate" — but check assigned_to before calling something the user's own commitment: a null one is an item they raised that nobody has picked up. Filter by status (todo open, suggested AI-proposed, done complete). Page with starting_after.
USE INSTEAD: list_action_items when you want one specific conversation or folder rather than everything of yours.
EXAMPLE: {"status":"todo","limit":25}
RETURNS: {results: [{id, title, status, notes_text?, assigned_to?, due_date?, container_id?, container_type?, source_message_id?, creator_id, ...}], total?, results_count?, has_more?, next_cursor?, filters?}. Keep paging while has_more is true, passing next_cursor as starting_after.
NARROW: pass response_fields ["results.id","results.title","results.status","results.assigned_to","results.due_date"] unless you need more — the full payload is much larger. |
| list_action_itemsA | List action items belonging to one container — a conversation, a folder, or home.
USE WHEN: You have a container_id and want its action items. container_type is channel for a conversation, folder for a folder, or home. A conversation id is NOT a folder id — resolve container_id with the tool matching your container_type. Filter by status or assigned_to (pass the string null for unassigned).
USE INSTEAD: list_my_action_items for everything assigned to you regardless of where it lives.
FIRST: container_id comes from list_conversations (field results[].id) when container_type is channel — call it first if you don't have one.
FIRST: container_id comes from get_root_folders (field results[].id) when container_type is folder — call it first if you don't have one.
EXAMPLE: {"container_type":"channel","container_id":"conv-abc","status":"todo"}
RETURNS: Same as list_my_action_items: {results: [...], total?, results_count?, has_more?, next_cursor?, filters?}.
NARROW: pass response_fields ["results.id","results.title","results.status","results.assigned_to"] unless you need more — the full payload is much larger. |
| get_action_itemA | Get one action item by its ID, with full detail.
USE WHEN: You have an action item ID and need its notes, assignee, due date, or source message.
USE INSTEAD: list_my_action_items or list_action_items if you do not have an ID yet — they already return the same fields per item, so a follow-up call is usually wasted.
FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"ai-abc"}
RETURNS: {id, title, status, notes_text?, creator_id, assigned_to?, due_date?, container_id?, container_type?, source_message_id?, last_updated_by, ...}. |
| create_action_itemA | Create an action item, optionally attached to a conversation or folder.
USE WHEN: Recording a task. Only title is required. Attach it by passing both container_type and container_id, and link it to what prompted it with source_message_id.
USE INSTEAD: suggest_action_items_from_messages to have tasks extracted from message content automatically instead of writing each one yourself.
EXAMPLE: {"title":"Send the pricing deck","assigned_to":"user-abc"}
RETURNS: {id, title, status, notes_text?, assigned_to?, due_date?, container_id?, container_type?, creator_id, ...}. New items start at status todo.
ERROR BAD_REQUEST: assigned_to is not a valid user ID, or container_id does not match container_type. — Resolve people with search_users (never pass a name) and containers with list_conversations or get_root_folders. |
| update_action_itemA | Change an action item's title, notes, assignee, or due date.
USE WHEN: Editing item content. Send only the fields you want changed — omitted fields are left as they are.
USE INSTEAD: set_action_item_status to move an item between todo / done / suggested; status is not editable here.
FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"ai-abc","due_date":"2026-10-01"}
RETURNS: The updated action item, same shape as get_action_item. |
| set_action_item_statusA | Move an action item between suggested, todo and done.
USE WHEN: Completing an item (done), reopening it (todo), or accepting an AI-suggested item by promoting it from suggested to todo.
USE INSTEAD: update_action_item for title, notes, assignee or due date; this tool only sets status.
FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"ai-abc","status":"done"}
RETURNS: The updated action item, same shape as get_action_item. |
| delete_action_itemA | Permanently delete an action item.
USE WHEN: The item was created in error and should not exist at all.
USE INSTEAD: set_action_item_status with done to complete an item — that keeps the record. Deleting cannot be undone, so prefer it only when the item is genuinely spurious.
FIRST: id comes from list_my_action_items (field results[].id) — call it first if you don't have one.
EXAMPLE: {"id":"ai-abc"}
RETURNS: Deletion confirmation for the removed item. |
| suggest_action_items_from_messageA | Extract action items from ONE message and return them immediately.
USE WHEN: Turning a single message into tasks — "what did she ask me to do?". The items come back in this call, already saved with status: "suggested"; promote the ones you want with set_action_item_status. Prefer this over suggest_action_items_from_messages whenever there is exactly one message, since it needs no polling.
USE INSTEAD: suggest_action_items_from_messages for two or more messages — it reasons over the whole set at once and can catch commitments that span messages, which calling this tool repeatedly cannot. create_action_item when you already know the task.
FIRST: message_id comes from list_messages (field results[].id) — call it first if you don't have one.
EXAMPLE: {"message_id":"msg-1"}
RETURNS: Array of the created action items, each with id, title, assigned_to, due_date, notes_text and status: "suggested". An empty array means the model found nothing actionable. Runs the extraction inline, so expect this call to take a few seconds. |
| suggest_action_items_from_messagesA | Queue AI extraction of candidate action items from specific messages. Runs in the background.
USE WHEN: Turning a conversation into tasks — "what did we agree to?". Pass the message_ids to analyse, then POLL list_my_action_items or list_action_items with status: "suggested" for the results, and promote the ones you want with set_action_item_status.
USE INSTEAD: suggest_action_items_from_message (singular) for a SINGLE message — it returns the items directly, with no polling. create_action_item when you already know the task and do not need it inferred — that returns the item synchronously, with an id.
FIRST: message_ids comes from list_messages (field results[].id) — call it first if you don't have one.
EXAMPLE: {"message_ids":["msg-1","msg-2"]}
RETURNS: ACKNOWLEDGEMENT ONLY — no items are returned. Extraction is queued and runs in the background, so poll a listing tool with status: "suggested" to see the results. |
| search_message_idsA | Find message IDs by notified state, mentions, labels, creator, conversation or workspace — returning IDs plus cursor metadata.
USE WHEN: Any filter list_messages cannot express: whether you were notified (notified_status), whether you were tagged (tagged_user_ids), or by label_ids. Cheap in tokens because it returns IDs only — hydrate the ones you need with get_message.
USE INSTEAD: list_messages when a date range, conversation or workspace filter is all you need and you want full message bodies in one call. search_messages_by_heard_status for unread/listened state, which this tool cannot filter on.
EXAMPLE: {"notified_status":"notified","limit":50}
RETURNS: {ids: [{...}], has_more, next_cursor?}. Keep paging while has_more is true, passing next_cursor back as next_cursor.
ERROR BAD_REQUEST: An ID list contains names rather than IDs, or exceeds 50 entries. — Resolve people to IDs with search_users and conversations with list_conversations; split lists longer than 50. |
| search_messages_by_heard_statusA | Find messages by whether you have listened to them, and get per-conversation unheard counts.
USE WHEN: "What have I not listened to yet" / "catch me up". heardStatus: "unheard" is the unread filter. The response also carries unheard_counts_by_channel, so you can prioritise conversations without fetching their messages.
USE INSTEAD: search_message_ids for notified state, mentions or date anchors — this tool accepts no date filter (see note below). list_messages for plain recent history.
EXAMPLE: {"heardStatus":"unheard","limit":25}
RETURNS: {messages: [{message_guid, creator_guid, creator_first_name, channel_guids, transcript_txt, message_ts, heard_status, ...}], unheard_counts_by_channel: {conversation_id: count}, success}. Use unheard_counts_by_channel to decide where to look first.
NARROW: pass response_fields ["unheard_counts_by_channel","messages.message_guid","messages.channel_guids","messages.creator_first_name","messages.transcript_txt","messages.message_ts"] unless you need more — the full payload is much larger. |
| list_inbox_notificationsA | List your inbox notifications, with a total unread count.
USE WHEN: Answering "what did I miss" or "where was I mentioned" — pass category: "mentions" for mentions. The response includes total_unread, so you can report a count without paging.
USE INSTEAD: search_message_ids with notified_status if you want the messages themselves rather than notification records. search_messages_by_heard_status for unlistened messages.
EXAMPLE: {"category":"mentions","limit":25}
RETURNS: {results: [...], total_results, total_unread, filters}. Pages with skip/limit, not cursors.
NARROW: pass response_fields ["results","total_unread","total_results"] unless you need more — the full payload is much larger. |