An Azure service that provides a hybrid, multi-cloud management platform for APIs.
Hey Muhammad,
Thanks for such a detailed write-up. You've already ruled out a lot, so I wouldn't spend more time recreating the API. At this point I'd also open an APIM support case while running a couple of additional checks.
I don't see a documented Developer-tier limitation that would explain this, since WebSocket passthrough is supported on that tier.
The empty HTTP 200 is the interesting part. If APIM were trying to reach the backend and failing because of DNS or networking, I'd normally expect a gateway error rather than a clean 200. So I'd start with routing and policies. Here's what I'd try.
1. Check the effective policy and request routing
In the portal, open the onHandshake operation and use "Calculate effective policy". Look for anything that could end the request early, especially inherited global policies or a return-response. Recreating the API doesn't touch the global policy, so it's worth a look.
If gateway diagnostics are enabled, this query should help:
ApiManagementGatewayLogs
| where TimeGenerated > ago(24h)
| where Url contains "/chathub"
| project
TimeGenerated,
ApiId,
OperationId,
Url,
ResponseCode,
BackendUrl,
BackendResponseCode,
LastErrorReason,
LastErrorMessage,
CorrelationId
| order by TimeGenerated desc
The key thing to confirm is whether OperationId corresponds to the WebSocket onHandshake operation. If WebSocket connection logging is enabled, you can also check ApiManagementWebSocketConnectionLogs and match entries by CorrelationId.
2. Run an isolated WebSocket test
This one should narrow things down nicely. Create a temporary WebSocket API on the same APIM instance with a different URL suffix, and point it at a trusted public WSS echo endpoint. Keep the policies minimal, and please don't send any credentials or sensitive data.
- If it returns 101, the gateway can handle WebSocket passthrough, and I'd then look at differences in backend connectivity, TLS and routing.
- If it also returns an empty 200, I'd look more closely at shared gateway configuration, global policies or a possible platform issue.
Of course, the second result isn't conclusive on its own. If the APIM instance has restricted outbound Internet access, that could also affect the test.
Your existing API stays untouched for this test.
3. Confirm network access to the private backend
Testing the App Service through its private endpoint is a good sign, but it doesn't prove APIM has the same access. The Developer tier supports VNet injection (internal or external mode), so is your instance set up with either?
If so, I'd check that APIM resolves the backend hostname to the expected private IP, and review routing, NSGs and outbound access on port 443. Given the empty 200, I wouldn't make this the first suspect.
Also, having chathub as the API suffix and /chathub in the backend URL isn't wrong by itself. They are separate parts of the routing configuration.
4. Provide the findings to Azure support
If the logs show the expected onHandshake operation, no policy is ending the request, and the isolated test behaves the same way, I'd ask Microsoft to look at the gateway processing path. Please include the failed handshake timestamps, correlation IDs, effective policy, gateway logs and the isolated test results.
One thing that would really help: does the gateway log show OperationId = onHandshake for the failed requests, or is it empty or pointing somewhere else? That's what I'd check first.
References: