Skip to content

API keys

chronicle.api_keys mints and manages the sk_... keys that automation and agents authenticate with, and pins each one to exactly the authority it should carry. This page is the minting/management reference — for token formats and methodic auth login, see the auth guide.

Minting a key

create returns the full record including the secret (key). key_type is "agent" (automation, the default) or "user" (a researcher). With no restriction, the key inherits your full owner authority.

from methodic import Chronicle

chronicle = Chronicle.from_env()

minted = chronicle.api_keys.create(
    "ci-runner",
    key_type="agent",
    expires_at="2026-12-31T00:00:00Z",   # optional; omit for the default lifetime
)
print(minted["id"], minted["key"])        # sk_agent_... — store it now

The secret is shown exactly once

create and rotate are the only calls that return the key field. It is never retrievable again — copy it into a secret manager immediately. Lose it and you rotate.

Restrictions — the authority ceiling

A restriction narrows a key below the owner's authority (never above), mapping each privilege verb to the targets that verb is limited to; None means full owner authority. A restricted calling key can only mint or edit keys within its own restriction — the server enforces the subset rule.

Two module-level helpers build the common ceilings. Both pin every mutating verb — create, write, discuss, delete, trigger, stop — to a single object, deny administer, and leave read/audit unrestricted so the key still reads broadly:

Helper Mutating verbs pinned to Use
org_ceiling_restriction(organization_id) [organization:<id>] The UI's org-context key — mutate only inside one org
experiment_ceiling_restriction(experiment_id) [experiment:<id>] The dispatched-agent shape — mutate only one experiment
from methodic import api_keys

restriction = api_keys.experiment_ceiling_restriction("exp_7Qk")
scoped = chronicle.api_keys.create("agent-exp7Qk", restriction=restriction)

For anything else, pass the restriction dict yourself: {verb: [{"object_type": ..., "object_id": ...}, ...]}. See reference/client.md for the full shape.

Org-bound keys

create_org_bound is the convenience over create + org_ceiling_restriction — a key that can only mutate inside organization_id, while reads stay broad:

key = chronicle.api_keys.create_org_bound("acme-bot", "org_4f2a", key_type="agent")

Listing

list returns every key you own — each {id, name, key_type, created_at, expires_at, restriction?}, no secrets. The id is the handle for rotate, set_restriction, and revoke:

for k in chronicle.api_keys.list():
    print(k["id"], k["name"], k["key_type"])

Rotating

rotate is single-step: same key row (id, name, restriction), fresh secret. The old secret stops validating immediately and the new key is returned once. Reach for it when a key leaks or its setup snippet is lost — identity and grants are unchanged.

rotated = chronicle.api_keys.rotate("key_abc123")
print(rotated["key"])    # new secret — store it

Editing a restriction

set_restriction replaces a key's restriction in place (Cloudflare-style permission editing). Passing None clears it to full owner authority — only allowed when your calling credential is itself unrestricted.

chronicle.api_keys.set_restriction("key_abc123", api_keys.org_ceiling_restriction("org_4f2a"))
chronicle.api_keys.set_restriction("key_abc123", None)    # clear → full owner authority

Revoking

revoke is immediate — any agent using the key is locked out at once.

chronicle.api_keys.revoke("key_abc123")