---
title: "Server actions — API reference"
description: "Power, rebuild, password and rescue operations. Asynchronous; poll the server until `live.locked` is false."
url: https://www.gyrohosting.com/developers/en/api/server-actions.html
language: en
openapi: https://www.gyrohosting.com/developers/openapi.json
api_version: 2.30.0
---

# Server actions

Power, rebuild, password and rescue operations. Asynchronous; poll the server until `live.locked` is false.

Base URL: `https://www.gyrohosting.com/api/v1/client` · OpenAPI: https://www.gyrohosting.com/developers/openapi.json


## POST /cloud/servers/{id}/actions/{action}

**Run a server action** · operationId `serverAction` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/serverAction.json

Heavy actions (rebuild, reset, rescue, snapshot restore, password reset) are limited per server per day.
A one-time `root_password` is returned only when the request has **no** `Idempotency-Key`
(idempotent answers are stored for replay, secrets never are; you then get `root_password_withheld: true`).

**Region tr-ist-1**: poweron, shutdown, reboot, poweroff (same as shutdown), rebuild and reset_password are available; reset, enable_rescue and disable_rescue answer 422 `action_not_supported`. rebuild accepts the images of the server's own product (GET /cloud/images?region=tr-ist-1); the SSH keys given at creation are installed again once the rebuilt server is ready (follow `ssh_keys.state`). Prepaid servers: DELETE always cancels at once (no cancellation request).

**2.14.0 (Gyro Compute, tr-ist-1)**: `reset` (hard reset) is available too; `rebuild` accepts `user_data` and installs the server's SSH keys again; `poweroff` is a hard power off (shutdown = graceful). rescue actions answer 422 `action_not_supported`.

**2.19.1 (rebuild + app)**: `rebuild` accepts `app` (+ optional `app_domain`) on cloud servers: the disk is wiped, the new system is installed and the app is set up on it (progress in GET /cloud/servers/{id}/app, `/app/log`; login details once in the app status). A rebuild **without** `app` closes the server's previous app record (its automatic address is removed). What a rebuild keeps: IP addresses (incl. additional IPv4), server name, plan, SSH keys, firewall rules; tr-ist-1 deletes additional disks and snapshots, EU/US/SG keeps volumes, snapshots and backups. Errors: `app_with_user_data`, `invalid_app`, `invalid_app_domain`, `app_not_supported` (legacy VDS), `tool_action_failed` with the reason (app not available for the image, hourly limit).

**rebuild erases data** (needs `"confirm": true`): the disk is re-created from the image; on tr-ist-1 additional disks and snapshots are deleted too, IP addresses, SSH keys of the order and the plan stay. A plan change (`/cloud/services/{id}/resize`) never erases data.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |
| `action` (required) | path | string (poweron, shutdown, reboot, poweroff, reset, rebuild, reset_password, enable_rescue, disable_rescue) | `shutdown` = graceful (ACPI), `poweroff` = hard power cut, `reset` = hard reset (needs confirm), `rebuild` = reinstall from `image` (needs confirm, **wipes the disk**), `reset_password` / `enable_rescue` return a one-time `root_password`.  |

### Request body

| Field | Type | Description |
|---|---|---|
| `image` | string | rebuild only: image slug from /cloud/images |
| `confirm` | boolean | required for reset and rebuild |
| `user_data` | string | rebuild only (tr-ist-1 Gyro Compute): cloud-init for the new system; must start with `#cloud-config` or `#!`. Cannot be combined with `app`. |
| `app` | string | rebuild only: one-click app id from GET /cloud/apps, installed automatically on top of the new system (cloud servers: Gyro Cloud EU/US/SG and Istanbul). The image must be one the app supports (`os` of the app). Follow the install with GET /cloud/servers/{id}/app and /app/log. Cannot be combined with `user_data`; at most 3 app installs per server per hour. |
| `app_domain` | string | rebuild with `app` only: your domain for the app (its A record must point to the server); empty = automatic `<ip-with-dashes>.gyroapp.net` address. |

### Responses

- **202**: Accepted
- **404**: Not found — also returned for objects owned by someone else
- **409**: State conflict (`server_locked`, `not_actionable`, `ssh_key_exists`, `server_limit`, `idempotency_in_flight`)
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/actions/reboot' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"image": "ubuntu-24.04", "confirm": true, "user_data": "string", "app": "uptime-kuma", "app_domain": "string"}'
```
```bash
gyro server power off 12345 --help    # all flags
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/actions/reboot", headers=h, json={"image": "ubuntu-24.04", "confirm": True, "user_data": "string", "app": "uptime-kuma", "app_domain": "string"}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/actions/reboot", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"image": "ubuntu-24.04", "confirm": true, "user_data": "string", "app": "uptime-kuma", "app_domain": "string"}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## POST /cloud/servers/{id}/console

**Open a one-time VNC console ticket** · operationId `openConsole` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/openConsole.json

Returns a websocket URL and password valid for about a minute. Never send an Idempotency-Key here (400). In tr-ist-1 the ticket is a WebMKS websocket (`protocol: webmks`, empty password: the URL is the one-time secret).
tr-ist-1: the WebSocket URL is on konsol.gyrohosting.com (single-use ticket). 2.14.0 (Gyro Compute): `protocol: web`, `url` is a one-time browser page (90 s) with keyboard + screen; `wss_url` carries the same URL for older clients.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Server id (= service id in the client area) |

### Responses

- **201**: Ticket
- **400**: Malformed request (e.g. missing Idempotency-Key)
- **404**: Not found — also returned for objects owned by someone else
- **409**: State conflict (`server_locked`, `not_actionable`, `ssh_key_exists`, `server_limit`, `idempotency_in_flight`)

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/console' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro server console 12345
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/console", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/servers/12345/console", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## POST /cloud/bulk

**Run one action on up to 50 servers** · operationId `bulkServerAction` · scope `cloud_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/bulkServerAction.json




### Request body

| Field | Type | Description |
|---|---|---|
| `action` (required) | string (poweron, shutdown, reboot, poweroff, reset, rebuild, disable_rescue) |  |
| `server_ids` (required) | array<integer> |  |
| `image` | string |  |
| `confirm` | boolean |  |

### Responses

- **207**: Per-target results
- **422**: Validation or business rule failure (`confirm_required`, `invalid_image`, `tool_action_failed` ...)

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/bulk' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action": "poweron", "server_ids": [1], "image": "string", "confirm": true}'
```
```bash
gyro bulk --help    # all flags
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/bulk", headers=h, json={"action": "poweron", "server_ids": [1], "image": "string", "confirm": True}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/bulk", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"action": "poweron", "server_ids": [1], "image": "string", "confirm": true}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```
