API Reference

Complete reference for all KYA REST API endpoints.

Base URL & Docs#

InterfaceURL
API basehttp://localhost:8000
OpenAPI JSONhttp://localhost:8000/openapi.json
Swagger UIhttp://localhost:8000/docs
ReDochttp://localhost:8000/redoc
Playground UIhttp://localhost:5173 (pnpm --filter playground dev)

Authentication#

Sensitive endpoints require the workspace header:

X-Workspace-Id: <workspace_uuid>

Workspace bootstrap uses a separate token:

X-Bootstrap-Token: <bootstrap_token>

Error Format#

All business errors follow this shape:

{
  "detail": {
    "code": "WORKSPACE_MISMATCH",
    "message": "Workspace does not match authenticated context"
  }
}

Workspaces#

POST/workspaces
Request body
{
  "name": "My Workspace",
  "slug": "my-workspace"  // optional
}
Response 201
{
  "id": "ws_01J...",
  "name": "My Workspace",
  "slug": "my-workspace",
  "status": "active",
  "created_at": "2025-01-15T10:00:00Z"
}
StatusCodeCondition
201Workspace created
401AUTH_BOOTSTRAP_MISSINGX-Bootstrap-Token header absent
401AUTH_BOOTSTRAP_INVALIDToken value does not match server config
409WORKSPACE_SLUG_ALREADY_EXISTSSlug already taken
503WORKSPACE_BOOTSTRAP_DISABLEDKYA_WORKSPACE_BOOTSTRAP_TOKEN not set server-side
GET/workspaces/{workspace_id}
StatusCodeCondition
200Success
403WORKSPACE_MISMATCHX-Workspace-Id header does not match path param
404WORKSPACE_NOT_FOUNDWorkspace does not exist

Agents#

POST/agents
Request body
{
  "workspace_id": "ws_01J...",
  "name": "payment-agent",
  "public_key": "base64_ed25519_public_key",
  "runtime_type": "claude"  // optional: claude, codex, custom
}
Response 201
{
  "id": "agt_01J...",
  "workspace_id": "ws_01J...",
  "name": "payment-agent",
  "status": "active",
  "fingerprint": "sha256:abc123...",
  "created_at": "2025-01-15T10:00:00Z"
}
GET/agents/{agent_id}
POST/agents/{agent_id}/revoke

Policies#

POST/policies
Request body
{
  "workspace_id": "ws_01J...",
  "name": "payment-policy",
  "rules": {
    "allowed_tools": ["charge_payment", "get_balance"],
    "spend_limits": {
      "max_per_tx": 50,
      "max_per_day": 500,
      "max_per_month": 5000
    },
    "rate_limits": {
      "actions_per_minute": 10,
      "calls_per_hour": 100
    }
  }
}
POST/agents/{agent_id}/bind_policy
Request body
{
  "workspace_id": "ws_01J...",
  "policy_id": "pol_01J..."
}

Capabilities#

POST/capabilities/request
Request body
{
  "workspace_id": "ws_01J...",
  "agent_id": "agt_01J...",
  "action": "charge_payment",
  "ttl_seconds": 300  // 5–1800
}
Response 201
{
  "capability_token": "eyJhbGciOiJFZERTQSJ9...",
  "expires_at": "2025-01-15T10:05:00Z",
  "jti": "cap_01J..."
}

Verification#

POST/verify
Request body
{
  "workspace_id": "ws_01J...",
  "agent_id": "agt_01J...",
  "capability_token": "eyJhbGciOiJFZERTQSJ9...",
  "action": "charge_payment",
  "payload": {
    "amount": 45,
    "currency": "EUR"
  },
  "signature": "base64_ed25519_signature",
  "payload_hash": "sha256_hex_of_canonical_json"
}
Response — ALLOW
{
  "decision": "ALLOW",
  "reason_code": null,
  "audit_event_id": "evt_01J..."
}
Response — DENY
{
  "decision": "DENY",
  "reason_code": "SPEND_LIMIT_EXCEEDED",
  "audit_event_id": "evt_01J..."
}

Deny Reason Codes#

CodeMeaning
AGENT_REVOKEDAgent has been revoked and can no longer act
POLICY_NOT_BOUNDNo active policy bound to this agent
CAPABILITY_INVALIDCapability token is malformed or unrecognized
CAPABILITY_EXPIREDCapability token TTL has passed
CAPABILITY_REVOKEDCapability token was explicitly revoked (blacklisted)
CAPABILITY_SCOPE_MISMATCHAction does not match the capability's scope
SIGNATURE_INVALIDEd25519 signature verification failed
SPEND_LIMIT_EXCEEDEDTransaction or daily/monthly spend limit exceeded
RATE_LIMIT_EXCEEDEDAction rate limit exceeded for this agent

Audit#

GET/audit/events
GET/audit/export.json
GET/audit/export.csv
GET/audit/integrity/check
Integrity response
{
  "status": "OK",      // OK | BROKEN | PARTIAL
  "checked_events": 1247,
  "first_event_id": "evt_01J...",
  "last_event_id": "evt_09K..."
}