Skip to content

API: Message channels ​

Halo HTTP API for message channels and notifications: connect IM channels, bind chats to Digital Humans, read chat transcripts, test notifications.

Message channels connect Digital Humans to IM platforms such as WeCom, Feishu and WeChat; notifications send alerts out. Use these operations to connect and disconnect channels, bind chats to Digital Humans, read the transcripts of bound chats, and test notifications. Create channels and enter their credentials in Settings › Message Channels.

Paths are relative to your Halo base URL, and every request carries the access password. Set $HALO_URL and $HALO_TOKEN as in the quickstart; base URL, authentication and error conventions are in the HTTP API overview.

OperationEndpoint
Clear a digital human's chat history in a bound IM chat (Digital Humans) IrreversiblePOST /api/apps/:appId/im-chat/clear
Read a digital human's transcript in a bound IM chat (Digital Humans)GET /api/apps/:appId/im-chat/messages
Stop a digital human's in-progress reply in a bound IM chat (keeps history) (Digital Humans)POST /api/apps/:appId/im-chat/stop
Check whether a Feishu bot is actually reachable, not just connectedPOST /api/feishu-bot/reachability
Get this build's default guest-access permission settings for new IM instancesGET /api/im-channels/permission-defaults
List available IM channel provider types and their config fieldsGET /api/im-channels/providers
Reconnect one IM channel instancePOST /api/im-channels/reconnect
Reload all IM channel instances from saved configPOST /api/im-channels/reload
Get connection status for all IM channel instances, or one via ?instanceId=GET /api/im-channels/status
List every chat thread a digital human has, its own and IM onesGET /api/im-sessions
List the IM chats a digital human pushes to through another digital human's botGET /api/im-sessions/linked
Remove a chat binding from the IM session registryPOST /api/im-sessions/remove
Set a custom display name for a chat bindingPOST /api/im-sessions/set-custom-name
Toggle whether a run's result is auto-pushed to this chat when it finishesPOST /api/im-sessions/set-proactive
Let a digital human push to an IM chat another digital human's bot knows, or stop itPOST /api/im-sessions/set-push-link
Drop cached notification-channel access tokensPOST /api/notify-channels/clear-cache
Read the product-level notification channel customisationGET /api/notify-channels/product-config
Send a test notification through one configured channelPOST /api/notify-channels/test
Reconnect all configured WeCom bot instancesPOST /api/wecom-bot/reconnect
Check whether a WeCom bot channel is configured and connectedGET /api/wecom-bot/status
Clear WeChat iLink credentials for an instance and stop itPOST /api/weixin-ilink/disconnect
Set the bot token for an already-configured WeChat iLink instancePOST /api/weixin-ilink/save-token

Check whether a Feishu bot is actually reachable, not just connected ​

POST /api/feishu-bot/reachability Assistant

  • A Feishu app awaiting administrator release connects normally and receives nothing, so "connected" alone does not mean the bot works. inboundCount 0 with a long connectedSinceMs is the signature of that case. No credentials in this response.

Request body

json
{
  "instanceId": "<instanceId — from GET /api/im-channels/status>"
}

Response

ts
{success:true,data:{state,connectedSinceMs,lastInboundAgoMs,inboundCount,lastError?}}

Example

bash
curl -sX POST "$HALO_URL/api/feishu-bot/reachability" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"instanceId":"<instanceId — from GET /api/im-channels/status>"}'

Get this build's default guest-access permission settings for new IM instances ​

GET /api/im-channels/permission-defaults Assistant

Response

ts
{success:true,data:{defaultEnabled?,defaultGuestAccess?,defaultGuestPolicy?:{allowedTools?},ownerIdHint?,ownerSetupGuideUrl?} | null}

Example

bash
curl -s "$HALO_URL/api/im-channels/permission-defaults" \
  -H "Authorization: Bearer $HALO_TOKEN"

List available IM channel provider types and their config fields ​

GET /api/im-channels/providers Assistant

  • Schema only. No endpoint here creates an instance from it — the user creates instances in Settings > Message Channels. Schema only (field definitions and empty defaults) — no configured instance data or secrets.

Response

ts
{success:true,data:[{type,displayName,description,direction,configFields:[{key,label,type,placeholder?,required?}],defaultConfig}]}

Example

bash
curl -s "$HALO_URL/api/im-channels/providers" \
  -H "Authorization: Bearer $HALO_TOKEN"

Reconnect one IM channel instance ​

POST /api/im-channels/reconnect Reversible Assistant

Request body

json
{
  "instanceId": "<instanceId — from GET /api/im-channels/status>"
}

Response

ts
{success:boolean,error?}

Errors

  • 400 if instanceId is missing. success:false with an error message if the instanceId is unknown.

Example

bash
curl -sX POST "$HALO_URL/api/im-channels/reconnect" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"instanceId":"<instanceId — from GET /api/im-channels/status>"}'

Reload all IM channel instances from saved config ​

POST /api/im-channels/reload Reversible Assistant

  • Use after a config change made through another route to apply it without restarting Halo. Stops and rebuilds any instance whose config changed — brief interruption, no data lost.

Response

ts
{success:true}

Example

bash
curl -sX POST "$HALO_URL/api/im-channels/reload" \
  -H "Authorization: Bearer $HALO_TOKEN"

Get connection status for all IM channel instances, or one via ?instanceId= ​

GET /api/im-channels/status Assistant

  • No credentials in this response. instanceId not found → {success:false,error}.

Query parameters: instanceId

Response

ts
{success:true,data:{id,type,enabled,connected,state?,appId,appName?,reason?,identityResolution?}[] | <single instance object>}

Example

bash
curl -s "$HALO_URL/api/im-channels/status" \
  -H "Authorization: Bearer $HALO_TOKEN"

List every chat thread a digital human has, its own and IM ones ​

GET /api/im-sessions Assistant

  • Optional ?appId= narrows it to one digital human. This is the only listing of its threads — there is no sessions/list beside sessions/create.
  • source says what a thread is: "local" = a named thread the user created in Halo, "im" = a real chat with a person on an IM platform, "http" = created through this API.
  • Reading or writing one thread needs a conversationId, which is not a field here — build it from four fields of the record: app-chat:<appId>:<channel>:<chatType>:<chatId>.
  • Only "local" and "http" threads accept a message from this API. An "im" thread is refused on send — this API must not put words into a real conversation with a person.

Query parameters: appId

Response

ts
{success:true,data:[{appId,channel,source:"local"|"im"|"http",chatType:"direct"|"group",chatId,displayName,customName?,proactive,instanceId,pushLinks?:[{appId,autoSync}]}]}

Example

bash
curl -s "$HALO_URL/api/im-sessions" \
  -H "Authorization: Bearer $HALO_TOKEN"

List the IM chats a digital human pushes to through another digital human's bot ​

GET /api/im-sessions/linked Assistant

  • Each record is the session as the bot's own digital human holds it (its appId is that one). The asking digital human's entry in pushLinks says whether its run results are auto-pushed there.

Query parameters: appId (required)

Response

ts
{success:true,data:[{appId,channel,chatType,chatId,displayName,instanceId,pushLinks:[{appId,autoSync}]}]}

Example

bash
curl -s "$HALO_URL/api/im-sessions/linked?appId=<appId — a uuid from GET /api/apps>" \
  -H "Authorization: Bearer $HALO_TOKEN"

Remove a chat binding from the IM session registry ​

POST /api/im-sessions/remove Reversible Assistant

  • removed:false means no matching session was found — not an error. Only removes display metadata (custom name, proactive flag, other digital humans' push links to it); the chat re-registers itself on its next inbound message, message history is not stored here.

Request body

json
{
  "appId": "<appId — a uuid from GET /api/apps>",
  "channel": "wecom-bot",
  "chatId": "<chatId — from GET /api/im-sessions>"
}

Response

ts
{success:true,data:{removed:boolean}}

Example

bash
curl -sX POST "$HALO_URL/api/im-sessions/remove" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"appId":"<appId — a uuid from GET /api/apps>","channel":"wecom-bot","chatId":"<chatId — from GET /api/im-sessions>"}'

Set a custom display name for a chat binding ​

POST /api/im-sessions/set-custom-name Reversible Assistant

Request body

json
{
  "appId": "<appId — a uuid from GET /api/apps>",
  "channel": "wecom-bot",
  "chatId": "<chatId — from GET /api/im-sessions>",
  "name": "Sales Team Chat"
}

Response

ts
{success:true} or {success:false,error}

Errors

  • 404 if no matching session exists yet.

Example

bash
curl -sX POST "$HALO_URL/api/im-sessions/set-custom-name" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"appId":"<appId — a uuid from GET /api/apps>","channel":"wecom-bot","chatId":"<chatId — from GET /api/im-sessions>","name":"Sales Team Chat"}'

Toggle whether a run's result is auto-pushed to this chat when it finishes ​

POST /api/im-sessions/set-proactive Reversible Assistant

Request body

json
{
  "appId": "<appId — a uuid from GET /api/apps>",
  "channel": "wecom-bot",
  "chatId": "<chatId — from GET /api/im-sessions>",
  "proactive": true
}

Response

ts
{success:true} or {success:false,error}

Errors

  • 404 if no matching session exists yet — the chat must have messaged the digital human at least once.

Example

bash
curl -sX POST "$HALO_URL/api/im-sessions/set-proactive" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"appId":"<appId — a uuid from GET /api/apps>","channel":"wecom-bot","chatId":"<chatId — from GET /api/im-sessions>","proactive":true}'

Let a digital human push to an IM chat another digital human's bot knows, or stop it ​

POST /api/im-sessions/set-push-link Reversible Assistant

  • link:{autoSync} adds the chat to the digital human's push targets or updates it; autoSync:true also pushes its run results there. link:null removes it.
  • Replies in that chat still go to the digital human the bot answers for. 404 when the session does not exist, is not an IM chat, or is the digital human's own.

Request body

json
{
  "appId": "<appId of the digital human that pushes>",
  "session": {
    "appId": "<the session's own appId>",
    "channel": "wecom-bot",
    "chatId": "<chatId — from GET /api/im-sessions>"
  },
  "link": {
    "autoSync": false
  }
}

Response

ts
{success:true} or {success:false,error}

Example

bash
curl -sX POST "$HALO_URL/api/im-sessions/set-push-link" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"appId":"<appId of the digital human that pushes>","session":{"appId":"<the session'\''s own appId>","channel":"wecom-bot","chatId":"<chatId — from GET /api/im-sessions>"},"link":{"autoSync":false}}'

Drop cached notification-channel access tokens ​

POST /api/notify-channels/clear-cache Reversible Assistant

  • Worth trying when a channel that used to work starts failing to authenticate — the next send fetches a fresh token. It changes no configuration.

Response

ts
{"success":true}  // no data

Example

bash
curl -sX POST "$HALO_URL/api/notify-channels/clear-cache" \
  -H "Authorization: Bearer $HALO_TOKEN"

Read the product-level notification channel customisation ​

GET /api/notify-channels/product-config Assistant

  • Presentation only — help links this build shows per channel. data is null when the build customises nothing. It does not say which channels the user configured.

Response

ts
{"success":true,"data":{"wecom":{"docs":{...}},"email":{"docs":{...}}}}

Example

bash
curl -s "$HALO_URL/api/notify-channels/product-config" \
  -H "Authorization: Bearer $HALO_TOKEN"

Send a test notification through one configured channel ​

POST /api/notify-channels/test Reversible Assistant

  • channelType is one of wecom, dingtalk, feishu, email or webhook.
  • Delivers a real message: a fixed test text through that channel. The text cannot be changed, so this is a test, not a way to send notifications.
  • "No notification channels configured" means none is set up yet; channels are set up in Settings › Message Channels.

Request body

json
{
  "channelType": "wecom"
}

Response

ts
{"success":true,"data":{...delivery result}}

Example

bash
curl -sX POST "$HALO_URL/api/notify-channels/test" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"channelType":"wecom"}'

Reconnect all configured WeCom bot instances ​

POST /api/wecom-bot/reconnect Reversible Assistant

  • A brief connection interruption while it reconnects — no data lost.

Response

ts
{success:true}

Example

bash
curl -sX POST "$HALO_URL/api/wecom-bot/reconnect" \
  -H "Authorization: Bearer $HALO_TOKEN"

Check whether a WeCom bot channel is configured and connected ​

GET /api/wecom-bot/status Assistant

Response

ts
{success:true,data:{configured:boolean,enabled:boolean,connected:boolean}}

Example

bash
curl -s "$HALO_URL/api/wecom-bot/status" \
  -H "Authorization: Bearer $HALO_TOKEN"

Clear WeChat iLink credentials for an instance and stop it ​

POST /api/weixin-ilink/disconnect Reversible Assistant

  • Clears the WeChat Bot credentials of this channel and stops it. Reconnecting needs the same token again (POST /api/weixin-ilink/save-token) or a new QR pairing in Settings › Message Channels.

Request body

json
{
  "instanceId": "<instanceId — from GET /api/im-channels/status>"
}

Response

ts
{success:true} or {success:false,error}

Example

bash
curl -sX POST "$HALO_URL/api/weixin-ilink/disconnect" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"instanceId":"<instanceId — from GET /api/im-channels/status>"}'

Set the bot token for an already-configured WeChat iLink instance ​

POST /api/weixin-ilink/save-token Reversible Assistant

  • Optional fields: baseUrl, accountId.
  • instanceId must already exist (created earlier in the Settings UI) — this route cannot create a new instance, only fill in its token.
  • Never echoes the token back in the response.
  • {success:false,error:"..."} when instanceId is not found in config.
  • Takes over that channel identity immediately — a wrong token silently hijacks it until corrected.

Request body

json
{
  "instanceId": "<instanceId — from GET /api/im-channels/status>",
  "botToken": "..."
}

Response

ts
{success:true} or {success:false,error}

Example

bash
curl -sX POST "$HALO_URL/api/weixin-ilink/save-token" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"instanceId":"<instanceId — from GET /api/im-channels/status>","botToken":"..."}'

基于 MIT 协议开源 · Open source under the MIT license