Deploy your hosted agent directly from source code—without building a container—by calling the Foundry Agent Service REST API.
This article shows you how to deploy a Hosted agent in Foundry Agent Service from Python or .NET source code, without building or pushing a container image. You upload a .zip of your code (and optionally your dependencies), and Agent Service either runs it as-is or builds your dependencies for you in the cloud.If you’re deploying for the first time or want the fastest path, use the Quickstart: Deploy your first hosted agent instead. The quickstart uses the Azure Developer CLI (azd) or the Foundry Toolkit for VS Code, which package your source, upload it, poll for active, and configure role-based access control automatically. Choose Code (or Source Code (ZIP upload)) when the quickstart asks for a deployment method.Use this article when you want to deploy source-code agents directly with the REST API—for custom tooling, language-agnostic automation, or integration with existing CD systems. In this article, you complete the following tasks:
The code_configuration.runtime field in the agent definition accepts the following values. Pick the runtime that matches the binaries in your zip—Linux x86_64 wheels for Python, or the TargetFramework of your dotnet publish output for .NET.
The Agent Service runtime includes the platform-built container image for each value of code_configuration.runtime. To keep your deployed agents fully supported, Foundry aligns hosted agent language support with end-of-life support for each language. Support ends on the community end-of-support date for the language version. Microsoft might retire a code_configuration.runtime value earlier when platform constraints (such as the underlying base image) require it.For upstream end-of-support schedules, see:
After a language end-of-life date, you can still create, update, and run hosted agents that use the retired runtime value. However, those agents aren’t eligible for support, new features, or security patches until you upgrade them to a supported runtime by setting a current code_configuration.runtime value and redeploying.
You need Foundry Project Manager at project scope to deploy a Hosted agent. This role grants the data-plane permissions to create and update agents, plus the ability to assign Foundry User to the platform-created agent identity that your running code uses to call models and tools.Your agent runs as a platform-assigned managed identity that’s separate from your user identity. That identity needs Foundry User to call models from inside the container. If you deploy with azd or the Foundry Toolkit for VS Code, the tooling assigns this role automatically. If you deploy with REST, grant it yourself—see Hosted agent permissions reference.For REST calls, include the preview feature header on mutating requests (Create, Update, Delete) while the feature is in preview:
GET requests work without it today, but include it on every call to be safe—the header gates preview behavior and might be enforced more strictly before GA.
Every source-code deployment follows the same sequence: package → create or update → poll until active → invoke. The source-code path uses code_configuration in the agent definition; the image-based path uses container_configuration instead—the two are mutually exclusive on a single version.For a guided walkthrough using azd or the Foundry Toolkit, see the Quickstart. The rest of this article walks the same lifecycle using the REST API.
Use the REST API for direct HTTP-based deployments or custom tooling. The sections below walk through a first deployment in order: set up variables, build a zip, create the agent, poll until active, and invoke it. Update, version, download, and log-streaming endpoints are grouped under Ongoing operations.
The remaining REST examples use Bash-style curl commands. On Windows, run them in PowerShell with curl.exe, using backticks (`) instead of backslashes for line continuation.
Before you call Create, build a flat zip with two files. This is the minimum payload Agent Service accepts for a Python remote_build deployment.
agent-code.zip├── main.py # your agent loop (starts a Foundry hosting server)└── requirements.txt # dependencies (for example, agent-framework, agent-framework-foundry-hosting)
metadata.json (the agent definition shown in Metadata example) sits next to the zip on disk and is sent as a separate multipart part—it isn’t inside the zip. For full layouts (including bundled mode and .NET), see Package the zip manually. For working source files, see the Python and .NET samples.
The x-ms-code-zip-sha256 header records the SHA-256 of the zip you uploaded. The service stores it and echoes it back on code:download so you can detect drift between what you expected to deploy and what’s deployed. Always include it.The Create call also requires x-ms-agent-name: <agent-name>. Update calls omit it because the name is already part of the URL.
For the Invocations protocol, replace the protocol_versions entry with { "protocol": "invocations", "version": "1.0.0" }. For bundled mode, set "dependency_resolution": "bundled" and follow Build Linux dependencies locally.code_configuration and container_configuration are mutually exclusive in the agent definition: include code_configuration for source-code deploy (this article) or container_configuration for image-based deploy. See Deploy a hosted agent (container) for the image variant.
x-ms-agent-name is required only on the Create call. The name must start and end with alphanumeric characters, can contain hyphens in the middle, and must not exceed 63 characters. The response includes an initial status of creating.
Provisioning failed. Inspect the version’s error object—error.code (for example, ProvisioningError) and error.message summarize the failure. For remote_build, error.message includes the final restore or compile error line (pip for Python, NuGet for .NET), an exit code, and an aka.ms troubleshooting link. (Container log streaming doesn’t apply to provisioning failures—the container never starts. Use error.message for the cause.)
curl -X POST "$ENDPOINT/agents/$AGENT/endpoint/protocols/invocations?api-version=v1" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -H "Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1Preview" \ -d '{"input":"Hello, this is a test invocation!"}'
Useful response headers:
Header
Use
x-agent-session-id
Container session ID. Pass to :logstream. Returned even on 424 / 500.
x-ms-region
Region that handled the call. Useful when filing support tickets.
For the Responses protocol, the per-call response identifier is the id field in the response JSON body (for example, caresp_<random>). Use it to correlate the call with container logs or to reference the call in a support request.
To deploy a code change or a definition update, repost the multipart body to the agent resource. The service uses content-addressable versioning: a new version is minted only when the zip’s SHA-256 or the agent definition actually changes. Identical reposts return the existing latest version.
The response is the full agent envelope with versions.latest populated. Poll the resulting version as shown in Poll for active.If your tooling prefers a version-shaped response (a bare AgentVersionObject instead of the agent envelope), post the same multipart body to $ENDPOINT/agents/$AGENT/versions?api-version=$API_VERSION. The dedup rule is identical—both endpoints share the same content-addressable logic.
Two response headers help you confirm what you downloaded:
Header
Use
x-ms-agent-version
Version number the service served. When you omit agent_version, use this header to learn which version is currently “latest”.
x-ms-code-zip-sha256
SHA-256 the service stored for the uploaded zip. Compare it against your local computation to detect drift between what you expected to deploy and what’s deployed.
Logs are delivered as server-sent events. {sessionId} is the value of x-agent-session-id from the invoke response. Use this endpoint to debug runtime failures and 424 session_not_ready responses. The log-streaming endpoint doesn’t require the Foundry-Features preview header.
If you use azd, skip this section—azd builds the zip for you. Read it if you use the REST API, if you switch to bundled dependency resolution, or if you need full control over the upload contents.The zip must be flat at the root—no top-level wrapper folder.
The entry_point you set in the agent definition still refers to the published assembly name (for example, ["dotnet", "MyAgent.dll"]), produced by the server-side publish.
Acquire a token with --resource https://ai.azure.com.
403 Forbidden
Caller lacks RBAC on the project
Grant Foundry User (or higher) at project scope.
409 conflict on Create (Agent '<name>' already exists)
Agent name already exists
Use Update (POST /agents/{name}), or pick a new name.
400 bad_request (Agent version is still being provisioned) on invoke
A new version is mid-deploy and the active version is being swapped in
Poll the version status until active, then retry.
424 session_not_ready on invoke
Container started but /readiness didn’t return HTTP 200 within the timeout
Stream logs with :logstream, fix the readiness probe or startup error, redeploy.
409 conflict on DELETE agent (Agent has active sessions)
Open sessions block deletion
Wait for sessions to go idle, or append &force=true to cascade-delete sessions.
Version stuck in creating (>10 min, remote build)
Server build failed or couldn’t resolve requirements.txt
Switch to dependency_resolution: bundled and prebuild locally.
Version transitions to failed
Bad zip layout, syntax error, or (remote_build) a restore/compile failure
Read the version’s error object first—error.code classifies the failure and error.message contains the underlying restore or compile error line (pip for Python, NuGet for .NET) plus a troubleshooting link. Verify the folder structure. Use :logstream only after the container starts.
ModuleNotFoundError at runtime
packages/ missing, contains raw .whl files, or has Windows binaries
Rebuild with pip install --target packages/ --platform manylinux2014_x86_64 --only-binary=:all:.
# Delete one versioncurl -X DELETE "$ENDPOINT/agents/$AGENT/versions/1?api-version=$API_VERSION" \ -H "Authorization: Bearer $TOKEN"# Delete the agent and all its versionscurl -X DELETE "$ENDPOINT/agents/$AGENT?api-version=$API_VERSION" \ -H "Authorization: Bearer $TOKEN"# Force-delete the agent (cascades to any active sessions)curl -X DELETE "$ENDPOINT/agents/$AGENT?api-version=$API_VERSION&force=true" \ -H "Authorization: Bearer $TOKEN"
If you scaffolded the project from the Quickstart with azd, run azd down from the project root to remove the entire provisioned environment instead.
Deleting an agent removes all of its versions and terminates active sessions. This action can’t be undone.