A unified, runnable walkthrough that takes a non-Microsoft agent (LangGraph, Claude, plain Python) from an app-only token to a verified entry in the Agent 365 registry — with the real tenant limits and the license gate the docs bury.
How do you register an agent in Entra Agent ID via the Graph API?
To register an agent in Entra Agent ID via the Graph API, you acquire an app-only token with the AgentInstance.ReadWrite.All application permission, POST a JSON body to https://graph.microsoft.com/beta/agentRegistry/agentInstances that contains both the operational agent instance and a nested agentCardManifest, and then GET /agentRegistry/agentInstances/{id} to confirm a 200 response. That single POST is the whole trick most tutorials miss — the operational record (inventory) and the discovery card (collaboration) are created together, not in two separate fragile calls.
This guide exists because the official path to register agent Entra Agent ID Graph API resources is scattered across three product silos: Microsoft Entra Agent ID (identity), the Agent Registry (discovery), and Microsoft Agent 365 (the control plane). The first page of search results is Microsoft’s own fragmented docs plus a couple of thin hobby posts. None of them walk a non-Microsoft agent — a LangGraph graph, a Claude-backed service, a plain Python worker — end to end. We do, with runnable curl and Python.
Two things to internalize before you start. First, this is the self-serve path: agents built on Microsoft platforms (Copilot Studio, Foundry Agent Service) get registered automatically; agents on non-Microsoft platforms must register themselves through Graph. Second, the beta agentRegistry surface is converging. As of the May 2026 announcement on every relevant reference page, these beta endpoints are being replaced by the Agent Registry APIs powered by Microsoft Agent 365. They still work today, and we cover them in full, but we also show the durable path so your integration does not rot.
Internal reading that pairs with this: our primers on Non-Human Identity Governance, OAuth for AI Agents, SPIFFE/SPIRE for AI Agents, What Is an AI Agent Registry, and FIDO Agentic Authentication give you the conceptual scaffolding behind every step below.

Prerequisites: the licensing gate the docs bury
Before any code runs, your tenant needs a Microsoft 365 Copilot license with Frontier enabled, verified under Copilot > Settings in the Microsoft 365 admin center; without it, agent instance creation silently fails downstream even when your token and payload are perfect. This is the single most common cause of a confusing ‘the call succeeded but my agent never appears’ report, and it is mentioned only in passing on the setup pages.
Here is the full preflight checklist for the self-serve, app-only flow. None of it is optional, and skipping the license check is the classic time-sink.
You also need an agent identity blueprint to exist before you register an instance — the blueprint is the template (the agent *type*) that agent identities inherit permissions from. You create it either programmatically (POST to /v1.0/applications/ with @odata.type of Microsoft.Graph.AgentIdentityBlueprint) or, far more reliably, by running the Agent 365 CLI command a365 setup all, which creates the Azure resources, the blueprint, its principal, and the inheritable permissions in one shot.
If agent registration calls return 2xx but nothing shows up in the Microsoft 365 admin center registry, check the license first. A Microsoft 365 Copilot license with Frontier enabled is the prerequisite that makes the Agent 365 registry accept your blueprint and instances. Verify it under Copilot > Settings before debugging your code.
| Requirement | What it is | Where to verify |
|---|---|---|
| Microsoft 365 Copilot + Frontier | License gate that activates Agent 365 registration | Microsoft 365 admin center > Copilot > Settings |
| Entra role | Agent Registry Administrator (least-privileged for instance create); Agent ID Developer for blueprint create | Microsoft Entra admin center > your profile > Assigned roles |
| App registration | A confidential client app with a secret or certificate for the client_credentials flow | Entra admin center > App registrations |
| Graph application permission | AgentInstance.ReadWrite.All (admin-consented) | App registration > API permissions |
| Agent identity blueprint | The template the agent instance attaches to (agentIdentityBlueprintId) | Entra admin center > Agents > Agent blueprints |
Step 1: Get an app-only token (client_credentials)
Acquire an app-only access token by POSTing your client ID, client secret, the scope https://graph.microsoft.com/.default, and grant_type=client_credentials to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token; the returned bearer token carries the AgentInstance.ReadWrite.All application permission you consented to. This is the standard OAuth 2.0 client credentials grant — no user is in the loop, which is exactly right for an autonomous agent registering itself.
The .default scope is important: it tells Microsoft Entra to issue a token containing every application permission that has been admin-consented for this app, rather than asking you to enumerate scopes. Make sure AgentInstance.ReadWrite.All shows a green ‘Granted for [tenant]’ in the app registration’s API permissions blade first.
Here is the raw call with curl, so you can confirm the token works before touching any SDK.
# Step 1 — app-only token via the client_credentials grant
TENANT_ID="00000000-0000-0000-0000-000000000000"
CLIENT_ID="11111111-1111-1111-1111-111111111111"
CLIENT_SECRET="your-client-secret"
TOKEN=$(curl -s -X POST \
"https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=${CLIENT_ID}" \
-d "client_secret=${CLIENT_SECRET}" \
-d "scope=https://graph.microsoft.com/.default" \
-d "grant_type=client_credentials" \
| python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
# Quick sanity check: this should print a JWT, not an error
echo "${TOKEN}" | cut -c1-32
Step 2: POST the agentInstance with a nested agent card
Create the agent instance and its agent card in one call by POSTing to https://graph.microsoft.com/beta/agentRegistry/agentInstances with a JSON body that supplies the required ownerIds and displayName, ties the instance to your blueprint via agentIdentityBlueprintId, and embeds an agentCardManifest object for discovery. The agent instance is the operational/inventory record; the agent card manifest is the discovery/collaboration metadata other agents read to call yours. The beta API lets you post both at once.
Required fields are minimal: ownerIds (a string collection — these are the human or service-principal IDs accountable for the agent) and displayName. Everything else is optional but you want most of it: originatingStore labels where the agent came from (use your platform name, e.g. ‘LangGraph’ or ‘Cyntr’), sourceAgentId is your own internal ID, url and preferredTransport describe the A2A endpoint, and additionalInterfaces lists alternate transports (JSONRPC, GRPC, HTTP+JSON).
The nested agentCardManifest follows the A2A agent-card shape: description, provider, protocolVersion, version, capabilities (streaming, pushNotifications, stateTransitionHistory), defaultInputModes/defaultOutputModes, and a skills array. A successful call returns 201 Created with the full agentInstance object, including the server-assigned id you will use to verify.
Below is a complete, idiomatic Python registration for a non-Microsoft agent. Note the single POST that carries both the instance and the card.
import requests
GRAPH = "https://graph.microsoft.com/beta"
TOKEN = "<paste the access_token from Step 1>"
BLUEPRINT_ID = "d0108c41-d2d2-4e78-b073-92f57b752bd0" # your agentIdentityBlueprintId
OWNER_ID = "daf58b0e-44e1-433c-b6b0-ca70cae320b8" # human/SP accountable for the agent
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json",
}
# One POST creates the operational instance AND the discovery agent card.
body = {
"displayName": "Support Triage Agent", # required
"ownerIds": [OWNER_ID], # required (string collection)
"originatingStore": "LangGraph", # your platform name
"sourceAgentId": "support-triage-001", # your internal id
"agentIdentityBlueprintId": BLUEPRINT_ID,
"url": "https://agents.example.com/a2a/v1",
"preferredTransport": "JSONRPC",
"additionalInterfaces": [
{"url": "https://agents.example.com/a2a/v1", "transport": "JSONRPC"},
{"url": "https://agents.example.com/a2a/json", "transport": "HTTP+JSON"},
],
# Nested agent card manifest = discovery / collaboration metadata
"agentCardManifest": {
"ownerIds": [OWNER_ID],
"originatingStore": "LangGraph",
"displayName": "Support Triage Agent Card",
"description": "Triages inbound support tickets and routes them.",
"iconUrl": "https://agents.example.com/icon.png",
"provider": {"organization": "Example Inc", "url": "https://example.com"},
"protocolVersion": "1.0",
"version": "1.0.0",
"documentationUrl": "https://agents.example.com/docs",
"capabilities": {
"streaming": False,
"pushNotifications": False,
"stateTransitionHistory": True,
},
"defaultInputModes": ["application/json"],
"defaultOutputModes": ["application/json", "text/html"],
"skills": [
{
"id": "ticket-triage",
"displayName": "Ticket Triage",
"description": "Classify and route a support ticket.",
"tags": ["support", "routing"],
"examples": ["Triage this ticket", "Route to billing"],
"inputModes": ["application/json", "text/plain"],
"outputModes": ["application/json"],
}
],
},
}
resp = requests.post(f"{GRAPH}/agentRegistry/agentInstances", headers=headers, json=body)
resp.raise_for_status() # expect 201 Created
instance = resp.json()
print("Registered agentInstance id:", instance["id"])
Step 3: GET to verify the agent instance
Confirm the registration succeeded by sending a GET to https://graph.microsoft.com/beta/agentRegistry/agentInstances/{agentInstanceId} with your bearer token; a 200 OK with the agentInstance object — including displayName, ownerIds, agentIdentityBlueprintId, url, and preferredTransport — means the agent is in the registry. The reading permission is the lower-privileged AgentInstance.Read.All, so you can use a read-only token here if you separate concerns.
Use the id returned from the 201 in Step 2. If you only have the operational details, you can also list instances and filter, but a direct GET by ID is the cleanest verification. Below are both the curl one-liner and the Python check.
Once you see the 200, the agent will also surface in the Microsoft 365 admin center under Agents > All Agents > Registry, where administrators can govern it (apply Conditional Access, run access reviews, and see risk signals from Entra, Defender, and Purview).
# Step 3 — verify via GET (curl)
INSTANCE_ID="Support Triage Agent: support-triage-001" # url-encode if it has spaces
curl -s -X GET \
"https://graph.microsoft.com/beta/agentRegistry/agentInstances/${INSTANCE_ID}" \
-H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool
# --- or in Python ---
# r = requests.get(f"{GRAPH}/agentRegistry/agentInstances/{instance['id']}", headers=headers)
# r.raise_for_status() # 200 OK
# print(r.json()["displayName"], "->", r.json()["agentIdentityBlueprintId"])
Troubleshooting: 401, 403, 404, and the silent no-show
401 Unauthorized — your token is missing or expired. Re-run Step 1 and confirm the .default scope returned a token (decode the JWT and check the ‘roles’ claim contains AgentInstance.ReadWrite.All). 403 Forbidden — the application permission was added but not admin-consented, or the signed-in principal lacks the Agent Registry Administrator role for delegated calls. Grant admin consent in the app registration’s API permissions blade. 404 on the GET — the {agentInstanceId} is wrong or not URL-encoded; instance IDs can contain spaces and colons, so encode them. The ‘silent no-show’ (2xx but the agent never appears in the M365 admin center) is almost always the license gate: confirm Microsoft 365 Copilot with Frontier is enabled under Copilot > Settings. Finally, if the blueprint was created before the platform required managerApplications, the registry will reject it — recreate it with a365 setup all or patch managerApplications via Graph.What are the Entra Agent ID blueprint limits per tenant?
App-only (non-Microsoft platform) registration is capped at 250 active agent identity blueprints per tenant, and each blueprint is limited to 250 active agent identities — a hard ceiling of design significance, not a soft quota you can ignore. If you architect one agent identity per end user, you will exhaust a blueprint at 250 users and the tenant at 250 blueprints. Model blueprints as agent *types* (the ‘Support Triage’ template) and identities as deployed instances of that type.
These numbers are the single most consequential planning input the fragmented docs bury. The blueprint is the reusable template that defines the identity type and the permissions agent identities inherit; the agent identity is the actual principal that authenticates. The ratio matters: 250 blueprints × 250 identities is your theoretical envelope, but you should keep blueprints few and well-governed.
The pros and cons below summarize the design trade-off between the raw Graph beta path and the durable, SDK/CLI-driven path, given the convergence underway.
Pros
Cons
250 active blueprints per tenant. 250 active agent identities per blueprint. Treat blueprints as agent types, not per-user instances, or you will hit the ceiling. These limits apply to the self-serve, app-only registration path for non-Microsoft agents.
The May 2026 convergence: which path should you build on?
Starting May 2026, the beta Agent Registry APIs in Microsoft Graph are being replaced by the Agent Registry APIs powered by Microsoft Agent 365; the beta endpoints still function today, but for any new non-Microsoft agent you should drive registration through the Microsoft 365 Agents SDK or the Agent 365 CLI rather than hand-coding against /beta/agentRegistry. Microsoft’s own reference pages now carry this notice on every relevant endpoint, and the agentRegistry resource is flagged as deprecated in the Graph beta overview.
The convergence does not remove capability — agent registration APIs remain supported, agent identity stays in Microsoft Entra Agent ID, and identity governance and security controls are unchanged. What changes is *where* registration lives: Agent 365 becomes the unified registry and control plane, while Entra remains the identity foundation. Practically, that means the most durable way to register a non-Microsoft agent is the CLI.
If you have an existing identity-issuance workflow you cannot change yet, the supported pattern is: create the agent identity blueprint via the Graph API, then immediately follow with a call to the Agent Registry API to post the corresponding agent card, and handle the two calls in a retry-safe way. But if you have any flexibility, the CLI collapses all of it into one command.
Here is the recommended durable path with the Agent 365 CLI, including the retry-only-registration flag that saves you when a transient failure hits the registration step.
# Durable path — let the Agent 365 CLI create the blueprint,
# permissions, identity, and registry entry in one command.
# 0. (optional) validate prerequisites, incl. the license/role checks
a365 setup requirements
# 1. Full setup, config-free, for a non-Microsoft agent
# Creates: Entra blueprint + principal, permissions, agent identity,
# and registers the agent card in the Agent 365 registry.
a365 setup all --agent-name "SupportTriageAgent"
# 2. If only the registration step failed (transient error),
# retry it without repeating the blueprint/permissions work:
a365 setup all --agent-registration-only
“The operational record and the discovery card are created in a single POST — that one detail, buried in the beta reference, is what every other walkthrough gets wrong.”
Alatirok analysis of the Microsoft Graph beta agentRegistry reference
Putting it together: a self-serve registration checklist
Use the beta endpoints to learn it, ship on the SDK/CLI to keep it
To register agent Entra Agent ID Graph API resources end to end: confirm the Copilot+Frontier license, create or reuse an agent identity blueprint, get an app-only token, POST the agentInstance with a nested agentCardManifest, and GET to verify a 200 — staying inside the 250/250 limits and planning for the Agent 365 convergence. That is the entire loop, and it works today for a LangGraph, Claude, or plain-Python agent that has never touched Copilot Studio.
The strategic call is which path to build on. For a one-off integration or a workflow you cannot rewrite, the raw beta endpoints in Steps 1–3 are fully runnable and give you total control. For anything you intend to maintain past 2026, wrap registration in the Microsoft 365 Agents SDK or the a365 CLI so the convergence does not break you. Either way, governance is the point: a registered agent inherits Conditional Access, access reviews, and risk detection — the same machinery that governs human and workload identities.
If you found this useful, the natural next reads on Alatirok are Non-Human Identity Governance (why agents need first-class identities at all), OAuth for AI Agents (the token mechanics underneath Step 1), SPIFFE/SPIRE for AI Agents (the open-standard alternative to Entra-native identity), What Is an AI Agent Registry (the concept this whole flow implements), and FIDO Agentic Authentication (where agent auth is heading).
Builder’s take
I build agents at Cyntr and Loomfeed that mostly live outside Microsoft’s stack — Go and Python services, not Copilot Studio declaratives. When I went to register one into a customer’s Entra tenant, the docs were split across three product silos and two of them contradicted each other on the convergence timeline. Here is what actually mattered:
- The single most useful fact buried in the reference: you do not need two API calls. The POST to /agentRegistry/agentInstances accepts a nested agentCardManifest, so the operational record and the discovery card are created together. Most blog walkthroughs miss this and do it as two fragile calls.
- Treat the May 2026 convergence as a real fork in the road. If you are starting fresh, drive registration through the Microsoft 365 Agents SDK or ‘a365 setup all’ — not the raw beta endpoints — because the beta agentRegistry surface is explicitly being superseded by the Agent 365-powered APIs.
- The 250-blueprints-per-tenant and 250-identities-per-blueprint ceilings are not soft. If you spin one agent identity per end user (a pattern I almost shipped), you will hit the wall fast. Model blueprints as agent *types*, not agent *instances*.
- The license gate is the thing that silently breaks self-serve: no Microsoft 365 Copilot license with Frontier enabled and your agent instance creation just fails downstream. Verify it under Copilot > Settings before you write a line of code.
- Use a federated managed identity for the blueprint credential in production. Client secrets are fine for a laptop demo; they are a liability for an autonomous, long-lived non-human identity.
Frequently asked questions
Non-Microsoft agents (LangGraph, Claude, plain Python) use the self-serve Graph path: get an app-only token with AgentInstance.ReadWrite.All, POST to https://graph.microsoft.com/beta/agentRegistry/agentInstances with the required ownerIds and displayName plus a nested agentCardManifest, then GET /agentRegistry/agentInstances/{id} to verify a 200. The agent must attach to an existing agent identity blueprint via agentIdentityBlueprintId. For new builds, Microsoft recommends driving the same flow through the Microsoft 365 Agents SDK or the ‘a365 setup all’ CLI command instead of the raw beta endpoints.
The agent instance is the operational and inventory record used for execution and management — it carries ownerIds, the blueprint link, the endpoint URL, and preferred transport. The agent card manifest is the discovery and collaboration metadata other agents read to call yours — it follows the A2A agent-card shape with description, provider, protocolVersion, capabilities, defaultInputModes/OutputModes, and a skills array. The Graph beta POST lets you create both in a single call by embedding agentCardManifest inside the agentInstance body.
For the app-only flow, your app registration needs the AgentInstance.ReadWrite.All application permission with admin consent; reads can use the lower-privileged AgentInstance.Read.All. For delegated calls, the signed-in user must hold the Agent Registry Administrator role (the least-privileged role supported for the instance create operation). Creating the agent identity blueprint itself requires the Agent ID Developer or Agent ID Administrator role, and Global Administrator is needed to grant the OAuth2 permission consents.
App-only registration for non-Microsoft agents is capped at 250 active agent identity blueprints per tenant, and each blueprint is limited to 250 active agent identities. Architect blueprints as agent types (reusable templates) rather than one per end user, or you will exhaust the per-blueprint ceiling quickly. These are hard limits that should shape your identity design, not soft quotas.
Yes — the self-serve Agent 365 registration path requires a Microsoft 365 Copilot license with Frontier enabled, verified under Copilot > Settings in the Microsoft 365 admin center. This license gate is the most common cause of a confusing failure where registration calls return a success code but the agent never appears in the registry. Note that simply viewing the agent inventory in the M365 admin center does not require this license; creating and registering agents does.
They still function, but starting May 2026 the beta Agent Registry APIs in Microsoft Graph are being replaced by the Agent Registry APIs powered by Microsoft Agent 365, and the agentRegistry resource is flagged as deprecated in the Graph beta overview. Agent registration capability, agent identity in Entra, and governance controls all remain supported — what changes is where registration lives. For durable integrations, use the Microsoft 365 Agents SDK or the Agent 365 CLI (‘a365 setup all’) rather than hand-coding against the raw beta endpoints.
Primary sources
- Register Agents to the Agent Registry — Microsoft Learn
- Create agentInstance — Microsoft Graph beta — Microsoft Learn
- Get agentInstance — Microsoft Graph beta — Microsoft Learn
- Microsoft Entra Agent ID APIs in Microsoft Graph (beta overview) — Microsoft Learn
- Create an agent identity blueprint — Microsoft Learn
- Agent Registry convergence with Microsoft Agent 365 — Microsoft Learn
- Setup agent blueprint (Agent 365 CLI) — Microsoft Learn
- Agent 365 CLI setup command reference — Microsoft Learn
Last updated: June 2, 2026. Related: Identity Provenance.