Skip to content
Automating / Change requests

Change requests

The human gate. Everything the API and CLI propose waits here.

KamalCloud’s API and CLI can read the account’s servers, apps and change requests. Neither can change anything.

What they can do is propose. A proposal becomes a change request: a row saying what was asked for, by which token, with the exact values. It does nothing until a person opens KamalCloud and approves it.

This is what makes a KamalCloud token safe to hand to a script, a CI job or an agent. The worst a stolen read token can do is read. The worst a stolen write token can do is fill a queue somebody has to say no to.

The catalogue

Only a fixed list of actions can be proposed. An action name that is not on it is refused with a 422, and the list comes back with the refusal. Each action takes exactly the keys it declares; any other key is dropped before the request is saved, so nothing reaches a model it was not meant for.

Values are not checked when the request is made. A step that names no fix is saved as asked and fails only once somebody approves it, with the list of fixes KamalCloud knows in the error.

Action Parameters
servers.create connection, provider, name, server_type, location, image
servers.resize server_id, server_type
servers.harden server_id, step
environments.deploy environment_id
accessories.back_up accessory_id

step is one of firewall, web_ports, cloud_firewall, ssh_password_auth, ssh_root_login, ssh_keepalive, fail2ban, fail2ban_aggressive, automatic_updates, upgrade, swap or storage – see Hardening. From the CLI that is kamal-cloud harden 12 firewall.

GET /api/v1/actions returns this list, with the step names in the servers.harden summary, so a client finds out what it may propose rather than guessing at names.

Which connection

Where an account holds several connections to one provider, an action that would build something has to say which: connection names it. Naming only a provider works when that provider has exactly one connection, and is refused when it does not – building in one of two Hetzner projects on a coin toss is not a thing KamalCloud will do.

Approving

Change requests lists requests by status, pending first, oldest at the top. Anyone in the account can see the list; only an admin can approve or reject. Each one shows the sentence for the request’s own values – “Build web-3, a cx42 in nbg1, at Production Hetzner” – rather than a generic summary, because approving “build a server” without knowing which is not approving anything.

Approve it and it runs, in the account it was proposed for and as the person who approved it, so whatever it creates is attributed to them rather than to nobody. Reject it and it stops there.

A request moves pending → approved → applied, or to rejected, or to failed if it was approved and the work itself failed. The error and the result are both recorded.

From the client’s side

POST /api/v1/change_requests answers 202 Accepted – accepted for review, not carried out. The distinction is the whole feature, so the status code makes it too.

Poll GET /api/v1/change_requests/:id, or use kamal-cloud wait <id> to block until somebody decides.

Read tokens and write tokens

A token is read-only unless it was issued with write access. A read-only token trying to propose is told plainly rather than getting a confusing permission error. Issue read-only tokens by default; there are few reasons for a script to need more.

Issuing and revoking tokens is admin only.