Teams Bot-initiated Graph call doesn’t create a shared chat for participants

Summary

A bot-initiated Microsoft Teams call, triggered via the Microsoft Graph /communications/calls API, successfully connects all intended participants into a single audio/video session. However, Teams does not automatically create a shared group chat thread for these participants. Instead, each participant sees only their existing 1:1 chat thread with the bot. This behavior differs significantly from the user experience when a call is initiated from the Teams UI or when a Teams meeting is scheduled, where a shared conversation context is established.

Root Cause

The core issue lies in the architectural design of the Graph /communications/calls resource. This API endpoint is fundamentally a Signaling and Control mechanism for the Azure Communication Services (ACS) underlay, not a high-level orchestration tool that mimics full Teams client behavior.

  • Lack of Chat Context Binding: The call payload schema for bot-initiated outgoing calls does not contain a property to link the call to a Microsoft Teams chat thread (graphically represented as a threadId).
  • Signaling-Only Scope: The API is designed to establish the media session (RTC) and manage call state. It treats the chat component as a separate, parallel entity that is typically initialized by the user interface, not by the signaling API.
  • Identity Handling: When a bot (Application identity) initiates a call to users (User identities), Teams interprets this as a service interaction. The system defaults to preserving the existing 1:1 relationship with the service (the bot) rather than aggregating users into a new ephemeral group context.

Why This Happens in Real Systems

In enterprise distributed systems, distinct services often handle communication channels. In the Microsoft 365 ecosystem:

  1. Teams Client (UI): When a human clicks “Call Group,” the client performs a sequence: create a chat thread, then invoke the signaling layer to start the call, passing the new thread ID.
  2. Graph API: When a bot calls the API, it skips the “create chat” step entirely. It goes straight to the signaling layer.
  3. Result: Because the chat service (Teams Datastore) is decoupled from the Signaling service (Graph Communications), and no explicit link is provided, the chat service never receives the instruction to group these users together.

Real-World Impact

  • Confusion: Users expect to see a group conversation to send text messages, share files, or continue the discussion post-call. They are left isolated in separate 1:1 threads with the bot.
  • Broken Continuity: The conversational context is fragmented. If a user wants to share a link relevant to the call, they don’t know where to send it because there is no central group chat.
  • Adoption Friction: This behavior makes bot-initiated calls feel “less native” and clunky compared to standard Teams calls, potentially reducing usage of the automation features.

Example or Code

To reproduce the issue, developers must utilize the Beta endpoint with a payload similar to the following. Note the absence of any chatId or threadId parameter in the call object.

const call = {
  '@odata.type': '#microsoft.graph.call',
  direction: 'outgoing',
  subject: 'Urgent Sync',
  callbackUri: `${config.callBackUri}/call-callback`,
  source: {
    '@odata.type': '#microsoft.graph.participantInfo',
    identity: {
      '@odata.type': '#microsoft.graph.identitySet',
      application: {
        '@odata.type': '#microsoft.graph.identity',
        id: '',
        displayName: 'Automator'
      }
    }
  },
  targets: [
    {
      '@odata.type': '#microsoft.graph.invitationParticipantInfo',
      identity: {
        '@odata.type': '#microsoft.graph.identitySet',
        user: {
          '@odata.type': '#microsoft.graph.identity',
          id: '',
          displayName: 'User One'
        }
      }
    },
    {
      '@odata.type': '#microsoft.graph.invitationParticipantInfo',
      identity: {
        '@odata.type': '#microsoft.graph.identitySet',
        user: {
          '@odata.type': '#microsoft.graph.identity',
          id: '',
          displayName: 'User Two'
        }
      }
    }
  ],
  requestedModalities: ['audio', 'video'],
  tenantId: ''
};

// This request creates the call, but NOT the chat
await graphClient
  .api('/communications/calls')
  .version('beta')
  .post(call);

How Senior Engineers Fix It

Senior engineers understand that API limitations often require orchestrating multiple services to achieve the desired user experience.

  1. Create the Chat Thread First: Before invoking the Graph Calls API, use the POST /chats endpoint to create a new group chat or utilize an existing one.
    • Endpoint: POST https://graph.microsoft.com/v1.0/chats
    • Body: {"chatType": "group", "members": [...]} -> Returns a chatId.
  2. Inject Context (Workaround): While the Calls API doesn’t support a chatId property, senior engineers might attempt to inject the chat ID into the subject or callback data for internal tracking, though this does not force Teams UI to bind them.
  3. The Ultimate Fix (Meetings API): Instead of using the low-level /communications/calls API, use the /me/onlineMeetings API.
    • Creating a meeting (POST /me/onlineMeetings) automatically creates the associated chat thread.
    • You can then use the joinWebUrl to invite users or have the bot join, ensuring the chat exists natively.

Why Juniors Miss It

  • Assumption of Feature Parity: Juniors often assume that if an API allows starting a call, it must also handle the associated UI elements (like chats) automatically. They don’t realize the Graph API is a “power tool” that gives you raw control but fewer conveniences than the UI.
  • Misunderstanding the Abstraction: They treat the POST /communications/calls endpoint as a “Make a Teams Call” button rather than a “Create a VoIP Signaling Session” command.
  • Lack of Holistic View: They focus on getting the media connected (the “Call” part) and fail to verify the collateral data artifacts (the “Chat” part) required for a complete Teams experience.