Skip to main content

Kubernetes clusters API endpoints

These endpoints manage Cloider Kubernetes clusters: create them, follow their status, pause and resume them, download their kubeconfig, run kubectl and helm commands in them, and delete them. Inside a cluster you use the standard Kubernetes API with the kubeconfig, not these endpoints.

All paths are relative to https://cloider.com/api. See Authentication for the token header.

At a glance​

MethodPathAccess
GET/clustersRead
POST/clustersWrite
GET/clusters/:hashed_id/statusRead
GET/clusters/:hashed_id/kubeconfigRead
POST/clusters/:hashed_id/pauseWrite
POST/clusters/:hashed_id/resumeWrite
DELETE/clusters/:hashed_idWrite
GET/clusters/servicesRead
POST/clusters/:hashed_id/execWrite
GET/clusters/:hashed_id/terminalWrite

The cluster object​

{
"hashed_id": "k3x9p",
"cluster_name": "staging",
"cluster_label": "staging",
"cluster_version": "1.34",
"is_ha": false,
"status": "Ready",
"created_at": "2026-10-12T10:22:41.502113Z"
}
FieldTypeDescription
hashed_idstringThe cluster's id, used in every other cluster endpoint
cluster_namestringThe name you gave it. Names can repeat within an account
cluster_labelstringA name that is unique among the account's clusters: the name, or the name with -1, -2 and so on when it is taken
cluster_versionstringThe Kubernetes minor version, for example 1.34
is_habooleanWhether the control plane is highly available. Always false today
statusstringSee the table below
created_atstringWhen the cluster was created, RFC 3339

Cluster statuses​

StatusMeaningNext
CreatingThe control plane is being provisionedStarting
StartingStarting up after a create or a resumeReady
ReadyRunning. The kubeconfig works
PausingBeing pausedPaused
PausedStopped. Workloads don't run, data is keptStarting after a resume
TerminatingBeing deletedTerminated
TerminatedDeleted. No longer listed by GET /clusters
FailedSomething went wrong. Contact support

Status values covers every product's statuses.

List clusters​

GET /clusters

Returns the account's clusters, newest first. Deleted (Terminated) clusters aren't included.

Access: any token.

curl https://cloider.com/api/clusters \
-H "Authorization: Bearer $CLOIDER_TOKEN"
Response
[
{
"hashed_id": "p8w2d",
"cluster_name": "production",
"cluster_label": "production",
"cluster_version": "1.34",
"is_ha": false,
"status": "Ready",
"created_at": "2026-10-14T08:02:19.661034Z"
},
{
"hashed_id": "k3x9p",
"cluster_name": "staging",
"cluster_label": "staging",
"cluster_version": "1.33",
"is_ha": false,
"status": "Paused",
"created_at": "2026-10-12T10:22:41.502113Z"
}
]

To find a cluster's id by its label in a script:

CLUSTER_ID=$(curl -s https://cloider.com/api/clusters \
-H "Authorization: Bearer $CLOIDER_TOKEN" \
| jq -r '.[] | select(.cluster_label == "staging") | .hashed_id')

Create a cluster​

POST /clusters

Creates a cluster and starts provisioning it. The request returns as soon as the cluster is recorded, with its id; the cluster then goes from Creating to Starting to Ready, which usually takes a few minutes. Poll its status until it is Ready.

Access: Read & Write token.

Request body​

FieldTypeRequiredDescription
cluster_namestringYes2 or more characters: lower case letters, digits and -. Must start with a letter, not end with -, no spaces
cluster_versionstringYesOne of the versions in GET /options cluster_versions, today 1.34, 1.33 or 1.32. There is no default in the API
is_habooleanNoMust be false or left out. true is refused
curl -X POST https://cloider.com/api/clusters \
-H "Authorization: Bearer $CLOIDER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cluster_name": "staging", "cluster_version": "1.34"}'
Response
{"hashed_id": "k3x9p"}

If the account already has a cluster labelled staging, the new one is created anyway and labelled staging-1. Creating is not idempotent: sending the request twice creates two clusters.

Errors​

StatusFieldMessage
400cluster_nameCluster name must not be empty, Cluster name must not have spaces, Cluster name can not be upper case, Cluster name can not start with numbers, Cluster name must not have special characters except "-", Cluster name must not start with any special character, Cluster name must not end with any special character, Cluster name must be at least 2 characters
400cluster_versionInvalid cluster version!
400is_haHA clusters are not supported at the moment!
400_Free plan users can not create more than one cluster. UPGRADE NOW!
400_Your account is suspended. Upgrade to a paid plan to continue using our services.
400_You have read-only access to this account, you can not create clusters! (a Restricted member)
403_This API token is read only!

Wait until a cluster is ready​

CLUSTER_ID=$(curl -s -X POST https://cloider.com/api/clusters \
-H "Authorization: Bearer $CLOIDER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cluster_name": "staging", "cluster_version": "1.34"}' | jq -r .hashed_id)

while true; do
STATUS=$(curl -s https://cloider.com/api/clusters/$CLUSTER_ID/status \
-H "Authorization: Bearer $CLOIDER_TOKEN")
echo "status: $STATUS"
[ "$STATUS" = "Ready" ] && break
[ "$STATUS" = "Failed" ] && exit 1
sleep 5
done

The CLI does the same with cloider cluster create staging --wait.

Get a cluster's status​

GET /clusters/:hashed_id/status

Returns the cluster's status as plain text, for example Ready. It is the cheapest way to poll a cluster.

Access: any token.

Path parameterDescription
hashed_idThe cluster's id
curl https://cloider.com/api/clusters/k3x9p/status \
-H "Authorization: Bearer $CLOIDER_TOKEN"
Response
Ready

A deleted cluster keeps answering Terminated. An id that doesn't exist, or belongs to another account, answers 404 with the plain text body Not Found.

Download the kubeconfig​

GET /clusters/:hashed_id/kubeconfig

Returns the cluster's kubeconfig file, which kubectl, helm and every Kubernetes client use to reach the cluster's API with admin rights. The body is the YAML file, sent as a download named config.

Access: any token, including read only tokens. The kubeconfig grants full control of the cluster, so treat the token, and the file, as secrets.

curl -s https://cloider.com/api/clusters/k3x9p/kubeconfig \
-H "Authorization: Bearer $CLOIDER_TOKEN" \
-o staging.kubeconfig

chmod 600 staging.kubeconfig
KUBECONFIG=staging.kubeconfig kubectl get nodes

The kubeconfig is ready once the cluster is Ready; before that the body can be empty. Its server address is the cluster's own API endpoint, https://<name>-<id>.cloider.com. Connect with kubectl explains how to merge it with other contexts.

Pause a cluster​

POST /clusters/:hashed_id/pause

Pauses a cluster: its workloads stop and its data and configuration are kept. The cluster goes to Pausing, then Paused. While paused it isn't billed for compute; see Pause and resume for what a paused cluster costs.

Access: Read & Write token.

curl -X POST https://cloider.com/api/clusters/k3x9p/pause \
-H "Authorization: Bearer $CLOIDER_TOKEN"

The response is the account's cluster list, with this cluster now Pausing:

Response
[
{
"hashed_id": "k3x9p",
"cluster_name": "staging",
"cluster_label": "staging",
"cluster_version": "1.34",
"is_ha": false,
"status": "Pausing",
"created_at": "2026-10-12T10:22:41.502113Z"
}
]

Poll GET /clusters/k3x9p/status until it says Paused. Pause only a Ready cluster: the endpoint doesn't check the current status, so pausing a cluster that is still being created or already paused only confuses its status.

StatusMessage
403This API token is read only!
403You have read-only access to this account, ... (a Restricted member)
404Not Found (plain text)

Resume a cluster​

POST /clusters/:hashed_id/resume

Starts a paused cluster again. It goes to Starting, then Ready, with the same API endpoint, kubeconfig and data as before.

Access: Read & Write token.

curl -X POST https://cloider.com/api/clusters/k3x9p/resume \
-H "Authorization: Bearer $CLOIDER_TOKEN"

The response is the cluster list, with this cluster Starting. Poll the status until it is Ready. Resume only a Paused cluster. Errors are the same as for pausing.

Delete a cluster​

DELETE /clusters/:hashed_id

Deletes a cluster with everything in it: workloads, persistent volumes and load balancers. This can't be undone. The cluster goes to Terminating, then Terminated, and disappears from GET /clusters.

Access: Read & Write token.

curl -X DELETE https://cloider.com/api/clusters/k3x9p \
-H "Authorization: Bearer $CLOIDER_TOKEN"

The response is the cluster list, with this cluster Terminating. To wait for the deletion, poll GET /clusters/k3x9p/status until it says Terminated.

StatusMessage
403This API token is read only!
403You have read-only access to this account, you can not delete clusters!
404Not Found (plain text)

See Delete a cluster before you delete one with data you need.

List services in your clusters​

GET /clusters/services

Returns the Kubernetes Services of every cluster in the account, with their namespace and ports. It is what the dashboard offers when you route a domain path to a cluster service with a target.

Access: any token.

curl https://cloider.com/api/clusters/services \
-H "Authorization: Bearer $CLOIDER_TOKEN"
Response
[
{
"id": "k3x9p",
"name": "staging",
"services": [
{
"service": "web",
"namespace": "default",
"ports": [{"protocol": "TCP", "port": 80}]
},
{
"service": "api",
"namespace": "shop",
"ports": [{"protocol": "TCP", "port": 8080}]
}
]
}
]
FieldDescription
idThe cluster's hashed_id
nameThe cluster's name
servicesEach Service with its service name, namespace and ports (protocol, port)

The services are read live from the clusters, so the request takes longer than most. When there are no clusters the body can be null instead of []. If the clusters can't be read, the answer is 502 with the plain text Failed to fetch data.

Run a command with exec​

POST /clusters/:hashed_id/exec

Runs one command in the cluster's terminal environment, where kubectl and helm are installed and already pointed at the cluster, and streams back its output and exit code. It is meant for scripts and AI agents that want the output of a command rather than an interactive shell. cloider cluster exec uses it.

Access: Read & Write token. The cluster must be Ready.

Request body​

FieldTypeRequiredDescription
commandstring listYesThe program and its arguments, for example ["kubectl", "get", "pods", "-A"]. Run directly, not through a shell. Up to 64 KiB in total, no NUL bytes
stdinstring (base64)NoBytes to send to the command's standard input, base64 encoded, up to 2 MiB. Leave it out and the command gets no input
timeoutintegerNoSeconds before the command is stopped. Default 600, at most 3600

To use pipes, && or other shell features, run a shell yourself: ["sh", "-c", "kubectl get pods -A | grep -v Running"].

Response: an event stream​

The answer is a server-sent event stream (text/event-stream) that lasts as long as the command runs. Use curl -N so curl prints events as they arrive.

curl -N -X POST https://cloider.com/api/clusters/k3x9p/exec \
-H "Authorization: Bearer $CLOIDER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"command": ["kubectl", "get", "nodes"]}'
Response
: open

event: stdout
data: TkFNRSAgICAgICAgIFNUQVRVUyAgIFJPTEVTICAgQUdFICAgVkVSU0lPTgo=

event: exit
data: 0

event: end
data: 1

EventdataMeaning
stdoutbase64A chunk of standard output. Decode it to bytes; chunks don't follow line boundaries
stderrbase64A chunk of standard error
exitthe exit code, for example 0The command finished
timeoutthe timeout in secondsThe command ran out of time and was stopped
errora messageThe command couldn't be run, or the stream was cut off
end1Nothing follows. Close the connection

Lines that start with : (: open, : ping) are comments that keep the connection alive; ignore them. Exactly one of exit, timeout or error comes before end. Closing the connection stops the command.

Pipe a manifest to kubectl apply -f - by sending it as stdin:

curl -N -X POST https://cloider.com/api/clusters/k3x9p/exec \
-H "Authorization: Bearer $CLOIDER_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg stdin "$(base64 < deploy.yaml)" \
'{command: ["kubectl", "apply", "-f", "-"], stdin: $stdin}')"
Read an exec stream in JavaScript
exec.mjs
const res = await fetch('https://cloider.com/api/clusters/k3x9p/exec', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CLOIDER_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ command: ['kubectl', 'get', 'pods', '-A'] }),
});
if (!res.ok) throw new Error(JSON.stringify(await res.json()));

const decoder = new TextDecoder();
let buffer = '';
let exitCode = null;

for await (const chunk of res.body) {
buffer += decoder.decode(chunk, { stream: true });
let sep;
while ((sep = buffer.indexOf('\n\n')) !== -1) {
const raw = buffer.slice(0, sep);
buffer = buffer.slice(sep + 2);
let event = 'message';
const data = [];
for (const line of raw.split('\n')) {
if (line.startsWith(':')) continue;
if (line.startsWith('event: ')) event = line.slice(7);
if (line.startsWith('data: ')) data.push(line.slice(6));
}
const value = data.join('\n');
if (event === 'stdout') process.stdout.write(Buffer.from(value, 'base64'));
if (event === 'stderr') process.stderr.write(Buffer.from(value, 'base64'));
if (event === 'exit') exitCode = Number(value);
if (event === 'timeout' || event === 'error') console.error(event, value);
}
}
process.exitCode = exitCode ?? 1;

Errors​

Errors that happen before the command starts are ordinary JSON errors, not events:

StatusFieldMessage
400commandGive a command to run!, The command can't contain NUL bytes!, The command is longer than 64 KiB!
400stdinstdin is bigger than 2 MiB!
400timeoutThe timeout can be an hour at most!
403_This API token is read only!
404_Cluster not found!
409_This cluster is paused. Resume it to run a command!, This cluster is being deleted!, This cluster is not ready yet!, This cluster's terminal isn't running right now!
503_The command could not be started, try again in a moment!

Don't retry an exec request automatically after the stream drops: the command may have run.

Open a web terminal​

GET /clusters/:hashed_id/terminal

Returns the URL of an interactive browser terminal for the cluster, with kubectl and helm ready to use. This is what the dashboard's terminal opens. For scripted commands, use exec instead.

Access: Read & Write token. A read only token gets 403 Terminals need a Read & Write API token!.

curl https://cloider.com/api/clusters/k3x9p/terminal \
-H "Authorization: Bearer $CLOIDER_TOKEN"
Response
{
"url": "https://cloider.com/terminal?name=staging&id=k3x9p&token=eyJhbGciOiJIUzI1NiIs...",
"cluster_slug": "staging-k3x9p"
}

When you call it with an API token, the URL carries a short lived terminal token that is valid for 2 minutes, so open it right away. The URL grants a shell on the cluster: don't log it or share it. Web terminal and exec describes the terminal.