Skip to main content
Use Teams Phone extensibility (TPE) or Twilio to connect a phone number to your Microsoft Foundry voice agent. Receive inbound calls and place outbound calls through the call-job API.
Items marked preview in this article are currently in preview. This preview is provided without a service-level agreement, and Microsoft doesn’t recommend it for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.

Prerequisites

The Foundry RBAC roles were recently renamed. Foundry User, Foundry Owner, Foundry Account Owner, and Foundry Project Manager were previously named Azure AI User, Azure AI Owner, Azure AI Account Owner, and Azure AI Project Manager. You might still see the previous names in some places while the rename rolls out. The role IDs and core permissions are unchanged by the rename.
  • Permission to update the agent and its channels, manage project connections, and create or update telephony bindings.

Teams Phone extensibility prerequisites

For the Teams Phone extensibility path, you need:
  • A Teams Phone service number assigned to a resource account. See Get Microsoft Teams Calling Plan phone numbers for your tenant.
  • The setup in Prepare Teams Phone extensibility, completed with a Teams or Microsoft 365 administrator.
  • Access to the selected Azure Communication Services resource.
  • For inbound calls, Event Grid write permission on that resource.
  • Help from a tenant administrator when secure webhook setup requires Microsoft Entra application or app-role changes.
The current project-managed-identity flow requires the Foundry project and Azure Communication Services resource to be in the same Microsoft Entra tenant.

Twilio prerequisites

For the Twilio path, you need:
  • A Twilio account with at least one active, voice-capable phone number for inbound calls.
  • A Twilio project connection, or the Account SID and Primary Auth Token to create one.
Twilio doesn’t require an Azure Communication Services resource, Teams resource account, or Event Grid subscription. Store the Auth Token in the project connection, not in binding requests, logs, screenshots, or support requests.

Compare the channel integrations

Choose the provider that owns your number. The Twilio option appears only in supported public-cloud environments.

Understand the call path

The channel integration determines how an inbound call reaches the agent.
For Teams Phone extensibility, your Teams tenant keeps ownership of the number and Azure Communication Services provides the call automation and media path:
  1. A caller dials the Teams phone number.
  2. Teams routes the call to your resource account.
  3. The resource account routes the call to your Communication Services resource.
  4. Communication Services raises a Microsoft.Communication.IncomingCall event through Event Grid to your agent’s telephony callback endpoint.
  5. Foundry matches the callee to a telephony binding, answers the call on your Communication Services resource, and streams the audio to the agent.
Because the Teams number stays in Teams, the agent can act as one destination among others in your existing call flow. You can leave auto attendants and call queues in place and route selected paths to the agent. For Twilio, Foundry uses the selected project connection to discover the numbers in your Twilio account and create a binding for each number you select. You don’t create an Azure Communication Services resource or Event Grid subscription for the Twilio path.

Prepare Teams Phone extensibility

A Teams or Microsoft 365 administrator usually completes these steps. Skip this section for Twilio.
  1. Follow Teams Phone System extensibility quick start to provision the application, bot, resource account, and Azure Communication Services association.
  2. Create or select the Azure Communication Services resource that receives calls for the resource account.
  3. Create the Teams resource account with the Phone Extensibility application ID.
  4. Associate the resource account with the Azure Communication Services resource, and synchronize the resource account.
  5. Acquire a Teams service number and assign it to the resource account. The number can use Calling Plan, Operator Connect, or Direct Routing according to your Teams telephony configuration.
  6. Assign the Microsoft Teams Phone Resource Account license when required.
  7. Provide Azure Communication Services server consent for the exact tenant and resource-account object ID.
  8. For inbound calls, place a controlled call and confirm that Azure Communication Services emits Microsoft.Communication.IncomingCall.
Provide the Foundry owner with the callable Teams number, Azure Communication Services ARM resource ID, and resource-account object ID. For inbound setup, also confirm that Azure Communication Services received the test call.

Set up your preferred interface

Choose Foundry portal, Python SDK, or REST. The Python examples share a client and variables across sections.
Open your project in the Foundry portal. You don’t need the Python packages or a manually acquired bearer token for the portal steps.

Configure a provider connection

Use a project connection for your provider. The portal number setup flow can create it for you. For SDK or REST requests, create or select the connection first.

Create a connection to Communication Services

For Teams, use the category AzureCommunicationServices. Set target to the resource’s HTTPS endpoint, such as https://<resource-name>.communication.azure.com, not its Azure resource ID. Store the matching resource ID in ResourceId metadata. Choose an authentication type supported by the connection: For a managed identity or service principal, grant the required Communication Services permissions before creating a binding or placing calls.

Configure the Twilio project connection

For Twilio, use these settings: Use the connection’s name as connection_name in binding and outbound requests. Don’t include provider credentials in those requests.

Understand telephony bindings

A binding routes inbound calls to one agent. You don’t need a binding for outbound call jobs. Create and list bindings at {projectEndpoint}/agents/{agentName}/telephony/bindings. Append /{bindingId} to read, update, or delete one. Use the latest ETag for conditional updates and deletion. Creating a Twilio binding updates the number’s voice URL and status callback, replacing its existing inbound voice routing. Use a number you want to route to this agent.

Connect a number in the Foundry portal

The portal provides separate setup flows for Teams Phone extensibility and Twilio. Select Microsoft Teams for the Teams Phone extensibility flow.

Open the phone-number channel

  1. In Foundry, open Build > Agents.
  2. Select the voice-based agent.
  3. Open Channels.
  4. In Phone numbers, select Add a number.
  5. Select Microsoft Teams or Twilio.

Connect a Microsoft Teams number

The Teams Phone extensibility flow creates or updates the Azure Communication Services project connection and telephony binding. Depending on the secure-delivery option, Foundry can also configure the webhook application and IncomingCall Event Grid subscription.

Choose secure incoming-call delivery

When Secure incoming-call delivery is shown, choose the approved mode.Under Manual configuration, choose the option that matches your setup:
  • Use a customer-managed app registration and let Foundry configure Event Grid: Use a dedicated single-tenant application that you own, or ask an administrator to complete the changes.
  • Event Grid and app registration are already configured: Use only when authenticated Event Grid delivery to the exact Foundry webhook is complete. Foundry skips that bootstrap work.
For a customer-managed application:
  1. Select an eligible single-tenant app registration.
  2. Enter any governance reference required by your organization.
  3. If the application isn’t listed, confirm that you’re an owner and refresh.
  4. Ask a tenant administrator to complete required API permissions and app-role assignments.
Never disable authentication to work around a webhook validation error.

Select Azure Communication Services

In Azure Communication Services resource, select the resource that receives the calls.If it isn’t listed:
  • Confirm the tenant and subscription.
  • Confirm you can read the resource.
  • Confirm the expected resource provider is registered.
  • Ask an Azure administrator to correct RBAC.
Foundry creates or updates the project connection to the Azure Communication Services endpoint and uses the project managed identity. Don’t enter an Azure Communication Services key or connection string.

Enter the Teams number details

Enter the Resource account object ID that the Teams administrator provides. Foundry constructs:

Connect a Twilio number

  1. In Phone numbers, select Add a number > Twilio.
  2. Select a compatible existing Twilio connection. If none is available, select Create a new Twilio connection.
  3. To create a connection, enter:
    • A unique Connection name.
    • The Twilio Account SID. It starts with AC and contains 34 characters.
    • The Twilio Primary Auth Token.
  4. Select Connect or Continue.
  5. Select one or more voice-capable phone numbers discovered from the Twilio account. You can’t select numbers without the Voice capability.
  6. Select Continue.
  7. Review the agent, connection, masked Account SID, and selected numbers.
  8. Optionally change the display label for each number.
  9. Select Add selected numbers.
  10. Review the result for each number. Retry any number that has a failed or unconfirmed result.
  11. Select Done after all binding operations finish.
Foundry stores the Twilio credentials in the project connection and creates a separate telephony binding for each selected number.If you don’t find any voice-capable numbers, get a number in the Twilio Console and retry discovery.

Manage a connected number

The Phone numbers card shows each connected number, its optional label, and its provider.
  1. Open the number’s actions menu.
  2. Select View details.
  3. Select Edit if the binding supports updates.
  4. For Microsoft Teams, update the displayed phone number or label. The resource-account object ID and connection are read-only.
  5. For Twilio, update the label. The phone number and connection are read-only.
  6. Select Save.

Binding update rules

Set status to active to accept new inbound calls again. Both providers support updates to status and label. Teams bindings also support changes to connection_name and the display phone_number. The provider and resource-account object ID are immutable. For Twilio, delete and recreate the binding to change its phone number or connection.

Register the Event Grid subscription

This section applies only to Teams inbound calls, not Twilio or outbound-only setup. Create an Event Grid subscription on the Communication Services resource that targets the binding’s incoming_call_url. If the portal already configured secure delivery, don’t create a duplicate subscription. Before running the Bash example, sign in with az login and set these variables: Complete the application and role setup in Deliver events to Microsoft Entra protected endpoints first. Obtain the webhook tenant and audience from the administrator who configures secure incoming-call delivery. The webhook application identifies the token audience; it isn’t the Microsoft Event Grid first-party application.
Reference: az eventgrid event-subscription create. During creation, Event Grid sends a validation event that the endpoint answers automatically. Foundry validates the Microsoft Entra token that Event Grid attaches to each delivery, and then requires an active binding whose project, agent, Communication Services resource, and callee all match the event. Calls that don’t match a binding aren’t answered. Event Grid allows up to 500 event subscriptions per system topic. Plan incoming-call delivery within the Event Grid quotas and limits.

Place outbound calls by using the API

Create an outbound call job to call a phone number through a project connection. Creating a call job doesn’t change inbound routing. Complete Set up your preferred interface before running the Python or REST examples. Use a destination you have permission to call. Create or select the provider connection, but skip the inbound binding and Event Grid procedures for outbound-only use.

Set the outbound caller and destination

The connection category selects the provider. Use these required settings: Supply a connection name, not a resource ID or URL. Don’t send provider, telephony_binding_id, or the legacy connection field in an outbound request. Generate an idempotency key of 1 to 256 characters for each new call intent. Reuse it with an equivalent request when retrying an uncertain response. The service returns the same job; reusing the key with a different request returns 409 Conflict. Creation returns 202 Accepted with the job’s id, ETag, Location, and Retry-After in seconds. Acceptance doesn’t mean the recipient answered or the call completed. The service resolves the latest saved agent definition for each attempt. Provide any required agent inputs in structured_inputs.
This section covers outbound calls through the API. Select Python SDK or REST to create, read, or cancel a call job. You can use a project connection created in the portal without creating an inbound binding.

Interpret the job status

Inspect status, attempt_count, and terminal_reason. Terminal statuses are completed, blocked, expired, failed, and cancelled. Interpret the reason with the status: a queued job can retain a temporary dispatch-deferral reason. Cancellation returns 202 Accepted while pending, or 200 OK when the job is terminal. Continue reading the job until it reaches a terminal status. Cancellation doesn’t hang up a connected call; a cancellation request after connection can return 409 Conflict. A job ID isn’t a live call ID. Don’t pass it to /telephony/calls/{callId}.

Optional outbound settings

Use these settings in the Python request model or REST JSON body. The SDK converts Python date and duration objects to the REST wire format. For Python, use TelephonyCallJobSchedule and TelephonyOutboundFixedIntervalRetryPolicy to construct these optional values.

Configure transfer to a person

An agent that can’t complete a request should reach a human rather than end the call. Configure named transfer targets for the agent. These targets are separate from its telephony bindings. The examples use PSTN targets, which work with either provider. Use destinations approved for your call flow.
Select Python SDK or REST for the transfer-target configuration examples.
Use these destination kinds for provider-specific routing: There’s no twilio destination kind. For Python, use PSTNTelephonyTransferDestination, TeamsTelephonyTransferDestination, or SipTelephonyTransferDestination for the corresponding destination. Give each target a description that says when to use it. The agent chooses based on that text. Transfer requests select a target from the agent’s configured list rather than supplying an arbitrary destination.

Manage a live call

These operations list and manage inbound calls. Use a live call ID, not an outbound job ID. Complete Set up your preferred interface before running the examples.
Select Python SDK or REST to list calls or send a transfer or end-call request.

Configure audio for phone calls

Phone networks carry narrowband audio, so tune the agent for the channel:
  • Set noise_reduction.type to azure_deep_noise_suppression for contact center traffic.
  • Increase silence_duration_ms. Callers on a phone pause more than callers at a keyboard.
  • Add phrase_list hints for the identifiers callers read aloud, such as order or policy numbers.
  • Attach the end_conversation system tool so the agent can end a completed call.
See Configure a voice agent.

Test the call

  1. Wait for the selected provider and binding changes to propagate. For Microsoft Teams, also allow time for Azure Communication Services and Event Grid propagation.
  2. From a controlled caller, call the configured number.
  3. Confirm the agent answers.
  4. Complete a short conversation.
  5. Interrupt the agent.
  6. Use one safe tool or knowledge path.
  7. Test the approved human-handoff behavior.
  8. End the call.
  9. Confirm that monitoring and trace data appear.
Record:
  • Test timestamp and time zone.
  • Called number.
  • Callee identifier.
  • Telephony provider and provider call ID, such as an Azure Communication Services correlation ID or Twilio Call SID.
  • Agent name and version.
  • For Microsoft Teams, the Azure Communication Services resource ID and Event Grid delivery result.
  • For Twilio, the Foundry project connection name.
For an outbound test, create a job for an approved test recipient and record the job ID, status, attempt count, and reason. Don’t treat 202 Accepted as proof that the call connected.

Trace phone calls

When a call arrives through telephony, the session’s root trace span records the provider, the provider’s call ID, and the dialed and calling numbers. You can correlate a Foundry session with a record in your telephony provider. Caller and callee phone numbers are personal data. Review who can read your project’s Application Insights resource before you enable content capture. See Voice agent tracing, monitoring, and evaluation.

Troubleshoot telephony

Disconnect a number

Remove the inbound mapping when you no longer want the number to route calls to this agent. Outbound jobs don’t require a binding; cancel any unwanted jobs separately.
  1. Open the agent Channels tab.
  2. In Phone numbers, open the number’s actions menu.
  3. Select Disconnect number.
  4. Confirm.
Disconnecting removes the Foundry binding. It doesn’t:
  • Release the Teams or Twilio number.
  • Remove the Teams resource account.
  • Delete Azure Communication Services.
  • Remove the bot or app registration.
  • Revoke Teams Phone extensibility consent.
  • Delete the Twilio account or the Foundry project connection.
Coordinate upstream cleanup separately. For Twilio, review the number’s voice routing before using it with another application.

Security checklist

  • Use Microsoft Entra authentication for Foundry API requests. Prefer managed identity for the Azure Communication Services connection.
  • Don’t share Azure Communication Services keys, connection strings, tokens, bot secrets, or portal cookies.
  • Store the Twilio Auth Token in the project connection. If it’s exposed, rotate it and update the connection.
  • Confirm that the Twilio account owns each inbound number and authorizes each outbound caller number.
  • For Teams inbound calls, validate that the Event Grid topic is the intended Azure Communication Services resource.
  • Use the exact public Foundry project webhook endpoint.
  • Keep webhook audience and Event Grid delivery identity concepts separate.
  • Use a dedicated single-tenant webhook application when governance requires it.
  • Don’t persist service-generated call callback or media tokens.
  • Confirm the binding target before update or deletion.
  • Apply recording, consent, disclosure, retention, and privacy requirements.
  • Prevent sensitive caller data from being read aloud or unnecessarily stored.
Use these guides to configure and validate the agent behind your telephony channel: