Skip to Content
Conceptsdid:web identity documents

did:web identity documents

Every AgentValet agent has a W3C Decentralized Identifier of the form:

did:web:api.agentvalet.ai:agents:<agent_id>

It is derived from the agent id and nothing else, so it exists the moment an agent is registered. GET /v1/agents/me returns it as did. What is opt-in is publishing the DID document: once an organisation admin turns on Agent identity documents in Settings, each of that org’s agents resolves at

https://api.agentvalet.ai/agents/<agent_id>/did.json

exactly as the did:web method  specifies (colons become path segments, /did.json is appended). Any standard DID resolver, including the Universal Resolver, resolves it without knowing anything about AgentValet.

What the document says

The document publishes the same RSA public key the proxy verifies the agent’s bearer tokens against. Nothing is re-keyed or invented for the DID:

{ "@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/jws-2020/v1"], "id": "did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83", "controller": "did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83", "verificationMethod": [{ "id": "did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83#key-3f1a9c2e", "type": "JsonWebKey2020", "controller": "did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83", "publicKeyJwk": { "kty": "RSA", "n": "...", "e": "AQAB", "alg": "RS256", "use": "sig", "kid": "agt_7o00saqajyahinuuc6g83" } }], "authentication": ["did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83#key-3f1a9c2e"], "assertionMethod": ["did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83#key-3f1a9c2e"], "service": [ { "id": "did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83#authzen", "type": "AuthZENPolicyDecisionPoint", "serviceEndpoint": "https://api.agentvalet.ai/v1/authzen/access" }, { "id": "did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83#trqp", "type": "TRQPAuthorization", "serviceEndpoint": "https://api.agentvalet.ai/v1/trqp/authorization" }, { "id": "did:web:api.agentvalet.ai:agents:agt_7o00saqajyahinuuc6g83#trqp-recognition", "type": "TRQPRecognition", "serviceEndpoint": "https://api.agentvalet.ai/v1/trqp/recognition" } ] }

The key fragment (#key-3f1a9c2e) is a fingerprint of the key, so it changes when the key is rotated. The service entries are how a relying party finds the decision endpoints: #authzen for AuthZEN 1.0 (POST /v1/authzen/access, bearer required), and #trqp / #trqp-recognition for the ToIP Trust Registry Query Protocol (POST /v1/trqp/authorization and /recognition), which answer publicly for agents whose organisation has opted in. All three return the effective answer, not just whether a grant exists. The same Settings toggle that publishes the document also opens the public TRQP path for the org’s agents, so a document never advertises an endpoint that would refuse to answer.

A verifier can prove the link in one step: sign anything with the agent’s private key and verify it with publicKeyJwk. scripts/did-web-resolve.mjs in the repository does exactly that.

What the document never says

Owner, organisation and agent name are never included. A document reveals that an agent id exists, its public key, and whether it is currently active. Agent ids are 80 to 108 bits of random and cannot be enumerated, so a document is only reachable by someone who already holds the id.

Status

The document tracks the agent’s lifecycle, visible within a minute (Cache-Control: public, max-age=60):

Agent statusResolution
Active, own keyFull document as above
Active, authenticated by AgentValet itself (Claude web MCP clients, child agents)Keyless document whose controller is did:web:api.agentvalet.ai (and the parent’s DID for a child). This is the truthful statement: their tokens are verified against the broker’s key, not one they hold
SuspendedDocument with the key present but empty authentication and assertionMethod: the key still belongs to the agent, it currently has no authority. A receipt signed before the suspension stays checkable
Revoked or deleted410 Gone with {"deactivated": true, "id": "<did>"}
Pending, unbound, unknown, or the organisation has not opted in404

The root identifier did:web:api.agentvalet.ai resolves at /.well-known/did.json and carries the broker’s own signing key, the one that verifies broker-issued tokens.

Honest limits

This is did:web, not did:webvh: there is no signed key-history log, so a verifier holding a receipt signed under a rotated or deleted key cannot resolve that historical key. Rotation is visible (the fragment changes) but not replayable. If you need verifiable key history, tell us.

Last updated on