Skip to content

REST API

The API listens on port 8080 of the operator pod (exposed by the kimo Service in a Helm install). All endpoints except /api/v1/health require authentication, which is handled by the active scoring backend — for the generic backend that means Authorization: Bearer <apiKey>.

All CRs live in the default namespace in the current release.

Health

GET /api/v1/health

Unauthenticated. Returns {"status": "ok"}.

Templates

GET /api/v1/templates
GET /api/v1/templates/{name}

List and fetch ChallengeTemplate objects — what a platform uses to render its challenge list. 404 if the named template doesn't exist.

Instances

Create an instance

POST /api/v1/instances
{
  "template": "demo-web",
  "team": "team-alpha",
  "player": "alice",
  "powChallenge": "a1b2...",
  "powNonce": 1048113
}
  • template and team are required; player is required in spirit for perPlayer templates (it becomes part of the instance name).
  • powChallenge/powNonce are required only when the template has PoW enabled — see Proof of work.
  • Instance names are deterministic: <template>-<team>[-<player>], which makes a second create for the same team a 409 instead of a duplicate pod.

Responses: 201 with the created instance · 400 missing fields · 404 unknown template · 409 template not ready or instance already exists · 428 PoW required/invalid · 429 template's maxInstances reached.

List / get / delete

GET    /api/v1/instances?team=<team>&challenge=<template>
GET    /api/v1/instances/{name}
DELETE /api/v1/instances/{name}

List supports filtering by team and challenge labels. Delete removes the instance and everything it owns (pod, service, network policy) and emits an instance.deleted event to the backend; returns 204.

The interesting field on a fetched instance is status:

{
  "phase": "Running",
  "endpoint": "demo-web-team-alpha.default.svc:8080",
  "startedAt": "2026-08-23T15:24:31Z",
  "expiresAt": "2026-08-23T16:24:31Z"
}

Extend an instance

PATCH /api/v1/instances/{name}/extend
{"ttl": "2h"}

Sets the instance's TTL override. The TTL is measured from startedAt, not from now — extending to 2h means the instance lives two hours total. Takes effect within one reconcile; an instance already in Expiring recovers to Running if the new expiry is in the future. 400 for an unparsable duration, 404 for an unknown instance.

Proof of work

GET /api/v1/pow/challenge?template=<name>

Returns a single-use puzzle for a PoW-enabled template:

{"challenge": "a1b2c3...", "difficulty": 20, "expiresAt": "2026-08-23T15:30:00Z"}

Webhooks

POST /api/v1/webhooks/configure
{"url": "https://scoreboard.example.com/events", "secret": "hmac-secret"}

Registers a webhook for lifecycle events (generic backend only — backends that don't support runtime webhook registration return an error). Events are signed with X-KIMO-Signature (hex HMAC-SHA256 of the request body using secret).