# Volumes

### List the persistent volumes in an environment

`GET /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes`

**Required role:** reader

**Parameters**

- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Returns**

- `200` · `VolumeDto[]`

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
[
  {
    "id": "acct_01example0000000000000000x",
    "environmentId": "environment_01example0000000000000000x",
    "serviceId": "svc_01example0000000000000000x",
    "name": "my-app",
    "mountPath": "example",
    "sizeGb": 0,
    "status": {
      "state": "ready",
      "location": "example",
      "currentSizeGb": 1,
      "usedBytes": 1,
      "commands": [
        {
          "id": "acct_01example0000000000000000x",
          "kind": "expand",
          "status": "running",
          "startedAt": "2026-01-01T00:00:00.000Z",
          "completedAt": "2026-01-01T00:00:00.000Z",
          "error": "example",
          "detail": "example"
        }
      ]
    },
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-01-01T00:00:00.000Z"
  }
]
```

### Get a persistent volume

`GET /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}`

**Required role:** reader

**Parameters**

- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Returns**

- `200` · `VolumeDto`

Attributes of `VolumeDto`:

- `id` · `string` · read-only
- `environmentId` · `string` · read-only — The environment this volume belongs to.
- `serviceId` · `string | null` · read-only — The service mounting this volume; null when detached (an orphan).
- `name` · `string` · read-only — Volume name, unique within the environment.
- `mountPath` · `string` · read-only — Path the volume is mounted at when attached.
- `sizeGb` · `integer` · read-only — Current volume size in GB.
- `status` · `object` · read-only — Read-only: live disk state (provisioning/ready, actual size, usage).
- `createdAt` · `string <date-time>` · read-only
- `updatedAt` · `string <date-time>` · read-only

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "id": "acct_01example0000000000000000x",
  "environmentId": "environment_01example0000000000000000x",
  "serviceId": "svc_01example0000000000000000x",
  "name": "my-app",
  "mountPath": "example",
  "sizeGb": 0,
  "status": {
    "state": "ready",
    "location": "example",
    "currentSizeGb": 1,
    "usedBytes": 1,
    "commands": [
      {
        "id": "acct_01example0000000000000000x",
        "kind": "expand",
        "status": "running",
        "startedAt": "2026-01-01T00:00:00.000Z",
        "completedAt": "2026-01-01T00:00:00.000Z",
        "error": "example",
        "detail": "example"
      }
    ]
  },
  "createdAt": "2026-01-01T00:00:00.000Z",
  "updatedAt": "2026-01-01T00:00:00.000Z"
}
```

### Destroy a detached (orphan) volume

`DELETE /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}`

**Required role:** editor

Deletes a DETACHED volume and its data permanently. 409 if still attached (detach from its service first); 412 without confirmDataLoss.

**Parameters**

- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Request body**

- `confirmDataLoss` · `boolean` · required — Must be true to proceed: deleting a detached volume destroys its data permanently.

**Returns**

- `204`

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId \
  -X DELETE \
  -H "Authorization: Bearer kc_your_api_token" \
  -H "Content-Type: application/json" \
  -d '{
      "confirmDataLoss": true
    }'
```

### Get a volume’s live state

`GET /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}/status`

**Required role:** reader

The disk’s live lifecycle, actual size/usage, the location it is provisioned in, and which day-2 commands (expand/snapshot/restore) are currently in flight. The console gates the volume actions on this.

**Parameters**

- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Returns**

- `200` · `VolumeStatusDto`

Attributes of `VolumeStatusDto`:

- `state` · `"ready" | "provisioning" | "repairing" | "unknown"` · read-only — Live state of the attached disk: `ready` (bound + in use), `provisioning` (being created/attached), `repairing`, or `unknown`.
- `location` · `string` · read-only — The Control Plane location the volume is actually provisioned in (when provisioned).
- `currentSizeGb` · `number` · read-only — Actual provisioned capacity in GiB, as Control Plane reports it.
- `usedBytes` · `number` · read-only — Bytes currently used on the disk.
- `commands` · `object[]` · read-only — Recent day-2 commands (newest first), persisted by Koo — live AND terminal state, so the console shows an in-progress or just-completed/failed operation even after a page reload.

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId/status \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "state": "ready",
  "location": "example",
  "currentSizeGb": 1,
  "usedBytes": 1,
  "commands": [
    {
      "id": "acct_01example0000000000000000x",
      "kind": "expand",
      "status": "running",
      "startedAt": "2026-01-01T00:00:00.000Z",
      "completedAt": "2026-01-01T00:00:00.000Z",
      "error": "example",
      "detail": "example"
    }
  ]
}
```

### Grow a persistent volume

`POST /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}/expand`

**Required role:** editor

Grow-only — Control Plane rejects a shrink (422). The mounting service’s spec is kept in sync.

**Parameters**

- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Request body**

- `sizeGb` · `integer` · required — New volume size in GB. Must be larger than the current size — volumes only grow.

**Returns**

- `200` · `VolumeDto`

Attributes of `VolumeDto`:

- `id` · `string` · read-only
- `environmentId` · `string` · read-only — The environment this volume belongs to.
- `serviceId` · `string | null` · read-only — The service mounting this volume; null when detached (an orphan).
- `name` · `string` · read-only — Volume name, unique within the environment.
- `mountPath` · `string` · read-only — Path the volume is mounted at when attached.
- `sizeGb` · `integer` · read-only — Current volume size in GB.
- `status` · `object` · read-only — Read-only: live disk state (provisioning/ready, actual size, usage).
- `createdAt` · `string <date-time>` · read-only
- `updatedAt` · `string <date-time>` · read-only

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId/expand \
  -X POST \
  -H "Authorization: Bearer kc_your_api_token" \
  -H "Content-Type: application/json" \
  -d '{
      "sizeGb": 0
    }'
```

**Example response** (`200`)

```json
{
  "id": "acct_01example0000000000000000x",
  "environmentId": "environment_01example0000000000000000x",
  "serviceId": "svc_01example0000000000000000x",
  "name": "my-app",
  "mountPath": "example",
  "sizeGb": 0,
  "status": {
    "state": "ready",
    "location": "example",
    "currentSizeGb": 1,
    "usedBytes": 1,
    "commands": [
      {
        "id": "acct_01example0000000000000000x",
        "kind": "expand",
        "status": "running",
        "startedAt": "2026-01-01T00:00:00.000Z",
        "completedAt": "2026-01-01T00:00:00.000Z",
        "error": "example",
        "detail": "example"
      }
    ]
  },
  "createdAt": "2026-01-01T00:00:00.000Z",
  "updatedAt": "2026-01-01T00:00:00.000Z"
}
```

### List a volume’s snapshots (live Control Plane state)

`GET /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}/snapshots`

**Required role:** reader

**Parameters**

- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Returns**

- `200` · `VolumeSnapshotDto[]`

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId/snapshots \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
[
  {
    "name": "my-app",
    "id": "acct_01example0000000000000000x",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "sizeGb": 1,
    "status": "creating"
  }
]
```

### Take a manual snapshot of a volume

`POST /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}/snapshots`

**Required role:** editor

A timestamped name is generated when omitted.

**Parameters**

- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Request body**

- `name` · `string` · optional — Optional name for the snapshot. A timestamped name is generated when omitted.

**Returns**

- `200` · `VolumeSnapshotDto`

Attributes of `VolumeSnapshotDto`:

- `name` · `string` · read-only — Snapshot name — use it to restore or delete the snapshot.
- `id` · `string` · read-only — Control Plane snapshot identifier.
- `createdAt` · `string <date-time>` · read-only — When the snapshot was taken.
- `sizeGb` · `number` · read-only — Snapshot size in GB.
- `status` · `"creating" | "ready" | "deleting"` · read-only — Durable lifecycle (creating/ready/deleting); absent for a cpln-only snapshot.

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId/snapshots \
  -X POST \
  -H "Authorization: Bearer kc_your_api_token" \
  -H "Content-Type: application/json" \
  -d '{}'
```

**Example response** (`200`)

```json
{
  "name": "my-app",
  "id": "acct_01example0000000000000000x",
  "createdAt": "2026-01-01T00:00:00.000Z",
  "sizeGb": 1,
  "status": "creating"
}
```

### Restore a volume in place from a snapshot

`POST /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}/snapshots/{name}/restore`

**Required role:** editor

Destructive — overwrites the volume’s current data with the snapshot’s. 412 without confirmDataLoss.

**Parameters**

- `name` _(path)_ · `string` · required — Snapshot name to restore.
- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Request body**

- `confirmDataLoss` · `boolean` · required — Must be true to proceed: restoring overwrites the volume’s current data with the snapshot’s.

**Returns**

- `204`

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId/snapshots/:name/restore \
  -X POST \
  -H "Authorization: Bearer kc_your_api_token" \
  -H "Content-Type: application/json" \
  -d '{
      "confirmDataLoss": true
    }'
```

### Delete a volume snapshot

`DELETE /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/volumes/{volumeId}/snapshots/{name}`

**Required role:** editor

**Parameters**

- `name` _(path)_ · `string` · required — Snapshot name to delete.
- `volumeId` _(path)_ · `string` · required
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Returns**

- `204`

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/volumes/:volumeId/snapshots/:name \
  -X DELETE \
  -H "Authorization: Bearer kc_your_api_token"
```
