Microsoft Foundry from zero: deploy a model, set quota and call it safely
Set up Microsoft Foundry from nothing: create the resource and a project, deploy a model with the right deployment type and quota, give your team the roles that actually let them build, and make the first call with Entra ID instead of a key.
AI & agentsFix a problem9 min read
Microsoft Foundry is where you deploy a model and build agents on Azure today. It's the same platform that was called Azure AI Foundry, and Azure OpenAI before that, under one resource type with projects inside it. The set-up takes about fifteen minutes. What takes longer is getting three things right that the wizard doesn't explain: which deployment type to pick, how quota works, and why someone with the Owner role still can't call the model.
Before you start
- An Azure subscription, and a role that can create the resource: Foundry Account Owner or Foundry Owner on the subscription or resource group. With the Azure CLI, Contributor or Owner on the resource group is enough.
- The Owner role if you'll be giving other people access, because only a role that can assign roles can do that.
- Azure CLI 2.80.0 or later if you prefer the command line; the project commands were added in that version.
- A region check. Not every model or feature is in every region, and the Responses API and agents are in fewer regions than the models. Check before you create the resource; moving later means creating a new one.
Create the resource and a project
A Foundry resource is the Azure resource (type Microsoft.CognitiveServices/accounts, kind AIServices) that holds your model deployments, quota, networking and access control. A project is a folder inside it that organises one team's work and is where developers build.
In the portal: sign in to ai.azure.com with the New Foundry toggle on, select Create a new project, name it, and under Advanced options choose the resource group and location. The portal creates the resource and the project together, and, if you can assign roles, gives you the Foundry User role on it.
With the Azure CLI, after az login:
az group create --name my-foundry-rg --location eastus
az cognitiveservices account create \
--name my-foundry-resource \
--resource-group my-foundry-rg \
--kind AIServices \
--sku S0 \
--location eastus \
--custom-domain my-foundry-resource \
--assign-identity \
--allow-project-management true
az cognitiveservices account project create \
--name my-foundry-resource \
--resource-group my-foundry-rg \
--project-name my-foundry-project \
--location eastus
Three things in that command matter. --assign-identity creates the managed identity that project management needs; without it, creating the project fails. --allow-project-management true can't be changed after the resource exists. The custom domain must be unique across Azure, so a taken name fails with CustomDomainInUse.
Your project endpoint is https://<resource>.services.ai.azure.com/api/projects/<project>. It's on the project's home page, or from az cognitiveservices account project show under properties.endpoints. Developers need it, plus the deployment name.
Deploy a model
In the portal: Build > Models > Deploy > Deploy a base model, pick the model, and choose Deploy > Default settings or customise the deployment type and capacity. With the CLI, list what's available in your region first, because a model, version or type that isn't there fails with DeploymentModelNotSupported:
az cognitiveservices model list --location eastus \
--query "[?model.name=='gpt-5-mini'].{version:model.version,skus:join(',',model.skus[].name)}" \
--output table
az cognitiveservices account deployment create \
--name my-foundry-resource \
--resource-group my-foundry-rg \
--deployment-name gpt-5-mini \
--model-name gpt-5-mini \
--model-version "2025-08-07" \
--model-format OpenAI \
--sku-capacity 10 \
--sku-name GlobalStandard
The deployment name is what your code sends as the model. Keep it the same as the model name unless you have a reason not to.
Which deployment type
| Type | Where requests are processed | Billing | Choose it when |
|---|---|---|---|
| Global Standard | Any Azure region | Per token | Your default: new models arrive here first, it's the cheapest, and it's in the most regions |
| Data Zone Standard | Within the US, EU or Asia Pacific data zone of your resource | Per token | Your rules say processing must stay in that zone |
| Standard | Within your resource's Azure geography | Per token | Processing must stay in the geography; arrives last for new models |
| Provisioned (global, data zone or regional) | As above, on reserved capacity | Reserved throughput | Steady high volume, or latency that must not vary |
| Batch (global or data zone) | Asynchronous jobs | Per token, about half price | Large jobs that aren't time-sensitive |
| Developer | Global, no SLA | Per token | Trying out a fine-tuned model only |
Data at rest stays in your resource's geography whichever type you choose; the types differ in where the request is processed. Microsoft's own advice is to start with Global Standard and move only for data residency, reserved throughput or batch work.
Set the quota
Quota is a per-subscription allowance of tokens per minute (TPM) for each model, region and deployment type. Each deployment takes a slice of it, and that slice is the deployment's rate limit. A requests-per-minute limit comes with it in a fixed ratio that varies by model: for older chat models, one unit of capacity is 1,000 TPM and 6 RPM.
- Manage it under Manage > Quota in the portal, where you can move TPM between deployments and request more. Changes take up to 15 minutes to apply.
- To see quota at all, a person needs the Cognitive Services Usages Reader role at the subscription scope. A role on the resource group or the resource doesn't do it.
- Quota increases go through Microsoft's request form, in order, and priority goes to subscriptions that use what they already have.
- Deleting a resource through the API without deleting its deployments first leaves the quota unavailable for 48 hours unless you purge the resource.
Put the TPM where the traffic is. A common surprise is approved quota at the subscription level while the deployment that actually gets the calls has a small allocation. Our guide to Azure OpenAI 429 errors covers what happens then.
Give your team the right roles
Foundry separates managing the resource from building in it, and the familiar Azure roles only do the first.
| Role | Gives | Give it to |
|---|---|---|
| Foundry User | Build and test in a project, call models and agents, read the resource | Developers, on the project |
| Foundry Agent Consumer | Call agent endpoints only | Apps and service principals that only use agents |
| Foundry Project Manager | Build, manage projects, publish agents, and give others Foundry User | Team leads, on the resource |
| Foundry Account Owner | Create projects and resources, deploy models, assign roles; not build | Managers and platform admins |
| Foundry Owner | All of the above | A small team that does everything |
| Owner or Contributor (Azure) | Create resources and deployments; no data actions | Nobody as their only role |
So a subscription Owner who tries to create an agent gets "no permission", because Owner and Contributor grant management operations only. Give them Foundry User too. The project's managed identity needs Foundry User on the resource as well; the portal does this for you when the creator can assign roles.
The roles were recently renamed from Azure AI User, Azure AI Owner, Azure AI Account Owner and Azure AI Project Manager, and both names still appear. In scripts, use the role IDs instead: Foundry User is 53ca6127-db72-4b80-b1b0-d745d6d5456d. Don't use the roles that start with "Cognitive Services" for Foundry work, except Usages Reader for quota, and not Azure AI Developer either, which is for hubs and machine learning workspaces.
PROJECT_ID=$(az cognitiveservices account project show \
--name my-foundry-resource --resource-group my-foundry-rg \
--project-name my-foundry-project --query id -o tsv)
az role assignment create \
--role "53ca6127-db72-4b80-b1b0-d745d6d5456d" \
--assignee "someone@contoso.com" \
--assignee-principal-type User \
--scope "$PROJECT_ID"
In the portal the same lives under Manage > Project details > Users. Adding a Microsoft Entra security group instead of people saves doing this again later.
Make the first call
Use Microsoft Entra ID rather than an API key. Roles apply only to Entra sign-ins; a key grants full access to the resource with no role check, so it's one secret away from everything. The SDK handles sign-in through DefaultAzureCredential, which uses az login on your machine and a managed identity in Azure.
pip install "azure-ai-projects>=2.3.0" azure-identity
az login
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
project = AIProjectClient(
endpoint="https://<resource>.services.ai.azure.com/api/projects/<project>",
credential=DefaultAzureCredential(),
)
openai = project.get_openai_client()
response = openai.responses.create(
model="gpt-5-mini", # your deployment name
input="What is the size of France in square miles?",
)
print(response.output_text)
This uses the Responses API, which is the current API for models and agents; the openai package talks to Foundry through the project endpoint, and api-version parameters are gone in favour of stable v1 routes. If you call REST directly, the token scope is https://ai.azure.com/.default.
To turn keys off for good, set disableLocalAuth: true on the resource in Bicep or the portal once every caller uses Entra ID.
Things that catch people out
| What you see | Why | Fix |
|---|---|---|
401 with a valid account | Wrong token scope, or no data-plane role | Use the https://ai.azure.com/.default scope; give the caller Foundry User |
404 | Wrong endpoint, deployment name or API version | Compare the deployment name in Build > Models with your model value |
| Owner can't create an agent | Owner is management only | Add Foundry User |
| Quota page is empty | No subscription-scope Usages Reader | Assign Cognitive Services Usages Reader on the subscription |
| Agents or Responses API missing from the portal | The resource's region doesn't support them | Create a resource in a supported region |
| SDK samples fail with odd errors | azure-ai-projects 1.x with the new portal, or 2.x with the classic one | Match the SDK major version to the portal you use |
Sources
- Quickstart: Set up Microsoft Foundry resources, Microsoft Learn
- Quickstart: Get started with Microsoft Foundry SDK, Microsoft Learn
- Deployment types for Microsoft Foundry Models, Microsoft Learn
- Manage Azure OpenAI in Microsoft Foundry Models quota, Microsoft Learn
- Role-based access control for Microsoft Foundry, Microsoft Learn
- Troubleshoot common HTTP errors for Azure OpenAI, Microsoft Learn
- What is Microsoft Foundry?, Microsoft Learn
Did this fix it?
Comments
No comments yet. Share what worked for you.
Sign in to comment. Comments show under a display name you choose, never your email.