← Back to documentation

Microsoft Foundry and Azure OpenAI API setup

Configure a deployed model, v1 endpoint, identity, streaming and usage checks.

Scope and prerequisites

Start with an authorised Azure subscription, resource and model deployment. This guide uses the OpenAI Python SDK with Microsoft’s v1 chat endpoint; it does not provision resources or assume that every model has identical capabilities. In the portal, record the resource, actual model version, deployment name, deployment type, quota and network access method. The request’s model value is your deployment name, not a name guessed from another provider’s catalogue.

Select a deployment that supports Chat Completions and the example’s max_completion_tokens parameter. Check Responses, tools, images, reasoning parameters and streaming separately. If a deployment does not support Responses, repeatedly changing the URL will not enable it. Azure OpenAI models and non-OpenAI Foundry models can differ in capabilities and permissions; a project management endpoint is not an inference endpoint.

Confirm the endpoint and identity

The v1 base URL uses the resource’s /openai/v1/ route. Microsoft also supports the corresponding services.ai.azure.com resource hostname format. Copy the configuration for your resource, keeping project URLs and older /deployments/... routes separate. The v1 API does not require a dated api-version; older APIs have their own version requirements.

Review deployment type before deciding where processing is allowed. A resource name alone does not establish the boundary for Global, Data Zone or regional deployments. Have an administrator assign inference access at the required resource scope. For Azure OpenAI, check Cognitive Services OpenAI User. For non-OpenAI Foundry models, check the applicable Cognitive Services User requirements. Having the Subscription Owner or Contributor role does not automatically grant inference access.

Install and make a minimal request

python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade openai

Replace these placeholder settings with your own resource and deployment. Have the authorised server environment supply AZURE_OPENAI_API_KEY securely. Do not place a key in browser code, source control or shared terminal records.

export AZURE_OPENAI_BASE_URL='https://YOUR-RESOURCE.openai.azure.com/openai/v1/'
export AZURE_OPENAI_DEPLOYMENT='YOUR-DEPLOYMENT-NAME'

Save the following as azure_chat.py. Run python azure_chat.py with a harmless test sentence only after approving model charges. The output limit of 128 and client timeout of 30 seconds are example controls, not platform quotas or support commitments. Automatic SDK retries are disabled initially so failures remain easier to inspect.

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.environ["AZURE_OPENAI_BASE_URL"],
    api_key=os.environ["AZURE_OPENAI_API_KEY"],
    timeout=30.0,
    max_retries=0,
)
request = {
    "model": os.environ["AZURE_OPENAI_DEPLOYMENT"],
    "messages": [{"role": "user", "content": "Reply with one short greeting."}],
    "max_completion_tokens": 128,
}
answer = client.chat.completions.create(**request)
if not answer.choices:
    raise RuntimeError("No completion choice returned")
print(answer.choices[0].message.content or "")
print(answer.usage.model_dump() if answer.usage else "usage unavailable")

Replace a static key with Entra ID

A server application can use managed identity or another approved Entra credential chain. Install the dependency, then replace the client initialisation above with this version. Complete the role assignment and verify the runtime identity first. Do not print access tokens. The current official v1 examples use the scope https://ai.azure.com/.default.

python -m pip install --upgrade azure-identity
from azure.identity import DefaultAzureCredential, get_bearer_token_provider

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://ai.azure.com/.default"
)
client = OpenAI(
    base_url=os.environ["AZURE_OPENAI_BASE_URL"],
    api_key=token_provider,
    timeout=30.0,
    max_retries=0,
)

Parse a stream and investigate failures

For a deployment supporting streaming chat, replace the non-streaming call with the code below. Check for choices before indexing them and consume text deltas. Capture usage independently if supplied. Some deployments require a supported usage option to return it; missing usage is not evidence of zero charges. Responses uses a different event structure and needs its own parser.

usage = None
with client.chat.completions.create(**request, stream=True) as events:
    for part in events:
        if part.usage is not None:
            usage = part.usage
        if not part.choices:
            continue
        text = part.choices[0].delta.content
        if text:
            print(text, end="", flush=True)
print()
print(usage.model_dump() if usage else "usage unavailable")
  • 401/403: check credential source, resource scope, role and network policy without logging keys or tokens.
  • 404: check hostname, v1 route and deployment name; make sure this is not a management endpoint.
  • 400: check the model’s API, parameters and content constraints. Remove optional parameters to isolate a mismatch.
  • 429: check quota and concurrency, use any returned waiting guidance and bounded backoff. Do not retry timeouts or 5xx indefinitely.

Acceptance, cost and data handling

Retain sanitised request identifiers, model and deployment versions, finish reasons, timings and usage for comparison with Azure billing. Test truncation, refusal and disconnected streams as separate outcomes. Check output, cache, deployment capacity and third-party service charges under the actual billing arrangement rather than importing another channel’s rates.

Review retention, content safety processing and deployment geography under the applicable service terms. Control application logs and access independently. This example has only received offline syntax checks: no subscription was used, no secret was read and no model call was made. Account access, response quality and charges need verification in an authorised environment.

Claude: confirm the native API and purchasing eligibility

Claude uses an independent Messages API. Use AnthropicFoundry with the resource base URL https://YOUR-RESOURCE.services.ai.azure.com/anthropic; its HTTP Messages target is /anthropic/v1/messages. The request's model is the actual deployment name, which can differ from the catalogue model ID. The OpenAI v1 examples above cover deployments that explicitly support that API. A Foundry project management URL, the OpenAI v1 route and Claude's native route serve different purposes; membership in the partner catalogue does not make every model OpenAI-compatible.

Before configuring the client:

  1. Confirm a paid, eligible Azure subscription, supported billing country and permission to purchase the Marketplace offer. Microsoft's current Claude documentation explicitly excludes Cloud Solution Provider (CSP) subscriptions; other subscription restrictions also apply. An Azure account alone does not establish eligibility.
  2. Record the model, hosting version, deployment type and currently supported deployment region from the model card and deployment details. Version 1 runs on Anthropic infrastructure; version 2 is hosted on Azure. Both offer Global Standard; only selected Azure-hosted model versions offer Data Zone Standard (US). Availability must be checked for the precise model/version/type combination, not inferred from a resource's country.
  3. Copy the native endpoint and deployment name. For Entra inference, verify Cognitive Services User at the Foundry resource scope and the actual runtime identity. The Azure OpenAI role and resource-management roles do not replace this check. Confirm network access independently.
  4. Check authentication support, Messages parameters, streaming and quota for the deployment. Some gated models require Entra ID only. Files, Skills, tools and other advanced capabilities differ by hosting/model version; do not copy parameters from a different Claude deployment.

Anthropic-hosted v1 requests may be processed outside Azure and the selected Azure region. For Azure-hosted v2, review the selected Global or Data Zone processing scope separately from data stored at rest. In both configurations, Anthropic is the seller/operator and an independent processor of prompts and outputs. Apply the Claude Marketplace and data-processing terms; Azure OpenAI retention or SLA statements do not automatically cover Claude.

Claude: an independent API key request

For a deployment that accepts API keys, install the packages and configure these placeholders on an authorised server. The secret environment supplies the key; never put it into browser code or a copied example. Save the following Python as a separate Claude example. It has only been checked offline here: no package installation or cloud request was executed. The token limit and timeout are illustrative controls, and automatic SDK retries are disabled.

Both the API key and Entra examples below set base_url explicitly. The SDK still reads ANTHROPIC_FOUNDRY_RESOURCE automatically, so unset that variable before configuring the client. Alternatively, initialise with resource, omit base_url and unset the automatically read ANTHROPIC_FOUNDRY_BASE_URL setting.

python -m pip install --upgrade anthropic azure-identity
# Explicit base_url must not be combined with the SDK resource-name fallback.
unset ANTHROPIC_FOUNDRY_RESOURCE
# Copy both values from your actual Foundry deployment in the console.
export FOUNDRY_CLAUDE_BASE_URL='https://YOUR-RESOURCE.services.ai.azure.com/anthropic'
export FOUNDRY_CLAUDE_DEPLOYMENT='YOUR-CLAUDE-DEPLOYMENT-NAME'
# Supply FOUNDRY_CLAUDE_API_KEY through the approved server secret environment.
import os
from anthropic import AnthropicFoundry

client = AnthropicFoundry(
    base_url=os.environ["FOUNDRY_CLAUDE_BASE_URL"],
    api_key=os.environ["FOUNDRY_CLAUDE_API_KEY"],
    timeout=30.0,
    max_retries=0,
)
message = client.messages.create(
    model=os.environ["FOUNDRY_CLAUDE_DEPLOYMENT"],
    max_tokens=128,
    messages=[{"role": "user", "content": "Reply with one short greeting."}],
)
for block in message.content:
    if block.type == "text":
        print(block.text)
print(message.stop_reason)
print(message.usage.model_dump())

The response contains typed content blocks; print only text blocks and inspect stop_reason and usage before accepting the result. Native HTTP uses x-api-key plus anthropic-version: 2023-06-01; it does not use the OpenAI choices response schema. Do not add thinking or tool parameters until the deployed model's supported combinations are confirmed.

Claude: replace the key with Entra ID

Keep import os, AnthropicFoundry and the Messages request above, replacing only the client initialisation with this block. Use an approved credential chain, preferably the application's managed identity, and verify the resource role first. azure_ad_token_provider obtains tokens for https://ai.azure.com/.default; the native HTTP equivalent is Authorization: Bearer .... Supply one authentication method: remove the explicit API key and any automatically inferred ANTHROPIC_FOUNDRY_API_KEY setting when using this provider. Do not print tokens.

from azure.identity import DefaultAzureCredential, get_bearer_token_provider

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://ai.azure.com/.default"
)
client = AnthropicFoundry(
    base_url=os.environ["FOUNDRY_CLAUDE_BASE_URL"],
    azure_ad_token_provider=token_provider,
    timeout=30.0,
    max_retries=0,
)

Claude: streaming, failures and acceptance

For an eligible deployment, Messages supports SSE with stream=True. Its native flow is message_start, indexed content_block_start / content_block_delta / content_block_stop, then message_delta and message_stop. Text deltas use delta.type == "text_delta"; tools and thinking use different block types. Handle ping, unknown events and errors separately, retain final usage/stop information, and mark a disconnect before completion as incomplete. OpenAI choices[].delta and Responses event parsers cannot parse this protocol. A successful HTTP status does not guarantee that a stream finishes successfully.

For Claude-specific 401/403, inspect the selected authentication path, token scope and resource role; for 404, verify /anthropic and the exact deployment name. A 400 can indicate an unsupported parameter or a model-specific retention requirement, which needs review under the applicable terms. A purchasing or region error requires checking subscription eligibility and model/version availability. For 429, check the subscription/model/version quota and bound retries; creating another resource in a different region may still share the same Global quota pool. Reconcile actual Marketplace Claude Consumption Unit (CCU) meters, input/output and cache usage with billing instead of applying the preceding OpenAI deployment's rates. Test a harmless completion, truncation and a disconnected stream in the authorised environment before accepting the integration.

Official references

Checked on 17 October 2026; recheck the current documentation and portal before use.