+++
title = "Cluster API Introduction"
weight = 96
updated = 2026-10-13
aliases = ["/docs/cluster-api-introduction.html", "/docs/bonsai-api/endpoints/cluster-api/", "/docs/api/endpoints/cluster-api/"]

[extra]
nav_title = "Cluster API Introduction"
weight = 10
+++

The Clusters API provides a means of managing clusters on your account.

{{ legacy_api_notice() }}

The Clusters API provides a means of managing clusters on your account. This API supports the following actions:

- **View all** clusters in your account
- **View** a single cluster in your account
- **Create** a new cluster
- **Update** a cluster in your account
- **Destroy** a cluster in your account

All calls to the Clusters API must be [authenticated](@/docs/api/legacy/authentication/overview/index.md) with an active [API token](@/docs/account/api-tokens/index.md). Viewing clusters needs the `clusters:read` [scope](@/docs/account/api-tokens/index.md#scopes); creating, updating and destroying them needs `clusters:write`. A token without the scope a call needs gets an [HTTP 403: Forbidden](@/docs/api/legacy/errors/403-forbidden/index.md) error.

<span id="bonsai-cluster-object"></span>

## The Bonsai Cluster Object

The Bonsai API provides a standard format for Cluster objects. A Cluster object includes:

<table>
<thead>
<tr>
<th>Attribute</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>slug</td><td>A string representing a unique, machine-readable name for the cluster. The slug is made from the cluster's name at creation: up to its first three words, in lowercase letters only, joined with dashes and cut to 20 characters, then a dash and an 8-character random suffix. For example, a cluster named <code>first_testing_cluster</code> could get the slug <code>first-testing-cluste-1rb4k7wm</code>. Renaming the cluster does not change its slug.</td>
</tr>
<tr>
<td>name</td><td>A string representing the human-readable name of the cluster.</td>
</tr>
<tr>
<td>uri</td><td>A URI to get more information about this cluster.</td>
</tr>
<tr>
<td>plan</td><td>An Object with some information about the cluster's current subscription plan. This hash has two keys:

- **slug**. The unique, machine-readable name of the plan.
- **uri**. A URI to retrieve more information about this plan.

You can see more details about the plan by passing the slug to the [Plans API](@/docs/api/legacy/endpoints/plans-api/index.md).
</td>
</tr>
<tr>
<td>release</td><td>An Object with some information about the cluster's current release. This hash has seven keys:

- **name.** The human-readable name of the release.
- **slug.** The unique slug of the release.
- **service_type**. The name of the search service: `elasticsearch` or `opensearch`.
- **version.** The version of the release this cluster is running on.
- **package_name**. The package name of the release.
- **multitenant**. A Boolean, true when the release is available on multitenant deployments.
- **uri.** A URI to retrieve more information about this release.

You can see more details about the release by passing the slug to the [Releases API](@/docs/api/legacy/endpoints/releases-api/index.md).
</td>
</tr>
<tr>
<td>space</td><td>An Object with some information about where the cluster is running. This has three keys:

- **path.** The path to the space. This string maps to a geographic region or data center.
- **region.** The geographic region in which the cluster is running.
- **uri.** A URI with more information about the space

You can see more details about the space by passing the path to the [Spaces API](@/docs/api/legacy/endpoints/spaces-api/index.md).
</td>
</tr>
<tr>
<td>stats</td><td>An Object with a collection of statistics about the cluster. This hash has three keys:

- **docs.** The number of documents in the index.
- **shards_used.** The number of shards the cluster is using.
- **data_bytes_used.** Integer representing the number of bytes the cluster is using on disk.

This attribute should not be used for real-time monitoring! Stats are updated every 10-15 minutes. To monitor real-time metrics, monitor your cluster directly, via the [Index Stats API](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-stats.html).
</td>
</tr>
<tr>
<td>access</td><td>An Object containing information about connecting to the cluster. This hash has three keys:

- **host.** The host name of the cluster. It can be `null` while the cluster is provisioning, until the cluster has been placed.
- **port.** The HTTP port the cluster is running on.
- **scheme.** The HTTP scheme needed to access the cluster (defaults to "https")

The cluster's credentials are not part of this object. See [Create a new cluster](#create-new-cluster) for how to build the cluster's URL.
</td>
</tr>
<tr>
<td>state</td><td>A String representing the current state of the cluster. This indicates what the cluster is doing at any given moment. There are 5 defined states:

- **PROVISIONING.** The cluster is in the process of being created.
- **PROVISIONED.** The cluster has been created.
- **READONLY**. The cluster is in read only mode.
- **DISABLED.** The cluster has been disabled.
- **DEPROVISIONED.** The cluster has been destroyed.

A cluster's state is the first of `READONLY`, `DISABLED`, `DEPROVISIONED` and `PROVISIONING` that applies to it. Any other cluster is `PROVISIONED`, including one whose provisioning failed: use `provision_state` to tell those apart.
</td>
</tr>
<tr>
<td>provision_state</td><td>A String with more detail about where the cluster is in its life. One of:

- **draft.** The cluster has been created, and its provisioning has not started yet.
- **provisioning.** The cluster is being provisioned.
- **provisioned.** The cluster has been provisioned.
- **error.** Provisioning the cluster failed. Please [contact support](mailto:support@bonsai.io).
- **destroyed.** The cluster has been destroyed.
- **unknown.** None of the above.

</td>
</tr>
</tbody>
</table>

A cluster without a plan, release or space still gets the `plan`, `release` and `space` objects, with the same keys, all `null`. The exception is `space.region`: when a cluster has no space but has a region, `region` holds that region.

```json
"plan": {
  "slug": null,
  "uri": null
},
"release": {
  "name": null,
  "slug": null,
  "service_type": null,
  "version": null,
  "package_name": null,
  "multitenant": null,
  "uri": null
},
"space": {
  "path": null,
  "region": "aws-us-east-1",
  "uri": null
}
```

<span id="view-all-clusters"></span>

## View all clusters

The Bonsai API provides a method to get a list of all **active** clusters on your account. An HTTP GET call is made to the `/clusters` endpoint, and Bonsai will return a JSON list of Cluster objects. This API call will not return deprovisioned clusters. This call uses [pagination](@/docs/api/legacy/reference/api-result-pagination/index.md), so you may need to make multiple requests to fetch all clusters.

#### Supported Parameters (Query String Parameters)

<table>
<thead>
<tr>
<th>Param</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>q</td><td>Optional. A string for filtering clusters by name. A cluster matches when its name contains the string, ignoring case.</td>
</tr>
<tr>
<td>tenancy</td><td>Optional. <code>child</code> limits the results to clusters on multitenant (shared) hardware. Any other value is ignored.</td>
</tr>
<tr>
<td>location</td><td>Optional. A path limiting the results to the clusters in one place. It can be the path of a space, such as <code>omc/bonsai/us-east-1/common</code>, the first two parts of a space path, such as <code>omc/bonsai</code>, or the path of a server group (pod) in a space. You can get a list of available spaces with the [Spaces API](@/docs/api/legacy/endpoints/spaces-api/index.md). Any other path, such as a region path or a path that matches nothing, returns an empty list.</td>
</tr>
<tr>
<td>page</td><td>Optional. The page number, starting at 1. See [API Result Pagination](@/docs/api/legacy/reference/api-result-pagination/index.md).</td>
</tr>
<tr>
<td>size</td><td>Optional. The number of clusters on each page, from 1 to 1000. Defaults to 1000.</td>
</tr>
</tbody>
</table>

#### HTTP Request

An HTTP GET call is made to `/clusters`.

#### HTTP Response

Upon success, Bonsai responds with an HTTP 200: OK code, along with a JSON list representing the clusters on your account, newest first:

```javascript
{
  "pagination": {
    "page_number": 1,
    "page_size": 1000,
    "total_records": 2
  },
  "clusters": [
    {
      "slug": "first-testing-cluste-1rb4k7wm",
      "name": "first_testing_cluster",
      "uri": "https://api.bonsai.io/clusters/first-testing-cluste-1rb4k7wm",
      "plan": {
        "slug": "sandbox",
        "uri": "https://api.bonsai.io/plans/sandbox"
      },
      "release": {
        "name": "Elasticsearch 7.10.2",
        "slug": "elasticsearch-7.10.2",
        "service_type": "elasticsearch",
        "version": "7.10.2",
        "package_name": "7.10.2",
        "multitenant": true,
        "uri": "https://api.bonsai.io/releases/elasticsearch-7.10.2"
      },
      "space": {
        "path": "omc/bonsai/us-east-1/common",
        "region": "aws-us-east-1",
        "uri": "https://api.bonsai.io/spaces/omc/bonsai/us-east-1/common"
      },
      "stats": {
        "docs": 0,
        "shards_used": 0,
        "data_bytes_used": 0
      },
      "access": {
        "host": "first-testing-cluste-1rb4k7wm.us-east-1.bonsaisearch.net",
        "port": 443,
        "scheme": "https"
      },
      "state": "PROVISIONED",
      "provision_state": "provisioned"
    },
    {
      "slug": "second-testing-clust-1rb4x2pd",
      "name": "second_testing_cluster",
      "uri": "https://api.bonsai.io/clusters/second-testing-clust-1rb4x2pd",
      "plan": {
        "slug": "sandbox",
        "uri": "https://api.bonsai.io/plans/sandbox"
      },
      "release": {
        "name": "Elasticsearch 7.10.2",
        "slug": "elasticsearch-7.10.2",
        "service_type": "elasticsearch",
        "version": "7.10.2",
        "package_name": "7.10.2",
        "multitenant": true,
        "uri": "https://api.bonsai.io/releases/elasticsearch-7.10.2"
      },
      "space": {
        "path": "omc/bonsai/us-east-1/common",
        "region": "aws-us-east-1",
        "uri": "https://api.bonsai.io/spaces/omc/bonsai/us-east-1/common"
      },
      "stats": {
        "docs": 0,
        "shards_used": 0,
        "data_bytes_used": 0
      },
      "access": {
        "host": "second-testing-clust-1rb4x2pd.us-east-1.bonsaisearch.net",
        "port": 443,
        "scheme": "https"
      },
      "state": "PROVISIONED",
      "provision_state": "provisioned"
    }
  ]
}
```

<span id="view-single-cluster"></span>

## View a single cluster

The Bonsai API provides a method to retrieve information about a single cluster on your account. Unlike the list, this also returns a destroyed cluster, in the `DEPROVISIONED` state.

#### Supported Parameters

No parameters are supported for this action.

#### HTTP Request

An HTTP GET call is made to `/clusters/[:slug]`.

#### HTTP Response

Upon success, Bonsai will respond with an `HTTP 200: OK` code, along with a JSON body representing the Cluster object:

```javascript
{
  "cluster": {
    "slug": "second-testing-clust-1rb4x2pd",
    "name": "second_testing_cluster",
    "uri": "https://api.bonsai.io/clusters/second-testing-clust-1rb4x2pd",
    "plan": {
      "slug": "sandbox",
      "uri": "https://api.bonsai.io/plans/sandbox"
    },
    "release": {
      "name": "Elasticsearch 7.10.2",
      "slug": "elasticsearch-7.10.2",
      "service_type": "elasticsearch",
      "version": "7.10.2",
      "package_name": "7.10.2",
      "multitenant": true,
      "uri": "https://api.bonsai.io/releases/elasticsearch-7.10.2"
    },
    "space": {
      "path": "omc/bonsai/us-east-1/common",
      "region": "aws-us-east-1",
      "uri": "https://api.bonsai.io/spaces/omc/bonsai/us-east-1/common"
    },
    "stats": {
      "docs": 0,
      "shards_used": 0,
      "data_bytes_used": 0
    },
    "access": {
      "host": "second-testing-clust-1rb4x2pd.us-east-1.bonsaisearch.net",
      "port": 443,
      "scheme": "https"
    },
    "state": "PROVISIONED",
    "provision_state": "provisioned"
  }
}
```

A slug that does not name a cluster on your account gets an [HTTP 404: Not Found](@/docs/api/legacy/errors/404-not-found/index.md) error, with the message `Cluster not found.`

<span id="create-new-cluster"></span>

## Create a new cluster

The Bonsai API provides a method to create new clusters on your account. An HTTP POST call is made to the `/clusters` endpoint, and Bonsai will create the cluster.

#### Supported Parameters

<table>
<thead>
<tr>
<th>Param</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td><td>Required. A String representing the name for your new cluster.</td>
</tr>
<tr>
<td>plan</td><td>Required. A String representing the slug of the plan for your new cluster. You can get a list of available plans via the [Plans API](@/docs/api/legacy/endpoints/plans-api/index.md).</td>
</tr>
<tr>
<td>space</td><td>Required. A String representing the path of the Space where the new cluster will be created. You can get a list of available spaces with the [Spaces API](@/docs/api/legacy/endpoints/spaces-api/index.md).</td>
</tr>
<tr>
<td>release</td><td>Optional. A String representing the slug of the search service release to use. You can get a list of available releases with the [Releases API](@/docs/api/legacy/endpoints/releases-api/index.md). Without it, Bonsai picks the best release available for the plan.</td>
</tr>
</tbody>
</table>

#### HTTP Request

An HTTP POST call is made to `/clusters` along with a JSON payload of the supported parameters:

```bash
curl -X POST https://api.bonsai.io/clusters \
  -H "Authorization: Bearer bonsai_<key>_<secret>" \
  -H "Content-Type: application/json" \
  -d '{"name": "test 7.x", "plan": "sandbox", "space": "omc/bonsai/us-east-1/common"}'
```

#### HTTP Response

Bonsai will respond with an `HTTP 202: Accepted` code, along with a short message and details about the cluster that was created:

```javascript
{
  "message": "Your cluster is being provisioned.",
  "monitor": "https://api.bonsai.io/clusters/test-x-1rb5c3hn",
  "access": {
    "user": "utji08pwu6",
    "pass": "18v1fbey2y",
    "host": "test-x-1rb5c3hn",
    "port": 443,
    "scheme": "https",
    "url": "://utji08pwu6:18v1fbey2y@"
  },
  "status": 202
}
```

The `user` and `pass` are the cluster's credentials. Save them: no other API call returns them. You can also find them in the [Access section of the cluster dashboard](@/docs/features/credential-management/index.md).

In this response, `host` is the cluster's slug rather than its host name, and `url` is only the credentials part of a URL. To build the cluster's URL:

1. Poll the `monitor` URL, which [views the cluster](#view-single-cluster), until its `access.host` is not `null`.
2. Join the `scheme` and `access.host` from that response with `user` and `pass` from this one: `<scheme>://<user>:<pass>@<host>`.

For the example above, that gives:

```
https://utji08pwu6:18v1fbey2y@test-x-1rb5c3hn.us-east-1.bonsaisearch.net
```

Polling every 3-5 seconds is enough, and keeps you within the [rate limits](@/docs/api/legacy/overview/index.md#api-access-limitations). The cluster is ready when its `state` is `PROVISIONED` and its `provision_state` is `provisioned`.

#### Errors

A request with a missing or unknown `name`, `plan`, `space` or `release` gets an `HTTP 422: Unprocessable Entity` error naming the problem, and no cluster is created:

```json
{
  "errors": [
    "Plan 'sandboxing' not found. Please use the /plans endpoint for a list of available plans."
  ],
  "status": 422
}
```

The [API Error 422: Unprocessable Entity](@/docs/api/legacy/errors/422-unprocessable-entity/index.md) page lists every message. A body that is not valid JSON, or no body at all, gets an [HTTP 400: Bad Request](@/docs/api/legacy/errors/400-bad-request/index.md) error.

<span id="update-cluster"></span>

## Update a cluster

The Bonsai API provides a method to update the name or plan of your cluster. An HTTP PUT or PATCH call is made to the `/clusters/[:slug]` endpoint, and Bonsai will update the cluster.

#### Supported Parameters

<table>
<thead>
<tr>
<th>Param</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td><td>A String representing the new name for your cluster. Changing the cluster name will not change its slug or its URL.</td>
</tr>
<tr>
<td>plan</td><td>A String representing the slug of the new plan for your cluster. Updating the plan may trigger a data migration. You can get a list of available plans via the [Plans API](@/docs/api/legacy/endpoints/plans-api/index.md).</td>
</tr>
</tbody>
</table>

#### HTTP Request

To make a change to an existing cluster, make an HTTP PUT or PATCH call to `/clusters/[:slug]` with a JSON body for one or more of the supported params.

#### HTTP Response

Bonsai will respond with an `HTTP 202: Accepted` code, along with short message:

```javascript
{
  "message": "Your cluster is being updated.",
  "monitor": "https://api.bonsai.io/clusters/[:slug]",
  "status": 202
}
```

#### Errors

If any part of the update is refused, the API responds with an error and applies nothing else in the request. For example, a `name` the cluster can't take gets an `HTTP 422: Unprocessable Entity` error with the validation message, and the plan in the same request is not changed:

```json
{
  "errors": [
    "Name is too long (maximum is 512 characters)"
  ],
  "status": 422
}
```

A plan that is unknown, or that the cluster can't change to, also gets an `HTTP 422: Unprocessable Entity` error, and then the name is not changed either. See [API Error 422: Unprocessable Entity](@/docs/api/legacy/errors/422-unprocessable-entity/index.md) for the other messages. A body that is not valid JSON, or no body at all, gets an [HTTP 400: Bad Request](@/docs/api/legacy/errors/400-bad-request/index.md) error.

<span id="destroy-cluster"></span>

## Destroy a cluster

The Bonsai API provides a method to delete a cluster from your account. To guard against deleting the wrong cluster, the request must include the cluster's name, like the confirmation in the dashboard.

#### Supported Parameters

<table>
<thead>
<tr>
<th>Param</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>name</td><td>Required. A String with the name of the cluster you are deleting. It must match the cluster's <code>name</code> exactly, including case. This is the cluster's name, not its slug.</td>
</tr>
</tbody>
</table>

#### HTTP Request

An HTTP DELETE call is made to the `/clusters/[:slug]` endpoint, with a JSON body and a `Content-Type: application/json` header:

```bash
curl -X DELETE https://api.bonsai.io/clusters/second-testing-clust-1rb4x2pd \
  -H "Authorization: Bearer bonsai_<key>_<secret>" \
  -H "Content-Type: application/json" \
  -d '{"name": "second_testing_cluster"}'
```

The `Content-Type: application/json` header is required: without it, the API does not read the `name` in the body, and refuses the request as if there were no `name`. If your HTTP client can't send a body with a DELETE request, pass `name` in the query string instead, URL-encoded: `/clusters/[:slug]?name=second_testing_cluster`.

#### HTTP Response

Bonsai will respond with an HTTP 202: Accepted code, along with a short message:

```javascript
{
  "message": "Your cluster is being deprovisioned.",
  "monitor": "https://api.bonsai.io/clusters/[:slug]",
  "status": 202
}
```

#### Error

A request without a `name` parameter is refused with an `HTTP 400: Bad Request` error, and the cluster is not deleted:

```json
{
  "errors": [
    "Pass the name of the cluster as `name`."
  ],
  "status": 400
}
```

A blank `name` gets the same error. A `name` that does not match the cluster's name exactly gets an `HTTP 422: Unprocessable Entity` error:

```json
{
  "errors": [
    "The `name` you passed does not match the name of cluster second-testing-clust-1rb4x2pd."
  ],
  "status": 422
}
```

We are rolling out the checks on blank and mismatched names gradually, so for now such a request may still delete the cluster. Always send the cluster's exact name.

A cluster that has already been destroyed can't be destroyed or updated again: the request gets an `HTTP 422: Unprocessable Entity` error, `Cluster [:slug] is terminated.`
