Skip to content

API

API reference

Kryton exposes a versioned REST API under /api/v1. All machine operations are scoped to a project. Authentication uses bearer tokens (KRYTON_TOKEN) or trusted proxy headers when configured.

How to get a token: AUTH.md (./scripts/ensure-api-keys.sh → cat ~/.kryton/lab.token, or krytonctl generate-token for Helm/CI).

OpenAPI spec: openapi.yaml.


Endpoints

GET    /api/v1                          # discovery catalog (public)
GET    /api/v1/me
GET    /api/v1/projects
GET    /api/v1/capabilities
GET    /api/v1/doctor
GET    /api/v1/storage
GET    /api/v1/storage/config
PUT    /api/v1/storage/config
GET    /api/v1/storage/setup
POST   /api/v1/storage/setup
GET    /api/v1/settings
PUT    /api/v1/settings
POST   /api/v1/settings/test
POST   /api/v1/integrations/atlas/test
GET    /api/v1/images
GET    /api/v1/golden
POST   /api/v1/golden
GET    /api/v1/golden/{id}
GET    /api/v1/golden/{id}/passport      # guestkit Cutover Passport JSON, 404 if none recorded
POST   /api/v1/golden/{id}/bootstrap
GET    /api/v1/jobs
GET    /api/v1/jobs/{id}
GET    /api/v1/summary?project=<project>
GET    /api/v1/machines?project=<project>&limit=<n>&cursor=<opaque>
POST   /api/v1/machines
GET    /api/v1/machines/{id}?project=<project>
GET    /api/v1/machines/{id}/console?project=<project>
POST   /api/v1/machines/{id}/console-ticket?project=<project>
GET    /api/v1/machines/{id}/vnc?project=<project>
POST   /api/v1/machines/{id}/start?project=<project>
POST   /api/v1/machines/{id}/stop?project=<project>
POST   /api/v1/machines/{id}/snapshot?project=<project>
GET    /api/v1/machines/{id}/snapshots?project=<project>
POST   /api/v1/machines/{id}/snapshots/{sid}/restore?project=<project>
DELETE /api/v1/machines/{id}/snapshots/{sid}?project=<project>
DELETE /api/v1/machines/{id}?project=<project>
GET    /api/v1/events
GET    /api/v1/events/stream

Public (no auth): GET /api/v1 · GET /openapi.yaml · GET /healthz · GET /readyz · GET /metrics.

OpenAPI 3.1: openapi.yaml — also served live at /openapi.yaml.


Integrating from other projects

Kryton is designed for Zyvor products (Axiom, Haven, automation) to drive Windows VMs over HTTP.

# 1. Discover the surface (no token required)
curl -sS "$KRYTON_URL/api/v1" | jq .

# 2. Fetch OpenAPI for codegen
curl -sS "$KRYTON_URL/openapi.yaml" -o kryton.openapi.yaml

# 3. Call authenticated APIs
curl -sS -H "Authorization: Bearer $KRYTON_TOKEN" \
  "$KRYTON_URL/api/v1/machines?project=default"

CORS — set KRYTON_CORS_ORIGINS to the calling app origins (comma-separated), or * in lab:

Environment=KRYTON_CORS_ORIGINS=https://axiom.example,https://haven.example

Auth for service-to-service:

Mode How
apikey Authorization: Bearer <token> — create with AUTH.md; hash with krytonctl hash-token for keys.json
proxy Edge sets X-Kryton-User, X-Kryton-Role, X-Kryton-Projects, X-Kryton-Proxy-Secret
disabled Lab only (KRYTON_ALLOW_INSECURE=true)
# Lab shortcut
export KRYTON_TOKEN=$(cat ~/.kryton/lab.token)
# or: export KRYTON_TOKEN=$(ssh user@host 'cat ~/.kryton/lab.token')

Minimal create flow:

curl -sS -X POST "$KRYTON_URL/api/v1/machines" \
  -H "Authorization: Bearer $KRYTON_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "project": "default",
    "name": "win-app01",
    "image": "windows-11-enterprise",
    "compute": {"cpu": 4, "memoryMiB": 8192},
    "disk": {"sizeGiB": 80, "storageClass": "rook-ceph-block"}
  }'

Watch progress via GET /api/v1/jobs or GET /api/v1/events/stream (SSE).

CLI equivalent: KRYTON_URL=… KRYTON_TOKEN=… krytonctl ….


Projects

GET /api/v1/projects returns the configured project list and default project.


Capabilities

Browser consoles (iframes, new tabs, websockets) can't send an Authorization header. POST /api/v1/machines/{id}/console-ticket (viewer role) returns a 10-minute signed ticket; append it as ?console_ticket= to that machine's /console or /vnc URL. Krytond also sets it as an HttpOnly, SameSite=Strict cookie scoped to /api/v1/machines/{id}/ so console sub-resources and reconnects keep working. A ticket only grants GET on that one machine's console paths, and every ticket is invalidated when krytond restarts.

GET /api/v1/capabilities reports what the active provider supports (start/stop, snapshots, console, etc.). Use this to build provider-aware UIs without hard-coding behavior.


Doctor

GET /api/v1/doctor runs environment diagnostics and returns a structured report:

{
  "healthy": true,
  "provider": "dockur",
  "findings": [
    {"check": "auth", "status": "pass", "message": "Auth mode apikey"},
    {"check": "kvm", "status": "pass", "message": "/dev/kvm is available"}
  ]
}

Finding status values: pass · warn · fail. CLI equivalent: krytonctl doctor.


Images

GET /api/v1/images returns the catalog. Each entry includes minimum CPU/memory, disk size, and (for dockur) a dockurVersion mapping.


Machines

List and get

GET /api/v1/machines?project=default returns machines in the project, paginated:

Param Default Notes
limit 50 Max items per page, capped at 500
cursor (none) Opaque value from the previous response's nextCursor; omit for the first page
{
  "items": [ { "id": "…", "…": "…" } ],
  "nextCursor": "MzY5Y2E3MzctOGJmYy00YTY0LWEyNGUtYzJhMzIwMTgyNzFh"
}

nextCursor is absent on the last page. Machines are ordered by ID for a stable sort across pages — the provider itself gives no ordering guarantee.

GET /api/v1/machines/{id}?project=default returns a single machine.

Machine object

Field Type Description
id string Stable Kryton UUID
project string Project scope
provider string demo · dockur · kubevirt
state string Lifecycle state
spec object Desired configuration
providerRef object Provider-specific reference
ipAddresses string[] Guest IPs when known
consoleUrl string Web console URL (dockur/demo)
progressPercent int Install progress 0–100
message string Human-readable status
conditions array Structured conditions
createdAt / updatedAt timestamp Audit timestamps
expiresAt timestamp TTL expiry when set

Create

POST /api/v1/machines

{
  "project": "default",
  "name": "finance-win01",
  "image": "windows-server-2025",
  "compute": {"cpu": 4, "memoryMiB": 8192},
  "disk": {"sizeGiB": 80},
  "network": {"networkId": ""},
  "ttlMinutes": 0
}

Validate CPU and memory against the image catalog minimums. Names must be DNS-style labels (≤ 63 characters).

Linux templates (ubuntu-26.04, ubuntu-24.04, ubuntu-22.04, debian-13, debian-12, rocky-10, rocky-9, almalinux-10, almalinux-9, centos-stream-10, fedora-44) take the same body plus an optional initialization block, rendered into cloud-init. Guests are password-locked, so supply at least one key to log in:

{
  "project": "default",
  "name": "linux-dev",
  "image": "ubuntu-24.04",
  "compute": {"cpu": 2, "memoryMiB": 2048},
  "disk": {"sizeGiB": 20},
  "initialization": {
    "username": "ubuntu",
    "sshAuthorizedKeys": ["ssh-ed25519 AAAA... you@laptop"]
  }
}

Linux machines run on the libvirt or kubevirt provider; see LINUX-TEMPLATES.md.

Lifecycle actions

Action Method Path
Start POST /api/v1/machines/{id}/start?project=…
Stop POST /api/v1/machines/{id}/stop?project=…
Snapshot POST /api/v1/machines/{id}/snapshot?project=…
List snapshots GET /api/v1/machines/{id}/snapshots?project=…
Restore snapshot POST /api/v1/machines/{id}/snapshots/{sid}/restore?project=…
Delete snapshot DELETE /api/v1/machines/{id}/snapshots/{sid}?project=…
Delete DELETE /api/v1/machines/{id}?project=…

Events

GET /api/v1/events returns recent CloudEvents history.

GET /api/v1/events/stream opens an SSE stream for live lifecycle updates.

Common event types:

Type When
io.kryton.machine.created Machine record created
io.kryton.machine.install.started Dockur install begins
io.kryton.machine.started Machine running
io.kryton.machine.stopped Machine stopped
io.kryton.snapshot.created Snapshot requested
io.kryton.snapshot.restored Restore requested
io.kryton.snapshot.deleted Snapshot deleted

Errors

All errors use a consistent envelope:

{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "name must be a DNS-style label up to 63 characters",
    "requestId": "..."
  }
}

Common codes: INVALID_REQUEST · NOT_FOUND · FORBIDDEN · CONFLICT · INTERNAL_ERROR · RATE_LIMITED.


Rate limiting

Set KRYTON_RATE_LIMIT_RPS (and optionally KRYTON_RATE_LIMIT_BURST) to cap requests per caller — a token bucket keyed by API-key name (or remote address when auth is disabled). Disabled by default (KRYTON_RATE_LIMIT_RPS=0). Exceeding the limit returns 429 with error.code: "RATE_LIMITED"; back off and retry.


Authentication

API key mode — send Authorization: Bearer <token>.

Proxy mode — the reverse proxy sets:

  • X-Kryton-User
  • X-Kryton-Role (viewer · operator · admin)
  • X-Kryton-Projects (comma-separated)
  • X-Kryton-Proxy-Secret (shared secret)

Roles are always intersected with project scope.