September 08, 2026
Akumina AI Configuration for Content Safety
Akumina AI Configuration for Content Safety
This guide explains how to publish AI models through the Azure AI Gateway tier so that applications call a single governed endpoint instead of calling each model provider directly. The gateway holds every provider credential, applies policy before the request reaches a backend, and emits token and latency telemetry for each call.
The AI Gateway tier is a separate product surface from the AI-gateway capabilities built into a classic Azure API Management instance. It is administered from its own portal at ai.gateway.azure.com, not from the Azure portal; it has no XML policy documents, no API URL suffix, and no operations to define. Models are registered as assets and are routed to by name. If you are configuring Microsoft Foundry behind a classic APIM instance instead, that is a different procedure and a different endpoint shape.
| Term | Meaning |
|---|---|
| Gateway | The resource you create in the portal. Its name forms the runtime hostname, so it cannot be changed afterwards. |
| Model provider | A logical backend grouping — one Foundry account, or one third-party vendor — that holds the endpoint address and the credential used to reach it. |
| Model | A single published model inside a provider. Callers select it by putting its name in the request body’s model field. Names must be unique across the whole gateway. |
| Runtime access key | The key an application sends to the gateway. Created on the Keys page and passed in the api-key header. |
| Policy | A governance rule (content safety, IP filter, token rate limit, request rate limit) configured as a portal card and evaluated before the backend is called. |
The AI Gateway tier has a standalone web portal. It is not a blade inside the Azure portal, and browsing to portal.azure.com will not find it.
https://ai.gateway.azure.com.There are three different names in play, and only two of them can be changed later. Deciding all three before you create anything is the single most useful piece of preparation for this product.
On first use, select Create gateway and complete the form:
The name you type becomes the hostname, and the runtime endpoint takes this shape:
https://<gateway>.azure-api.net/default/models/openai/v1
Because that hostname is public DNS, the name must be globally unique and is restricted to characters that are legal in a hostname — lowercase letters, digits, and hyphens. The portal validates the value as you type it.
Applying your naming standard. Encode owner, workload, environment, and region in the name, and keep it short enough to stay readable in a URL. A convention that works well:
<org>-aigw-<workload>-<env>-<region> akm-aigw-core-dev-eus2 akm-aigw-core-prd-eus2
Avoid embedding a model or vendor name in the gateway name. One gateway is expected to front many providers, so a name like akm-aigw-openai-prd ages badly the moment a second vendor is added.
The gateway routes on an exact match of the model value in the request body, so model names are a public contract with every client application. Two rules follow:
gpt-4o cannot both be imported as-is.When you import from Foundry, the deployment name in Foundry becomes the model name in the gateway. If your standard requires names such as akm-gpt-4o-chat, rename the deployments in Foundry before you import, rather than trying to correct them afterwards. Deployment names that collide with a model already in the gateway are skipped during import and reported as warnings — the import as a whole still succeeds, which makes the warnings easy to miss.
The provider display name is presentation only and is safe to set to whatever reads best for your teams; the provider name is the identifier. Neither appears in the request body.
Foundry models are imported by discovery: the gateway scans the subscriptions you nominate, finds Foundry and Azure OpenAI accounts, and registers their deployments. You do not enter endpoints or keys by hand.
/settings/start), then select Import Foundry models. The same action is available later from the models page as Import from Foundry.The import creates one model provider per Foundry account and registers each of that account’s deployments as a model. The models are callable immediately — there is no publish or deploy step.
| Method | How it works | When to use it |
|---|---|---|
| Key-based | The gateway reads the Foundry account key and stores it, then sends it to the backend in the api-key header. This is the default. |
Quick pilots, or accounts where Entra-only authentication is not yet possible. Requires local authentication to be enabled on the account. |
| Managed identity | The gateway authenticates to Foundry with its own system-assigned or user-assigned identity. The wizard can enable the system-assigned identity and assign the Foundry User role for you. | Recommended for production. No provider secret is ever stored, and access is revoked by removing a role assignment. |
The Foundry User role ID is 53ca6127-db72-4b80-b1b0-d745d6d5456d. If you prefer to assign it yourself rather than let the wizard do it:
RG="/subscriptions/<sub-id>/resourceGroups/<rg>" ACC="$RG/providers/Microsoft.CognitiveServices/accounts/<foundry-account>" az role assignment create \ --assignee-object-id "<gateway-principal-id>" \ --assignee-principal-type ServicePrincipal \ --role "53ca6127-db72-4b80-b1b0-d745d6d5456d" \ --scope "$ACC"
az role definition list --name "Foundry User" and substitute the value it returns. Role assignments also take a few minutes to propagate — an import or a call that fails with 403 immediately after the assignment is usually just early, so retry before investigating.Each model is registered against one or more supported endpoints. The endpoint type determines the request and response schema the caller must use and the path the caller posts to. All paths hang off the gateway’s models base:
| API type | Request path | Typical use |
|---|---|---|
| OpenAI Chat Completions | .../models/openai/v1/chat/completions |
The default for Foundry, Azure OpenAI, OpenAI, and any OpenAI-compatible vendor. |
| OpenAI Responses | .../models/openai/v1/responses |
The newer OpenAI stateful surface, for reasoning models and tool-using agents. |
| Anthropic Messages | .../models/anthropic/v1/messages |
Claude models called in Anthropic’s native Messages schema, passed through. |
| Other | Provider-specific passthrough | Vendors whose schema is neither OpenAI nor Anthropic. The gateway governs and forwards without translating. |
Providers that can be published this way include Microsoft Foundry, Azure OpenAI, OpenAI, Anthropic, AWS Bedrock, Google Vertex and Gemini, and self-hosted or custom OpenAI-compatible endpoints.
model field of the request body and forwards to whichever provider owns that name. A caller never names the provider, and switching a model from one vendor to another needs no client change — only that the name stays the same.
{
"model": "akm-gpt-4o-chat",
"messages": [
{ "role": "user", "content": "Summarize the incident report." }
]
}
Any provider that is not discovered automatically is added through Add a custom model. The flow is identical for every vendor; only the field values differ.
| Field | Value |
|---|---|
| Base endpoint URL | https://api.openai.com/v1 |
| Authentication header name | Authorization |
| API key | Bearer sk-... |
| Supported endpoints | OpenAI chat completions, OpenAI responses |
| Field | Value |
|---|---|
| Base endpoint URL | https://api.anthropic.com |
| Authentication header name | x-api-key |
| API key | Your Anthropic API key |
| Supported endpoints | Anthropic messages |
anthropic-version header on every request. The gateway does not add it, so the calling application must send it — see the curl example under Validating with curl.| Field | Value |
|---|---|
| Base endpoint URL | https://generativelanguage.googleapis.com/v1beta/openai |
| Authentication header name | Authorization |
| API key | Bearer <Google AI Studio key> |
| Supported endpoints | OpenAI chat completions |
Google publishes an OpenAI-compatible surface for Gemini, which is why this registers as an OpenAI chat completions model rather than as passthrough. The key comes from Google AI Studio and is a long-lived string, so it fits the static-header model cleanly.
Vertex AI is the enterprise surface for the same models, addressed per region:
https://<region>-aiplatform.googleapis.com
Authorization header will therefore start returning 401 shortly after it is configured. Unless you have a process that rotates the stored value on a schedule, prefer the Gemini OpenAI-compatible endpoint under Google Gemini for gateway-published models, and keep Vertex for workloads that call Google directly.| Field | Value |
|---|---|
| Base endpoint URL | https://bedrock-runtime.<region>.amazonaws.com |
| Authentication header name | Authorization |
| API key | Bearer <Bedrock API key> |
| Supported endpoints | Other (provider-specific passthrough) |
Bedrock’s native authentication is AWS Signature Version 4, which signs each request with a hash of its body and a timestamp. That cannot be expressed as a static header. Amazon Bedrock API keys solve this: they are bearer tokens accepted in the Authorization header in place of SigV4. AWS positions long-term keys for exploration only, and short-term keys — valid for up to 12 hours, or the console session duration if that is shorter — as the production choice, so a rotation process is required either way.
If neither option is acceptable, the alternative is to front Bedrock with a component that can perform SigV4 signing — a classic Azure API Management instance with a signing policy, or a small proxy of your own — and register that component’s endpoint as the custom model instead.
Anything that speaks the OpenAI schema — a self-hosted inference server, a Hugging Face Text Generation Inference endpoint, another vendor’s compatibility layer — is registered the same way: its base URL, its header name, its key, and the OpenAI chat completions endpoint type. If the endpoint is reachable only from a private network, configure outbound virtual network integration on the gateway’s Networking page first, and make sure the backend hostname resolves to its private address.
Every runtime call passes through four stages inside the gateway. Knowing the order is what makes the status codes under Troubleshooting diagnosable, because each stage fails differently.
| Stage | What happens | What it means when it fails |
|---|---|---|
| 1 | Authenticate | The gateway validates the runtime access key in the api-key header. A missing or unknown key is rejected here, before any policy or backend is touched. |
| 2 | Resolve the model | The model value in the request body is matched exactly against the registered models. No match means no backend can be selected. |
| 3 | Evaluate policies | Content safety, IP filter, token rate limit, and request rate limit all evaluate before the backend is called. If any one blocks, the request stops and the backend is never charged. |
| 4 | Forward and record | The gateway calls the provider using the stored backend credential — key, OAuth, or managed identity — returns the response, and emits OpenTelemetry logs, latency, and token counts. |
Two consequences are worth stating plainly. First, applications never hold a provider credential — they hold a gateway key, and the gateway holds the provider secrets, so rotating an OpenAI or Anthropic key is an administrative change with no client deployment. Second, because policy runs at stage 3, a blocked request costs nothing at the provider and appears in gateway telemetry but not in the provider’s billing.
Policies are configured as portal cards rather than XML documents. Add one under Policies › Add policy, choose the policy type, select the models it applies to, and complete the configuration step.
| Policy | Blocks with | Controls |
|---|---|---|
| Content safety | 400 | Azure AI Content Safety checks on prompts and inputs; severity thresholds for hate, sexual, violence, and self-harm; Prompt Shields; blocklists. |
| IP filter | 403 | Allow and deny lists of IPv4/IPv6 CIDR ranges, to keep runtime calls inside approved networks. |
| Token rate limit | 429 | Prompt plus completion token throughput per caller identity or caller IP, over a minute, hour, or day. Models only. |
| Request rate limit | 429 | Call volume per caller identity or caller IP over a 30-second, 1, 2, or 5-minute window. |
Token rate limits also return remaining-tokens and consumed-tokens response headers, plus remaining-quota-tokens where the limit period is an hour or longer. Well-behaved clients can use them to self-throttle before they are rejected.
Applications authenticate to the gateway with a runtime access key, passed in the api-key header:
api-key: <runtime-access-key>
Create keys in the portal under Keys › Create API key. In preview a key is gateway-scoped: it reaches every published model and tool, and per-asset scoping is not yet available. Issue one key per application per environment so that a compromised key can be rotated without a coordinated outage.
| Header | Result |
|---|---|
api-key |
Correct. This is the header the AI Gateway tier reads. |
Ocp-Apim-Subscription-Key |
Rejected. This is the classic API Management subscription header and has no meaning here. |
Authorization: Bearer <key> |
Rejected. The OpenAI and Anthropic SDKs send their credential this way by default, so an SDK pointed at the gateway without explicit header configuration will fail until it is overridden. |
subscription-key |
Rejected. There is no query-string equivalent for the runtime access key. |
The other headers a call may need are the ordinary ones: Content-Type: application/json on every request, anthropic-version on Anthropic Messages calls, and optionally x-correlation-id to tie a gateway log entry back to an application trace. Never put personal data, secrets, or prompt content in the correlation ID.
api-key header carries the gateway’s key. The Foundry, OpenAI, or Anthropic key stays inside the gateway’s provider configuration and must never be sent by a client.Test the gateway on its own before wiring an application to it. Replace <gateway> with your gateway name and <runtime-access-key> with a key from the Keys page.
curl -X POST "https://<gateway>.azure-api.net/default/models/openai/v1/chat/completions" \
-H "api-key: <runtime-access-key>" \
-H "Content-Type: application/json" \
-d '{"model":"akm-gpt-4o-chat","messages":[{"role":"user","content":"hi"}]}'
curl -X POST "https://<gateway>.azure-api.net/default/models/openai/v1/responses" \
-H "api-key: <runtime-access-key>" \
-H "Content-Type: application/json" \
-d '{"model":"akm-gpt-4o-chat","input":"hi"}'
curl -X POST "https://<gateway>.azure-api.net/default/models/anthropic/v1/messages" \
-H "api-key: <runtime-access-key>" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"akm-claude-sonnet","max_tokens":256,"messages":[{"role":"user","content":"hi"}]}'
cmd.exe; using them corrupts the JSON body and produces a 400 or a provider-side error that looks unrelated to quoting. Wrap the body in double quotes and escape the inner ones, or put the body in a file and reference it with -d @body.json.
curl -X POST "https://<gateway>.azure-api.net/default/models/openai/v1/chat/completions" ^
-H "api-key: <runtime-access-key>" ^
-H "Content-Type: application/json" ^
-d "{\"model\":\"akm-gpt-4o-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}"
The symptoms below are ordered roughly by how often teams meet them. The status code identifies which stage of How it works rejected the call.
| Symptom | Root cause | Fix |
|---|---|---|
| 401 on every call | The runtime access key is not in the header the gateway reads — commonly sent as Authorization: Bearer by an SDK’s default behaviour, or as Ocp-Apim-Subscription-Key by habit. |
Send the key in the api-key header. If you are using the OpenAI or Anthropic SDK, override its default auth header explicitly rather than relying on the client constructor’s key argument. |
| 401 only after an import change | A Foundry provider was imported with managed identity, but the account does not accept Entra ID authentication — or a stored third-party key has expired, which is the normal end state for a Google Vertex OAuth token. | Confirm the backend accepts the chosen method. For Vertex, refresh the stored token or move to the Gemini OpenAI-compatible endpoint. |
| 403 | Either an IP filter policy rejected the caller’s address, or the gateway’s managed identity lacks the Foundry User role at the backend scope. | Check the IP filter policy’s allow list against the caller’s egress address. Otherwise verify the role assignment and allow several minutes for propagation. |
| 404 or model not found | The model value does not exactly match a registered model name, or the request was posted to the path of a different API type. |
Compare the model string character for character against the models list — matching is exact. Confirm the path matches the model’s registered endpoint type. |
| 400 with a content-safety message | The content safety policy blocked the prompt at a configured severity threshold, or a blocklist term matched. | Review the thresholds and blocklists on the policy card. Test the same prompt against the provider directly to confirm the gateway is the source of the block. |
| 400 from the provider | The payload is valid JSON but contains a parameter the model rejects, or the body was corrupted by shell quoting. | Send the same body directly to the provider. On Windows, re-test with -d @body.json to eliminate cmd.exe quoting. |
| 429 with Retry-After | A token rate limit or request rate limit was exceeded. | Honour Retry-After. Use the remaining-tokens and remaining-quota-tokens response headers to self-throttle, and raise the limit on the policy card if the ceiling is genuinely too low. |
| Import finds fewer accounts than expected | The signed-in account lacks Reader on some subscriptions, so those resources are invisible to discovery. | Grant Reader on the missing subscriptions and select Refresh to re-run discovery. |
| Import succeeds but a deployment is missing | Its name collided with a model already registered in the gateway and was skipped with a warning. | Rename the deployment in Foundry to a unique value and re-import, or remove the conflicting model first. |
| Foundry validation fails during import | Key-based import was chosen but local authentication is disabled on the account, or managed identity was chosen without the Foundry User role. | Enable local authentication, or assign the Foundry User role to the gateway identity. |
| Every import action refuses to start | No gateway is selected in the portal session. | Select the gateway on the home page, then retry. |
| Timeouts to a private backend | Outbound virtual network integration is configured but the backend hostname does not resolve to its private address, or a subnet or NSG rule is missing. | Check the private DNS zone links, and confirm the delegated subnet (/27 minimum, /24 recommended) allows outbound TCP 443 to the Storage and AzureKeyVault service tags. |
x-correlation-id and look the call up in monitoring. With Application Insights connected, the gateway records request volume, latency, errors, and token counts per model.gen_ai.request.model, gen_ai.response.model, gen_ai.operation.name, and gen_ai.token.type.