Reference For: developers

API conventions

Authentication, the error envelope, tasks, versions, compare-and-set and paging of the native REST API. English only.

This page describes what every operation of the native REST API has in common. The operations themselves are in the generated pages of the REST API reference. The API reference pages are in English in every language.

Requests and data

  • The controller serves the API over HTTPS on the address of [http] listen in controller.toml (port 8443 in the examples of this documentation). Every operation is under the path prefix /v1/.
  • Bodies are JSON. Field names are camelCase.
  • Object ids are strings such as vm-42 or host-7. Timestamps are RFC 3339 in UTC.
  • Every request may carry the header x-request-id. The controller uses its value as the correlation id of the request, or generates one. The id appears in the logs, in audit records and in the correlationId of an error, and an error response carries it in the header x-request-id.

Authentication

Every operation except the sign-in calls needs a bearer token in the Authorization header:

HTTP
GET /v1/about HTTP/1.1
Host: controller.example.com:8443
Authorization: Bearer <token>

Without a token, or with an invalid one, the API answers 401 with the message id error.unauthenticated.

Programmatic login

POST /v1/identity/login takes a user name and a password and returns the session token:

JSON
{"username": "admin", "password": "<password>", "kind": "interactive"}

kind is interactive (the default) or api. The field outcome of the answer is one of:

OutcomeMeaning
sessionThe answer carries session, with the bearer token (shown once), sessionId, expiresAt and the user.
mfa_requiredThe account has two-step verification. The answer carries pendingToken; send it with the code to POST /v1/identity/mfa/complete.
mfa_enrolment_requiredThe session exists but is restricted until two-step verification is set up.

A session is restricted while the password must be changed or two-step verification must be set up. Other operations then fail with error.password_rotation_required or error.mfa_required, and the field passwordRotationRequired or mfaEnrolmentRequired of the session says which step is open. The self-service operations of the account, such as the password change and the set-up of two-step verification, still work.

kyvernon login is the same call. Login attempts are limited: too many attempts fail with 429, the message id error.auth.rate_limited and the header Retry-After.

API tokens

An API token is a long-lived credential for automation that cannot enter a code. Its form is kyvt_<id>_<secret>. An account has at most 16 tokens. A token is created with POST /v1/auth/api-tokens for the caller, or for another user with POST /v1/identity/users/{username}/api-tokens, and is shown once. To use it, send it as the password of POST /v1/identity/login with kind set to api; the answer is a session like any other. See Portal integration for a service account that holds a token.

Browser sessions

The web console signs in through the operations under /v1/auth/. They keep the access token in memory, a refresh token in the cookie kyv_refresh and check the header X-Kyvernon-CSRF. Clients other than a browser use the programmatic login.

Errors

A failed request returns an HTTP status and one flat JSON body, for example:

JSON
{
  "code": "NOT_FOUND",
  "message": "virtual machine vm-99 not found",
  "messageId": "error.not_found",
  "args": {},
  "correlationId": "9d1f4c0e-7a53-4a8e-b2c4-3f6b8f0e7a11"
}
FieldMeaning
codeA stable code from the table below. Clients branch on it.
messageAn English text for developers. Do not show it to end users or parse it.
messageIdThe key of the message, for example error.not_found. Console and clients localise on it. A client treats an id it does not know like its code. It can be absent.
argsThe arguments of the message, as strings. The meaning of each is in the error codes.
correlationIdThe correlation id of the request. Give it to the administrator who reads the logs.
CodeHTTP statusMeaning
INVALID_ARGUMENT400The request is malformed or a value is out of range.
UNAUTHENTICATED401The caller is not authenticated or the session expired.
PERMISSION_DENIED403The caller lacks a required privilege.
NOT_FOUND404The object does not exist, or the caller may not know it does.
ALREADY_EXISTS409An object with the same unique key exists.
CONFLICT409The object changed since it was read (see compare-and-set below).
FAILED_PRECONDITION412The object is in a state that does not allow the operation.
RESOURCE_EXHAUSTED429A quota, a queue bound or a rate limit was reached. Try again later.
CANCELLED499The caller cancelled the operation.
INTERNAL500A bug or an I/O failure. The details are logged, not returned.
UNIMPLEMENTED501The operation is not implemented.
UNAVAILABLE503The service cannot answer now. Retrying is safe.
DEADLINE_EXCEEDED504The operation did not finish in time.

A few message ids use another status than their code: error.datastore_upload_too_large answers 413 and error.datastore_range_invalid answers 416. The full list of message ids, their arguments and their status is in the error codes. The gRPC API reports the same codes as gRPC status codes.

Tasks

An operation that takes time does not wait for the result. It answers 202 with a task reference, and the work continues in the controller:

JSON
{"taskId": "task-17"}

Follow the task with these operations:

OperationUse
GET /v1/tasks/{id}The task as it is now.
GET /v1/tasks/{id}/waitLong polling. The answer comes when the task has ended or after timeout seconds (default 30, at most 300). Either way the answer is 200 with the task, so a client asks again while the state is queued or running.
POST /v1/tasks/{id}/cancelCancels a task of the caller, or any task with the privilege Global.CancelTask.
GET /v1/tasksA page of tasks. Filters: target, state (comma-separated), user, chainId, since; order is asc (default) or desc.

The state of a task is queued, running, success, error or cancelled. A task has a progress from 0 to 100. On success result holds the payload of the operation, and some operations leave it empty. On failure error holds an error body as above, and retryable says whether the same request may succeed later. chainId groups the tasks and events of one action. The kyvernon command-line client does the polling with --wait.

A request is refused with RESOURCE_EXHAUSTED when the queue of the controller is full. The limits are in Configuration.

Versions and compare-and-set

  • The path prefix /v1/ is the version of the API. A client ignores fields and message ids it does not know.
  • GET /v1/about returns version (the build), apiVersion, whether the node is the leader and the current storeVersion. The OpenAPI document of each release carries its own version number, and every release of the documentation has the document to download in the REST API reference.
  • Every stored object has a version. An update that replaces or changes an object carries expectedVersion, the version the client read. When the object has changed since, the controller refuses the update with 409, the code CONFLICT and the message id error.conflict. Read the object again, apply the change to the new state and send it again. Updates of a virtual machine configuration are merged when the changes do not touch the same settings; when they cannot be merged the answer is 409 with error.vm.concurrent_modification.
  • Listings carry the store version they were read at. The change feed GET /v1/inventory/changes takes that value as since, and a client with resync: true in the answer lists again.

Paging

Operations that list many items return a page:

JSON
{"items": [], "version": 4182, "next": "<cursor>"}

limit is the largest number of items; the default is 100 and the maximum is 1000 for the operations that state it. next is a cursor. Send it as after in the next request, with the same filters and the same order. The last page has no next.

Version 0.1. Last changed: 2026-11-13