How to Fix Azure Communication Services Setup & Errors
Why Azure Communication Services Breaks , And Why the Error Messages Don't Help
I've seen this exact situation on dozens of Azure projects: you spin up a new Azure Communication Services resource, grab your connection string, write what looks like perfectly correct SDK code , and then nothing works. Maybe your SMS messages vanish into the void. Maybe your phone number acquisition fails with a cryptic error. Maybe your email sends return a 202 status (which Microsoft docs say is a success) and yet the recipient never gets anything. The whole experience can feel like shouting into a void.
Here's the thing, Azure Communication Services is genuinely powerful. It gives you voice, video calling, chat, SMS, email, and Advanced Messaging for WhatsApp all through a single multichannel communication API. That breadth is exactly what makes it tricky. Each channel, calling, SMS, email, chat, has its own provisioning requirements, its own SDK surface, and its own failure modes. When something breaks, the error messages are often too generic to tell you which layer is the problem.
The most common reasons I see Azure Communication Services setups fail fall into four buckets:
- Resource provisioning in the wrong region. Phone number availability varies by Azure geography. If your resource is in a region that doesn't support voice or SMS for your target country, acquisition will fail silently or throw a 404.
- Malformed or expired connection strings. The ACS connection string encodes both the endpoint and the access key. Rotating keys in the portal but forgetting to update your app config is one of the most common causes of sudden 401 errors.
- Missing sender authentication for email. The ACS email channel requires a verified sender domain or a free Azure subdomain. Skipping that step means your emails queue and never deliver.
- Call Automation webhook misconfiguration. If your callback URL isn't publicly reachable or returns the wrong HTTP status, the CreateCall and AnswerCall APIs fail asynchronously, and before the November 2024 update added
CreateCallFailedandAnswerFailedevents, you'd have had almost no way to know why.
The problem with Azure Communication Services troubleshooting is that Microsoft's portal doesn't surface many of these failures in an obvious place. You have to know to check Azure Metrics, Event Grid subscriptions, and the Call Diagnostics tools, none of which are on by default. I'll walk you through all of it.
Browse all Microsoft fix guides →The Quick Fix for Azure Communication Services, Try This First
If you're in a hurry and just need something working, start here. Roughly 60% of Azure Communication Services failures I've seen come down to one of these two root causes, both fixable in under five minutes.
Step 1: Regenerate and redeploy your connection string. Go to the Azure portal, open your Communication Services resource, and click Keys in the left-hand menu. You'll see two keys, Primary and Secondary. Copy the full connection string (not just the key itself, the full string that starts with endpoint=https://). Paste that into wherever your application reads it, environment variable, app setting, Key Vault secret, and restart your service. A mismatched or stale connection string causes 401 Unauthorized on every single API call, across every channel.
Step 2: Confirm your resource's provisioning state is Succeeded. In the Azure portal, open your Communication Services resource and look at the Essentials panel at the top. The Provisioning state field should read Succeeded. If it says Creating, Failed, or Updating, your resource isn't ready to accept traffic. Failed provisioning is rare but does happen, the fix is to delete the resource and recreate it in the same resource group. Takes about 90 seconds to provision.
If both of those check out and things still aren't working, the issue is channel-specific, SMS, email, phone calling, and chat each have their own setup requirements. The step-by-step section below breaks each one down.
Before anything else, confirm that your ACS resource exists in a supported Azure geography for what you're trying to do. This is where a lot of teams get burned early. Azure Communication Services is available in multiple Azure geographies, but phone number acquisition and PSTN calling are region-restricted. Not every Azure region supports acquiring local or toll-free numbers for every country.
To check: open the Azure portal, navigate to your Communication Services resource, and in the left menu select Phone numbers. Click Get. If the country you need isn't listed, your resource region doesn't support it. You have two options: create a new ACS resource in a supported region, or use Azure Communication Services direct routing to bring your own phone numbers via a SIP-enabled session border controller.
For the SMS channel specifically, you need a phone number with SMS capability enabled. When acquiring a number, the portal shows you which capabilities each number type supports. A number provisioned for voice only will silently drop outbound SMS, the API call will return success but the message won't go anywhere. Always double-check capability flags.
To confirm via the REST API rather than the portal:
GET https://<your-resource>.communication.azure.com/phoneNumbers?api-version=2023-05-01
Authorization: Bearer <your-access-token>
Look at the capabilities object in the response. You want to see "sms": "inbound+outbound" for full SMS, or "calling": "inbound+outbound" for voice. If those aren't there, the number isn't configured for what you need.
If it worked: your phone numbers list loads without error, and the capabilities match what you need. Move to Step 2.
Azure Communication Services SDKs, available for JavaScript/TypeScript, .NET, Python, Java, and more, all authenticate the same way: either a connection string or a managed identity credential. The connection string approach is the most common, and it's also the most common source of 401 errors in my experience.
A valid ACS connection string looks like this:
endpoint=https://<your-resource-name>.communication.azure.com/;accesskey=<base64-encoded-key>
Two things break this silently. First, trailing whitespace, if you copied the connection string from the portal and accidentally grabbed a space at the end, the SDK will parse it incorrectly and you'll get authentication failures with no obvious error message. Trim the string in your code or config. Second, using just the access key (the base64 string) instead of the full connection string, the SDK expects both the endpoint and the key together in that format.
In JavaScript/TypeScript, initialize your SMS client like this:
import { SmsClient } from "@azure/communication-sms";
const connectionString = process.env.COMMUNICATION_SERVICES_CONNECTION_STRING;
const smsClient = new SmsClient(connectionString);
const sendResults = await smsClient.send({
from: "+15551234567",
to: ["+15559876543"],
message: "Hello from Azure Communication Services"
});
If you're on a managed identity setup (recommended for production), swap the connection string for a DefaultAzureCredential and pass your resource endpoint URL separately. Make sure the managed identity has the Contributor role on the ACS resource, Reader isn't enough to send messages.
If it worked: your first SDK call returns a result object with httpStatusCode: 202 for SMS sends, or a valid response body for other channels. No more 401 errors.
Email is the channel I see most misconfigured. Azure Communication Services email works through a separate sub-resource called an Email Communication Service, it's not built into your main ACS resource automatically. A lot of developers miss this and can't figure out why their email sends return 202 but nothing arrives.
Here's the setup path: in the Azure portal, search for Email Communication Services and create one. Then, link it to your main Communication Services resource by going to your ACS resource → Email in the left menu → Connect your email domain. Without this link, the SDK call will appear to succeed (202 Accepted) but emails won't actually be dispatched.
For the sender domain: you have two choices. The quick one is the free azurecomm.net subdomain Microsoft provides, no DNS changes needed, works in minutes. The production choice is connecting your own domain, which requires adding SPF, DKIM, and DMARC records to your DNS. Microsoft's email documentation explicitly calls out sender authentication as a best practice, and for good reason. Without proper DKIM/DMARC alignment, your emails will land in spam folders or get rejected by major providers.
To send an email using the SDK:
import { EmailClient } from "@azure/communication-email";
const client = new EmailClient(connectionString);
const emailMessage = {
senderAddress: "donotreply@your-verified-domain.com",
content: {
subject: "Test email from ACS",
plainText: "Hello, this is a test.",
},
recipients: {
to: [{ address: "user@example.com", displayName: "Test User" }],
},
};
const poller = await client.beginSend(emailMessage);
const result = await poller.pollUntilDone();
The beginSend method returns a long-running operation poller. If you only await client.beginSend() without calling pollUntilDone(), you'll miss delivery errors. Poll until done to get the final status field, look for Succeeded.
If it worked: result.status is "Succeeded" and the recipient receives the email within a few seconds.
Voice and video calling in Azure Communication Services runs through the Calling SDK on the client side, and optionally through Call Automation on the server side for IVR flows, bots, and programmable call routing. Both have distinct failure patterns.
For the client-side Calling SDK, the most common issue is a missing or expired user access token. Every call participant needs a short-lived token issued by your backend using the ACS Identity SDK. Tokens expire after 24 hours by default. If a user's session persists longer than that, their call attempts will fail with a 401. The fix: implement token refresh in your application. Your backend should expose an endpoint that generates a fresh token, and your frontend should call it before the current token expires.
Generating a user access token in Node.js looks like this:
import { CommunicationIdentityClient } from "@azure/communication-identity";
const identityClient = new CommunicationIdentityClient(connectionString);
const user = await identityClient.createUser();
const tokenResponse = await identityClient.getToken(user, ["voip"]);
console.log(tokenResponse.token); // short-lived JWT
console.log(tokenResponse.expiresOn); // expiry timestamp
For Call Automation, the server-side API for building IVR workflows, recording calls, and running bots, the critical thing since the November 2024 update is handling the new CreateCallFailed and AnswerFailed events. Previously, if your CreateCall API call failed asynchronously, you'd get nothing back. Now, these events fire on your callback webhook. Make sure your webhook endpoint is publicly reachable (use a tool like ngrok for local development), returns HTTP 200 quickly, and processes events asynchronously in a background queue.
You can now also monitor Call Automation callback events directly in Azure Metrics, go to your ACS resource → Metrics → select the Call Automation namespace. This is a huge improvement for debugging production call flows.
If it worked: incoming call events appear in your webhook handler, and the Metrics dashboard shows callback event counts incrementing normally.
The Chat SDK and Advanced Messaging for WhatsApp both require a thread or conversation context before any messages can flow, and that context needs a valid user access token with the right scopes.
For chat, the common failure point is scope mismatch. When you generate a user token, you must explicitly include the "chat" scope. A token generated with only the "voip" scope will get rejected by the Chat API with a 403 Forbidden. Check your token generation code and include both scopes if you need both channels:
const tokenResponse = await identityClient.getToken(user, ["voip", "chat"]);
For Advanced Messaging for WhatsApp, setup is more involved. You need to register a WhatsApp Business Account through the Azure portal's Advanced Messaging section. The process involves connecting your Meta (Facebook) Business Manager account to your ACS resource. Before going live, Microsoft provides an Advanced Messaging sandbox you can use to test message flows without a real WhatsApp Business account, highly recommend starting there to verify your integration before committing to the full registration process.
Once registered, sending a WhatsApp message requires using an approved message template for the first outbound message to a new user (this is a WhatsApp Business Platform rule, not an ACS rule). Trying to send a free-form message to a user who hasn't messaged you first will get rejected. Use the template message API for your initial outreach:
// Advanced Messaging send via ACS REST API
POST https://<resource>.communication.azure.com/messages/notifications:send?api-version=2024-02-01
{
"channelRegistrationId": "<your-channel-id>",
"to": "+15551234567",
"kind": "template",
"template": {
"name": "your_approved_template_name",
"language": { "code": "en_US" }
}
}
If it worked: the API returns 202 Accepted and the recipient receives the WhatsApp template message on their device within seconds.
Advanced Troubleshooting for Azure Communication Services
If the steps above haven't resolved your Azure Communication Services problem, you're likely dealing with something at the infrastructure or configuration layer. Here's where to dig deeper.
Using Azure Call Diagnostics
The Call Diagnostics tool in the Azure portal is criminally underused. Go to your ACS resource → Diagnostics → Call Diagnostics. You can search for a specific call by its Call ID (which the Calling SDK exposes as call.id on any active call object). The tool shows you detailed media quality data, packet loss percentages, jitter metrics, and end-to-end call flow topology. If users are reporting choppy audio or dropped calls, this is the first place to look, not application logs.
Event Grid and Webhook Delivery Failures
Azure Communication Services publishes events, incoming SMS, incoming calls, call ended, message delivered, through Azure Event Grid. If your application isn't receiving these events, check Event Grid first, not your application. In the Azure portal, go to your ACS resource → Events. Look at the Metrics tab for your event subscription. High Delivery Failed counts mean your webhook endpoint is returning errors or is unreachable.
Common webhook issues:
- Your endpoint returns a non-2xx HTTP status for the Event Grid handshake validation request (a special
SubscriptionValidationEventthat fires during subscription creation) - Your endpoint takes longer than 30 seconds to respond, Event Grid treats this as a failure and will retry with exponential backoff
- SSL certificate errors on your webhook URL, Event Grid requires a valid, trusted TLS certificate
Network-Level Issues: Firewall and TURN Server Access
For voice and video calling, the Calling SDK uses WebRTC under the hood, which means it needs UDP access to Microsoft's TURN and STUN servers. If your users are behind a corporate firewall that blocks UDP, calls will either fail to connect or fall back to TCP-only mode (which degrades quality significantly). The Azure Communication Services calling documentation lists the specific IP ranges and ports that need to be allowed. You'll want to work with your network team to allowlist those ranges.
Teams Interoperability Errors
Azure Communication Services supports interoperability with Microsoft Teams, letting your ACS-built apps join Teams meetings or accept calls from Teams users. This requires your ACS resource to be in a tenant that has Teams Interoperability enabled. If Teams interop calls fail with a 403, check that the feature is enabled in your Azure Active Directory tenant settings, and that your ACS resource is in the same Azure AD tenant as your Teams deployment.
Job Router Not Routing Correctly
Job Router, ACS's customer interaction routing engine, requires both a distribution policy and a queue to be configured before jobs will be routed. A common mistake is creating jobs without creating a classification policy first, jobs end up in a pending state indefinitely. Use the ACS portal or REST API to verify your queue has at least one worker registered with matching labels.
Prevention & Best Practices for Azure Communication Services
I know it's tempting to focus purely on fixing things when they break. But a few hours of upfront setup will save you from most of the common Azure Communication Services failure modes entirely.
Use managed identity instead of connection strings in production. Connection strings contain your access key in plain text. If that string ends up in source control (it happens more often than anyone admits), your entire ACS resource is compromised. With managed identity, there's no secret to leak, Azure handles authentication automatically. Assign the Communication Services Contributor role to your app's managed identity and pass the endpoint URL rather than a connection string.
Set up Azure Monitor alerts for your ACS resource. Go to your ACS resource → Alerts → New alert rule. Create alerts on key metrics like SmsDeliveryFailed, IncomingCallFailed, and API error rate spikes. Without alerts, you'll find out about delivery failures from angry customers rather than from your monitoring system.
Implement token refresh before expiry, not on failure. User access tokens expire after 24 hours. If you only refresh tokens when a call fails with a 401, your users experience an interruption. Instead, check the token's expiresOn timestamp client-side and refresh it proactively, say, when less than 30 minutes remain. The ACS Calling SDK also emits a tokenCredentialExpired event you can listen for.
Test in the sandboxes before going live. Advanced Messaging provides a WhatsApp sandbox. Use it. It lets you send and receive WhatsApp messages without a registered business account, which means you can validate your entire message flow before going through the Meta business verification process, which can take days.
Keep your SDK versions current. ACS SDKs update frequently. The November 2024 release added CreateCallFailed and AnswerFailed events and background noise suppression for the WebJS Calling SDK. The October 2024 release added extended caller ID information (callerInfo.displayName and callerInfo.identifier) in incoming call notifications. Staying one or two minor versions behind means missing fixes for bugs that are already resolved upstream.
- Rotate your ACS access keys on a 90-day schedule using Azure Key Vault's automatic rotation feature
- Enable DKIM and DMARC on your email sender domain before sending any production email, your deliverability depends on it
- Use the Call Diagnostics tool in the Azure portal to baseline call quality during testing, before real users hit the system
- Subscribe to the ACS release notes RSS feed, the team ships substantial updates monthly and the changelog tells you exactly what changed in each SDK version
Frequently Asked Questions About Azure Communication Services
What is Azure Communication Services and what does it actually do?
Azure Communication Services is Microsoft's multichannel communication API platform, it lets you add SMS, email, voice calling, video calling, chat, and WhatsApp messaging to your own applications without building any of the underlying infrastructure yourself. Instead of integrating five different third-party services for five different channels, you get REST APIs and client library SDKs that cover all of them from a single Azure resource. You can use the channels individually or combine them, for example, an IVR system that sends an SMS confirmation, records the call, and logs a chat transcript all through the same resource.
Why are my Azure Communication Services SMS messages not being delivered?
The most common reason is that your phone number doesn't have SMS capability enabled, even though the API accepted your send request with a 202 status. Go to the Azure portal, open your ACS resource, click Phone numbers, select your number, and check the Capabilities section. It needs to show SMS as inbound+outbound. The second most common cause is a carrier filter on the recipient's network, some carriers block short codes or unregistered numbers, especially in the US, where 10DLC registration is now required for most business SMS. If deliveries are failing to US numbers specifically, 10DLC campaign registration is likely the fix.
How do I get a phone number in Azure Communication Services?
In the Azure portal, open your Communication Services resource and select Phone numbers from the left menu, then click Get. You'll choose a number type (local, toll-free, or short code), a country, and the capabilities you need (SMS, calling, or both). Not all number types are available in all countries, the picker will only show what's supported for your resource's region. Once purchased, the number appears in your phone numbers list within a minute or two and is immediately usable via the SDK. You can also acquire numbers programmatically through the ACS REST API if you need to automate provisioning.
Why is my Azure Communication Services email sending a 202 but the email never arrives?
A 202 Accepted from the email send API means Azure accepted the message for delivery, it does not mean it was delivered. The actual delivery is asynchronous. You need to poll the operation using poller.pollUntilDone() to get the final status. If the final status is Failed, the error detail will tell you why. The most common culprits are: the sender domain hasn't been verified (check your Email Communication Service resource → Domains), the sender address doesn't match the connected domain, or the recipient address has previously hard-bounced. Also confirm you've linked your Email Communication Service to your main ACS resource, without that link, emails never dispatch despite the 202.
How does Azure Communication Services voice calling work, does it need WebRTC?
Yes, the client-side Calling SDK uses WebRTC for browser-based voice and video calling. That means your users' browsers need to support WebRTC (all modern browsers do) and your network needs to allow WebRTC traffic, specifically UDP to Microsoft's TURN servers on ports 3478 and 443. The SDK handles the ICE negotiation and TURN relay automatically, but corporate firewalls that block UDP will cause calls to fail or fall back to lower-quality TCP-only media. On the server side, Call Automation uses SIP under the hood for PSTN connectivity, you can bring your own SIP trunk via direct routing without going through the portal phone number acquisition flow.
Can I use Azure Communication Services with Microsoft Teams?
Yes, Teams Interoperability is one of the built-in capabilities of Azure Communication Services. Your ACS-built apps can join Teams meetings as external participants, make and receive calls to/from Teams users, and participate in Teams Phone calls. This is useful for building custom interfaces around Teams, like a healthcare patient portal that joins a Teams video appointment without requiring patients to install the Teams client. The main requirement is that your ACS resource must be in the same Azure Active Directory tenant as your Teams organization, and Teams Interoperability must be enabled at the tenant level by an admin.