microsoft/teams.net
Publicmirrored fromhttps://github.com/microsoft/teams.netAvailable
core/docs/CreateConversation-API-Behavior.md
432lines · modecode
| 1 | # CreateConversation API Behavior |
| 2 | |
| 3 | Technical reference documenting the exact behavior of the Teams Bot Framework `POST /v3/conversations` endpoint, based on integration test results captured on 2026-04-17. |
| 4 | |
| 5 | ## Endpoint |
| 6 | |
| 7 | ``` |
| 8 | POST {serviceUrl}/v3/conversations |
| 9 | Content-Type: application/json; charset=utf-8 |
| 10 | Authorization: Bearer {token} |
| 11 | ``` |
| 12 | |
| 13 | Service URL: `https://smba.trafficmanager.net/teams/` |
| 14 | |
| 15 | ## Supported Conversation Types |
| 16 | |
| 17 | The endpoint supports exactly **two** conversation creation patterns: |
| 18 | |
| 19 | 1. **1:1 Personal Chat** (proactive messaging to a single user) |
| 20 | 2. **Channel Thread** (new thread in an existing Teams channel) |
| 21 | |
| 22 | **Group chat creation is NOT supported** — every variation returns `400 BadSyntax`. |
| 23 | |
| 24 | --- |
| 25 | |
| 26 | ## 1:1 Personal Chat |
| 27 | |
| 28 | ### Minimal (working) |
| 29 | |
| 30 | ```http |
| 31 | POST https://smba.trafficmanager.net/teams/v3/conversations |
| 32 | |
| 33 | { |
| 34 | "isGroup": false, |
| 35 | "members": [ |
| 36 | { |
| 37 | "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" |
| 38 | } |
| 39 | ], |
| 40 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 41 | } |
| 42 | ``` |
| 43 | |
| 44 | ```http |
| 45 | HTTP/1.1 201 Created |
| 46 | Server: Microsoft-HTTPAPI/2.0 |
| 47 | MS-CV: p82ptW4x80GRgeZm9NkMlQ.0 |
| 48 | Content-Type: application/json; charset=utf-8 |
| 49 | Content-Length: 140 |
| 50 | |
| 51 | { |
| 52 | "id": "a:1p0iicaJlVi-_KIYKDDvLi4c2pMZMc8B0bPauUJq9pZ6IHPzMOrXbWS4g7Wktn1hwl8J3FecCj4cn33DInsp7AGj8mSSb23S5cQJTjU_CXlYs-eph-CchluBdnSKVFm40" |
| 53 | } |
| 54 | ``` |
| 55 | |
| 56 | **Notes:** |
| 57 | - `isGroup` must be `false` |
| 58 | - `members` must contain exactly 1 member |
| 59 | - Member ID must be in MRI format (`29:...`), not pairwise bot framework ID (`29:guid`) |
| 60 | - `tenantId` is required |
| 61 | - Response `id` starts with `a:` prefix (personal chat conversation ID) |
| 62 | - Calling with the same member returns the same conversation ID (idempotent) |
| 63 | |
| 64 | ### With bot specified (working) |
| 65 | |
| 66 | ```http |
| 67 | { |
| 68 | "isGroup": false, |
| 69 | "bot": { |
| 70 | "id": "28:3738fe3d-bca2-479d-8e45-1660de89ee41" |
| 71 | }, |
| 72 | "members": [ |
| 73 | { |
| 74 | "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" |
| 75 | } |
| 76 | ], |
| 77 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 78 | } |
| 79 | ``` |
| 80 | |
| 81 | ```http |
| 82 | HTTP/1.1 201 Created |
| 83 | MS-CV: 2yFg6cTgzUeVB8q/F9pHkA.0 |
| 84 | ``` |
| 85 | |
| 86 | **Notes:** |
| 87 | - `bot.id` uses `28:{appId}` format |
| 88 | - Bot field is optional for 1:1 — the API infers the bot from the auth token |
| 89 | - Same response as without bot |
| 90 | |
| 91 | ### With initial activity (working) |
| 92 | |
| 93 | ```http |
| 94 | { |
| 95 | "isGroup": false, |
| 96 | "members": [ |
| 97 | { |
| 98 | "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" |
| 99 | } |
| 100 | ], |
| 101 | "activity": { |
| 102 | "type": "message", |
| 103 | "text": "[Diagnostic] 1:1 with initial activity" |
| 104 | }, |
| 105 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 106 | } |
| 107 | ``` |
| 108 | |
| 109 | ```http |
| 110 | HTTP/1.1 201 Created |
| 111 | MS-CV: PB7kLrArfE6r21I3q5gMRA.0 |
| 112 | |
| 113 | { |
| 114 | "id": "a:1p0iicaJlVi-_KIYKDDvLi4c2pMZMc8B0bPauUJq9pZ6IHPzMOrXbWS4g7Wktn1hwl8J3FecCj4cn33DInsp7AGj8mSSb23S5cQJTjU_CXlYs-eph-CchluBdnSKVFm40" |
| 115 | } |
| 116 | ``` |
| 117 | |
| 118 | **Notes:** |
| 119 | - The activity is sent as the first message in the conversation |
| 120 | - Response does NOT include `activityId` (unlike channel threads) |
| 121 | - If the conversation already exists, the activity is still sent |
| 122 | |
| 123 | --- |
| 124 | |
| 125 | ## Channel Thread |
| 126 | |
| 127 | ### With activity (working) |
| 128 | |
| 129 | ```http |
| 130 | { |
| 131 | "isGroup": true, |
| 132 | "activity": { |
| 133 | "type": "message", |
| 134 | "text": "[Diagnostic] channel thread" |
| 135 | }, |
| 136 | "channelData": { |
| 137 | "channel": { |
| 138 | "id": "19:LydFnezGKSkhYoiLNP6kZ8AuXQr36EDAkvG9CNJSPKc1@thread.tacv2" |
| 139 | } |
| 140 | }, |
| 141 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 142 | } |
| 143 | ``` |
| 144 | |
| 145 | ```http |
| 146 | HTTP/1.1 201 Created |
| 147 | Server: Microsoft-HTTPAPI/2.0 |
| 148 | MS-CV: 7hdK6FlaqE+BjXxKvUCQUg.0 |
| 149 | Content-Type: application/json; charset=utf-8 |
| 150 | Content-Length: 122 |
| 151 | |
| 152 | { |
| 153 | "id": "19:LydFnezGKSkhYoiLNP6kZ8AuXQr36EDAkvG9CNJSPKc1@thread.tacv2;messageid=1776390257332", |
| 154 | "activityId": "1776390257332" |
| 155 | } |
| 156 | ``` |
| 157 | |
| 158 | **Notes:** |
| 159 | - `isGroup` must be `true` |
| 160 | - `channelData.channel.id` must reference a valid channel |
| 161 | - `activity` is **required** — the thread root message |
| 162 | - Response `id` is `{channelId};messageid={messageId}` (the thread conversation ID) |
| 163 | - Response includes `activityId` (the thread root message ID, used for replies) |
| 164 | - `members` is NOT required (thread is visible to all channel members) |
| 165 | |
| 166 | ### With members and activity (working) |
| 167 | |
| 168 | ```http |
| 169 | { |
| 170 | "isGroup": true, |
| 171 | "members": [ |
| 172 | { |
| 173 | "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" |
| 174 | } |
| 175 | ], |
| 176 | "activity": { |
| 177 | "type": "message", |
| 178 | "text": "[Diagnostic] channel thread with members" |
| 179 | }, |
| 180 | "channelData": { |
| 181 | "channel": { |
| 182 | "id": "19:LydFnezGKSkhYoiLNP6kZ8AuXQr36EDAkvG9CNJSPKc1@thread.tacv2" |
| 183 | } |
| 184 | }, |
| 185 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 186 | } |
| 187 | ``` |
| 188 | |
| 189 | ```http |
| 190 | HTTP/1.1 201 Created |
| 191 | MS-CV: +YAgno/+yUqSpHSvnRVcOQ.0 |
| 192 | |
| 193 | { |
| 194 | "id": "19:LydFnezGKSkhYoiLNP6kZ8AuXQr36EDAkvG9CNJSPKc1@thread.tacv2;messageid=1776390250598", |
| 195 | "activityId": "1776390250598" |
| 196 | } |
| 197 | ``` |
| 198 | |
| 199 | **Notes:** |
| 200 | - Adding `members` to a channel thread request does not cause an error |
| 201 | - The members field appears to be ignored (thread visibility is determined by channel membership) |
| 202 | |
| 203 | ### Without activity (FAILS) |
| 204 | |
| 205 | ```http |
| 206 | { |
| 207 | "isGroup": true, |
| 208 | "channelData": { |
| 209 | "channel": { |
| 210 | "id": "19:LydFnezGKSkhYoiLNP6kZ8AuXQr36EDAkvG9CNJSPKc1@thread.tacv2" |
| 211 | } |
| 212 | }, |
| 213 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 214 | } |
| 215 | ``` |
| 216 | |
| 217 | ```http |
| 218 | HTTP/1.1 400 Bad Request |
| 219 | Server: Microsoft-HTTPAPI/2.0 |
| 220 | MS-CV: 1juAJRUj5ki4igxWv3Y8EQ.0 |
| 221 | Content-Type: application/json; charset=utf-8 |
| 222 | Content-Length: 85 |
| 223 | |
| 224 | { |
| 225 | "error": { |
| 226 | "code": "BadSyntax", |
| 227 | "message": "Incorrect conversation creation parameters" |
| 228 | } |
| 229 | } |
| 230 | ``` |
| 231 | |
| 232 | **Conclusion:** `activity` is mandatory for channel thread creation. You cannot create an empty thread. |
| 233 | |
| 234 | --- |
| 235 | |
| 236 | ## Group Chat (NOT SUPPORTED) |
| 237 | |
| 238 | All of the following variations return the same `400 BadSyntax` error. The `MS-CV` header is included for each to enable service-side log correlation. |
| 239 | |
| 240 | ### 2 members, no bot, no channelData |
| 241 | |
| 242 | ```http |
| 243 | { |
| 244 | "isGroup": true, |
| 245 | "members": [ |
| 246 | { "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" }, |
| 247 | { "id": "29:100DQ6CrcJc9p_L654DvdNtwAazXhnxkoNAedgV0ZAgalPOz0oy7RmLG0VKCPhdia_w0lJJLUp0QEw6ogU7zyWg" } |
| 248 | ], |
| 249 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 250 | } |
| 251 | ``` |
| 252 | |
| 253 | ```http |
| 254 | HTTP/1.1 400 Bad Request |
| 255 | MS-CV: /qe9JFWupEGpNA9S/vIXaQ.0 |
| 256 | |
| 257 | { "error": { "code": "BadSyntax", "message": "Incorrect conversation creation parameters" } } |
| 258 | ``` |
| 259 | |
| 260 | ### 2 members, with bot |
| 261 | |
| 262 | ```http |
| 263 | { |
| 264 | "isGroup": true, |
| 265 | "bot": { "id": "28:3738fe3d-bca2-479d-8e45-1660de89ee41" }, |
| 266 | "members": [ |
| 267 | { "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" }, |
| 268 | { "id": "29:100DQ6CrcJc9p_L654DvdNtwAazXhnxkoNAedgV0ZAgalPOz0oy7RmLG0VKCPhdia_w0lJJLUp0QEw6ogU7zyWg" } |
| 269 | ], |
| 270 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 271 | } |
| 272 | ``` |
| 273 | |
| 274 | ```http |
| 275 | HTTP/1.1 400 Bad Request |
| 276 | MS-CV: Sm3G0wjzV0y2EKXpeJu7jQ.0 |
| 277 | |
| 278 | { "error": { "code": "BadSyntax", "message": "Incorrect conversation creation parameters" } } |
| 279 | ``` |
| 280 | |
| 281 | ### 2 members, bot, channelData.tenant |
| 282 | |
| 283 | ```http |
| 284 | { |
| 285 | "isGroup": true, |
| 286 | "bot": { "id": "28:3738fe3d-bca2-479d-8e45-1660de89ee41" }, |
| 287 | "members": [ |
| 288 | { "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" }, |
| 289 | { "id": "29:100DQ6CrcJc9p_L654DvdNtwAazXhnxkoNAedgV0ZAgalPOz0oy7RmLG0VKCPhdia_w0lJJLUp0QEw6ogU7zyWg" } |
| 290 | ], |
| 291 | "channelData": { "tenant": { "id": "3f3d1cea-7a18-41af-872b-cfbbd5140984" } }, |
| 292 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 293 | } |
| 294 | ``` |
| 295 | |
| 296 | ```http |
| 297 | HTTP/1.1 400 Bad Request |
| 298 | MS-CV: lmTBZpEylUeAiMTGSPnpVQ.0 |
| 299 | |
| 300 | { "error": { "code": "BadSyntax", "message": "Incorrect conversation creation parameters" } } |
| 301 | ``` |
| 302 | |
| 303 | ### 2 members, bot, topic, activity, channelData (all fields) |
| 304 | |
| 305 | ```http |
| 306 | { |
| 307 | "isGroup": true, |
| 308 | "bot": { "id": "28:3738fe3d-bca2-479d-8e45-1660de89ee41" }, |
| 309 | "members": [ |
| 310 | { "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" }, |
| 311 | { "id": "29:100DQ6CrcJc9p_L654DvdNtwAazXhnxkoNAedgV0ZAgalPOz0oy7RmLG0VKCPhdia_w0lJJLUp0QEw6ogU7zyWg" } |
| 312 | ], |
| 313 | "topicName": "Diagnostic group test", |
| 314 | "activity": { "type": "message", "text": "group chat init" }, |
| 315 | "channelData": { "tenant": { "id": "3f3d1cea-7a18-41af-872b-cfbbd5140984" } }, |
| 316 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 317 | } |
| 318 | ``` |
| 319 | |
| 320 | ```http |
| 321 | HTTP/1.1 400 Bad Request |
| 322 | MS-CV: zkVf7eA6BEytpPgWI8KH9Q.0 |
| 323 | |
| 324 | { "error": { "code": "BadSyntax", "message": "Incorrect conversation creation parameters" } } |
| 325 | ``` |
| 326 | |
| 327 | ### 1 member, isGroup=true |
| 328 | |
| 329 | ```http |
| 330 | { |
| 331 | "isGroup": true, |
| 332 | "members": [ |
| 333 | { "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" } |
| 334 | ], |
| 335 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 336 | } |
| 337 | ``` |
| 338 | |
| 339 | ```http |
| 340 | HTTP/1.1 400 Bad Request |
| 341 | MS-CV: yP2h6kv4iUG08nVbdcQJ0g.0 |
| 342 | |
| 343 | { "error": { "code": "BadSyntax", "message": "Incorrect conversation creation parameters" } } |
| 344 | ``` |
| 345 | |
| 346 | ### 1 member, bot, channelData.tenant |
| 347 | |
| 348 | ```http |
| 349 | { |
| 350 | "isGroup": true, |
| 351 | "bot": { "id": "28:3738fe3d-bca2-479d-8e45-1660de89ee41" }, |
| 352 | "members": [ |
| 353 | { "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" } |
| 354 | ], |
| 355 | "channelData": { "tenant": { "id": "3f3d1cea-7a18-41af-872b-cfbbd5140984" } }, |
| 356 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 357 | } |
| 358 | ``` |
| 359 | |
| 360 | ```http |
| 361 | HTTP/1.1 400 Bad Request |
| 362 | MS-CV: 10bRBNHyxk+eigCT8saVDg.0 |
| 363 | |
| 364 | { "error": { "code": "BadSyntax", "message": "Incorrect conversation creation parameters" } } |
| 365 | ``` |
| 366 | |
| 367 | ### 3 members, bot, channelData.tenant |
| 368 | |
| 369 | ```http |
| 370 | { |
| 371 | "isGroup": true, |
| 372 | "bot": { "id": "28:3738fe3d-bca2-479d-8e45-1660de89ee41" }, |
| 373 | "members": [ |
| 374 | { "id": "29:1aK9mYhSZ3egG5Ve2UaOoEjrOppWz-gl7AQmsXeW-4XS1et5FiZ3_V45othuWHgfY0Ytv82M6WnH8lRI8gLMeHg" }, |
| 375 | { "id": "29:100DQ6CrcJc9p_L654DvdNtwAazXhnxkoNAedgV0ZAgalPOz0oy7RmLG0VKCPhdia_w0lJJLUp0QEw6ogU7zyWg" }, |
| 376 | { "id": "29:1wh0NxivaCTCGl7pmILex0arFbszG6RaKMMOXImiDOCu3-T1qzkGdsmA_AfFpawkDaQl0kfvVy9RkVWQNGl30-w" } |
| 377 | ], |
| 378 | "channelData": { "tenant": { "id": "3f3d1cea-7a18-41af-872b-cfbbd5140984" } }, |
| 379 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984" |
| 380 | } |
| 381 | ``` |
| 382 | |
| 383 | ```http |
| 384 | HTTP/1.1 400 Bad Request |
| 385 | MS-CV: gfacBHOnI0CQ+n6Nxim+1w.0 |
| 386 | |
| 387 | { "error": { "code": "BadSyntax", "message": "Incorrect conversation creation parameters" } } |
| 388 | ``` |
| 389 | |
| 390 | --- |
| 391 | |
| 392 | ## Summary Table |
| 393 | |
| 394 | | Scenario | `isGroup` | `channelData.channel.id` | `activity` | `members` | HTTP | Result | |
| 395 | |---|---|---|---|---|---|---| |
| 396 | | 1:1 personal chat | `false` | — | optional | 1 (required) | **201** | Conversation created | |
| 397 | | 1:1 with bot | `false` | — | optional | 1 (required) | **201** | Conversation created | |
| 398 | | 1:1 with initial activity | `false` | — | message | 1 (required) | **201** | Conversation + message | |
| 399 | | Channel thread | `true` | required | **required** | optional | **201** | Thread created | |
| 400 | | Channel thread + members | `true` | required | **required** | ignored | **201** | Thread created | |
| 401 | | Channel thread, no activity | `true` | required | — | — | **400** | BadSyntax | |
| 402 | | Group: any member count | `true` | — | any | 1-3 | **400** | BadSyntax | |
| 403 | | Group: with bot | `true` | — | any | 1-3 | **400** | BadSyntax | |
| 404 | | Group: all fields | `true` | — | message | 2 | **400** | BadSyntax | |
| 405 | |
| 406 | ## Response Headers |
| 407 | |
| 408 | Common response headers across all requests: |
| 409 | |
| 410 | | Header | Description | |
| 411 | |---|---| |
| 412 | | `Server` | Always `Microsoft-HTTPAPI/2.0` | |
| 413 | | `MS-CV` | Correlation vector for service-side log tracing | |
| 414 | | `Content-Type` | Always `application/json; charset=utf-8` | |
| 415 | | `Date` | Server-side timestamp | |
| 416 | | `Content-Length` | Response body size | |
| 417 | |
| 418 | The `MS-CV` header is the key diagnostic value — it can be used to correlate with Teams service-side logs for deeper investigation of `BadSyntax` failures. |
| 419 | |
| 420 | ## Key Observations |
| 421 | |
| 422 | 1. **Member ID format matters.** The API requires MRI-format IDs (`29:1aK9...`), not the pairwise bot framework IDs stored in `TEST_USER_ID` env vars (`29:guid`). MRI IDs can be obtained from `GET /v3/conversations/{id}/members`. |
| 423 | |
| 424 | 2. **1:1 conversations are idempotent.** Calling CreateConversation with the same member always returns the same conversation ID (`a:...` prefix). |
| 425 | |
| 426 | 3. **Channel threads require an activity.** You cannot create an empty thread — the initial message IS the thread. |
| 427 | |
| 428 | 4. **Group chat creation is a platform limitation.** The `POST /v3/conversations` endpoint does not support creating multi-user group chats. The error is always `BadSyntax: Incorrect conversation creation parameters` regardless of parameter combinations. This applies to the Teams channel (msteams) specifically — other Bot Framework channels may behave differently. |
| 429 | |
| 430 | 5. **`tenantId` is required** for all Teams conversation creation. Omitting it causes auth failures. |
| 431 | |
| 432 | 6. **`bot` field is optional.** The API infers the bot identity from the bearer token for 1:1 chats. |
| 433 | |