|
| 1 | +--- |
| 2 | +title: Answer Teams Phone calls from Call Automation |
| 3 | +titleSuffix: An Azure Communication Services article |
| 4 | +description: This article describes how to receive and answer incoming Teams Phone Extensibility calls on Azure Communication Services. |
| 5 | +author: sofiar |
| 6 | +manager: miguelher |
| 7 | +services: azure-communication-services |
| 8 | +ms.author: sofiar |
| 9 | +ms.date: 05/19/2025 |
| 10 | +ms.topic: quickstart |
| 11 | +ms.service: azure-communication-services |
| 12 | +ms.subservice: identity |
| 13 | +--- |
| 14 | + |
| 15 | +# Answer Teams Phone calls from Call Automation |
| 16 | + |
| 17 | +Use Azure Communication Services Call Automation to receive and answer calls for a Teams resource account. |
| 18 | + |
| 19 | +[!INCLUDE [public-preview-notice.md](../../includes/public-preview-include-document.md)] |
| 20 | + |
| 21 | +## Prerequisites |
| 22 | + |
| 23 | +- An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). |
| 24 | + |
| 25 | +- A Communication Services resource, see [Create a Communication Services resource](../../quickstarts/create-communication-resource.md). |
| 26 | + |
| 27 | +- A configured Event Grid endpoint. [Incoming call concepts - An Azure Communication Services concept document](../../concepts/call-automation/incoming-call-notification.md#receiving-an-incoming-call-notification-from-event-grid) |
| 28 | + |
| 29 | +- A Microsoft Teams resource account with an associated phone number. [Create a new Teams Resource account](/powershell/module/teams/new-csonlineapplicationinstance) |
| 30 | + |
| 31 | +- Create and host an Azure Dev Tunnel. [Instructions here](/azure/developer/dev-tunnels/get-started). |
| 32 | + |
| 33 | +## Associate your Teams resource account with your Communication Services resource |
| 34 | + |
| 35 | +Execute the following command. Make sure you have your Azure Communication Services resource identifier ready. To find it, see [Get an immutable resource identifier](/azure/communication-services/concepts/troubleshooting-info#get-an-immutable-resource-id). |
| 36 | + |
| 37 | +```powershell |
| 38 | +Set-CsOnlineApplicationInstance -Identity <appIdentity> -AcsResourceId <acsResourceId> |
| 39 | +``` |
| 40 | + |
| 41 | +For more details, follow this guide: [Associate your Azure Communication Services resource with the Teams Resource account](/powershell/module/teams/set-csonlineapplicationinstance#-acsresourceid) |
| 42 | + |
| 43 | +## Configure your Communication Services resource to accept calls for the Teams resource account |
| 44 | + |
| 45 | +Send a request to the Microsoft Teams Extension access assignments API to allow receiving calls for the Teams resource account. For more details on how to authenticate the web request, follow this guide: [Authentication](/rest/api/communication/authentication) |
| 46 | + |
| 47 | +The following example shows a request for a Teams Tenant with identifier `87d349ed-44d7-43e1-9a83-5f2406dee5bd` and a Teams resource account oid with identifier `e5b7f628-ea94-4fdc-b3d9-1af1fe231111`. |
| 48 | + |
| 49 | +```http |
| 50 | +PUT {endpoint}/access/teamsExtension/tenants/87d349ed-44d7-43e1-9a83-5f2406dee5bd/assignments/e5b7f628-ea94-4fdc-b3d9-1af1fe231111?api-version=2025-03-02-preview |
| 51 | +
|
| 52 | +{ |
| 53 | + "principalType" : "teamsResourceAccount", |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +The {principalType} needs to be `teamsResourceAccount`. |
| 58 | + |
| 59 | +### Response |
| 60 | + |
| 61 | +The following example shows the response. |
| 62 | + |
| 63 | +```http |
| 64 | +HTTP/1.1 201 Created |
| 65 | +Content-type: application/json |
| 66 | +
|
| 67 | +{ |
| 68 | + "objectId": "e5b7f628-ea94-4fdc-b3d9-1af1fe231111", |
| 69 | + "tenantId": "87d349ed-44d7-43e1-9a83-5f2406dee5bd", |
| 70 | + "principalType" : "teamsResourceAccount", |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +## Stop accepting calls for the Teams resource account |
| 75 | + |
| 76 | +Send a request to the Microsoft Teams Extension access assignments API to delete the entry for your Teams resource account. |
| 77 | + |
| 78 | +```http |
| 79 | +DELETE {endpoint}/access/teamsExtension/assignments/e5b7f628-ea94-4fdc-b3d9-1af1fe231111?api-version=2025-03-02-preview |
| 80 | +``` |
| 81 | + |
| 82 | +### Response |
| 83 | + |
| 84 | +```http |
| 85 | +HTTP/1.1 204 NoContent |
| 86 | +Content-type: application/json |
| 87 | +
|
| 88 | +{} |
| 89 | +``` |
| 90 | + |
| 91 | +To verify that the Teams resource account is no longer linked with the Communication Services resource, you can send a GET request to the Microsoft Teams Extension access assignments API. Verify that its response status code is 404. |
| 92 | + |
| 93 | +```http |
| 94 | +GET {endpoint}/access/teamsExtension/assignments/e5b7f628-ea94-4fdc-b3d9-1af1fe231111?api-version=2025-03-02-preview |
| 95 | +``` |
| 96 | + |
| 97 | +## Receive and answer incoming calls |
| 98 | + |
| 99 | +### Setup and host your Azure DevTunnel |
| 100 | + |
| 101 | +DevTunnels create a persistent endpoint URL which allows anonymous access. We use this endpoint to notify your application of calling events from the Azure Communication Services Call Automation service. |
| 102 | + |
| 103 | +```powershell |
| 104 | +devtunnel create --allow-anonymous |
| 105 | +
|
| 106 | +devtunnel port create -p 8080 |
| 107 | +
|
| 108 | +devtunnel host |
| 109 | +``` |
| 110 | + |
| 111 | +### Handle Incoming Call event and answer the call |
| 112 | + |
| 113 | +```csharp |
| 114 | +app.MapPost("/api/incomingCall", async ( |
| 115 | + [FromBody] EventGridEvent[] eventGridEvents, |
| 116 | + ILogger<Program> logger) => |
| 117 | +{ |
| 118 | + if (eventGridEvent.TryGetSystemEventData(out object systemEvent)) |
| 119 | + { |
| 120 | + switch (systemEvent) |
| 121 | + { |
| 122 | + case SubscriptionValidationEventData subscriptionValidated: |
| 123 | + var responseData = new SubscriptionValidationResponse |
| 124 | + { |
| 125 | + ValidationResponse = subscriptionValidationEventData.ValidationCode |
| 126 | + }; |
| 127 | + return Results.Ok(responseData); |
| 128 | + |
| 129 | + case AcsIncomingCallEventData incomingCall: |
| 130 | + var callbackUri = new Uri(new Uri(devTunnelUri), $"/api/callbacks"); |
| 131 | + var options = new AnswerCallOptions(incomingCallContext, callbackUri); |
| 132 | + |
| 133 | + AnswerCallResult answerCallResult = await callAutomationClient.AnswerCallAsync(options); |
| 134 | + logger.LogInformation($"Answered call for connection id: {answerCallResult.CallConnection.CallConnectionId}"); |
| 135 | + |
| 136 | + //Use EventProcessor to process CallConnected event |
| 137 | +
|
| 138 | + var answerResult = await answerCallResult.WaitForEventProcessorAsync(); |
| 139 | + if (answerResult.IsSuccess) |
| 140 | + { |
| 141 | + logger.LogInformation($"Call connected event received for connection id: {answerResult.SuccessResult.CallConnectionId}"); |
| 142 | + var callConnectionMedia = answerCallResult.CallConnection.GetCallMedia(); |
| 143 | + } |
| 144 | + return Results.Ok(); |
| 145 | + |
| 146 | + default: |
| 147 | + logger.LogInformation($"Received unexpected event of type {eventGridEvent.EventType}"); |
| 148 | + return Results.BadRequest(); |
| 149 | + } |
| 150 | + } |
| 151 | + return Results.Ok(); |
| 152 | +}); |
| 153 | +``` |
| 154 | +### Sample Incoming Call event with Teams resource account identifier and custom context (VoIP and SIP) |
| 155 | + |
| 156 | +```json |
| 157 | +{ |
| 158 | + "to": { |
| 159 | + "kind": "unknown", |
| 160 | + "rawId": "28:orgid:cc123456-5678-5678-1234-ccc123456789" |
| 161 | + }, |
| 162 | + "from": { |
| 163 | + "kind": "phoneNumber", |
| 164 | + "rawId": "4:+12065551212", |
| 165 | + "phoneNumber": { |
| 166 | + "value": "+12065551212" |
| 167 | + } |
| 168 | + }, |
| 169 | + "serverCallId": "aHR0cHM6Ly9hcGkuZmxpZ2h0cHJveHkudGVhbXMubWljcm9zb2Z0LmNvbS9hcGkvdjIvZXAvY29udi11c3dlLTAyLXNkZi1ha3MuY29udi5za3lwZS5jb20vY29udi9fVERMUjZVS3BrT05aTlRMOHlIVnBnP2k9MTAtNjAtMTMtMjE2JmU9NjM4NTMwMzUzMjk2MjI3NjY1", |
| 170 | + "callerDisplayName": "+12065551212", |
| 171 | + "customContext": |
| 172 | + { |
| 173 | + "voipHeaders": |
| 174 | + { |
| 175 | + "X-myCustomVoipHeaderName": "myValue" |
| 176 | + }, |
| 177 | + }, |
| 178 | + "incomingCallContext": "<CALL_CONTEXT VALUE>", |
| 179 | + "correlationId": "2e0fa6fe-bf3e-4351-9beb-568add4f5315" |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +## Next steps |
| 184 | + |
| 185 | +> [!div class="nextstepaction"] |
| 186 | +> [REST API for Teams Phone extensibility](./teams-phone-extensiblity-rest-api.md) |
| 187 | +
|
| 188 | +## Related articles |
| 189 | + |
| 190 | +- [Teams Phone extensibility overview](../../concepts/interop/tpe/teams-phone-extensibility-overview.md) |
| 191 | +- [Teams Phone System extensibility quick start](./teams-phone-extensibility-quickstart.md) |
0 commit comments