---
title: "Add node pool"
method: POST
path: "/api/v1/k8s/clusters/{cluster_id}/pools"
tags: ["Kubernetes"]
---

# Add node pool

`POST /api/v1/k8s/clusters/{cluster_id}/pools`

Add a node pool. Nodes deploy asynchronously; the pool is `running` once every node has joined.

On a pay-as-you-go cluster the new nodes accrue hourly. On a subscription cluster the API charges the pro-rated cost of the new pool to the saved payment method (balance first) and raises the monthly price; in the dashboard the addition goes through checkout.

## Path parameters

- `cluster_id` string, required

## Headers

- `X-Project-ID` string, uuid, required

## Request body

- AddK8sNodePoolRequest
  - `name` string, required
  - `node_count` integer, required
  - `plan_id` integer — Worker plan for this pool — pools may use different plans. Omit to inherit the first pool's plan.
  - `min_nodes` integer
  - `max_nodes` integer
  - `autoscale_enabled` boolean
  - `labels` string
  - `taints` string

## Response `201`

Node pool created

- object
  - `success` boolean
  - `node_pool` K8sNodePool
    - `id` string, uuid, required
    - `cluster_id` string, uuid
    - `name` string, required
    - `node_count` integer, required — Target node count
    - `actual_node_count` integer — Nodes that currently exist (differs from `node_count` while scaling)
    - `min_nodes` integer
    - `max_nodes` integer
    - `autoscale_enabled` boolean
    - `plan_id` integer
    - `cpu` integer
    - `ram` integer — GB
    - `disk` integer — GB
    - `labels` string
    - `taints` string
    - `status` 'pending' | 'provisioning' | 'running' | 'scaling' | 'failed' | 'deleting' | 'deleted', required — `scaling`/`deleting` are asynchronous — watch `status_message` for the outcome (e.g. a drain blocked by a PodDisruptionBudget)
    - `status_message` string
    - `nodes` K8sNode[]
      - `id` string, uuid
      - `pool_id` string, uuid
      - `cluster_id` string, uuid
      - `name` string
      - `role` 'vnf' | 'master' | 'worker' | 'storage' — `vnf` is the cluster's network gateway
      - `status` 'pending' | 'provisioning' | 'running' | 'not_ready' | 'cordoned' | 'failed' | 'deleting' | 'deleted' — `running` means the kubelet reports Ready; `cordoned` = unschedulable (drain or manual cordon); `not_ready` = joined but failing health checks
      - `cpu` integer
      - `ram` integer — GB
      - `disk` integer — GB
      - `ip_address` string
      - `price_per_hour` number, double
      - `created_at` string, date-time
      - `updated_at` string, date-time
    - `created_at` string, date-time
    - `updated_at` string, date-time

## Other responses

- `400` — Invalid request parameters
- `404` — Resource not found
- `409` — Subscription-billed cluster — add the pool via the dashboard

## Changes

- **2026-08-27** `119e4aec8f63` — 1 info
  - the `node_count` request property's min was decreased from `2.00` to `1.00`
- **2026-08-23** `72c803a128b2` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/rafftechnologies/apis/raff-api/changes/api/v1/k8s/clusters/:cluster_id/pools/post.md)

---

[API](https://skmtc.dev/rafftechnologies/apis/raff-api.md) · [All operations](https://skmtc.dev/rafftechnologies/apis/raff-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/rafftechnologies/raff-api/revisions/2f4df56be77c/schema)
