From zero to a first authorization decision with evidence - in about 10 minutes. Check items off as you go.
Want it generated for you? Open the Connect wizard - pick an agent and copy a ready-to-paste snippet for the SDK, MCP, or raw HTTP.
AgentKey evaluates every tool call your AI agent wants to make against a stored policy, returns ALLOW, DENY, or approval required, and records verifiable evidence of the decision and of what actually ran. The default is deny: anything you have not explicitly allowed does not execute, and if the service cannot answer, the SDK fails closed.
Zero dependencies. Node 18+ and Python 3.8+.
npm install agentkey-ai # JavaScript / TypeScript (Node 18+) pip install agentkey # Python (3.8+)
Both SDKs default to the production API - no URL configuration needed. The key resolves from an explicit argument, then the AGENTKEY_API_KEY environment variable, then the config file written by `agentkey init` (~/.agentkey/config, 0600).
// JavaScript / TypeScript
import { AgentKeyClient } from "agentkey-ai";
const ak = new AgentKeyClient({ apiKey: process.env.AGENTKEY_API_KEY });
# Python
import os
from agentkey import AgentKeyClient
ak = AgentKeyClient(api_key=os.environ["AGENTKEY_API_KEY"])This is the first step that needs an account, and the only reason: API keys are issued per agent under your account, so your policies and evidence chain stay isolated to you and nobody else can act as your agent. Pick or create an agent in the Connect wizard and create a key - it is shown exactly once; store it as AGENTKEY_API_KEY and never commit it.
Copy, paste, run. Every new agent ships with exactly one isolated test permission - sandbox.send_test - that can only ever return allow or deny and never performs a real side effect. This single call produces a real policy-engine decision and a verifiable evidence event in your dashboard.
# Python - save as first_authorization.py, then: python first_authorization.py
from agentkey import AgentKeyClient
ak = AgentKeyClient() # reads AGENTKEY_API_KEY (or the config file from agentkey init)
result = ak.check_permission(action="send_test", resource="sandbox")
print("session_id: ", result.get("session_id"))
print("decision: ", "ALLOW" if result.get("allowed") else "DENY", "-", result.get("reason"))
if result.get("event_id"):
print("evidence_event_id:", result["event_id"])
print("YOU'RE DONE - your first real authorization is recorded. See it:")
print("https://agentkey.us/sessions/" + str(result.get("session_id")))
else:
reason = str(result.get("reason") or "")
if "Invalid API key" in reason:
print("Key invalid - create one at https://agentkey.us/connect")
elif "No permission configured" in reason:
print("Add a permission in the dashboard: resource 'sandbox',")
print("action 'send_test', decision allow - then run this again.")
else:
print("Denied by policy:", reason)
// JavaScript / TypeScript - save as first-authorization.mjs, then: node first-authorization.mjs
import { AgentKeyClient } from "agentkey-ai";
const ak = new AgentKeyClient(); // reads AGENTKEY_API_KEY (or the config file from npx agentkey init)
const result = await ak.checkPermission({ action: "send_test", resource: "sandbox" });
console.log("session_id: ", result.session_id);
console.log("decision: ", result.allowed ? "ALLOW" : "DENY", "-", result.reason);
if (result.event_id) {
console.log("evidence_event_id:", result.event_id);
console.log("YOU'RE DONE - your first real authorization is recorded. See it:");
console.log("https://agentkey.us/sessions/" + result.session_id);
} else {
const reason = String(result.reason || "");
if (reason.includes("Invalid API key")) {
console.log("Key invalid - create one at https://agentkey.us/connect");
} else if (reason.includes("No permission configured")) {
console.log("Add a permission in the dashboard: resource 'sandbox',");
console.log("action 'send_test', decision allow - then run this again.");
} else {
console.log("Denied by policy:", reason);
}
}A permission matches a resource + action pair and carries a decision (allow / ask / deny), optionally constrained by parameter conditions. No permission configured means the default is deny.
{
"resource": "stripe.charge",
"action": "invoke",
"decision": "allow",
"conditions": [
{ "field": "amount", "operator": "lte", "value": "100", "on_fail": "deny" }
]
}checkPermission is the core call. The three possible outcomes: ALLOW runs the action, DENY blocks it, and 'ask' pauses for a human approval in the dashboard. On any error or timeout the SDK fails closed - allowed: false.
const decision = await ak.checkPermission({
action: "invoke",
resource: "stripe.charge",
arguments: { amount: 150 },
});
// ALLOW: { allowed: true, reason: "...", event_id: "evt_..." }
// DENY: { allowed: false, reason: "denied by policy" }
// APPROVAL REQUIRED: { allowed: false, approval_required: true }
// → a human approves or denies it in the dashboardwrap() instruments an existing agent in one line - every tool call becomes paired authorization + execution evidence on a hash-chained session, with no call-site changes. Observe mode (default) records and blocks nothing; enforce mode raises on denials.
const agent = ak.wrap(myAgent); // observe mode (default)
// const agent = ak.wrap(myAgent, { mode: "enforce" });
// Or thread decisions into an explicit session:
const s = await ak.startSession({ metadata: { task: "daily-report" } });
await ak.checkPermission({
action: "invoke",
resource: "email.send",
sessionId: s.session_id,
});
await ak.endSession({ sessionId: s.session_id });Verification recomputes the chain from the stored raw events - it never trusts the stored root. Session-level signatures (HMAC-SHA256, plus Ed25519 when enabled) are produced at session close. Run it months later, from outside AgentKey.
const report = await ak.verifySession({ sessionId: s.session_id });
// report.integrity.status:
// "VERIFIED" | "VERIFIED WITH GAPS" | "INVALID" | "INCOMPLETE"
// Python: ak.verify_session(session_id)The common cases, and what each one means.
# allowed: false, reason "agentkey_unreachable" # → fail-closed by design: network error or timeout. The agent never # proceeds on a missing decision. Check connectivity and AGENTKEY_BASE_URL. # HTTP 403 / "Cloudflare error 1010" # → blocked by the edge WAF, not an auth failure. A proxy or wrapper is # likely stripping the SDK's User-Agent header - restore it. # "no API key configured" # → export AGENTKEY_API_KEY=... or run: agentkey init # HTTP 429 # → per-agent rate limit. Retry after the indicated interval.