Skip to content

Create a Cluster

Creation locks in name, type, and whether the cluster runs an HA control plane. Size and Kubernetes version can be changed later with a PATCH. type currently only accepts shared, so most requests can omit it. High availability (highAvailability) is opt-in and is a create-time-only setting: toggling it in either direction via PATCH is rejected. See High Availability for the full field and billing details.

For the complete request and response schema, see the Reference: clusters section.

POST /api/v1/tenants/{tenant}/clusters
Terminal window
export KUPE_TENANT="<tenant>"
curl -X POST \
-H "Authorization: Bearer $KUPE_API_KEY" \
-H "Content-Type: application/json" \
"https://api.kupe.cloud/api/v1/tenants/$KUPE_TENANT/clusters" \
-d '{
"name": "production",
"type": "shared",
"version": "1.31",
"resources": {
"cpu": "4",
"memory": "16Gi",
"storage": "100Gi"
}
}'
FieldRequiredMutableDescription
nameYesNoUnique cluster name.
displayNameNoNoDeprecated. Accepted for backward compatibility and ignored; the cluster name is the display name everywhere (console, CLI, kubeconfig contexts). Responses echo name here.
typeNoNoshared (the standard multi-tenant model) is the default and currently the only accepted value; it may be omitted. dedicated is reserved for a future release and is rejected today.
versionNoYesKubernetes version such as 1.31.
resourcesNoYesCPU, memory, and storage limits in Kubernetes quantity format (4, 16Gi, 100Gi).
alertsNoYesAlert configuration overrides, if you are already managing them through the API.

201 Created with the cluster object and an ETag header for use with later PATCH requests:

{
"name": "production",
"displayName": "production",
"type": "shared",
"version": "1.31",
"resources": { "cpu": "4", "memory": "16Gi", "storage": "100Gi" },
"status": { "phase": "Pending" },
"resourceVersion": "12345",
"createdAt": "2026-04-06T12:00:00Z"
}

The cluster is provisioned asynchronously: status.phase starts at Pending and progresses through Provisioning to Running.

Poll the GET endpoint until status.phase reaches Running. The script below has a 15-minute timeout and exits non-zero if it times out, so it is safe to use in CI:

Terminal window
export KUPE_TENANT="<tenant>"
export KUPE_CLUSTER="production"
TIMEOUT_SECONDS=900 # 15 minutes
INTERVAL=10
ELAPSED=0
while [ "$ELAPSED" -lt "$TIMEOUT_SECONDS" ]; do
PHASE=$(curl -s \
-H "Authorization: Bearer $KUPE_API_KEY" \
"https://api.kupe.cloud/api/v1/tenants/$KUPE_TENANT/clusters/$KUPE_CLUSTER" \
| jq -r '.status.phase')
echo "Phase: $PHASE (elapsed ${ELAPSED}s)"
case "$PHASE" in
Running)
echo "Cluster is ready"
exit 0
;;
Degraded)
# Degraded means the control plane is unhealthy; it may still recover on
# its own. There is no terminal Failed/Error phase, so keep polling and let
# the timeout below decide when to give up.
echo "Cluster is Degraded, still waiting..." >&2
;;
esac
sleep "$INTERVAL"
ELAPSED=$((ELAPSED + INTERVAL))
done
echo "Timed out waiting for cluster after ${TIMEOUT_SECONDS}s" >&2
exit 1

Once the cluster is Running, fetch its API endpoint and CA certificate:

Terminal window
curl -s \
-H "Authorization: Bearer $KUPE_API_KEY" \
"https://api.kupe.cloud/api/v1/tenants/$KUPE_TENANT/clusters/$KUPE_CLUSTER/connection-details"

This endpoint returns connection details, not a full interactive user kubeconfig blob. See Reference: cluster connection details for the exact response shape.

Only members with the admin role can create clusters. A 403 Forbidden is returned for readonly keys or members.