Base URL: https://<first-master-ip>:31007 (see k7 api status / k7 api endpoint).
Transport#
The NodePort is served over HTTPS by default. On the default install the certificate is signed by a playbook-minted cluster CA at /etc/k7/tls/ca.crt on the node — copy it to your client and trust it (curl --cacert ca.crt …, Client(..., verify_ssl="ca.crt"), k7 config set api.ca ca.crt). Clusters installed with --api-hostname present a Let’s Encrypt certificate; --api-tls-cert/--api-tls-key an operator-supplied one; --api-insecure-http serves plain http://. Disabling verification on an https:// URL is rejected by the CLI and SDK. See Security model.
Authentication#
Two kinds of credential are accepted:
Tokens starting k7_ (and the X-API-Key header) always take the API-key path; anything else on Authorization: Bearer is validated as an OIDC JWT against the configured issuer (RS256/ES256, iss, aud, exp, sub required). A bad key is never retried as OIDC.
Every principal resolves to a role: read-only or user inside one tenant, or operator / admin cluster-wide. API keys carry their role (k7 generate-api-key --role …); OIDC subjects get theirs from the role bindings (PUT /api/v1/role-bindings). One PERMISSIONS table maps every route to the roles that may call it. Checks compose — route role, then tenant, then the key’s namespace / node narrowing — and the first failure is a 403 naming the missing role or scope. See Tenants, roles and OIDC.
All endpoints return standard HTTP codes. 401 Unauthorized if the credential is missing, invalid or expired. 403 Forbidden if the role does not cover the route (a read-only key calling exec, a user key reading GET /api/v1/nodes/storage), if a tenant key touches another tenant’s namespace or an all-namespaces operation, or if a create exceeds a tenant quota (QuotaExceeded). In production mode, keys without a tenant or cluster role (pre-0.5 unscoped_legacy keys) get 403 on every route until re-issued.
Every response carries X-Request-ID (echoed in the audit log) and X-K7-Mode (production or development).
Response envelope#
Successful responses:
Errors:
Common error codes:
BadRequest(400): Invalid input or missing parametersUnauthorized(401): Missing or invalid API keyForbidden(403): role, tenant or namespace/node scope does not cover the requestQuotaExceeded(403): tenant quota hit —messagenames the dimension, limit, usage and requestLimitNotEnforceable(400): a configured tenant limit (diskIO,networkon k7d / k7d-fc,diskquota on k7d / k7d-fc) cannot be enforced by the backend, so the create is refused rather than running unlimitedNotFound(404): Resource was not foundConflict(409): Resource already existsUnprocessableEntity(422): Validation failedTenantConflict(500): a namespace is claimed by twoTenantobjects (only possible by hand-written CRs)InternalServerError(500): Unhandled errorPrometheusUnavailable(502):/usagecould not query Prometheus503 Service Unavailable: the API refuses rather than guesses — key-store snapshot older than 60 s, OIDC JWKS refresh failed, quota Lease not acquired within 5 s (QuotaLockTimeout/QuotaLockLost), a transient create failure such as the registry allowlist’s DNS not resolving, or a usage spool above its high-water mark with--metering-require-delivery(UsageSpoolFull)
Headers#
Required headers for requests with body:
Authentication headers (either):
Resources#
- Sandboxes: create, list, get, delete, delete-all, pause, resume, fork
- Exec: run a command in a sandbox and get stdout/stderr/exit_code
- Metrics: CPU and memory usage per sandbox
- Snapshots: list, inspect, create, delete, restore, GC
- Identity: who am I, OIDC discovery, API keys, role bindings
- Tenants: namespaces, quotas, defaults, dedicated nodes; usage showback
- Nodes: storage pools, dedication; remote install (opt-in)
Endpoints at a glance#
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/sandboxes | Create sandbox |
| GET | /api/v1/sandboxes | List sandboxes |
| GET | /api/v1/sandboxes/{name} | Get one sandbox |
| DELETE | /api/v1/sandboxes/{name} | Delete one sandbox |
| DELETE | /api/v1/sandboxes | Delete all in namespace |
| POST | /api/v1/sandboxes/{name}/exec | Run a command, get stdout/stderr/exit |
| GET | /api/v1/sandboxes/{name}/logs | Snapshot of pod logs (no streaming yet) |
| POST | /api/v1/sandboxes/{name}/pause | Scale to 0, optionally snapshot the PVC |
| POST | /api/v1/sandboxes/{name}/resume | Scale back to 1 |
| POST | /api/v1/sandboxes/{name}/fork | Clone source into a new sandbox (kql: disk clone; k7d / k7d-fc: warm CoW fork) |
| POST | /api/v1/sandboxes/{name}/snapshot | Snapshot a running sandbox without pausing it |
| GET | /api/v1/snapshots | List VolumeSnapshots managed by k7 |
| GET | /api/v1/snapshots/{name} | Inspect one VolumeSnapshot |
| DELETE | /api/v1/snapshots/{name} | Delete a VolumeSnapshot |
| POST | /api/v1/snapshots/{name}/restore | Boot a new sandbox from a standalone VolumeSnapshot |
| POST | /api/v1/snapshots/gc | Sweep stale kind=fork snapshots |
| GET | /api/v1/sandboxes/metrics | CPU/memory metrics per sandbox |
| GET | /api/v1/nodes/storage | Per-node storage-pool utilization (kfd thin-pool + k7d disk pool). operator / admin |
| POST | /api/v1/nodes/{name}/dedicate | Label + taint a node for a tenant ({"tenant": "acme"}). operator / admin |
| POST | /api/v1/nodes/{name}/undedicate | Remove the dedication. operator / admin |
| GET | /api/v1/auth/whoami | Principal, role(s), tenant and scopes of the caller |
| GET | /api/v1/auth/oidc | OIDC discovery for k7 login (issuer, client id, scopes); 404 when OIDC is off |
| POST | /api/v1/keys | Mint an API key (admin). Same fields as k7 generate-api-key |
| GET | /api/v1/keys | List keys (admin) |
| DELETE | /api/v1/keys/{name} | Revoke a key (admin) |
| GET | /api/v1/role-bindings | OIDC subject → role bindings and deny-subjects (admin) |
| PUT | /api/v1/role-bindings | Replace them (admin) |
| GET | /api/v1/tenants | List tenants with quotas and reconciled usage (operator / admin) |
| POST | /api/v1/tenants | Create a tenant (admin) |
| GET | /api/v1/tenants/{name} | Get one tenant |
| PATCH | /api/v1/tenants/{name} | Replace spec sections (admin) |
| DELETE | /api/v1/tenants/{name} | Delete a tenant (admin) |
| GET | /api/v1/usage | Showback from Prometheus (tenant, from, to, group_by); a tenant key only sees its own tenant |
| POST | /api/v1/install | Remote node install via the k7-node-installer pool (admin; 404 unless installed with --api-remote-install) |
| GET | /api/v1/install/{operation} | Per-node status of a remote install operation |
Health endpoints:
GET /→ basic API infoGET /health→ health check; also reportsmode,key_storesync state,oidc_issuer,tenant_status_errorandmeteringflush state (details)
