Resources, projects, and endpoints
Export PDFEvery permission, quota, network rule, and invoice in Foundry is attached to a specific level of the Azure resource hierarchy. This lesson defines each level, explains what belongs where, shows the difference between the new Foundry projects and the older hub-based projects, and walks through creating a resource and project from the command line so you understand every field.
The Azure hierarchy, level by level
Your organisation's Microsoft Entra ID directory. It holds users, groups, and app identities. One company usually has one tenant.
A billing and access boundary inside a tenant. Costs roll up to it, quotas (such as model TPM) are counted per subscription and region, and Azure Policy is often applied here.
A logical container for resources that share a lifecycle. Put one app's resources in one group so you can grant access and delete them together.
The Azure resource that is Foundry. Technically it is a Cognitive Services account of kind AIServices with project management enabled. It owns model deployments, connections, networking settings, keys, and the custom subdomain used in endpoints.
A child resource of the Foundry resource. It is the workspace where you build: agents, files, datasets, vector stores, evaluations, and traces live here. Projects share the parent's deployments and connections but keep their own data and access control.
Tenant (contoso.onmicrosoft.com)
└── Subscription: "AI-Prod" ← billing, quota per region
└── Resource group: rg-support-bot-prod ← lifecycle + RBAC boundary
├── Foundry resource: contoso-ai ← deployments, connections, network
│ ├── deployment: gpt-5-mini
│ ├── deployment: text-embedding-3-large
│ ├── connection: search-support (Azure AI Search)
│ ├── project: support-bot ← agents, files, evals, traces
│ └── project: sales-assistant
├── Azure AI Search: srch-support-prod
├── Storage account: stsupportprod
└── Application Insights: appi-support-prod
What lives at which level
| Thing | Lives on | Consequence |
|---|---|---|
| Model deployments | Foundry resource | Every project in the resource can call them; quota is shared. |
| Connections (Search, Storage, Bing, MCP) | Resource or project | Resource-level connections are shared; project-level ones are private to that project. |
| Network rules, private endpoints | Foundry resource | Apply to all projects at once. |
| API keys | Foundry resource | A key grants access to every project — another reason to prefer Entra ID. |
| Agents, conversations, files, vector stores | Project | Isolated per project; a teammate in another project cannot see them. |
| Evaluations, datasets, traces | Project | Each app keeps its own quality history. |
| Role assignments | Any level | Inherit downward: a role on the resource group applies to everything inside. |
A practical default is one project per application per environment (for example, support-bot-dev and support-bot-prod), and one Foundry resource per environment. Separate resources give you separate quota, networking, and blast radius; separate projects give you separate data and permissions.
Foundry projects vs hub-based projects
You will meet two project types. Know the difference so you pick the right one and recognise old instructions.
| Foundry project (current default) | Hub-based project (classic) | |
|---|---|---|
| Parent | Foundry resource (AIServices) | Azure AI hub (built on Azure Machine Learning) |
| Endpoint | https://<resource>.services.ai.azure.com/api/projects/<project> | Connection string or ML workspace endpoint |
| Setup | One resource, minutes to create | Hub plus Storage, Key Vault, and often more |
| New Agent Service, new portal | Yes | No (classic only) |
| Prompt flow, managed compute training | Limited | Yes |
| Use it for | All new generative AI apps and agents | Existing workloads that depend on Azure ML features |
Choosing a region
The region of the Foundry resource decides which models and features you can use, where data is stored at rest, and latency for your users.
- Model availability differs by region and deployment type. Check the model card or the region availability table before you create anything.
- Feature availability (some agent tools, evaluation features, hosted agents) also varies. Preview features usually reach a few US and European regions first.
- Data residency: data at rest stays in the resource's region. With Global deployments, inference may run in any Azure region; Data Zone deployments keep processing inside the US or the EU.
- Quota is per subscription, per region, per model. If one region is exhausted, another may have room.
Create a resource and project with the Azure CLI
The portal wizard does the same thing, but the CLI shows every decision explicitly and is repeatable. You need Azure CLI 2.80 or newer and the Contributor or Owner role on the resource group.
# variables — the custom domain must be globally unique
RG=rg-foundry-course
LOC=eastus2
RES=foundry-course-$RANDOM
PROJ=support-bot
# 1. resource group
az group create --name $RG --location $LOC
# 2. Foundry resource
az cognitiveservices account create \
--name $RES \
--resource-group $RG \
--kind AIServices \
--sku S0 \
--location $LOC \
--custom-domain $RES \
--assign-identity \
--allow-project-management true
# 3. project
az cognitiveservices account project create \
--name $RES \
--resource-group $RG \
--project-name $PROJ \
--location $LOC
# 4. verify both
az cognitiveservices account show -n $RES -g $RG --query properties.provisioningState -o tsv
az cognitiveservices account project show -n $RES -g $RG --project-name $PROJ \
--query properties.provisioningState -o tsv
| Flag | What it means |
|---|---|
--kind AIServices | Creates the multi-service account type that Foundry uses. Other kinds (for example OpenAI) create classic single-service accounts. |
--sku S0 | The standard pricing tier. Billing is still per use; the SKU unlocks production limits. |
--custom-domain | The subdomain in your endpoint (<name>.services.ai.azure.com). Required for Entra ID auth; must be globally unique, or you get CustomDomainInUse. |
--assign-identity | Gives the resource a system-assigned managed identity. Project creation fails without it. |
--allow-project-management true | Turns the account into a Foundry resource that can host projects. Cannot be changed after creation. |
Both show commands should print Succeeded. If project creation fails with a managed identity error, the resource was created without --assign-identity.
Endpoints: which URL is which
A Foundry resource exposes several endpoints. Using the wrong one is the most common beginner error.
| Endpoint | Shape | Use it for |
|---|---|---|
| Project endpoint | https://<res>.services.ai.azure.com/api/projects/<proj> | The Foundry SDK (AIProjectClient): agents, evaluations, datasets, connections, tracing. |
| Project OpenAI route | <project endpoint>/openai/v1 | OpenAI-compatible Responses, Conversations, Evals, Files, and Vector Stores scoped to the project. |
| Account OpenAI endpoint | https://<res>.openai.azure.com/openai/v1 | The plain OpenAI SDK for lowest latency and full compatibility, including embeddings and Chat Completions. |
| Anthropic endpoint | https://<res>.services.ai.azure.com/anthropic | Claude models deployed in Foundry, through the Anthropic SDK. |
| Tool endpoints | https://<res>.cognitiveservices.azure.com/... | Speech, Vision, Language, Content Safety, and other Foundry Tools. |
Here is a small offline helper that validates a project endpoint and derives the related URLs — handy as a startup check so a misconfigured environment variable fails fast with a clear message.
from urllib.parse import urlparse
def parse_project_endpoint(endpoint: str) -> dict:
"""Split a Foundry project endpoint into its parts."""
url = urlparse(endpoint)
host = url.hostname or ""
if not host.endswith(".services.ai.azure.com"):
raise ValueError(f"not a Foundry endpoint: {host}")
parts = [p for p in url.path.split("/") if p]
if len(parts) != 3 or parts[:2] != ["api", "projects"]:
raise ValueError("expected /api/projects/<project-name>")
resource = host.split(".")[0]
return {
"resource": resource,
"project": parts[2],
"openai_v1": f"{endpoint.rstrip('/')}/openai/v1",
"account_openai": f"https://{resource}.openai.azure.com/openai/v1",
}
ep = "https://contoso-ai.services.ai.azure.com/api/projects/support-bot"
for key, value in parse_project_endpoint(ep).items():
print(f"{key:<15} {value}")
try:
parse_project_endpoint("https://contoso-ai.openai.azure.com/")
except ValueError as err:
print("error:", err)
Store the project endpoint in an environment variable such as FOUNDRY_PROJECT_ENDPOINT and the deployment name in FOUNDRY_MODEL_DEPLOYMENT. Never hard-code them; dev and prod will differ.
Infrastructure as code
For real projects, describe the resources in Bicep or Terraform instead of clicking or running ad-hoc commands. You get code review, repeatable environments, and drift detection. The Foundry resource is Microsoft.CognitiveServices/accounts with kind: 'AIServices' and allowProjectManagement: true; projects are the child type accounts/projects; deployments are accounts/deployments. Microsoft publishes starter templates in the Foundry samples repositories and the Azure Developer CLI (azd) templates.
- Run the CLI script above, then open the portal and find your new project.
- Copy the project endpoint from the overview page and pass it to
parse_project_endpoint. - Run
az cognitiveservices account list -g $RG -o tableand identify the kind and location columns.
- Tenant → subscription → resource group → Foundry resource → project. Permissions inherit downward.
- Deployments, connections, keys, and networking live on the resource; agents, files, evaluations, and traces live in the project.
- Use Foundry projects for new work; hub-based projects are classic.
- Region decides model availability, feature availability, data residency, and quota.
- The project endpoint is the main entry point; the account OpenAI endpoint is for plain OpenAI SDK usage.
--allow-project-managementand the custom domain are set at creation and matter for everything after.