An OpenClaw Microsoft Teams connection can look healthy and still leave one channel quiet. The bot may be installed, the CLI may list the channel, and a direct message may work. None of those checks proves that the team channel is sending activity to the public endpoint, that OpenClaw accepts the sender, or that the reply is being placed in the expected post. The Teams troubleshooting documentation treats those as separate failure points.
Use one standard channel, one test user, and one explicit @mention. Inspect each boundary in order: HTTP endpoint, Teams app, credentials, access policy, and reply placement.
The commands and expected results below are documentation-derived. The source pages were opened on 2026-09-13, and no local Gateway or Teams tenant was exercised while writing this article. The acceptance message is a procedure for your instance, not a claimed hands-on result.
Define the pass condition first
Write down one result: after the Gateway is restarted, a named test user mentions the bot in one standard Teams channel and receives one reply in that same channel or thread. Do not use a broad group conversation as the first test.
Keep DM pairing separate from channel access. OpenClaw's pairing documentation says that approving a DM sender grants direct-message access only. It does not grant access to a team channel. The Teams access-control page describes standard channels as the baseline for real-time bot messaging and private-channel support as limited.
Prerequisites
- A machine that can run the OpenClaw Gateway and show its logs.
- A build with the Microsoft Teams plugin. The setup page says Teams is bundled in current packaged releases; older or custom builds may need
openclaw plugins install @openclaw/msteams. - A Teams tenant where you can register or install the app. The manual Azure Bot route needs an Azure Bot resource; the Teams CLI route can create a Teams-managed bot.
- An app ID, tenant ID, and client secret for the initial setup, or an already prepared certificate or managed identity for a hosted production deployment.
- A public HTTPS URL, a standard team channel, and a test user who can use the app and mention the bot. Teams cannot call
localhost.
Keep the client secret in a server-only environment variable or secret store. The examples use placeholders. Do not paste a real credential into a shared patch, issue, transcript, or support log.
Checkpoint 1: make the webhook reachable
OpenClaw documents port 3978 and path /api/messages as the default Teams webhook. For local work, Microsoft recommends a dev tunnel so Azure Bot Service can reach the process. Start the Gateway on that port, then run:
devtunnel user login
devtunnel host -p 3978 --allow-anonymousSet the Bot or Azure Bot messaging endpoint to the public URL printed by the tunnel followed by /api/messages. Microsoft Learn's dev-tunnel procedure says to keep the host command running and update the endpoint when the URL changes. A named persistent tunnel can reduce that maintenance.
The anonymous flag makes the tunnel reachable by Azure Bot Service; it does not remove bot authentication at the activity endpoint. It exposes the selected local port to the internet, so run only the service you intend to test and stop the tunnel afterward. Use the tunnel inspect URL to check whether traffic reached the relay. That is better evidence than opening /api/messages in a browser.
Pass condition: the tunnel is hosting the port, the configured endpoint includes the correct route, and an inspect view or Gateway log can show an incoming Teams request during a real Teams test.
Checkpoint 2: register the bot and install the Teams app
Use one of the documented provisioning paths for the first bring-up.
The Teams CLI path
The OpenClaw setup page documents the Teams CLI as a shortcut for bot registration, manifest creation, and credential generation. Its commands use the @preview distribution tag, and flags may change:
npm install -g @microsoft/teams.cli@preview
teams login
teams status
teams app create --name 'OpenClaw' --endpoint 'https://<your-host>/api/messages'
teams app doctor <TEAMS_APP_ID>The create command returns the client ID, client secret, tenant ID, and Teams App ID, then offers to install the app. Save those identifiers and use the doctor command to check bot registration, the Entra app, manifest validity, and SSO configuration. Do not mix a new app's credentials with an old manifest without recording the change.
The manual Azure Bot path
For manual setup, create an Azure Bot, record its Microsoft App ID and directory tenant ID, create a client secret, set the messaging endpoint, and enable the Microsoft Teams channel. Package a Teams app manifest that references the bot. OpenClaw's manifest reference calls for a matching botId, personal, team, and groupChat scopes, valid icons, and resource-specific consent permissions such as ChannelMessage.Read.Group and ChannelMessage.Send.Group.
Those RSC permissions apply inside the team or chat where the app is installed; they are not the same as Microsoft Graph application permissions. Microsoft's Bot Framework Teams guide recommends adding a production bot as part of a Teams app. Adding a bot by GUID is a testing path with reduced functionality.
When a manifest changes, increment its version, repackage the manifest and icons, upload it, reinstall it in the team, and fully quit and relaunch Teams. Upload success alone does not prove that the client is using the new permissions.
Checkpoint 3: give OpenClaw credentials and a narrow policy
The Teams configuration reference maps these authentication values to environment variables:
export MSTEAMS_APP_ID='<APP_ID>'
export MSTEAMS_APP_PASSWORD='<CLIENT_SECRET>'
export MSTEAMS_TENANT_ID='<TENANT_ID>'The Gateway process must see the same variables. If the channel is configured but authentication fails immediately, check process-level environment inheritance before changing the Teams manifest.
Put policy and routing in the OpenClaw configuration. This JSON5 example starts with one sender, one team, one channel, explicit mention gating, and a predictable post style:
{
channels: {
msteams: {
enabled: true,
webhook: { port: 3978, path: '/api/messages' },
dmPolicy: 'pairing',
groupPolicy: 'allowlist',
groupAllowFrom: ['<AAD_OBJECT_ID>'],
teams: {
'19:<TEAM_ID>@thread.tacv2': {
channels: {
'19:<CHANNEL_ID>@thread.tacv2': {
requireMention: true,
replyStyle: 'thread'
}
}
}
}
}
}
}Teams access is one account under channels.msteams. The default group policy is an allowlist. groupAllowFrom can contain a stable sender object ID, an access group, or a conversation ID. For a first test, a stable AAD object ID is easier to reason about than a display name.
Use the IDs in the path of the Teams URL. The segment after /team/ is the team conversation ID, and the segment after /channel/ is the channel ID after URL decoding. The groupId query parameter is a different identifier. Preserve the exact casing. OpenClaw logs name-to-ID resolution when Graph access allows it, but unresolved names are ignored for routing by default.
Keep requireMention: true for the first test. Setting groupPolicy: 'open' changes the policy question and should be a deliberate choice, not a quick fix.
Checkpoint 4: run the checks, then send one message
After applying the configuration, restart or reload the Gateway using your normal service method. Run:
openclaw status
openclaw gateway status
openclaw channels list --all
openclaw channels status --probe --channel msteams
openclaw channels capabilities --channel msteams
openclaw channels logs --channel msteams
openclaw logs --followThe channels CLI reference distinguishes inventory from live probing. channels list can show a configured entry without contacting the Gateway. channels status --probe is live when the Gateway is reachable; otherwise it falls back to configuration summaries. It may report transport state and values such as works or audit ok where the Teams probe supports them. Capabilities output is useful, but it is not a user-visible send.
Now send one short message that explicitly mentions the bot in the selected standard channel. Keep the log stream open. The acceptance test needs both an inbound activity in the Gateway log and one reply in the intended Teams location.
Read the failure by layer
No request reaches the local process
Check the public endpoint, the tunnel host process, and the Bot or Azure Bot messaging endpoint. Use the tunnel inspect URL to see whether traffic arrived. A manual request that returns 401 Unauthorized is not automatically a broken endpoint. OpenClaw says a request without an Azure JWT can be expected to reach the endpoint and fail authentication; use Teams or Azure Web Chat for a proper test.
The Gateway starts, but the channel is blocked
If channels status reports running: false, lifecycle: 'blocked', or a plugin-load error, the failure is below Teams message permissions. The CLI reference says configured channels remain visible when a plugin fails to load. Run openclaw doctor, repair or update the plugin as instructed, restart the Gateway, and probe again.
DM works, but the channel is silent
DM pairing is not group access. Check that the app is installed in the target team, groupPolicy allows group traffic, groupAllowFrom admits the sender, and both team and channel IDs are in the route. Then mention the bot. OpenClaw documents mention gating as the default safe behavior, and an allowlisted team or channel is still mention-gated.
Only one named channel fails
Recheck the URL-derived IDs before loosening access. A channel can be present in Teams while the configuration points at groupId or an old display name. Decode the path segment, preserve the conversation ID's casing, reload, and watch the startup mapping log. If a private channel is the only failing target, repeat the test in a standard channel first.
The manifest changed, but behavior did not
Raise the manifest version, upload the package, reinstall the app, and fully quit and relaunch Teams. Check that webApplicationInfo.id matches the bot App ID exactly and that the organization has not blocked RSC permissions. If text works but an unmentioned message does not arrive, check policy and manifest support for that behavior before calling it a permission failure.
The reply appears in the wrong place
This is often a presentation setting. OpenClaw says classic Teams posts normally use replyStyle: 'thread'; Slack-like Threads-style channels use replyStyle: 'top-level'. The Teams API does not expose the UI style, so set the value at the channel level. A separate post can mean the message arrived and the style is wrong.
Text works, but files or history do not
RSC-only access can read and send channel text in the installed team, but it does not provide channel or group file bytes or message history. The manifest reference says those capabilities need Microsoft Graph application permissions and tenant consent, followed by a manifest re-upload and app reinstall. Test text, an image, a file, and historical lookup as separate cases.
Messages arrive late or appear duplicated
OpenClaw documents fixed webhook timeouts: 15 seconds to receive headers, 30 seconds of inactivity, and 30 seconds for the request, with a shared 10-second budget for optional media and context enrichment. If admission misses the transport window, Teams may retry and OpenClaw may reject the repeated event ID. Inspect timing and event logs instead of treating every delayed activity as a new user message.
Rollback and the next safe step
Keep the last known-good channel configuration before widening policy or adding Graph permissions. If a change breaks the test, restore only the channels.msteams block, restart the Gateway, and repeat the same explicit mention. If a client secret appears in a transcript or shared file, rotate it in the identity provider, update the environment, and run the checks again. If the tunnel URL changed, update the Bot messaging endpoint first.
Once text delivery passes, decide whether you need ambient reads, history, attachments, cards, or a different reply style. For local testing, a client secret or certificate is the supported path through a dev tunnel; Microsoft notes that managed identity and federated credentials require the agent to run in its configured Azure environment. Change one capability at a time and keep the original text test as a regression check.
The final record should say which passed: endpoint reachability, app and manifest validation, credential loading, team and channel admission, explicit mention reply, and any optional file or history test. A live probe alone is a transport check, not proof that a user message can be accepted and answered.
Sources
- OpenClaw: Microsoft Teams setup. Accessed 2026-09-13.
- OpenClaw: Microsoft Teams access control. Accessed 2026-09-13.
- OpenClaw: Pairing. Accessed 2026-09-13.
- OpenClaw: Microsoft Teams manifest and permissions. Accessed 2026-09-13.
- OpenClaw: Microsoft Teams configuration. Accessed 2026-09-13.
- OpenClaw: Microsoft Teams message behavior. Accessed 2026-09-13.
- OpenClaw: Microsoft Teams troubleshooting. Accessed 2026-09-13.
- OpenClaw CLI: channels. Accessed 2026-09-13.
- Microsoft Learn: Test a local agent with a dev tunnel. Accessed 2026-09-13.
- Microsoft Learn: Connect a Bot Framework bot to Microsoft Teams. Accessed 2026-09-13.
Reference Trail
Sources and further reading
- Teams troubleshooting documentationdocs.openclaw.ai
- pairing documentationdocs.openclaw.ai
- setup pagedocs.openclaw.ai
- dev-tunnel procedurelearn.microsoft.com
- Bot Framework Teams guidelearn.microsoft.com