AI agents & governance
Agents are API-first citizens with guardrails. They discover their own capabilities, run product actions freely, but route destructive and code actions through a human — once — with a tamper-evident audit trail and a kill-switch behind it all.
Capability discovery
Mint an agent key with role:"agent" (read+write, never admin). It sees a product-only surface; account-admin actions are hidden.
/v1/whoami bearer Identity plus a per-action map of allowed | approval | denied, so an agent can self-discover what it may do without trial and error. The map reuses the real authorization check, so it can never drift from enforcement.
curl https://api.ollanode.com/v1/whoami \
-H "Authorization: Bearer $AGENT_KEY" { "actor_type":"agent", "role":"api_key", "is_owner":false,
"scopes":["read","write"], "extra_scopes":["videos:read"],
"capabilities":{ "videos:write":"allowed", "videos:delete":"approval",
"dns:write":"approval", "functions:write":"approval",
"logs:read":"allowed", "approvals:create":"allowed" } } - An agent inspects its own capabilities before planning actions.
- A UI renders what an agent key can and can’t do.
Approval gating
For agents, any delete plus functions:write (code deploy) and dns:write are gated: the call returns 202 without running, a human decides, and the agent replays the exact same request once with X-Approval-Id. The approval is bound to a request digest (key + action + resource + body hash), so replays or payload substitutions match nothing and are rejected.
# 1) agent attempts a gated action -> 202, nothing changed
curl -i -X DELETE https://api.ollanode.com/v1/videos/vid_123 \
-H "Authorization: Bearer $AGENT_KEY"
# HTTP/1.1 202 { "status":"pending_approval", "approval_id":"apr_abc", "message":"...resubmit with X-Approval-Id..." }
# 2) a human approves (an API/agent key can never decide)
curl -X POST https://api.ollanode.com/v1/approvals/apr_abc/decide \
-H "Authorization: Bearer $SESSION" \
-H "Content-Type: application/json" -d '{"decision":"approved"}'
# 3) agent replays the SAME request once, with the approval id
curl -X DELETE https://api.ollanode.com/v1/videos/vid_123 \
-H "Authorization: Bearer $AGENT_KEY" -H "X-Approval-Id: apr_abc" /v1/approvals approvals:create File an approval request explicitly (action, optional resource_id, payload).
/v1/approvals approvals:read List approval requests and their state.
/v1/approvals/{id}/decide admin (human) Approve or reject. Requires a signed-in human admin — never an API/agent key — and the decider cannot approve their own request. The decision is fail-closed audited.
Human-only guardrails
Team/user management, API-key lifecycle, approval decisions, and owner-only org actions are never agent-grantable — they return 403 for agents and show as denied in the capability map. Agent keys are structurally prevented from holding admin. Billing is intentionally not an API capability at all.
Tamper-evident audit
Every mutation is recorded in a hash-chain (prev_hash/entry_hash over all immutable fields), so tampering is detectable.
/v1/audit admin · agent · logs:read Recent audit entries (actor, action, resource, request id), newest first.
curl "https://api.ollanode.com/v1/audit?limit=50" -H "Authorization: Bearer $OLLANODE_API_KEY" /v1/audit/verify bearer Verify this project’s per-entry hash-chain integrity.
curl https://api.ollanode.com/v1/audit/verify -H "Authorization: Bearer $SESSION" { "scope":"project", "checked":128, "skipped_legacy":0, "intact":true, "tampered":[] } Kill-switch
/v1/admin/disable-agents?project_id=… X-Admin-Token Kill-switch: revoke ALL agent keys for a project at once (platform-operator credential, fail-closed audited).
curl -X POST "https://api.ollanode.com/v1/admin/disable-agents?project_id=proj_abc" \
-H "X-Admin-Token: $ADMIN_TOKEN"
# -> { "agents_revoked": N } list_videos, ingest_video, create_zone, request_approval, …). The full contract is at GET /openapi.json (OpenAPI 3.1).