Skip to content

Chats, AI mode, and channel health from Claude or Codex ​

From Claude Code, Codex, or any MCP client connected to the MyChatBot plugin or to the Sales-Management MCP you can:

  • decide who answers a chat: the AI, or a person (chat_set_mode, sales_conversations);
  • give back to the AI the chats that have sat with a manager for too long, many at once, after a preview (chat_bulk_return_to_ai, sales_conversations);
  • see how each channel is doing: on or off and why, when customers last wrote, open disconnect alerts (channel_get_health, sales_channels).

Every parameter and field is in the Sales tools reference. All three are yours: your own connection reaches them, and the session MyChatBot support gets when you ask it for a change does not (see Who can use which tool). A refused call's code is explained in Errors and refusals.

Who answers a chat ​

Every chat is in one of two modes, the same ones as the AI switch at the top of a chat in Active chats:

ModeWhat happens
aiThe assistant answers the customer.
managerThe assistant stays silent; a person answers from the dashboard or the channel's own app. The chat shows on the Operator tab.

chat_set_mode switches one chat. Find its chat_id with list_chats (filter by needs_operator: "yes" to see the chats with a person), then preview:

json
{ "chat_id": "568507", "mode": "ai", "dry_run": true }
json
{
  "chat_id": "568507",
  "assistant_id": "909",
  "communication_channel": "Instagram",
  "mode_before": "manager",
  "mode": "ai",
  "changed": false,
  "dry_run": true,
  "message": "dry run: nothing was changed. Without dry_run the chat goes to ai mode and leaves the Needs-attention queue."
}

Without dry_run the switch is made exactly as the dashboard's AI switch makes it:

  • the chat changes mode and leaves the Attention queue (needs_attention_cleared: true);
  • its timeline shows "Chat switched to AI mode" (or "to operator mode"), with the reason Given back to the AI over the Sales MCP (or Handed to a manager over the Sales MCP);
  • handing a chat to a manager counts as a switch made by hand: the assistant's auto-return brings it back after the interval unless Keep chats switched off by hand in operator mode is checked, a Telegram funnel the customer is in stops, and if the assistant assigns leads to managers automatically, the lead is assigned by those rules, as when the assistant hands a chat over itself.

Pass assistant_id too when you want the call refused unless the chat is that assistant's. A chat that already is in the mode you ask for is left as it is (changed: false).

The AI answers the next message, not the past ones

Giving a chat back to the AI does not answer what the customer wrote while it was with a person. The assistant replies to their next message. To answer now, reply yourself, or use Run assistant once in the chat.

Give stuck chats back to the AI ​

A chat handed to a person stays with them until someone gives it back. When nobody answers, the customer waits. chat_bulk_return_to_ai finds those chats and gives them back to the AI, each one as the dashboard's AI switch would, in two calls.

1. Preview (the default) ​

Call it with the filters you want. Without dry_run: false it never changes anything:

json
{ "assistant_id": "909", "communication_channel": "Instagram", "quiet_hours": 48 }
FilterMeaning
assistant_idOnly this assistant's chats
communication_channelOnly chats on this channel type, as list_channels names it (any letter case)
page_idOnly chats on one channel
quiet_hoursOnly chats where nobody on your team has written for at least this many hours (24 by default; 0 takes every chat with a person)
include_escalationsAlso take the chats the assistant handed to a person itself and nobody has answered yet (off by default)
limitThe most chats one call gives back: 50 by default, at most 100

Quiet hours count from the later of two moments: when the chat was handed to a person, and the last message your side wrote in it (a manager's reply, from the dashboard or from the channel's own app, or the assistant's last reply before the hand-over). A chat with neither in the last 90 days counts as quiet for at least 90 days. A chat whose messages cannot be read (it has no channel or contact id) is never taken by a quiet-hours filter: a person may be writing in it right now. Only quiet_hours: 0 takes it.

The answer lists the chats, the quietest first:

json
{
  "dry_run": true,
  "matched": 37,
  "selected": 37,
  "limit": 50,
  "quiet_hours": 48,
  "more_matching": false,
  "chat_ids": ["551203", "551877", "560114", "..."],
  "customers_waiting": 12,
  "customers_waiting_chat_ids": ["551203", "..."],
  "sample": [
    {
      "chat_id": "551203",
      "client_name": "Olena",
      "communication_channel": "Instagram",
      "handed_over_at": "2026-10-20T09:14:02Z",
      "team_last_wrote_at": "2026-10-20T09:20:45Z",
      "customer_last_wrote_at": "2026-10-21T17:02:11Z",
      "customer_waiting": true,
      "quiet_hours": 128,
      "escalated_by_assistant": false
    }
  ],
  "left_with_manager": { "assistant_escalations": 4, "spam": 1, "quiet_unknown": 0 },
  "scanned": 212,
  "scan_truncated": false,
  "preview_token": "1761401234.Xx…",
  "next": "To give these 37 chats back to the AI, call chat_bulk_return_to_ai again with the same filters, dry_run=false, chat_ids exactly as listed and this preview_token (valid 30 minutes)."
}
  • matched is how many chats qualify; selected how many this call would give back (at most limit); more_matching: true means another round is needed after this one.
  • customers_waiting counts the listed chats whose customer wrote after your side last did, and customers_waiting_chat_ids names them (customer_waiting: true in the sample). Given back, they also leave the Attention queue, and the AI answers only the customer's next message: answer those first, or leave them out with narrower filters.
  • left_with_manager counts the chats that matched but stay with a person: assistant_escalations (the assistant asked for a person and nobody has answered; those customers were told someone is coming), spam (never given back in bulk), and quiet_unknown (their messages cannot be read, see above).
  • The sample shows up to 20 chats. It carries customer names: share it only with people who may see the chats.

2. Give them back ​

Check the list, then call again with the same filters, dry_run: false, the chat_idsexactly as listed, and the preview_token:

json
{
  "assistant_id": "909",
  "communication_channel": "Instagram",
  "quiet_hours": 48,
  "dry_run": false,
  "chat_ids": ["551203", "551877", "560114", "..."],
  "preview_token": "1761401234.Xx…"
}
json
{
  "dry_run": false,
  "requested": 37,
  "returned_to_ai": 35,
  "returned_chat_ids": ["551203", "..."],
  "skipped": { "team_wrote_since": ["560114"], "already_with_ai": ["561002"] },
  "message": "35 chats are with the AI again; the assistant answers each customer's next message. 2 were skipped because they changed since the dry run (see skipped)."
}

Only the listed chats can change. Right before each one is changed, the chat and its messages are read again. A chat in which someone on your team wrote, or that was handed over again, after the preview is skipped, whatever quiet_hours is (with quiet_hours: 0 too). So is a chat that no longer qualifies. Each skipped chat is named under skipped:

ReasonMeaning
already_with_aiSomeone gave it back already
team_wrote_sinceSomeone on your team wrote in it, or it was handed over again, after the preview (or it is no longer quiet long enough)
filters_no_longer_matchIt no longer matches the filters you gave, for example it moved to another assistant
assistant_escalation / spamIt was escalated by the assistant or marked as spam since
quiet_unknownIts messages can no longer be read
not_foundIt is not one of this account's chats

A chat listed under failed_chat_ids could not be saved; run the preview again to retry it (a chat that did switch meanwhile is no longer listed).

The token is good for 30 minutes and only for this account, these filters, and this list of chats. A different list, other filters, or an old token is refused with preview_required: run the preview again. Running the same call twice gives nothing back the second time.

To give back more than 100 chats, preview and give back again: the chats already with the AI no longer match.

Channel health ​

channel_get_health shows how each channel is doing, from what MyChatBot has stored. It makes no live call to Meta, WhatsApp, or any other platform, so a change made there shows here only once the platform has told MyChatBot about it. Filter by assistant_id, communication_channel, or page_id; one call covers up to 50 channels. Credentials and tokens are never part of the answer.

json
{
  "channels": [
    {
      "communication_channel": "PersonalWhatsApp",
      "page_id": "380501112233@c.us",
      "assistant_id": "909",
      "is_on": false,
      "status": "paused",
      "status_reason": "paused by MyChatBot: WhatsApp logged this number out; scan the QR code again in the dashboard",
      "paused_at": "2026-10-23T08:00:00Z",
      "assistant": { "name": "Sofiia", "is_on": true },
      "last_activity_at": "2026-10-23T07:42:10Z",
      "last_customer_message_at": "2026-10-23T07:41:58Z",
      "last_reply_at": "2026-10-23T07:42:10Z",
      "open_alerts": [
        { "kind": "logged_out_rescan_needed", "message": "…", "raised_at": "2026-10-23T08:10:00Z", "seen": false }
      ],
      "personal_whatsapp": {
        "session": "logged_out",
        "authorized_at": "2026-09-01T10:00:00Z",
        "paused_reason": "disconnected",
        "paused_at": "2026-10-23T08:00:00Z",
        "removal_due_at": "2026-10-30T08:00:00Z"
      }
    }
  ],
  "count": 1,
  "activity_window": "last_customer_message_at and last_reply_at come from each channel's 20 most recently active chats over the last 90 days; null means none there",
  "checked_at": "2026-10-25T12:00:00Z"
}

What each field means ​

FieldMeaning
statusworking (on, with its assistant on); needs_attention (working, with an open disconnect alert); assistant_off (the channel is on but the assistant answering on it is off, deleted, or missing); paused (MyChatBot switched it off: Personal WhatsApp only); off (switched off); being_removed (a Personal WhatsApp number in the middle of being removed); unknown (on, but its assistant could not be read right now)
status_reasonThe same in words, with what brings it back where that is known
is_onThe channel's own switch, as in the dashboard
assistantThe assistant answering on the channel: is_on, and when off, off_reason as stored (insufficient_tokens, subscription_expired, outside_working_hours, moderation_flagged, plan_agent_limit, or null when switched off by hand) and reason in words
last_activity_atThe latest activity in the channel's chats, in either direction
last_customer_message_atWhen a customer last wrote, among the channel's 20 most recently active chats in the last 90 days; null when none did there. Instagram and Messenger can share a page: each channel then counts only its own chats
last_reply_atWhen your side last answered there: the assistant, or a person from the dashboard or the channel's own app
open_alertsThe channel's disconnect alerts that are not resolved yet (the ones in the dashboard's notifications): kind, the message you were sent, raised_at, and seen. The newest 2,000 alerts of the account are read; past that, alerts_note says so
paused_atWhen MyChatBot paused a Personal WhatsApp number
personal_whatsapp.sessionsigned_in (as last recorded), logged_out (WhatsApp ended the session: scan the QR code again before removal_due_at, when the number is removed), never_scanned (the QR code was never scanned; such a number is removed after about an hour), being_removed

Alert kinds: paused_for_balance, logged_out_rescan_needed, disconnected, instagram_account_changed, and instagram_not_linked.

What it cannot tell you ​

  • Why another channel is off. Only Personal WhatsApp records why MyChatBot switched it off (the balance ran out, or WhatsApp logged the number out). Any other channel that is off was switched off in the dashboard or over MCP; a Calls channel follows its assistant's Work Hours and plan, and says so.
  • Whether a token still works right now. Nothing is checked live. A channel whose platform stopped accepting it shows up through its open alert, once MyChatBot has noticed.
  • Knowledge and integration alerts. Alerts about a knowledge base, product feed, or integration are left out: they are not about a channel, and many of them clear on the next successful refresh. Use list_knowledge_sources and integration_verify for those.
  • Which channel an alert about a switched Instagram account belongs to. When one of your pages switched to another Instagram account, the alert names the new account, which no channel stores. The account-wide answer (no filters) lists such alerts, and any left behind by a channel removed since, under unmatched_open_alerts, so they are never dropped.

Typical requests ​

  • "Which chats have been waiting for a manager since Friday? Give them back to the AI." — chat_bulk_return_to_ai with quiet_hours, show the preview, then give them back.
  • "Hand the chat with Olena to me." — list_chats to find it, then chat_set_mode with mode: "manager".
  • "Why didn't my WhatsApp answer yesterday?" — channel_get_health with communication_channel: "PersonalWhatsApp", then list_chats and get_chat_messages for a chat in question.

See also ​