Docs menu

Microsoft Teams

Teams delivers messages to an HTTPS endpoint, so Deskhand needs a public URL. Slack does not; you can run both.

1. Expose the port

Deskhand serves Teams on http.port (3978 by default). For testing, a Cloudflare quick tunnel works:

cloudflared tunnel --url http://localhost:3978

It prints a URL like https://random-words.trycloudflare.com. Quick tunnel URLs change on every run, so use a named tunnel or your own reverse proxy for anything long-lived.

2. Create the Azure Bot

  1. In the Azure portal, create an Azure Bot. Choose Single Tenant and Create new Microsoft App ID.

  2. Under Configuration, set the messaging endpoint to your public URL plus /api/messages:

    https://random-words.trycloudflare.com/api/messages
  3. Under Configuration → Manage Password, create a client secret.

  4. Under Channels, add Microsoft Teams.

Copy the app ID, the secret, and your tenant ID into .env:

TEAMS_CLIENT_ID=00000000-0000-0000-0000-000000000000
TEAMS_CLIENT_SECRET=...
TEAMS_TENANT_ID=00000000-0000-0000-0000-000000000000

3. Enable it

chat:
  teams: { enabled: true }
http: { port: 3978 }
docker compose -f deploy/docker-compose.yml up -d --build

4. Install the Teams app

Edit deploy/teams-app/manifest.json: set id and bots[0].botId to your TEAMS_CLIENT_ID, and fill in developer. Zip manifest.json, color.png and outline.png (files at the zip root). In Teams: Apps → Manage your apps → Upload an app (or upload in the Teams admin center).

How it behaves

  • A personal chat with the app counts as a DM; it answers every message.
  • In channels and group chats, it answers when mentioned.
  • Approvals show as an Adaptive Card with Approve and Deny. If someone else clicks, they are told only the requester can decide.
  • Teams offers no thread history without Microsoft Graph, so Deskhand only sees the messages sent to it, not other replies in the thread.