KeysService
The project's own API keys: mint one, list them, retire one. Minting and retiring take an admin key, because a key that could mint its own reviewer would staff an approval gate rather than satisfy it. Listing carries no key material and is open to any of the project's keys.
Every call is a POST to https://api.atmon.ai/automaton.v1.KeysService/<Call> with a JSON body, and authenticates with Authorization: Bearer <your project key>. Field names in JSON are lowerCamelCase, so the field written tool_slug below is toolSlug on the wire. How to call the API has the whole convention.
Calls
| Call | Request | Response | Summary |
|---|---|---|---|
CreateKey | CreateKeyRequest | CreateKeyResponse | Mints a key for the project and returns its plaintext once. |
ListKeys | ListKeysRequest | ListKeysResponse | Lists the project's keys, newest first, with no key material. |
RevokeKey | RevokeKeyRequest | RevokeKeyResponse | Retires one of the project's keys. |
CreateKey
Mints a key for the project and returns its plaintext once. It requires the admin role, and an expiry already in the past is refused rather than stored, because a key born expired looks like a key that stopped working.
Request CreateKeyRequest, response CreateKeyResponse.
POST /automaton.v1.KeysService/CreateKey HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"name": "...",
"role": "KEY_ROLE_AGENT",
"expiresAt": "2026-01-31T09:15:00Z"
}
The response:
{
"key": {
"id": "...",
"name": "...",
"role": "KEY_ROLE_AGENT",
"createdAt": "2026-01-31T09:15:00Z",
"revokedAt": "2026-01-31T09:15:00Z",
"expiresAt": "2026-01-31T09:15:00Z",
"createdByUserId": "..."
},
"plaintext": "..."
}
ListKeys
Lists the project's keys, newest first, with no key material. Open to any of the project's keys.
Request ListKeysRequest, response ListKeysResponse.
POST /automaton.v1.KeysService/ListKeys HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{}
The response:
{
"keys": [{
"id": "...",
"name": "...",
"role": "KEY_ROLE_AGENT",
"createdAt": "2026-01-31T09:15:00Z",
"revokedAt": "2026-01-31T09:15:00Z",
"expiresAt": "2026-01-31T09:15:00Z",
"createdByUserId": "..."
}]
}
RevokeKey
Retires one of the project's keys. It requires the admin role, and it
refuses the key the request arrived on: revoking that would end the session
doing the administration, so a key retires itself with
automaton apikey revoke.
Request RevokeKeyRequest, response RevokeKeyResponse.
POST /automaton.v1.KeysService/RevokeKey HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"id": "..."
}
The response:
{}
Messages
CreateKeyRequest
CreateKeyRequest mints a key for the authenticated project. It names no project, because a key mints only for its own.
| Field | Type | # | Notes |
|---|---|---|---|
name | string | 1 | |
role | KeyRole | 2 | |
expires_at | google.protobuf.Timestamp | 3 | expires_at must be in the future when it is set. Absent means the key never expires. |
CreateKeyResponse
| Field | Type | # | Notes |
|---|---|---|---|
key | ProjectKey | 1 | |
plaintext | string | 2 | plaintext is the only time the key exists outside the caller's hands. It is never stored, never logged, and no later read returns it: a lost key is replaced, not recovered. |
ListKeysRequest
No fields. The call takes its scope from the authenticated project.
ListKeysResponse
| Field | Type | # | Notes |
|---|---|---|---|
keys | repeated ProjectKey | 1 |
ProjectKey
ProjectKey is one API key as a listing shows it. It carries no key material at all: the plaintext exists once, in CreateKeyResponse, and the server stores only its hash.
| Field | Type | # | Notes |
|---|---|---|---|
id | string | 1 | |
name | string | 2 | name is the label whoever minted it wrote, for their own bookkeeping. |
role | KeyRole | 3 | |
created_at | google.protobuf.Timestamp | 4 | |
revoked_at | google.protobuf.Timestamp | 5 | revoked_at is absent while the key is live. |
expires_at | google.protobuf.Timestamp | 6 | expires_at is absent when the key never expires. |
created_by_user_id | string | 7 | created_by_user_id is the console user who minted it, empty for every key minted by the CLI and for every key minted before accounts existed. It is bookkeeping, never an authorization: a key minted by a person is a distinct principal from that person, which is what lets separation of duty hold when an agent acts under a key its own reviewer created. The member-removal dialog reads this field, and it is the reason that dialog can list what a departing person's keys are before deciding which of them keep running. |
RevokeKeyRequest
RevokeKeyRequest retires one of the project's keys. It is idempotent: a key already revoked keeps its original revocation time.
| Field | Type | # | Notes |
|---|---|---|---|
id | string | 1 |
RevokeKeyResponse
No fields. The call takes its scope from the authenticated project.
Enums
KeyRole
KeyRole is what a key may do. The vocabulary is closed, because a role a key could present that the policy gate has never heard of is not a role, it is a hole. Adding one is a recorded decision rather than a field value.
| Value | # | Meaning |
|---|---|---|
KEY_ROLE_UNSPECIFIED | 0 | KEY_ROLE_UNSPECIFIED reads as KEY_ROLE_AGENT on a mint, which is what an omitted role means and what every key minted before roles existed reads as. |
KEY_ROLE_AGENT | 1 | KEY_ROLE_AGENT executes tools, submits jobs, and connects accounts for entities. It is the role an AI holds. |
KEY_ROLE_APPROVER | 2 | KEY_ROLE_APPROVER resolves approvals and answers asks addressed to approvers. It is a separation of duty rather than an escalation: it grants review, not execution, and not administration. |
KEY_ROLE_ADMIN | 3 | KEY_ROLE_ADMIN mints and revokes keys, writes the policy document and the principal directory, registers private toolkits, storage backends and telemetry destinations, and resolves approvals. It is the top of the vocabulary, and separation of duty still binds on it: an admin that requested a call may not release it. |
KEY_ROLE_VIEWER | 4 | KEY_ROLE_VIEWER reads what the governance surfaces show and changes nothing. |