Create a cluster
const url = 'https://api.aetherplatform.cloud/api/v1/organizations/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/clusters';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"example","region":"example","k8s_version":"example","plan":"starter","public_endpoint":false}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.aetherplatform.cloud/api/v1/organizations/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/clusters \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "example", "region": "example", "k8s_version": "example", "plan": "starter", "public_endpoint": false }'Creates a cluster and begins asynchronous provisioning. Returns 202 with the cluster record in provisioning status.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Organization UUID.
Request Bodyrequired
Section titled “Request Bodyrequired”object
A supported Kubernetes version as MAJOR.MINOR (e.g. “1.33”) or full MAJOR.MINOR.PATCH. Bare minors resolve to the latest available patch.
The package to bill this cluster from. The catalogue currently offers dev, starter, growth and scale, but the server validates the slug against its own catalogue rather than a fixed list, so treat those four as the values available today and not as the permitted set. Optional: omitted — or sent as an empty string, which is accepted and means the same thing — bills the cluster per resource (“custom”), with no package fee and no allowance. A slug that is unknown or retired is rejected at create time with 422 validation_error carrying plan/unavailable in details. Chosen at create time and immutable afterwards: no update field changes it, so moving between packages, or between a package and custom, means recreating the cluster.
The public apiserver endpoint: the cluster’s control-plane proxy also binds one IPv4 from the region’s public pool and the apiserver is published at public_ip (€4 at the time of writing; the current rate is shown in the portal and, once published, on the pricing page) as a flat month with no proration, locked the first time the billing sampler observes the address — one charge per cluster per month, on top of the cluster’s other resources, and no package fee includes it. The schema default stays false, but omitting the field or sending false is an implementation gap (tracked internally as I-14), not a supported alternative: the API still accepts it and creates a cluster with no public address, no endpoint charge and no supported access path. Such a cluster’s apiserver answers only on its private network — its own workers and the platform — and in production there is no supported way to reach it from a laptop or a CI pipeline; the kubectl proxy through the platform API (proxy-kubeconfig, not exposed in this reference) is a preview that is switched off in production and, where enabled, reaches private and public clusters alike. Private-network connectivity, which would make the public endpoint optional, is a future capability. Immutable after create; a 409 public_ip_pool_exhausted means the region has no free address.
Responses
Section titled “Responses”Cluster accepted for provisioning.
object
The apiserver URL aether-operator reports for the cluster: the private control-plane proxy address, or the public hostname when public_endpoint is true (which it is on every supported cluster — a cluster without the mandatory public endpoint is an implementation gap, tracked internally as I-14, see public_endpoint). Observed, not derived — null (and omitted from the response) until the cluster has been provisioned far enough for the operator to report one.
The version aether-operator reports once a rollout settles.
The per-cluster worker /24 (read-only; allocated at create time).
Whether this cluster’s apiserver is exposed on a public IPv4 and DNS name in addition to the private control-plane proxy path. Every cluster is required to have one: the public API endpoint is mandatory, billed at the published monthly rate for public_ip (€4 at the time of writing; the current rate is shown in the portal and, once published, on the pricing page) as a flat month with no proration, locked the first time the billing sampler observes the address — one line per cluster per month, see SubscriptionLine.kind public_ip. Set at create time and immutable afterwards; sending a different value to updateCluster is rejected with 422 public_endpoint/immutable. A cluster reading false is an implementation gap (tracked internally as I-14), not a supported configuration: the API still accepts public_endpoint: false at create time, and the resulting cluster has no public address, no endpoint charge and no supported access path. Its apiserver answers only on the cluster’s private network — its own workers and the platform — and in production there is no supported way to reach it from a laptop or a CI pipeline; the kubectl proxy through the platform API (proxy-kubeconfig, not exposed in this reference) is a preview that is switched off in production and, where enabled, reaches private and public clusters alike. Private-network connectivity, which would make the public endpoint optional, is a future capability.
The package this cluster is billed from, as chosen at create time: one of the package slugs in the catalogue (currently dev, starter, growth, scale; a retired slug can still appear on an existing cluster). null (and omitted from the response) means the cluster is billed per resource (“custom”). Immutable — no endpoint changes it.
Example
{ "status": "provisioning"}Missing or invalid credentials.
object
object
A stable, machine-readable error code.
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ] }}The resource already exists or conflicts with current state.
object
object
A stable, machine-readable error code.
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ] }}Request validation failed.
object
object
A stable, machine-readable error code.
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ] }}A required backend dependency is unavailable.
object
object
A stable, machine-readable error code.
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "field": "example", "code": "example", "message": "example" } ] }}