Microsoft Teams Phone
Bring your own Microsoft Teams phone number and let an Aethex voice agent answer and place calls on it. You link your Teams tenant once with admin consent, attach an existing number to an agent, and the number stays in your own Microsoft 365 account.
How it works
Aethex connects to Microsoft Teams Phone over Azure Communication Services. You keep your number in your own Microsoft 365 tenant. Aethex never buys or ports it. A Teams administrator grants Aethex access to your tenant, you link a Teams resource account that carries one of your existing numbers, and you attach that number to an agent. From then on, inbound calls to the number are answered by the agent, and you can place outbound calls through the same API. The agent runs on Aethex's self-hosted speech-to-text, language model, and text-to-speech pipeline.
Prerequisites
In your Microsoft 365 tenant you need: a Teams Phone licence (the standalone SKU is Teams Phone Standard; Microsoft 365 E5 includes it); a phone number on a Teams resource account, which carries the free Microsoft Teams Phone Resource Account licence instead, never Teams Phone Standard, which Microsoft does not support on a resource account; and a Teams or Global administrator to grant consent and run one Teams PowerShell command. For outbound calls from your own number, the resource account additionally needs a Pay-As-You-Go Calling Plan licence assigned to it, plus a funding source: either Communications Credits, or Phone services consumption switched on for that plan under Billing → Your products in the Microsoft 365 admin centre. A Direct Routing number needs neither. Since 1 November 2025 a Calling Plan on its own covers inbound only. On the Aethex side: an API key with the msteams:read and msteams:write scopes, and an agent to answer calls (create one from the dashboard or the Agents API).
What your Teams administrator does (once)
Everything below happens once, in your own Microsoft 365 tenant. Aethex never buys, ports or holds your number, and your Teams users are unaffected: the agent answers on a resource account, which is a licensed identity for voice apps rather than a person.1. Licence the tenant. You need Teams Phone (standalone or via E5). For the agent to place outbound calls you also need a Pay-As-You-Go Calling Plan for your zone, plus a funding source: either turn on Phone services consumption for that plan under Billing → Your products, or buy Communications Credits and keep a positive balance. Since 1 November 2025 a Calling Plan on its own covers inbound only.2. Buy the free resource-account licence. Marketplace → All products → Microsoft Teams Phone Resource Account. It costs nothing, but you must still place the order.3. Get a service number. Teams admin centre → Voice → Phone numbers → Add. Choose a Service number, not a User (subscriber) number: a resource account cannot hold a user number. You will be asked for an emergency address in the same country as the number.4. Create the resource account with the PowerShell command Aethex gives you (see the next section). The Teams admin centre cannot do this step, because the account has to be created against the Aethex application id.5. Licence the resource account: the free Teams Phone Resource Account licence, plus the Pay-As-You-Go Calling Plan if it will dial out. Set its usage location to the number's country. Do not give it Teams Phone Standard: Microsoft does not support that on a resource account and it stops the account working.6. Assign the number and link it to Aethex, then approve the consent link. Both are single commands or a single click, and both are covered in the next section.
Connect your Teams number
The whole flow runs through the REST API plus one admin consent click and one PowerShell command. Set AETHEX_API_KEY in your shell, then work through the steps in order.
Get an API key with Teams scopes
Create an API key that carries the
msteams:readandmsteams:writescopes. New keys include both by default, so a freshly created key works as-is. Export it asAETHEX_API_KEYfor the calls below.Start admin consent
Call
POST /connect. It returns aconsent_urlandstate_expires_in(seconds). Send your Teams or Global administrator to theconsent_url, where they sign in to Microsoft and approve Aethex's access. The link is single-use and expires whenstate_expires_inelapses. After approval, Microsoft shows a short confirmation page they can close, and the connection is recorded against your tenant. Aethex stores only your Microsoft tenant id, never a password or secret.Begin the connectionbashcurl -X POST https://api.aethexai.com/api/v1/integrations/telephony/msteams/connect \ -H "X-API-Key: $AETHEX_API_KEY" # Response: send your Teams admin to consent_url; it is valid for state_expires_in seconds. # { # "consent_url": "https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?client_id=...&state=...", # "state_expires_in": 600 # }Link a Teams resource account
Call
GET /resource-accountsto readconnect_command, a ready-to-run Microsoft Teams PowerShell line. Your Teams administrator runs it once to create a resource account linked to Aethex, then assigns one of your existing Teams numbers to that account in the Teams Admin Center. Two details Microsoft enforces: the resource account must carry the free Microsoft Teams Phone Resource Account licence, never Teams Phone Standard, which is unsupported on resource accounts and breaks them; and the number must be a service number, not a user (subscriber) number. TheApplicationIdandAcsResourceIdin the command arrive pre-filled, so copy the string verbatim and only replaceYOUR-TEAMS-DOMAINwith your tenant domain.Read and run the connect commandbash# 1. Read the ready-to-run PowerShell line from your connection. curl https://api.aethexai.com/api/v1/integrations/telephony/msteams/resource-accounts \ -H "X-API-Key: $AETHEX_API_KEY" # 2. In an elevated Microsoft Teams PowerShell session, paste the "connect_command" # string exactly as returned (ApplicationId and AcsResourceId arrive filled in), # replacing YOUR-TEAMS-DOMAIN with your tenant domain: Connect-MicrosoftTeams $ra = New-CsOnlineApplicationInstance \ -UserPrincipalName '[email protected]' \ -ApplicationId '<application-id>' -DisplayName 'Aethex Voice' Set-CsOnlineApplicationInstance -Identity '[email protected]' \ -ApplicationId '<application-id>' -AcsResourceId '<acs-resource-id>' Sync-CsOnlineApplicationInstance -ObjectId $ra.ObjectId -ApplicationId '<application-id>' # 3. In the Teams Admin Center, assign one of your existing Teams SERVICE numbers # (licensed with the free Teams Phone Resource Account SKU, never Teams Phone Standard) to that resource account.Confirm the number is linked
Call
GET /resource-accountsagain. Once Microsoft finishes provisioning (usually a few minutes), the account appears with its assignedphone_numberin E.164. Note the account'sid, which you pass to attach in the next step.Resource account with its numberjson{ "resource_accounts": [ { "id": "6c7d8e9f-0a1b-2c3d-4e5f-60718293a4b5", "user_principal_name": "[email protected]", "display_name": "Aethex Voice", "phone_number": "+14155550100" } ], "connect_command": "Connect-MicrosoftTeams; $ra = New-CsOnlineApplicationInstance ..." }Attach the number to an agent
Call
POST /attachwith the resource accountidand theagent_idthat should answer the number. Aethex authorizes the number into its calling resource and routes inbound calls to your agent. Re-attaching the same number just re-points it at a different agent.Bind the number to an agentbashcurl -X POST https://api.aethexai.com/api/v1/integrations/telephony/msteams/attach \ -H "X-API-Key: $AETHEX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "resource_account_id": "6c7d8e9f-0a1b-2c3d-4e5f-60718293a4b5", "agent_id": "8a1b2c3d-4e5f-6789-abcd-ef0123456789", "friendly_name": "Support line" }'Place and receive calls
Inbound calls to the attached number now reach the agent automatically, with no further setup. To dial out, call
POST /callswith anagent_idand a destinationto_number. The response returns acall_connection_idyou can use to correlate the call.Place an outbound callbashcurl -X POST https://api.aethexai.com/api/v1/integrations/telephony/msteams/calls \ -H "X-API-Key: $AETHEX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "8a1b2c3d-4e5f-6789-abcd-ef0123456789", "to_number": "+14155550123" }'
Authentication and scopes
Authenticate every request with your API key in the X-API-Key header. The Microsoft Teams endpoints require two scopes: msteams:read to view the connection and list resource accounts, and msteams:write to connect, attach a number, place a call, and disconnect. Both are part of the default scope bundle, so newly created keys already carry them. See Scopes for the full model.
403 Forbidden. Mint a new key or widen an existing one to include msteams:read and msteams:write.Inbound and outbound calls
Inbound: once a number is attached, calls to it are answered by the agent you bound it to. Outbound: POST /calls rings the destination and bridges the callee into the agent's voice pipeline. Outbound calls are billed like any other Aethex call and go through the same admission checks, so a hard billing block or a capacity limit is reported before the call is placed.
Common errors
The Teams endpoints return standard HTTP status codes. These are the ones you are most likely to hit; the API reference lists the errors per endpoint.
You called a Teams endpoint before completing admin consent, so there is no connection on your tenant yet.
Run POST /connect and have your Teams admin approve the consent_url first.
Your Microsoft session expired or the stored authorization is no longer valid, so Aethex can't read your resource accounts.
Call POST /connect again and re-approve. It silently refreshes the connection.
The resource account has no phone number assigned yet, or the number is already connected to another Aethex account.
Assign a number to the resource account in the Teams Admin Center, or release it from the other account before attaching it.
Outbound calling is blocked because the account has a hard billing block (for example, no credits or no payment method).
Resolve the balance or payment method in the billing dashboard, then retry POST /calls.
The voice backends are momentarily saturated, so a new outbound call couldn't reserve a slot.
Retry with backoff. Sustained 429s mean you should contact us to raise capacity.
Microsoft Teams Phone isn't enabled on this deployment, or a required Microsoft service is momentarily unavailable.
Retry shortly. If it persists, contact [email protected].
If something does not work
Signing in to Teams PowerShell fails with `AADSTS530035`. Your tenant blocks the device-code sign-in flow, usually because security defaults are switched on. The Teams PowerShell module falls back to device code on macOS and Linux, so run it from Windows, which uses a different flow, or temporarily turn security defaults off, wait about fifteen minutes for the change to take effect, sign in, then turn them back on."You can't assign licenses that contain these conflicting services." You have Teams Phone Standard ticked alongside the Resource Account licence. Untick Teams Phone Standard.The number will not assign to the resource account. Either the licences have not propagated yet, or the number is a User number rather than a Service number. Only service numbers can be assigned to a resource account.Inbound works but outbound calls fail. The resource account is missing the Pay-As-You-Go Calling Plan licence, or the tenant has no funding source. Check that the plan is assigned to the resource account itself, and that Phone services consumption is on or Communications Credits have a positive balance.Callers hear that the number is unavailable. The resource account is not yet fully linked. Re-run the link and sync commands from the previous section, and confirm the account shows a phone number and Enterprise Voice enabled.
API reference
For every endpoint, parameter, and response field, see the Microsoft Teams Phone API reference.
