Accept enrollment and status
Decide whether to recognize the Agent
Your Inspect document tells Agents which identity methods, commands, and claims your Service supports. If it advertises Enroll and Status, implement both at the paths derived from http.endpoint_base. Enroll requests an initial decision for an Agent identity; Status reads the current state for that authenticated identity. Neither command grants blanket permission to use every application resource.
This guide extends the Inspect publication example at https://api.example.com: its Service accepts did:web and has added contact.email to its advertised claim requirements. The Agent submits an email with Enroll. The Service may recognize the Agent immediately or keep enrollment pending while it verifies the value. Owner action may be required independently.
Authenticate before applying enrollment policy
Every exposed Enroll and Status endpoint accepts the baseline Authorization: AEP <jwt> client assertion. Verify its signature using an advertised Agent identity method and signing algorithm. Check that iss, sub, and the DID portion of kid identify the same Agent; aud names your advertised Service DID; and op matches the endpoint. Check the time window and reject a reused jti.
On Enroll, the request body's agent_did must match the authenticated Agent DID. Do not evaluate claims or reveal whether an Agent already has a record when assertion verification fails; use the non-disclosing not_recognized error. Status may additionally accept a session credential only if its concrete credential type permits that use. Methods advertised in authentication.methods for protected resources do not replace baseline command authentication. The Identity methods and client assertions page gives the full verification rules.
Evaluate the claims you requested
Read the optional claims object against the requirements you published in Inspect. A submitted contact.email value is information from the Agent, not proof that it belongs to the Agent or its Owner. If your policy needs verification, record that work separately from requirements the Agent has not yet satisfied. Do not put claim values in pending-status fields.
The core protocol does not prescribe how your Service verifies a claim or obtains Owner approval. It does require your response to describe the current state accurately. Unknown claims are ignored unless your local policy requires rejection. Keep the names you request in Inspect aligned with what this enrollment flow can process; see Claims and verification for the claim-design decisions.
Return the enrollment decision
For a new Agent record, return 200 OK with status equal to active, pending, or rejected. Active means the identity is enrolled and operational. Pending means the decision is awaiting asynchronous work; it is not an error. A Service that cannot yet verify the submitted email and also needs Owner action could return:
{
"owner_action_required": "true",
"status": "pending",
"verification_pending": ["contact.email"]
}Here verification_pending names the submitted email claim awaiting verification, while the string value of owner_action_required independently signals work for the Owner. Use requirements_pending for requirements the Agent still needs to satisfy, not for claims already submitted and awaiting verification. Omit empty pending arrays and omit owner_action_required unless it is the string true. Never include a claim value in a pending list.
Before making a new decision, check whether the authenticated Agent DID already has an enrollment record. If it does, return the current lifecycle representation—even if it is unavailable, suspended, or terminated. Do not treat Enroll as renewal, rerun policy, reset lifecycle timestamps, or replace the record. This is different from replaying the same request under an idempotency key.
Report the current state with Status
GET /aep/status has no request body in this example. After authenticating the Agent with an assertion whose op is status, read its current enrollment state; do not run Enroll again. Return 200 OK with one of the six lifecycle states and, when available, since as the time of the last state transition.
Suppose the email is verified, the Owner completes the required action, and your Service makes the Agent active. A later Status response can be:
{
"since": "2026-05-28T12:00:00Z",
"status": "active"
}Status can also return pending, unavailable, suspended, terminated, or rejected. Report verification_pending, requirements_pending, and owner_action_required as separate dimensions when they apply. Reporting a lifecycle state is a successful read; refusing a different operation because of that state uses an error response. The Enroll and Status page defines the exact state vocabulary and response rules.
Make Enroll safe to retry
Require a non-empty Idempotency-Key header on Enroll. Reject a missing or empty key with 400 invalid_request. If the optional body idempotency_key is present, it must match the header. For each authenticated Agent and key, retain the command, a cryptographic hash of a canonical representation of the request body, and its response for at least one hour.
The same key, command, and body return the cached response or an equivalent successful response. Reusing that key with a different command or body returns 409 idempotency_conflict. A retry presents a fresh assertion and jti; the idempotency key remains the same. A new key from an already-enrolled Agent invokes the existing-record rule above, not a new enrollment decision.
Check what you advertise
Fetch Inspect without credentials and confirm that it advertises only the commands, identity methods, and claim names you actually handle. Then exercise Enroll with a valid Agent assertion, a pending decision, and a later Status request for that same identity. Verify that retrying the same Enroll does not create another record, while reusing its key with a different body returns a conflict.
Once enrollment works, Protect a resource explains how to authenticate an Agent on an application endpoint and then apply your own authorization policy. Enrollment alone does not authorize that endpoint.