Agent enrollment
Connect an agent from a developer machine. The agent asks for a code, a person approves it in the browser, and the agent exchanges the code for a credential. A withHuman extension, not part of the protocol.
Enrollment is for an agent that runs on a developer machine, where nobody can hand it a credential in advance. The machine asks for a short code. A person approves that code in the browser, and the machine exchanges it for a credential of its own. No secret is ever copied by hand.
withhuman agent install <runtime> runs this flow for you. Use these endpoints to build the
same flow into your own tool. Neither endpoint needs authentication.
This is a withHuman extension. It is not part of the Agent Approval Protocol, so other providers may not offer it.
How it works:
- Start an enrollment with the runtime and instance name. Optionally set
requested_agent_nameto require an existing parent agent. The response carries anenrollment_codefor the machine, auser_codefor the person, and averification_uri. - Show the person the verification URI and the user code. They sign in,
enter the code, and select an existing agent or create one. This needs the
agent.credential.issuepermission, which owners and admins hold. Creating an agent also needsagent.write. Authorizing attaches the instance to the selected agent. A requested agent name fixes the target and never creates an agent automatically. - In the meantime, exchange the enrollment code
every few seconds. It returns
404until the person has authorized the code. Then it returns the selected agent, the new instance and its credential. Store the credential's token; it is not shown again.
Both codes expire ten minutes after the enrollment starts. The response to the first call says exactly when. If that time passes, start over.
Start an enrollment
/auth/agent_enrollmentsNo authStarts an enrollment and returns two codes. The enrollment_code stays on the machine. The user_code is for a person to enter at the verification_uri. Both expire at expires_at, ten minutes after this call. The person selects an existing agent or creates one in the browser, then authorizes the instance. An optional requested agent name fixes the target within the organization they sign into.
Request
Request body
The runtime being installed, independent of its parent agent.
Optional slug of an existing agent. The browser must authorize this target; it cannot create or substitute another agent.
A name for this instance, unique within the agent. The CLI defaults to the machine's hostname plus a unique suffix. Reviewers see it next to the agent's name.
Any JSON object to store with the instance, such as the hostname or operating system.
Response
Response codes
| Status | Body | Description |
|---|---|---|
201 | EnrollmentCode | The codes and where to use them |
400 | A required field is missing or blank |
Response body201
The secret the machine keeps. Send it to the exchange endpoint. Never show it to the person.
The short code the person enters in the browser. Three letters, a hyphen, and four letters or digits. Case does not matter.
The page where the person enters the user code.
When both codes stop working. Start a new enrollment after this.
Example
curl -X POST "$WITHHUMAN_URL/auth/agent_enrollments" \
-H "Content-Type: application/json" \
-d '{
"runtime": "claude-code",
"requested_agent_slug": "codex",
"instance_name": "eces-macbook",
"instance_metadata": {
"hostname": "eces-macbook",
"os": "darwin"
}
}'{
"enrollment_code": "whe_7c1f2a9e-4b3d-4f2e-9a1c-2d6e8b5f0a11_3f6b9c1d0e7a4b2c",
"user_code": "K7M-3PQ2",
"verification_uri": "https://app.withhuman.ai/connect/authorize",
"expires_at": "2026-09-08T12:02:11Z"
}Exchange an enrollment code
/auth/agent_enrollments/tokenNo authExchanges an authorized enrollment code for the new instance and its credential. Call this every few seconds after starting an enrollment. It returns 404 until a person has authorized the user code. Once it succeeds, the code is used up and a second call returns 404 as well. The credential's token appears only in this response, so store it right away.
Request
Request body
The enrollment_code returned when the enrollment started.
Response
Response codes
| Status | Body | Description |
|---|---|---|
200 | AgentEnrollmentCredential | The instance and its credential. The credential's token appears only in this response. |
401 | The enrollment code is not in the expected format | |
403 | The agent or the instance has been disabled since it was authorized | |
404 | The code has not been authorized yet, has expired, or has already been exchanged |
Response body200
An agent identity. The slug identifies it everywhere: URLs, role scopes, pipeline scopes, audit data and conditions. The name is a label for people.
One running copy of an agent.
Example
curl -X POST "$WITHHUMAN_URL/auth/agent_enrollments/token" \
-H "Content-Type: application/json" \
-d '{
"enrollment_code": "whe_7c1f2a9e-4b3d-4f2e-9a1c-2d6e8b5f0a11_3f6b9c1d0e7a4b2c"
}'{
"agent": {
"slug": "support-bot",
"organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"name": "Support bot",
"status": "active",
"created_at": "2026-09-08T12:02:11Z",
"updated_at": "2026-09-08T12:02:11Z",
"archived_at": "2026-09-08T12:02:11Z"
},
"agent_instance": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"agent_slug": "string",
"name": "ci-runner-07",
"status": "active",
"metadata": {
"region": "eu-west"
},
"created_at": "2026-09-08T12:02:11Z",
"last_seen_at": "2026-09-08T12:02:11Z"
},
"credential": {
"id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"token": "whc_live_3f6b9c1d0e7a4b2c",
"expires_at": "2026-09-08T12:02:11Z"
}
}