+++
title = "Credentials"
description = "A credential is a username and password for a cluster."
weight = 88
updated = 2026-11-03

[extra]
nav_title = "Credentials"
weight = 40
+++

<!-- Generated by script/build-api-reference.js from data/openapi/v1.yml and data/api-reference/pages.yml. Edit those and run `npm run build:api-reference`, not this file. -->

A credential is a username and password for a cluster. Each has an
access type:

| Access type | What it allows |
|---|---|
| `rw` | Read and write everything. Every cluster has at least one. |
| `ro` | Read only. |
| `rwm` | The actions in `allowed_actions`, from the addresses in `allowed_cidrs`. |
| `acl` | As `rwm`, limited to the indices matching `allowed_index_globs`. |

Which types a cluster takes depends on its plan, and `rwm` and `acl`
need a feature enabled on the account. Only showing or creating a
single credential returns its password.

**On this page:** [Credential object](#credential-object), [Credential object, with its secret](#credential-with-secret-object), [List a cluster's active credentials](#list-cluster-credentials), [Create a credential](#create-cluster-credential), [Show a credential, with its secret](#get-cluster-credential), [Revoke a credential](#revoke-cluster-credential).

## The Credential object {#credential-object}

| Field | Type | Description |
|---|---|---|
| `id` | string | Its ID. Never changes. |
| `name` | string or null | A label, or null. |
| `access_type` | string | One of `rw`, `ro`, `rwm`, `acl`. More may be added. |
| `default` | boolean | The cluster's default credential: its oldest active `rw` one, whose URL the dashboard shows as the cluster's. Exactly one of a cluster's credentials while it has an active `rw` one, which it does from provisioning until it's terminated, since the last one can't be revoked. |
| `allowed_actions` | array of strings | For `rwm` and `acl`, the actions it may take. Empty for `rw` and `ro`. |
| `allowed_index_globs` | array of strings | For `acl`, the indices it may reach. Empty otherwise. |
| `allowed_cidrs` | array of strings | For `rwm` and `acl`, the addresses it may connect from. Empty otherwise. |
| `created_at` | string (date-time) | When the credential was created. |

```json
{
  "id": "scc-a8Kd",
  "name": null,
  "access_type": "rw",
  "default": true,
  "allowed_actions": [],
  "allowed_index_globs": [],
  "allowed_cidrs": [],
  "created_at": "2026-10-26T14:03:05Z"
}
```

## The Credential object, with its secret {#credential-with-secret-object}

A credential's fields, plus its secret. Only showing or creating a single credential returns it.

| Field | Type | Description |
|---|---|---|
| `id` | string | Its ID. Never changes. |
| `name` | string or null | A label, or null. |
| `access_type` | string | One of `rw`, `ro`, `rwm`, `acl`. More may be added. |
| `default` | boolean | The cluster's default credential: its oldest active `rw` one, whose URL the dashboard shows as the cluster's. Exactly one of a cluster's credentials while it has an active `rw` one, which it does from provisioning until it's terminated, since the last one can't be revoked. |
| `allowed_actions` | array of strings | For `rwm` and `acl`, the actions it may take. Empty for `rw` and `ro`. |
| `allowed_index_globs` | array of strings | For `acl`, the indices it may reach. Empty otherwise. |
| `allowed_cidrs` | array of strings | For `rwm` and `acl`, the addresses it may connect from. Empty otherwise. |
| `created_at` | string (date-time) | When the credential was created. |
| `username` | string | The username to connect with. |
| `password` | string | The password to connect with. Keep it out of logs and source control. |
| `url` | string | A complete `https://user:pass@host` URL. |

```json
{
  "id": "scc-a8Kd",
  "name": null,
  "access_type": "rw",
  "default": true,
  "allowed_actions": [],
  "allowed_index_globs": [],
  "allowed_cidrs": [],
  "created_at": "2026-10-26T14:03:05Z",
  "username": "a8kd3x9q2m",
  "password": "7v1c8b4nq0w2e5r9",
  "url": "https://a8kd3x9q2m:7v1c8b4nq0w2e5r9@my-search-4823919.us-east-1.bonsaisearch.net"
}
```

## List a cluster's active credentials {#list-cluster-credentials}

<p class="api-endpoint"><span class="api-method api-method-get">GET</span> <code>/v1/clusters/{cluster_id}/credentials</code></p>

- **Scope:** `credentials:read`

Newest first. No secrets in the list. A terminated cluster has no active credentials.

### Parameters

| Name | In | Type | Description |
|---|---|---|---|
| `cluster_id` | path | string | Required. The cluster's ID, which is its slug. It never changes. |
| `limit` | query | integer | Page size. Defaults to 25. |
| `cursor` | query | string | The `next_cursor` of the previous page. Opaque. |

### Example request

```bash
curl https://api.bonsai.io/v1/clusters/my-search-4823919/credentials \
  -H "Authorization: Bearer $BONSAI_TOKEN"
```

### Response

`200 OK`. A page of [Credential objects](#credential-object) in `data`, with `next_cursor`. See [Pagination](@/docs/api/requests-and-responses/index.md#pagination).

```json
{
  "data": [
    {
      "id": "scc-a8Kd",
      "name": null,
      "access_type": "rw",
      "default": true,
      "allowed_actions": [],
      "allowed_index_globs": [],
      "allowed_cidrs": [],
      "created_at": "2026-10-26T14:03:05Z"
    }
  ],
  "next_cursor": null
}
```

### Errors

| Status | Codes |
|---|---|
| `400` | [`invalid_parameter`](@/docs/api/errors/index.md#invalid_parameter) |
| `401` | [`unauthorized`](@/docs/api/errors/index.md#unauthorized) |
| `403` | [`missing_scope`](@/docs/api/errors/index.md#missing_scope) |
| `404` | [`not_found`](@/docs/api/errors/index.md#not_found) |
| `429` | [`rate_limited`](@/docs/api/errors/index.md#rate_limited), [`too_many_failed_authentications`](@/docs/api/errors/index.md#too_many_failed_authentications) |

## Create a credential {#create-cluster-credential}

<p class="api-endpoint"><span class="api-method api-method-post">POST</span> <code>/v1/clusters/{cluster_id}/credentials</code></p>

- **Scope:** `credentials:write`
- **Idempotent:** with an `Idempotency-Key` header. See [Retrying safely](@/docs/api/retrying-safely/index.md).

Synchronous: the cluster's routes are updated before this answers, so
an `rw` or `ro` credential works as soon as it is returned. An `rwm` or
`acl` credential's permissions are then sent to the cluster in the
background, and apply once that finishes. The response carries the
password, as only this and [`GET /v1/clusters/{cluster_id}/credentials/{credential_id}`](#get-cluster-credential) do. The
cluster must be ready; a Hobby cluster may have one active credential.
A replay with the same `Idempotency-Key` returns the credential again
with `Idempotent-Replayed: true`, or `409 idempotency_replay_unavailable`
once it is revoked or can't be identified.

### Parameters

| Name | In | Type | Description |
|---|---|---|---|
| `cluster_id` | path | string | Required. The cluster's ID, which is its slug. It never changes. |
| `Idempotency-Key` | header | string | 1 to 255 printable ASCII characters. Kept for 24 hours. See [Retrying safely](@/docs/api/retrying-safely/index.md). |

### Body

A field this schema doesn't list is `400 invalid_parameter`.

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | Yes | A label. |
| `access_type` | string | Yes | One of `rw`, `ro`, `rwm`, `acl`. More may be added. Required, so full access is never a default. Which types a cluster takes depends on its plan; `rwm` and `acl` also need a feature enabled for the token's owner (`403 feature_not_enabled`). |
| `allowed_actions` | array of strings | No | For `rwm` and `acl` only. |
| `allowed_index_globs` | array of strings | No | For `acl` only. |
| `allowed_cidrs` | array of strings | No | For `rwm` and `acl` only, e.g. `203.0.113.0/24`. |

### Example request

```bash
curl -X POST https://api.bonsai.io/v1/clusters/my-search-4823919/credentials \
  -H "Authorization: Bearer $BONSAI_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name": "frontend", "access_type": "ro"}'
```

### Response

`201 Created`. The new credential and its secret. Returns a [CredentialWithSecret object](#credential-with-secret-object).

| Header | Description |
|---|---|
| `Location` | The credential's URL. |
| `Idempotent-Replayed` | `true` when this is the replay of an earlier request with the same `Idempotency-Key`, rebuilt from what it made as that is now; absent otherwise. |

```json
{
  "id": "scc-a8Kd",
  "name": null,
  "access_type": "rw",
  "default": true,
  "allowed_actions": [],
  "allowed_index_globs": [],
  "allowed_cidrs": [],
  "created_at": "2026-10-26T14:03:05Z",
  "username": "a8kd3x9q2m",
  "password": "7v1c8b4nq0w2e5r9",
  "url": "https://a8kd3x9q2m:7v1c8b4nq0w2e5r9@my-search-4823919.us-east-1.bonsaisearch.net"
}
```

### Errors

| Status | Codes |
|---|---|
| `400` | [`invalid_json`](@/docs/api/errors/index.md#invalid_json), [`body_required`](@/docs/api/errors/index.md#body_required), [`invalid_parameter`](@/docs/api/errors/index.md#invalid_parameter) |
| `401` | [`unauthorized`](@/docs/api/errors/index.md#unauthorized) |
| `403` | [`feature_not_enabled`](@/docs/api/errors/index.md#feature_not_enabled), [`missing_scope`](@/docs/api/errors/index.md#missing_scope) |
| `404` | [`not_found`](@/docs/api/errors/index.md#not_found) |
| `409` | [`idempotency_replay_unavailable`](@/docs/api/errors/index.md#idempotency_replay_unavailable), [`idempotency_key_in_use`](@/docs/api/errors/index.md#idempotency_key_in_use) |
| `422` | [`validation_failed`](@/docs/api/errors/index.md#validation_failed), [`idempotency_key_reused`](@/docs/api/errors/index.md#idempotency_key_reused) |
| `429` | [`rate_limited`](@/docs/api/errors/index.md#rate_limited), [`too_many_failed_authentications`](@/docs/api/errors/index.md#too_many_failed_authentications) |

## Show a credential, with its secret {#get-cluster-credential}

<p class="api-endpoint"><span class="api-method api-method-get">GET</span> <code>/v1/clusters/{cluster_id}/credentials/{credential_id}</code></p>

- **Scope:** `credentials:read`

Carries the credential's password, as only this and [`POST /v1/clusters/{cluster_id}/credentials`](#create-cluster-credential) do.

### Parameters

| Name | In | Type | Description |
|---|---|---|---|
| `cluster_id` | path | string | Required. The cluster's ID, which is its slug. It never changes. |
| `credential_id` | path | string | Required. The credential's ID, which is its slug. It never changes. |

### Example request

```bash
curl https://api.bonsai.io/v1/clusters/my-search-4823919/credentials/scc-a8Kd \
  -H "Authorization: Bearer $BONSAI_TOKEN"
```

### Response

`200 OK`. The credential and its secret. Returns a [CredentialWithSecret object](#credential-with-secret-object).

```json
{
  "id": "scc-a8Kd",
  "name": null,
  "access_type": "rw",
  "default": true,
  "allowed_actions": [],
  "allowed_index_globs": [],
  "allowed_cidrs": [],
  "created_at": "2026-10-26T14:03:05Z",
  "username": "a8kd3x9q2m",
  "password": "7v1c8b4nq0w2e5r9",
  "url": "https://a8kd3x9q2m:7v1c8b4nq0w2e5r9@my-search-4823919.us-east-1.bonsaisearch.net"
}
```

### Errors

| Status | Codes |
|---|---|
| `401` | [`unauthorized`](@/docs/api/errors/index.md#unauthorized) |
| `403` | [`missing_scope`](@/docs/api/errors/index.md#missing_scope) |
| `404` | [`not_found`](@/docs/api/errors/index.md#not_found) |
| `429` | [`rate_limited`](@/docs/api/errors/index.md#rate_limited), [`too_many_failed_authentications`](@/docs/api/errors/index.md#too_many_failed_authentications) |

## Revoke a credential {#revoke-cluster-credential}

<p class="api-endpoint"><span class="api-method api-method-delete">DELETE</span> <code>/v1/clusters/{cluster_id}/credentials/{credential_id}</code></p>

- **Scope:** `credentials:write`

Synchronous: the credential stops working on the cluster's routes
before this answers. An `rwm` or `acl` credential is then removed from
the cluster's permissions in the background. A revoked credential is
gone from this API, so revoking it again is a 404. The last active
`rw` credential can't be revoked (`422`).

### Parameters

| Name | In | Type | Description |
|---|---|---|---|
| `cluster_id` | path | string | Required. The cluster's ID, which is its slug. It never changes. |
| `credential_id` | path | string | Required. The credential's ID, which is its slug. It never changes. |

### Example request

```bash
curl -X DELETE https://api.bonsai.io/v1/clusters/my-search-4823919/credentials/scc-a8Kd \
  -H "Authorization: Bearer $BONSAI_TOKEN"
```

### Response

`204 No Content`. Revoked.

### Errors

| Status | Codes |
|---|---|
| `401` | [`unauthorized`](@/docs/api/errors/index.md#unauthorized) |
| `403` | [`missing_scope`](@/docs/api/errors/index.md#missing_scope) |
| `404` | [`not_found`](@/docs/api/errors/index.md#not_found) |
| `422` | [`validation_failed`](@/docs/api/errors/index.md#validation_failed) |
| `429` | [`rate_limited`](@/docs/api/errors/index.md#rate_limited), [`too_many_failed_authentications`](@/docs/api/errors/index.md#too_many_failed_authentications) |
