Skip to content

API Keys & Scopes ​

Keys authenticate every call to the Ovrin API. They are stored hashed — a lost key is replaced, never recovered.

Scopes ​

A key's scope decides which surface it can touch. A scoped key used anywhere else is rejected with 403, so a leaked partial key cannot read usage, mint keys, or touch billing.

ScopeCan use
allEverything (default)
sandboxes/sandboxes/* only — lifecycle, exec, files, code, endpoints
memory/memory/* only
secrets/secrets/* only
payments/payments/* only — but see the agent key
python
key = client.keys.create(name="ci", scope="sandboxes",
                         expires_at="2026-12-01T00:00:00Z")
ts
const key = await client.keys.create({
  name: "ci",
  scope: "sandboxes",
  expiresAt: "2026-12-01T00:00:00Z",
});

The raw key is returned once. Store it immediately.

Expiry ​

Pass an RFC 3339 timestamp and the key stops authenticating at that moment — at the control plane and at the tenant lookup the runtime uses, so sandbox creation through any SDK dies with it. Expired keys are indistinguishable from invalid ones by design.

Rotation ​

Rotation swaps a key in one server transaction: the old hash is revoked as the replacement is minted, so there is no window with two live keys — or none.

python
fresh = client.keys.rotate(key_id)               # same name + scope
fresh = client.keys.rotate(key_id, expires_at=...)  # fresh lifetime
ts
const fresh = await client.keys.rotate(keyId);

The replacement's raw key arrives once, in this response.

Revocation ​

DELETE /keys/{id} (or client.keys.delete) marks a key revoked; calls fail immediately. The console asks twice before firing.

The agent-payments key ​

The one payments-scoped key per account is special: a copy is kept encrypted server-side so sandboxes created with payments=true can inject it, letting code inside transact without holding your account key. Mint and rotate it through the payments surface:

python
client.payments.agent_key_status()
raw = client.payments.create_agent_key()   # rotates if one exists

POST /keys/{id}/rotate refuses payments keys (409) on purpose — rotating through the generic endpoint would desync that encrypted copy.