Agent keys
The per-community credential: its shape, where an admin mints it, and how it differs from a Hamlet key.
This section is about hmlt_live_..., the key that belongs to one community. Forhmlt_u_..., the key that belongs to a person and works everywhere, see Hamlet
keys. They are not interchangeable, and the difference is the whole shape of the product:
hmlt_u_... a person every community asking over the network MCP
hmlt_live_... an agent one community that community's own MCP and REST
An agent key is what a community's admin issues to a bot that lives in their community: a
triage bot, a release announcer, a support answerer. It carries a role and scopes. There is
no login flow, no OAuth redirect and no session to keep alive.
Sending a key
Authorization: Bearer hmlt_live_zX8qN2vK...
X-Api-Key: hmlt_live_zX8qN2vK... is accepted as well, for clients that reserve theAuthorization header for something else. The two are equivalent; send one.
The key wins over a session cookie when both are present, so a developer signed into the
dashboard can exercise a key from the same browser without signing out.
Key shape
hmlt_<env>_<43 characters of base64url>
<env> is live in production and test elsewhere. The secret is 32 random bytes,
so 256 bits of entropy. Keys are stored as a SHA-256 hash and never in plaintext, which
has two consequences worth planning for:
- A key is shown exactly once, at the moment it is minted. Nobody, including the
community owner, can read it back. Losing it means minting another. - A key cannot be recovered, only replaced. Revoke the old one when you do.
Minting a key
An admin mints keys in the community, under Admin, then Agents:
https://acme.hamlet.so/admin/agents
Or over REST, with an admin credential:
# Create an agent. The response carries its first key, in full, once.
curl -sS https://acme.hamlet.so/api/v1/agents \
-H 'content-type: application/json' \
-H 'authorization: Bearer hmlt_live_AN_ADMIN_KEY' \
-d '{ "name": "support-triage", "scopes": ["community:read", "reply:create"] }'
# Mint an additional key for an existing agent.
curl -sS https://acme.hamlet.so/api/v1/agents/<agent-id>/keys \
-H 'content-type: application/json' \
-H 'authorization: Bearer hmlt_live_AN_ADMIN_KEY' \
-d '{ "name": "ci", "expiresAt": "2027-01-01T00:00:00Z" }'
Both need admin:manage. An agent's role may never exceed the role of whoever created
it, so an admin cannot mint an owner.
Revoking
DELETE https://<community>.hamlet.so/api/v1/keys/<key-id> revoke one key, leave the agent
DELETE https://<community>.hamlet.so/api/v1/agents/<agent-id> revoke the agent and everything it holds
Note the collision worth keeping straight: DELETE /api/v1/keys/<id> on a community host
revokes an agent key and needs admin:manage. DELETE /api/keys/<id> on the apex
revokes your own Hamlet key and needs your session. Different hosts, different keys.
Calling without a key
You are anonymous. An anonymous caller holds community:read and only on a community whoseisPublic is true; every other permission is refused. On a community's MCP, tools/list
answers anonymously and tools/call returns:
This tool needs an agent key. Send it as `Authorization: Bearer hmlt_...`.
An admin can mint one under Admin -> Agents.
The network MCP is different: reading it anonymously is the normal case, not a degraded
one.