The module lifecycle stageGeneral Availability

API Capabilities

API documentation for external integration is available in the Deckhouse Commander interface in the settings menu in the upper right corner.

To use this API, you need to issue a token. The token is also issued in the Deckhouse Commander interface. The token must be passed in the X-Auth-Token header.

There are two types of tokens that have access to different methods in the API:

  • Global tokens that are issued on the workspace management page. Using global tokens, you can create workspaces and manage their role bindings.
  • Workspace tokens that are issued on the workspace page. Workspace tokens can be used to manage workspace entities (clusters, cluster templates, inventory catalogs, registries). Entity management is available only for the workspace in which it was issued.

What is available in the API when using a global token:

  1. View global roles
    1. GET /api/v1/global_roles
  2. Viewing and creating workspaces
    1. GET /api/v1/workspaces
    2. POST /api/v1/workspaces
  3. Create, change, delete bindings in workspaces
    1. GET /api/v1/workspace_role_bindings
    2. POST /api/v1/workspace_role_bindings
    3. GET /api/v1/workspace_role_bindings/:id
    4. PUT /api/v1/workspace_role_bindings/:id
    5. DELETE /api/v1/workspace_role_bindings/:id

What is available in the API when using the workspace token:

  1. Managing Cluster templates
    1. GET /api/v1/cluster_templates
    2. POST /api/v1/cluster_templates
    3. GET /api/v1/cluster_templates/:id
    4. PUT /api/v1/cluster_templates/:id
    5. DELETE /api/v1/cluster_templates/:id
  2. Reading inventory catalogs
    1. GET /api/v1/catalogs
    2. GET /api/v1/catalogs/:id
  3. Creating, modifying, deleting clusters
    1. POST /api/v1/clusters
    2. GET /api/v1/clusters
    3. GET /api/v1/clusters/:id
    4. PUT /api/v1/clusters/:id
    5. DELETE /api/v1/clusters/:id
  4. Creating, modifying, deleting catalog records
    1. POST /api/v1/records
    2. GET /api/v1/records
    3. GET /api/v1/records/:id
    4. PUT /api/v1/records/:id
    5. DELETE /api/v1/records/:id
  5. Creating, viewing, deleting registries
    1. POST /api/v1/registries
    2. GET /api/v1/registries
    3. GET /api/v1/registries/:id
    4. DELETE /api/v1/registries/:id
  6. Cluster tasks operations
    1. GET /api/v1/cluster_tasks
    2. GET /api/v1/cluster_task_logs

Create a workspace and assign a global role to users

Creating a workspace

curl -X 'POST' \
        "https://$COMMANDER_HOST/api/v1/workspaces" \
        -H 'accept: application/json' \
        -H "X-Auth-Token: $COMMANDER_GLOBAL_TOKEN" \
        -H 'Content-Type: application/json' \
        -d '{"name":"Workspace from API"}'
``

In response to the creation request, we will receive the workspace data. For subsequent requests, we will need its `id`.

```json
{
    "id": "088b8e03-e7c0-4655-aae7-d11b7609c579",
    "slug": "sftpp",
    "name": "Workspace from API",
    "comment": null,
    "main": false,
    "current_revision": 0,
    "created_at": "2026-01-15T12:19:57.002+03:00",
    "updated_at": "2026-01-15T12:19:57.002+03:00"
}

Getting a global role

To assign a global role to a user or group of users, you need to get the id of the global role.

curl -s -X 'GET' \
        "https://$COMMANDER_HOST/api/v1/global_roles" \
        -H 'accept: application/json' \
        -H "X-Auth-Token: $COMMANDER_GLOBAL_TOKEN"

We are interested in the id field of the required role:

[
  {
    "id": "818c3814-4973-452e-9985-d75fbe35eb4c",
    "name": "commander-admin",
    "comment": null,
    "labels": {
      "commander.deckhouse.io/owned-by": "commander"
    },
    "current_revision": 0,
    "commander_rules": [
      {
        "id": "455ccf46-f34c-4c75-970d-4dbc361adc68",
        "verbs": [
          "*"
        ],
        "resources": [
          "*"
        ],
        "resource_names": null,
        "created_at": "2025-04-30T23:46:18.616+03:00",
        "updated_at": "2025-04-30T23:46:18.616+03:00"
      }
    ],
    "kubernetes_rules": [
      {
        "id": "9713527d-69df-4ecb-9db2-35df194e18b5",
        "verbs": [
          "*"
        ],
        "resources": [
          "*"
        ],
        "resource_names": null,
        "api_groups": [
          "*"
        ],
        "created_at": "2025-06-06T16:56:32.208+03:00",
        "updated_at": "2025-06-06T16:56:32.208+03:00"
      }
    ],
    "created_at": "2025-04-30T23:46:18.567+03:00",
    "updated_at": "2025-04-30T23:46:18.567+03:00"
  }
]

Create a workspace binding

Now we can create a global role binding for the user in the created workspace:

PAYLOAD="$(jq -nc '{
    "workspace_id": "088b8e03-e7c0-4655-aae7-d11b7609c579",
    "name": "workspace-admins",
    "comment": "Role binding from API",
    "role": {
        "type": "GlobalRole",
        "id": "818c3814-4973-452e-9985-d75fbe35eb4c"
    },
    "subjects": [
        {
        "kind": "User",
        "name": "commander-admin@deckhouse.io"
        }
    ]
}')"
curl -X 'POST' \
        "https://$COMMANDER_HOST/api/v1/workspace_role_bindings" \
        -H 'accept: application/json' \
        -H "X-Auth-Token: $COMMANDER_GLOBAL_TOKEN" \
        -H 'Content-Type: application/json' \
        -d "$PAYLOAD"

We will receive a successful server response:

{
    "id": "05b3abdf-20a5-447b-823b-8e1a57b46158",
    "name": "workspace-admins",
    "comment": "Role binding from API",
    "current_revision": 0,
    "role_type": "GlobalRole",
    "role": {
        "id": "818c3814-4973-452e-9985-d75fbe35eb4c",
        "name": "commander-admin",
        "comment": null,
        "labels": {
            "commander.deckhouse.io/owned-by": "commander"
        },
        "current_revision": 0,
        "created_at": "2025-04-30T23:46:18.567+03:00",
        "updated_at": "2025-04-30T23:46:18.567+03:00"
    },
    "subjects": [
        {
            "kind": "User",
            "name": "commander-admin@deckhouse.io",
            "created_at": "2026-01-15T14:01:01.858+03:00",
            "updated_at": "2026-01-15T14:01:01.858+03:00"
        }
    ],
    "created_at": "2026-01-15T14:01:01.821+03:00",
    "updated_at": "2026-01-15T14:01:01.821+03:00"
}

Adding a user group to a role binding

The API allows you to add and remove users and user groups in workspace bindings.

As an example, let’s add a user group to an existing role binding:

PAYLOAD="$(jq -nc '{
    "current_revision": 0,
    "subjects": [
        {
          "kind": "User",
          "name": "commander-admin@deckhouse.io"
        },
        {
          "kind": "Group",
          "name": "Administrators"
        }
    ]
    }')"
curl -X 'PUT' \
        "https://$COMMANDER_HOST/api/v1/workspace_role_bindings/05b3abdf-20a5-447b-823b-8e1a57b46158" \
        -H 'accept: application/json' \
        -H "X-Auth-Token: $COMMANDER_GLOBAL_TOKEN" \
        -H 'Content-Type: application/json' \
        -d "$PAYLOAD"

We get a successful response with the modified list of subjects:

{
    "id": "05b3abdf-20a5-447b-823b-8e1a57b46158",
    "name": "workspace-admins",
    "comment": null,
    "current_revision": 1,
    "role_type": "GlobalRole",
    "role": {
        "id": "818c3814-4973-452e-9985-d75fbe35eb4c",
        "name": "commander-admin",
        "comment": null,
        "labels": {
            "commander.deckhouse.io/owned-by": "commander"
        },
        "current_revision": 0,
        "created_at": "2025-04-30T23:46:18.567+03:00",
        "updated_at": "2025-04-30T23:46:18.567+03:00"
    },
    "subjects": [
        {
            "kind": "Group",
            "name": "Administrators",
            "created_at": "2026-01-15T14:15:04.020+03:00",
            "updated_at": "2026-01-15T14:15:04.020+03:00"
        },
        {
            "kind": "User",
            "name": "commander-admin@deckhouse.io",
            "created_at": "2026-01-15T14:01:01.858+03:00",
            "updated_at": "2026-01-15T14:01:01.858+03:00"
        }
    ],
    "created_at": "2026-01-15T14:01:01.821+03:00",
    "updated_at": "2026-01-15T14:15:03.991+03:00"
}

Creating a Cluster using a Record from the Catalog

Let’s look at some fields of a cluster template:

curl -s -X 'GET' \
        'https://$COMMANDER_HOST/api/v1/cluster_templates?without_archived=true' \
        -H 'accept: application/json' \
        -H 'X-Auth-Token: $COMMANDER_TOKEN' |
        jq -r '.[] | select(.name == "YC Dev") | keys'
[
  "id",                                   # ID of the template.
  "name",                                 # Name of the template.

  "current_cluster_template_version_id",  # ID of the current available version of the template.

  "cluster_template_versions",            # List of versions of the template, with content of go-template and description of input parameters.

  "comment",                              # Comment on the template.
]

To create a cluster, we need the ID of the version of the template. We’ll take the latest version. In this example, we’ll select the template by name and take its field current_cluster_template_version_id:

curl -s -X 'GET' \
        'https://$COMMANDER_HOST/api/v1/cluster_templates?without_archived=true' \
        -H 'accept: application/json' \
        -H 'X-Auth-Token: $COMMANDER_TOKEN' |
        jq -r '.[] | select(.name == "YC Dev") | del(.cluster_template_versions)'
{
  "id": "fb999a72-efe7-4db7-af53-11b17bc0a687",
  "name": "YC Dev",
  "current_cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
  "comment": "",
  "current_revision": 12,
  "immutable": false,
  "created_at": "2024-02-05T17:35:44.318+03:00",
  "updated_at": "2024-04-10T18:00:57.835+03:00",
  "archived_at": null,
  "archive_number": null
}

Let’s get the scheme of input parameters and make sure that there is a record from the yandex-cloud-slot catalog among them.

curl -s -X 'GET' \
    'https://$COMMANDER_HOST/api/v1/cluster_templates?without_archived=true' \
    -H 'accept: application/json' \
    -H 'X-Auth-Token: $COMMANDER_TOKEN' |
    jq -r '
        .[] | select(.name == "YC Dev")
        | .cluster_template_versions[0] | select(.id == "8e75210a-f05c-421d-84b3-fc0697814d6d")
        | .params'

The scheme includes three mandatory parameters, including a record from the yandex-cloud-slot catalog (the catalog field):

[
  {
    "header": "Cluster Parameters"
  },
  {
    "key": "slot",
    "span": 4,
    "title": "Slot for cluster in Yandex Cloud",
    "catalog": "yandex-cloud-slot",
    "immutable": true
  },
  {
    "key": "releaseChannel",
    "enum": [ "Alpha", "Beta", "EarlyAccess", "Stable", "RockSolid" ],
    "span": 1,
    "title": "Update channel",
    "default": "EarlyAccess"
  },
  {
    "key": "kubeVersion",
    "enum": [ "Automatic", "1.25", "1.26", "1.27", "1.28", "1.29" ],
    "span": 1,
    "title": "Kubernetes version",
    "default": "Automatic"
  }
]

Let’s find a record from this catalog. First, we’ll determine the catalog ID by its identifier (slug).

curl -s -X 'GET' \
    'https://$COMMANDER_HOST/api/v1/catalogs?without_archived=true' \
    -H 'accept: application/json' \
    -H 'X-Auth-Token: $COMMANDER_TOKEN' |
    jq -r  '.[] | select(.slug == "yandex-cloud-slot") | .id'

7a620f64-852c-4595-b41e-364dad7c3e61

Now, we’ll choose the record from this catalog that is not already taken by another cluster:

curl -s -X 'GET' \
    'https://$COMMANDER_HOST/api/v1/records?without_archived=true' \
    -H 'accept: application/json' \
    -H 'X-Auth-Token: $COMMANDER_TOKEN' |
    jq -r  '[
    .[] |
    select(
            .catalog_id == "7a620f64-852c-4595-b41e-364dad7c3e61"
            and
            .cluster_id == null
    )
    ][0]'

From the received record, we will need the values content and ID:

{
  "id": "5f6727e7-630c-4b18-bcf0-868ea96a27ee",
  "current_revision": 10,
  "catalog_id": "7a620f64-852c-4595-b41e-364dad7c3e61",
  "cluster_id": null,
  "values": {
    "ip": "118.166.177.188",
    "name": "x"
  },
  "schema_matches": true,
  "created_at": "2024-04-03T12:50:07.266+03:00",
  "updated_at": "2024-04-17T16:51:33.200+03:00",
  "archived_at": null,
  "archive_number": null
}

Now we can create a cluster. For the record, we use the ID in the special field x-commander-record-id so as not to set a limit on the id field, which may be required by users in records:

curl -X 'POST' \
  'https://$COMMANDER_HOST/api/v1/clusters' \
  -H 'accept: application/json' \
  -H 'X-Auth-Token: $COMMANDER_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Cluster created by API",
  "cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
  "values": {
      "kubeVersion": "1.29",
      "releaseChannel": "EarlyAccess",
      "slot": {
         "x-commander-record-id": "5f6727e7-630c-4b18-bcf0-868ea96a27ee",
         "ip": "118.166.177.188",
         "name": "x"
       }
   }
}'

In response to the creation request, cluster data will arrive. We omitted some fields in the example below for brevity, including the rendered configuration:

{
    "id": "5436e6ef-d811-472f-9c9c-46cb9c6321d9",
    "name": "Cluster from API",
    "values": {
        "slot": {
            "ip": "118.166.177.188",
            "name": "x",
            "x-commander-record-id": "5f6727e7-630c-4b18-bcf0-868ea96a27ee"
        },
        "kubeVersion": "1.29",
        "releaseChannel": "EarlyAccess"
    },
    "cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
    "was_created": false,
    "status": "new"
}

Now let’s trace the process of cluster creation. We have to wait for the ‘in_sync’ status:

cluster_status="$(curl -s -X 'GET' \
    'https://$COMMANDER_HOST/api/v1/clusters/5436e6ef-d811-472f-9c9c-46cb9c6321d9' \
    -H 'accept: application/json' \
    -H 'X-Auth-Token: $COMMANDER_TOKEN' |
    jq -r '.status')"

while [ "in_sync" != "$cluster_status" ]
do
    cluster_status="$(curl -s -X 'GET' \
        'https://$COMMANDER_HOST/api/v1/clusters/5436e6ef-d811-472f-9c9c-46cb9c6321d9' \
        -H 'accept: application/json' \
        -H 'X-Auth-Token: $COMMANDER_TOKEN' |
        jq -r '.status')"
    echo $cluster_status
    sleep 5
done

creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
creating
# ...
in_sync