Last updated 2026-05-17
Azure AI Foundry — Anthropic
The azureanthropic provider talks to Claude
models hosted on Azure AI Foundry. The transport layer is
Azure-shaped (deployment-scoped URL or /openai/v1/messages,
api-version query parameter, api-key header
OR an AAD bearer token), but the request body and the SSE event
stream are byte-identical to direct
Anthropic.
Application code that already targets the
anthropic provider runs unchanged here — only the
constructor changes.
Picking the right Anthropic surface:
-
providers/anthropic— directapi.anthropic.com. -
providers/bedrock— Claude via AWS Bedrock (Converse API). -
providers/vertexanthropic— Claude via Google Vertex AI Model Garden. -
providers/azureanthropic(this page) — Claude via Azure AI Foundry.
Import path
import ( "github.com/elloloop/llmrouter" "github.com/elloloop/llmrouter/providers/azureanthropic")Two URL variants
Foundry exposes Claude under two endpoint shapes. Pick by whether you provisioned a Foundry deployment for a specific Claude variant, or you're hitting the resource-scoped messages endpoint that picks the variant from the request body.
- Deployment-scoped (recommended). Opt in by passing
WithDeployment("..."). The constructed URL is:
https://<resource>.services.ai.azure.com/openai/deployments/<deployment>/messages?api-version=<v> - Resource-scoped (
/openai/v1/messages). OmitWithDeployment. The constructed URL is:
https://<resource>.services.ai.azure.com/openai/v1/messages?api-version=<v>
Themodelfield in the request body selects the Claude variant.
Authentication
Auth is XOR: provide exactly one of
llmrouter.WithAPIKey(...) or
azureanthropic.WithAADToken(...). Providing both —
or neither — fails at New() with
ErrInvalidConfig.
- API key. Flows as the Azure-specific
api-keyrequest header (notx-api-key, the direct-Anthropic header — Foundry uses Azure conventions). - AAD bearer. Mint a token from your AAD source
(e.g.
azidentity) and return it from theAADTokenSourcecallback. The source is called once per request, so it's the right place to implement caching and refresh.
The anthropic-version header is never
sent — Foundry manages the API version via the
api-version query parameter. WithAPIVersion
is mandatory.
Construction
p, err := azureanthropic.New( llmrouter.WithAPIKey(os.Getenv("AZURE_FOUNDRY_KEY")), llmrouter.WithBaseURL("https://my-resource.services.ai.azure.com"), azureanthropic.WithDeployment("claude-3-5-sonnet"), azureanthropic.WithAPIVersion("2024-10-21"),)if err != nil { log.Fatal(err)}For AAD-bearer auth instead:
p, err := azureanthropic.New( llmrouter.WithBaseURL("https://my-resource.services.ai.azure.com"), azureanthropic.WithAPIVersion("2024-10-21"), azureanthropic.WithAADToken(func(ctx context.Context) (string, error) { // Implement caching + refresh in your token source. tok, err := myAzureCredential.GetToken(ctx, policy.TokenRequestOptions{ Scopes: []string{"https://cognitiveservices.azure.com/.default"}, }) if err != nil { return "", err } return tok.Token, nil }),)Capabilities
Because the body and SSE event stream are identical to direct Anthropic, every feature of the Anthropic provider works without code changes:
- Typed tool use via
ChatRequest.Toolsand translation totool_use/tool_resultblocks. - Extended thinking deltas for Claude 3.7+ (surfaced via
Choice.Delta.Thinking). - Prompt caching via
Message.CacheControl. - Multipart content (text + image blocks) via
ImageURLContent/ImageBytesContent. - Mid-stream error surfacing on
Stream.Err(). - Structured outputs via forced tool-use (set
ChatRequest.ResponseSchema— see Structured outputs on Anthropic). - Tool-result messages via
llmrouter.ToolResultMessage(toolCallID, content).
Full example
package main
import ( "context" "fmt" "log" "os"
"github.com/elloloop/llmrouter" "github.com/elloloop/llmrouter/providers/azureanthropic")
func main() { p, err := azureanthropic.New( llmrouter.WithAPIKey(os.Getenv("AZURE_FOUNDRY_KEY")), llmrouter.WithBaseURL(os.Getenv("AZURE_FOUNDRY_ENDPOINT")), azureanthropic.WithDeployment("claude-3-5-sonnet"), azureanthropic.WithAPIVersion("2024-10-21"), ) if err != nil { log.Fatal(err) }
stream, err := p.CompletionStream(context.Background(), llmrouter.ChatRequest{ Model: "claude-3-5-sonnet-20241022", MaxTokens: 1024, Messages: []llmrouter.Message{ llmrouter.TextMessage("system", "You are concise."), llmrouter.TextMessage("user", "In one sentence, what is Azure AI Foundry?"), }, }) if err != nil { log.Fatal(err) }
for chunk := range stream.Chunks() { for _, c := range chunk.Choices { fmt.Print(c.Delta.Content) } } if err := stream.Err(); err != nil { log.Fatal(err) } fmt.Println()}Error handling
Non-2xx responses surface as
*llmrouter.ErrUpstream
with Provider == "azureanthropic". Common cases:
401— missing or wrongapi-key/ expired AAD token.404— deployment not found, or wrong API version for this Foundry region.400— Azure content-filter trigger, or malformed body (the body shape must match Anthropic/v1/messages; checkMaxTokens).429— Foundry capacity throttle; honourRetry-After.
Caveats
- Translation code is duplicated. The body and SSE
translation lives in
providers/azureanthropic/translation.goas a byte-identical copy of the logic inproviders/anthropic. This is intentional — Foundry's transport layer is different but the wire protocol is the same, and keeping the translation here removes the cross-package coupling. The source file documents this with a sync target comment; if you find a wire-level fix inproviders/anthropic, mirror it here too. - Pin
api-version. Azure rollsapi-versionforward and old values eventually 404. Pin to a known-good value and bump deliberately. - No
x-api-keyheader. Direct Anthropic usesx-api-key; Foundry usesapi-key. The provider sets the right one — you do not need to do this yourself. - Auth is mutually exclusive. Providing both an
API key and an AAD source — or neither — fails fast in
New().
When to use this vs other Anthropic surfaces
- Use
azureanthropicwhen your organisation has standardised on Azure AI Foundry (single billing surface, Azure AAD for auth, regional data-residency requirements that need Microsoft as the data processor). - Use direct
Anthropic when you want the fastest path to the
latest model variants and you don't need an Azure billing path.
Anthropic ships new Claude variants on
api.anthropic.comfirst; Foundry lags by days to weeks. - Use Bedrock when you're on AWS and want a single IAM-based auth story shared with the rest of your AWS workloads.
- Use vertexanthropic when you're on GCP and want ADC-based auth alongside the rest of your Vertex usage.
See also
- Anthropic provider — direct API; same body and SSE shape.
- Azure OpenAI provider — same transport family for OpenAI's own models.
- Azure Serverless provider — same transport family for non-OpenAI/non-Claude models on Foundry.
- The Router — automatic platform resolution for Claude.