Skip to content

Servers API

{
"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

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).

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
Terminal window
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.

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.

Terminal window
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.

Request body
{"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).

202 Accepted
{"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.

202 Accepted
{"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