Power and actions guide
Reboot, power off and power on servers safely from scripts, and follow each action to the end. The endpoint details are on Actions and power.
Before you start
- The key needs the
powerpermission, and the server must be on the key's server list. "All servers" means the servers on the account when the list was saved; a newer server is not covered until the owner updates the list. - Every power request needs an
Idempotency-Key.
The pattern: request, then follow
A power request only queues the action and answers at once with 202 and an action id. The action itself runs moments later. Follow it with GET /actions/{id}, waiting poll_after seconds before the first look.
act=$(curl -sS -X POST https://api.redswitches.com/v1/servers/srv_123/power \
-H "Authorization: Bearer $REDSWITCHES_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"action":"reboot"}' | jq -r .id)
sleep 10
until state=$(curl -sS "https://api.redswitches.com/v1/actions/$act" \
-H "Authorization: Bearer $REDSWITCHES_API_KEY" | jq -r .state) \
&& [ "$state" != queued ] && [ "$state" != running ]; do
sleep 5
done
echo "$act: $state"const action = await rs.power.run("srv_123", { action: "reboot" });
const result = await rs.actions.wait(action.id);
if (result.state !== "done") console.error(result.state, result.reason);action = client.power.run("srv_123", action="reboot")
result = client.actions.wait(action.id)
if result.state != "done":
print(result.state, result.reason)action, err := client.Power.Run(ctx, "srv_123", "reboot")
if err != nil {
log.Fatal(err)
}
result, err := client.Actions.Wait(ctx, action.ID)
if err == nil && result.State != "done" {
log.Println(result.State, *result.Reason)
}{
"id": "act_42",
"kind": "power",
"server_id": "srv_123",
"action": "reboot",
"state": "done",
"reason": null,
"created": "2026-11-15T09:30:00Z",
"started": "2026-11-15T09:30:04Z",
"finished": "2026-11-15T09:30:07Z"
}
done means the command was carried out. A reboot then takes the usual time for the machine to come back; check your own service (SSH, HTTP) for that.
One action per server
Only one action runs on a server at a time. While one is queued, running or not yet settled, another request for the same server answers 409 server_busy, whatever key or Idempotency-Key you use. Wait for the first to finish.
The same answer comes while a server is being delivered or installed, or while a change started in the client area is under way.
When the outcome is unknown
If the command was sent but no clear answer came back, the action ends unknown. We do not retry it silently, because a second power-off or reboot could do harm. RedSwitches staff check the machine and settle the action. Until then, further API power actions on that server answer 409 server_busy. The power buttons in the client area keep working.
Ceilings and the power-off brake
| Ceiling | Default | Answer |
|---|---|---|
| Actions per server | 6 in a rolling hour | 429 action_limit, details.per: "server_hour" |
| Actions per account | 20 in a rolling hour | 429 action_limit, details.per: "account_hour" |
| Power-offs per account | 5 within 10 minutes pauses API power | 403 power_paused |
The power-off brake protects you from a runaway script. Four power-offs within 10 minutes go through; the fifth is refused, and API power for the whole account is paused and our staff are told. Every further power request answers 403 power_paused until staff resume it. Contact support to resume.
Only accepted actions count towards the ceilings.
Other refusals
| Answer | Meaning |
|---|---|
403 permission_denied | The key lacks power, or the server is not on its list. |
409 server_not_active | The server is pending, suspended or ended. A suspended server cannot be powered on through the API. |
422 not_supported | This server cannot be powered through the API. Use the client area. |
Queued too long
An action that has not started within 15 minutes expires: it ends failed with reason expired, and nothing is done. Send a new request (with a new Idempotency-Key) if you still want it.
Retries
If the power request itself times out, send it again with the same Idempotency-Key and body: you get the same action back, and the server is powered only once. See Idempotency and retries. Use a new key only for a new intention, such as a second reboot later.
Recipes
Reboot every server that has a label starting with web-, one at a time:
for id in $(curl -sS "https://api.redswitches.com/v1/servers?limit=100" \
-H "Authorization: Bearer $REDSWITCHES_API_KEY" | jq -r '.data[] | select(.label // "" | startswith("web-")) | .id'); do
curl -sS -X POST "https://api.redswitches.com/v1/servers/$id/power" \
-H "Authorization: Bearer $REDSWITCHES_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"action":"reboot"}'
sleep 120 # let it come back before the next one
doneconst { data } = await rs.servers.list({ limit: 100 });
for (const s of data.filter((x) => x.label?.startsWith("web-"))) {
const a = await rs.power.run(s.id, { action: "reboot" });
await rs.actions.wait(a.id);
}for s in client.servers.list(limit=100).data:
if (s.label or "").startswith("web-"):
a = client.power.run(s.id, action="reboot")
client.actions.wait(a.id)page, _ := client.Servers.List(ctx, &redswitches.ListOptions{Limit: 100})
for _, s := range page.Data {
if s.Label != nil && strings.HasPrefix(*s.Label, "web-") {
a, err := client.Power.Run(ctx, s.ID, "reboot")
if err == nil {
client.Actions.Wait(ctx, a.ID)
}
}
}{ "id": "act_44", "kind": "power", "server_id": "srv_123", "action": "reboot", "state": "queued", "poll_after": 10 }
Keep the 6-per-hour and 20-per-hour ceilings in mind for larger fleets.