Servers API
The server resource
Section titled “The server resource”{ "id": "01k…", "name": "app-1", "type": "app", "type_label": "App server", "status": "active", "status_message": null, "provider": "custom", "provider_label": "Custom (bring your own server)", "region": null, "ipv4": "203.0.113.20", "private_ipv4": "10.0.0.5", "ssh_port": 22, "php": "8.4", "agent": { "status": "online", "last_heartbeat_at": "2026-09-28T10:00:00+00:00", "version": "v0.2.6", "available_version": "v0.2.6", "update_available": false, "upgrade": null }, "load1": 0.12, "cpu_percent": 3.4, "memory_percent": 41.2, "disk_percent": 22.9, "created_at": "2026-09-26T10:00:00+00:00"}| Field | Values |
|---|---|
type |
app, web, db, cache, worker, lb, builder |
status |
creating, provisioning (machine check and plan), needs_attention (the machine check found a conflict; nothing was applied; status_message lists it), active, error, deleting. Only active servers are deploy targets. |
provider |
hetzner, digitalocean, vultr, linode, aws, custom |
private_ipv4 |
The server’s address on its private network, or null when it has none (falak ssh --private uses it) |
ssh_port |
The server’s SSH port |
php |
The default PHP version, or null |
agent |
null until an agent enrolled |
agent.status |
online / offline (and other Fleet states) |
agent.upgrade |
The latest upgrade: status (queued, running, succeeded, failed, cancelled), from_version, to_version, error, requested_at, finished_at |
GET /api/v1/servers — servers.view
Section titled “GET /api/v1/servers — servers.view”All servers of the organization, ordered by name, in {"data": [...]}.
GET /api/v1/servers/{server} — servers.view
Section titled “GET /api/v1/servers/{server} — servers.view”One server, plus stack (the chosen software) and php_versions (installed PHP versions).
POST /api/v1/servers — servers.create
Section titled “POST /api/v1/servers — servers.create”| Field | Rule |
|---|---|
name |
Required; up to 64 characters, ^[A-Za-z0-9][A-Za-z0-9 ._-]*$, unique in the organization |
type |
Required; a server type |
provider |
Required; a provider value |
credential_id |
Provider credential (not for custom) |
region, size, image |
Provider catalog values |
timezone |
IANA timezone |
stack.php |
{runtime, versions[], default}; runtime is frankenphp or fpm |
stack.node |
"20", "22" or "24" |
stack.database |
postgresql, mysql or mariadb |
stack.cache |
redis or valkey |
stack.docker |
Boolean |
ssh_key_ids[] |
Organization SSH keys to install |
curl -X POST https://falak.example.com/api/v1/servers \ -H "Authorization: Bearer $FALAK_TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \ -d '{"name": "app-1", "type": "app", "provider": "custom", "stack": {"php": {"runtime": "frankenphp", "versions": ["8.4"], "default": "8.4"}, "node": "22", "database": "postgresql", "cache": "redis", "docker": false}}'201 with the server resource plus install_command (custom servers only; null otherwise):
{"data": {"id": "01k…", "name": "app-1", "status": "creating", "…": "…", "install_command": "curl -fsSL https://falak.example.com/install/Xy3…a9 | sudo sh"}}Run install_command as root on the machine. See Connect your own server.
Machine check
Section titled “Machine check”Servers whose agent is v0.6.0 or later are checked before provisioning (see Machine check). Each component (base, docker, database, cache, edge, php, node, ssh, firewall, swap, hostname, unattended_upgrades, fail2ban) gets a decision: install, adopt, complete, block or skip.
GET /api/v1/servers/{server}/inspection — servers.view
Section titled “GET /api/v1/servers/{server}/inspection — servers.view”The latest check and the decisions for the server’s current stack; 404 when there is none (older agents, not enrolled yet).
{"data": {"supported": true, "status": "finished", "purpose": "provision", "checked_at": "2026-10-13T09:12:00+00:00", "agent_version": "v0.6.0", "blocking": true, "summary": "Machine check: 1 conflict to fix before provisioning. Port 80 is in use by nginx, which Falak's edge needs.", "components": [{"component": "edge", "decision": "block", "severity": "block", "reason": "Port 80 is in use by nginx, which Falak's edge needs.", "hint": "Stop and disable it (systemctl disable --now nginx.service) or move it to another port, then re-check.", "found": [{"name": "nginx", "version": "1.24.0", "source": "Ubuntu archive"}], "install": [], "keep": []}]}}status is running, finished or failed. Components sort blocks first, then warnings.
POST /api/v1/servers/{server}/inspection — servers.manage
Section titled “POST /api/v1/servers/{server}/inspection — servers.manage”Re-check: runs the check again and never applies anything. 202; 422 when the agent is too old or offline, or a check is already running. 10/min.
POST /api/v1/servers/{server}/provision — servers.manage
Section titled “POST /api/v1/servers/{server}/provision — servers.manage”The Provision button: applies the plan from the latest check, for a server in needs_attention or error whose latest check finished without blocks. 202 {"data": {"status": "provisioning", "command_id": "01k…"}}; 422 with the summary of what blocks. 10/min.
POST /api/v1/servers/{server}/reprovision — servers.manage
Section titled “POST /api/v1/servers/{server}/reprovision — servers.manage”Re-provision: the machine check first, then the plan. A server that was provisioned before keeps its status; when something blocks, its status_message starts with “Re-provisioning stopped.” and nothing is applied. 202. 10/min.
DELETE /api/v1/servers/{server} — servers.delete
Section titled “DELETE /api/v1/servers/{server} — servers.delete”Deletes the server. For provider servers, the machine is destroyed at the provider unless you pass destroy_at_provider=false. Returns 202 with no body.
curl -X DELETE "https://falak.example.com/api/v1/servers/01k…?destroy_at_provider=false" \ -H "Authorization: Bearer $FALAK_TOKEN" -H "Accept: application/json"POST /api/v1/servers/{server}/database-engine — servers.manage
Section titled “POST /api/v1/servers/{server}/database-engine — servers.manage”Installs a database or cache engine on a provisioned server that has none. Rate limited to 10/minute.
{"engine": "postgresql"}engine is postgresql, mysql or mariadb for a SQL database engine, or redis/valkey for a cache engine on a server type with a cache component (app, cache) — Valkey only where the OS packages it (Ubuntu 24.04 and 26.04, Debian 13; see Redis and Valkey). One engine install runs at a time. The engine joins the server’s stack and the provisioning plan converges with it (the distribution’s packages and service, as at creation).
{"data": {"engine": "postgresql", "status": "installing", "command_id": "01k…"}}Once the agent reports success, the engine appears under Databases (and, on app servers, is reachable from the server’s containers). When the plan fails, the engine is taken back out of the stack (audit event server.database_engine_install_failed).
| Status | Meaning |
|---|---|
202 |
Install started |
422 |
Unsupported engine; the server already runs (or is installing) one of that kind; a server type without that kind (only app servers can add a SQL or cache engine later; db and cache servers always have one); the server is not active; or the machine check blocks it (another engine of the kind, or its port taken — the message names it) |
POST /api/v1/servers/{server}/agent/upgrade — fleet.agents.manage
Section titled “POST /api/v1/servers/{server}/agent/upgrade — fleet.agents.manage”Upgrades the server’s agent to the build this control plane ships. Rate limited to 30/minute.
{"data": {"id": "01k…", "server_id": "01k…", "status": "running", "from_version": "v0.3.0", "to_version": "v0.4.0", "rollout_id": null, "error": null, "requested_at": "2026-09-28T10:00:00+00:00", "finished_at": null}}If an upgrade is already running, the same upgrade is returned. It succeeds once the restarted agent reports the new build, and fails on a download, checksum or pre-flight error, or after FALAK_AGENT_UPGRADE_TIMEOUT seconds.
| Status | Meaning |
|---|---|
202 |
Upgrade started (or already running) |
409 |
No agent, agent offline, no verifiable build for the server’s architecture, or already on that build |