API keys
Package: agentrouter.api_keys.v1 Service: ApiKeysService
Endpoints
List API keys
Changed in v0.11.0 (behaviour changes): Project Owners can list, disable and delete the API keys of their project. Super Admins can list the keys of their organization. Listing uses the new permission api_key_directory.read, which Project Owner, Super Admin, Viewer, User Admin and the admin management key hold. A User Admin bound to a project lists the keys of that project. The read and write management keys do not get it, so they cannot list other users' keys.
Changed in v0.11.0 (behaviour changes): An API key with no stored key type, from before key types were stored, now reports API_KEY_TYPE_MANAGEMENT, the type it works as. It reported API_KEY_TYPE_PROMPT before.
Changed in v0.11.0 (behaviour changes): Deleting or archiving a project now also hides the API keys that were revoked before it, so a new project with the same name does not list them as its own. ListApiKeys reports these keys as API_KEY_STATUS_DELETED, not API_KEY_STATUS_REVOKED; each keeps its revocation stamp and stays on the data plane's revocation list.
Changed in v0.11.0 (security updates): An Admin Console user with only an organization role can no longer list the API keys of every organization. Listing every organization needs the platform admin scope or api_key_directory.read at platform level.
Changed in v0.11.0 (new features): ListApiKeys lists the keys of one organization or project, with status, owner, text and ID filters, a filter for the keys that can hold their own fallback policy (override_targetable_only), sorting, counts and the key owners. Keys show their client, disabled state and deletion time. A fallback policy that targets a key shows the project of that key. A management key bound to an organization gets PERMISSION_DENIED for another organization's keys.
Changed in v0.9.0 (new features): GET /v1/api-keys takes project_id and application_keys_only filters, and each key now says whether it serves an application, so you can find an application's key and disable it to stop that application.
What it does: Returns API-key metadata. A request that names no customer_id reads the platform-wide directory, which includes soft-deleted keys for historical spend attribution. It needs the platform admin scope or api_key_directory.read on a platform binding. A request that names customer_id (and optionally project_id) reads only the keys of that tenant. api_key_directory.read on that customer or project authorizes it, so an org admin or a project owner can list the keys in their scope. api_keys.read does not: the read and write management keys and the Viewer hold it for the lookup RPCs. The organization-admin lift that the acting user of the Admin Console receives is never applied to this RPC. Filter by project_id and application_keys_only to find the key that serves one application; disabling that key with UpdateApiKey stops the application. A request that sets only page, name, project_id and application_keys_only keeps the legacy behaviour: UUID keyset pages, every status, no summary. Any other field switches to offset pages with filters, sorting and an optional summary.
Request fields:
| Field | Required | Description |
|---|---|---|
page | no | page_size defaults to 50 and is capped at 1000. page.filter and page.order_by are rejected; use the fields below. Legacy requests (no field other than name, project_id and application_keys_only) page by UUID keyset; all other requests page by offset, and their page token is bound to the other request fields. |
name | no | Exact, case-sensitive display-name match. Omit to enumerate every key. |
project_id | no | Exact project_id match; a key with no project reads as "default". Omit to list keys of every project. Also the authorization target, so a project owner can list the keys of their project. Without customer_id it filters the platform-wide directory, and then combines only with name and application_keys_only. |
application_keys_only | no | True returns only application keys (ApiKey.application), false returns only the other keys. Omit to return both. |
statuses | no | Only keys with one of these statuses. Empty means ACTIVE, INACTIVE and REVOKED: every key that is not deleted. |
owner_user_id | no | Only the keys this user owns (exact user id). |
search | no | Case-insensitive substring match on the key name, the key prefix, the owner user id, and the owner name and email. At most 200 characters. |
key_ids | no | Only these key ids (UUIDs). At most 1000. |
client_ids | no | Only the keys whose client is one of these ids (UUIDs). A key that is mapped to no client is its own client. At most 1000. |
override_targetable_only | no | Only the keys that can hold their own fallback override: the client group of the key is in the customer and project of the key. |
include_summary | no | Fill total_count, stats and owners in the response. |
order_by | no | Sort order: "name", "created_at", "status" or "owner", with an optional " desc". Empty means "created_at desc". Equal values sort by key id. |
customer_id | no | Only the keys of this customer. Also the authorization target: an api_key_directory.read grant on this customer authorizes the request. |
Response fields:
| Field | Required | Description |
|---|---|---|
keys | no | Safe metadata only; no plaintext, hash, or key address is returned. |
page | no | undocumented |
total_count | no | Number of keys that match every filter. Set only with include_summary. |
stats | no | Counts over the customer and project of the request (or every key when the request names no customer), ignoring the other filters. Set only with include_summary. |
owners | no | The distinct owners of the keys that are not deleted, in the same scope as stats, ordered by name. Set only with include_summary. |
{"signatures":{"go":"func (x *ApiKeysClient) ListApiKeys(ctx context.Context, req *api_keysv1.ListApiKeysRequest) (*api_keysv1.ListApiKeysResponse, error)","python":"list_api_keys(req: api_keys_pb2.ListApiKeysRequest) -\u003e ListApiKeysResponse","typescript":"listApiKeys(req: MessageInitShape\u003ctypeof tars_api_keys_v1_api_keys_pb.ListApiKeysRequestSchema\u003e): Promise\u003cListApiKeysResponse\u003e","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/api-keys\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tapi_keysv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/api_keys/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026api_keysv1.ListApiKeysRequest{}\n\n\tresp, err := client.ApiKeys().ListApiKeys(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/apikeys/listapikeys\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.api_keys.v1 import api_keys_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = api_keys_pb2.ListApiKeysRequest()\ntry:\n result = client.api_keys.list_api_keys(req)\n print(result)\nexcept Exception as err:\n print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n# agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n baseUrl: process.env.AGENTROUTER_BASE_URL,\n apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n const result = await client.apiKeys.listApiKeys(req)\n console.log(result)\n} catch (err) {\n console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n \"name\": \"apikeys\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"typescript\": \"^5.4.0\"\n }\n}\n"},{"name":"tsconfig.json","content":"{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true\n }\n}\n"}]},"curl":"curl \"${AGENTROUTER_BASE_URL}/v1/api-keys\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/api-keys","slug":"list-api-keys"}
Create api key
Changed in v0.8.0 (bug fixes): Adding or removing a model from a project now updates keys that carry their own settings (BYOK, fallback, traffic split, or a rate limit), so they no longer keep routing against the old model list. A key created with CreateApiKey or IssueMyKey now gets its own routes instead of waiting on an unrelated change. Both updates are sent in the background, so the call returns without waiting for them.
What it does: Creates a new JWT user-token API key for a user and returns the plaintext token exactly once.
Request fields:
| Field | Required | Description |
|---|---|---|
user_id | no | User ID that will own the API key. |
user_key_address | no | User key address input (typically email or user id). Required for API parity with client flows and request provenance checks. In JWT-based issuance, returned key_address is derived from user_id by the token service. |
name | no | Human-readable key name. |
enterprise_context | no | Optional enterprise context overrides for JWT user-token issuance. When customer_id is omitted, the key is minted under the calling credential's own customer; only a tenant-less admin credential falls back to customer "default". A tenant-bound caller may not target a different customer (PERMISSION_DENIED). |
Response fields:
| Field | Required | Description |
|---|---|---|
id | output-only | Key ID (UUID). |
user_id | no | User ID that owns the key. |
api_key | no | Plaintext key (returned once). |
prefix | no | 12-char key prefix. |
key_hash | no | 64-char hex HMAC hash of the full key. |
key_address | no | 16-char hex key address from the token service (currently xxhash64(user_id) for JWT issuance). |
key_suffix | no | Last 4 chars of the plaintext key (for display). |
{"signatures":{"go":"func (x *ApiKeysClient) CreateApiKey(ctx context.Context, req *api_keysv1.CreateApiKeyRequest) (*api_keysv1.CreateApiKeyResponse, error)","python":"create_api_key(req: api_keys_pb2.CreateApiKeyRequest) -\u003e CreateApiKeyResponse","typescript":"createApiKey(req: MessageInitShape\u003ctypeof tars_api_keys_v1_api_keys_pb.CreateApiKeyRequestSchema\u003e): Promise\u003cCreateApiKeyResponse\u003e","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/api-keys\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"user_id\": \"...\",\n \"user_key_address\": \"...\",\n \"name\": \"...\",\n \"enterprise_context\": {}\n }'"},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tapi_keysv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/api_keys/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026api_keysv1.CreateApiKeyRequest{}\n\n\tresp, err := client.ApiKeys().CreateApiKey(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/apikeys/createapikey\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.api_keys.v1 import api_keys_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = api_keys_pb2.CreateApiKeyRequest()\ntry:\n result = client.api_keys.create_api_key(req)\n print(result)\nexcept Exception as err:\n print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n# agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n baseUrl: process.env.AGENTROUTER_BASE_URL,\n apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n const result = await client.apiKeys.createApiKey(req)\n console.log(result)\n} catch (err) {\n console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n \"name\": \"apikeys\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"typescript\": \"^5.4.0\"\n }\n}\n"},{"name":"tsconfig.json","content":"{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true\n }\n}\n"}]},"curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/api-keys\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"user_id\": \"...\",\n \"user_key_address\": \"...\",\n \"name\": \"...\",\n \"enterprise_context\": {}\n }'"},"persona":"Admin","httpVerb":"POST","httpPath":"/v1/api-keys","slug":"create-api-key"}
Update api key
Changed in v0.11.0 (behaviour changes): Project Owners can list, disable and delete the API keys of their project. Super Admins can list the keys of their organization. Listing uses the new permission api_key_directory.read, which Project Owner, Super Admin, Viewer, User Admin and the admin management key hold. A User Admin bound to a project lists the keys of that project. The read and write management keys do not get it, so they cannot list other users' keys.
Changed in v0.11.0 (behaviour changes): Enabling, disabling, renaming or deleting an API key, from either console or the API, now writes one UPDATE_API_KEY or DELETE_API_KEY audit record per call, in the same transaction, naming the signed-in user. The Developer Console saves a status and name edit as two calls. A refused change writes one record with success set to false. The Admin Console's ENABLE, DISABLE, UPDATE, DELETE and BULK_ records for API keys stop, except for a change it refuses before the management plane sees it.
Changed in v0.11.0 (security updates): An Admin Console user who holds admin only through an organization role can change or delete only the API keys where that role grants API key edit or delete, and a management key only the keys of its own organization. Other keys return NOT_FOUND. Enabling a revoked key returns FAILED_PRECONDITION except for a platform admin that names no customer_id, so the Developer Console can no longer re-enable a key an admin revoked. Enabling a destroyed key always returns FAILED_PRECONDITION.
Changed in v0.11.0 (new features): UpdateApiKey and DeleteApiKey take an optional customer_id and project_id, so an organization admin or project owner can change the keys of their scope. UpdateApiKey can refuse a revoked key and record who disabled a key.
Changed in v0.9.0 (behaviour changes): UpdateApiKey called without user_id for a key that does not exist now returns NotFound or a field error, where it returned InvalidArgument with the message user_id is required.
Changed in v0.9.0 (new features): An administrator can disable or re-enable one application's API key by sending the key id alone to UpdateApiKey. An admin key bound to an organization reaches only that organization's application keys. A request that sets name on this path is refused with InvalidArgument.
Changed in v0.1.5 (bug fixes): Changing an API key's policy tags, or enabling or disabling a key, now takes effect on the data plane promptly. Previously these changes only reached a project's gateways on the periodic resync, so a re-tagged key kept its old routing and fallback for up to ~30 minutes, a rate-limit change from a tag was not applied until an unrelated policy edit, and a disabled key kept serving until the resync.
What it does: Updates mutable fields of an API key (name and/or active state). When the request names customer_id (and optionally project_id), that tenant is the authorization target: api_keys.edit on it authorizes the call, and a key outside it returns NOT_FOUND. A caller whose admin scope comes only from the Admin Console's organization lift also needs api_keys.edit on the key's own customer or project, or the call returns NOT_FOUND. The change and its UPDATE_API_KEY audit record commit together.
Request fields:
| Field | Required | Description |
|---|---|---|
user_id | no | User ID that owns the API key. Required, except for an application's key (the key created for an externally authenticated application): that key can be addressed by key_id alone to set is_active. A caller whose credential names a customer can reach only that customer's keys; a credential with no customer can reach any customer's. |
key_id | no | Key ID (UUID). |
name | no | Optional new name. |
is_active | no | Optional active state. |
customer_id | no | The customer the key must belong to. Also the authorization target, so an org admin or project owner can change the keys of their scope. A key of another customer returns NOT_FOUND. Omit it to keep the admin-scope authorization. |
project_id | no | The project, within customer_id, the key must belong to. Requires customer_id. |
fail_if_revoked | no | Refuse the change with FAILED_PRECONDITION when the key is revoked. Without it, a caller with the platform admin scope that names no customer_id clears the revocation when it enables a revoked key. Enabling a revoked key is FAILED_PRECONDITION for every other caller. |
record_disabled_by | no | With is_active, record who disabled the key and when (is_active false) or clear that record (is_active true). |
Response fields:
| Field | Required | Description |
|---|---|---|
success | no | True when the update was applied; failures surface as RPC errors instead. |
{"signatures":{"go":"func (x *ApiKeysClient) UpdateApiKey(ctx context.Context, req *api_keysv1.UpdateApiKeyRequest) (*api_keysv1.UpdateApiKeyResponse, error)","python":"update_api_key(req: api_keys_pb2.UpdateApiKeyRequest) -\u003e UpdateApiKeyResponse","typescript":"updateApiKey(req: MessageInitShape\u003ctypeof tars_api_keys_v1_api_keys_pb.UpdateApiKeyRequestSchema\u003e): Promise\u003cUpdateApiKeyResponse\u003e","curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/api-keys/key_01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"user_id\": \"...\",\n \"name\": \"...\",\n \"is_active\": false,\n \"customer_id\": \"...\",\n \"project_id\": \"...\",\n \"fail_if_revoked\": false,\n \"record_disabled_by\": false\n }'"},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tapi_keysv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/api_keys/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026api_keysv1.UpdateApiKeyRequest{}\n\n\tresp, err := client.ApiKeys().UpdateApiKey(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/apikeys/updateapikey\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.api_keys.v1 import api_keys_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = api_keys_pb2.UpdateApiKeyRequest()\ntry:\n result = client.api_keys.update_api_key(req)\n print(result)\nexcept Exception as err:\n print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n# agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n baseUrl: process.env.AGENTROUTER_BASE_URL,\n apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n const result = await client.apiKeys.updateApiKey(req)\n console.log(result)\n} catch (err) {\n console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n \"name\": \"apikeys\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"typescript\": \"^5.4.0\"\n }\n}\n"},{"name":"tsconfig.json","content":"{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true\n }\n}\n"}]},"curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/api-keys/key_01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"user_id\": \"...\",\n \"name\": \"...\",\n \"is_active\": false,\n \"customer_id\": \"...\",\n \"project_id\": \"...\",\n \"fail_if_revoked\": false,\n \"record_disabled_by\": false\n }'"},"persona":"Admin","httpVerb":"PATCH","httpPath":"/v1/api-keys/{key_id}","slug":"update-api-key"}
Delete api key
Changed in v0.11.0 (behaviour changes): Project Owners can list, disable and delete the API keys of their project. Super Admins can list the keys of their organization. Listing uses the new permission api_key_directory.read, which Project Owner, Super Admin, Viewer, User Admin and the admin management key hold. A User Admin bound to a project lists the keys of that project. The read and write management keys do not get it, so they cannot list other users' keys.
Changed in v0.11.0 (behaviour changes): Enabling, disabling, renaming or deleting an API key, from either console or the API, now writes one UPDATE_API_KEY or DELETE_API_KEY audit record per call, in the same transaction, naming the signed-in user. The Developer Console saves a status and name edit as two calls. A refused change writes one record with success set to false. The Admin Console's ENABLE, DISABLE, UPDATE, DELETE and BULK_ records for API keys stop, except for a change it refuses before the management plane sees it.
Changed in v0.11.0 (security updates): An Admin Console user who holds admin only through an organization role can change or delete only the API keys where that role grants API key edit or delete, and a management key only the keys of its own organization. Other keys return NOT_FOUND. Enabling a revoked key returns FAILED_PRECONDITION except for a platform admin that names no customer_id, so the Developer Console can no longer re-enable a key an admin revoked. Enabling a destroyed key always returns FAILED_PRECONDITION.
Changed in v0.11.0 (new features): UpdateApiKey and DeleteApiKey take an optional customer_id and project_id, so an organization admin or project owner can change the keys of their scope. UpdateApiKey can refuse a revoked key and record who disabled a key.
What it does: Soft-deletes an API key (sets deleted_at). customer_id and project_id authorize the call as on UpdateApiKey, with api_keys.delete. The delete and its DELETE_API_KEY audit record commit together.
Request fields:
| Field | Required | Description |
|---|---|---|
user_id | no | User ID that owns the API key. |
key_id | no | Key ID (UUID). |
customer_id | no | The customer the key must belong to, as on UpdateApiKeyRequest. |
project_id | no | The project, within customer_id, the key must belong to. Requires customer_id. |
commit_first | no | No effect. Every delete now commits before its data-plane teardown (fraser#10923), and a teardown that fails undoes the delete and fails the call. The field stays so that callers that set it keep working. |
Response fields:
| Field | Required | Description |
|---|---|---|
success | no | True when the key was soft-deleted; failures surface as RPC errors instead. |
{"signatures":{"go":"func (x *ApiKeysClient) DeleteApiKey(ctx context.Context, req *api_keysv1.DeleteApiKeyRequest) (*api_keysv1.DeleteApiKeyResponse, error)","python":"delete_api_key(req: api_keys_pb2.DeleteApiKeyRequest) -\u003e DeleteApiKeyResponse","typescript":"deleteApiKey(req: MessageInitShape\u003ctypeof tars_api_keys_v1_api_keys_pb.DeleteApiKeyRequestSchema\u003e): Promise\u003cDeleteApiKeyResponse\u003e","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/api-keys/key_01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tapi_keysv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/api_keys/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026api_keysv1.DeleteApiKeyRequest{}\n\n\tresp, err := client.ApiKeys().DeleteApiKey(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/apikeys/deleteapikey\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.api_keys.v1 import api_keys_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = api_keys_pb2.DeleteApiKeyRequest()\ntry:\n result = client.api_keys.delete_api_key(req)\n print(result)\nexcept Exception as err:\n print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n# agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n baseUrl: process.env.AGENTROUTER_BASE_URL,\n apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n const result = await client.apiKeys.deleteApiKey(req)\n console.log(result)\n} catch (err) {\n console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n \"name\": \"apikeys\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {\n \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"typescript\": \"^5.4.0\"\n }\n}\n"},{"name":"tsconfig.json","content":"{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true\n }\n}\n"}]},"curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/api-keys/key_01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"DELETE","httpPath":"/v1/api-keys/{key_id}","slug":"delete-api-key"}