# Deployments API

> Trigger, list, inspect, stream, cancel and roll back Falak deployments through the REST API, with the deployment, step, output and release resources.

Source: https://falak.sh/docs/api/deployments/

## The deployment resource

```json
{"id": "01k…", "site_id": "01k…", "number": 42,
 "status": "deploying", "phase": "migrate",
 "trigger": "api", "strategy": "zero-downtime",
 "branch": "main", "commit": "a1b2c3…", "message": "Fix checkout", "author": "Ada",
 "release_id": "01k…", "build_id": "01k…", "rolled_back": false,
 "url": "https://falak.example.com/sites/01k…/deployments/01k…", "error": null,
 "waiting_reason": null, "waiting_since": null,
 "created_at": "…", "started_at": "…", "finished_at": null}
```

| Field | Values |
|---|---|
| `status` | `queued`, `waiting`, `building`, `deploying`, `succeeded`, `failed`, `cancelled` |
| `phase` | `build`, `fetch`, `prepare`, `migrate`, `activate`, `restart`, `healthcheck`, `rollback`, or `null` |
| `trigger` | `manual`, `push`, `api`, `hook`, `rollback` |
| `strategy` | `zero-downtime`, `in-place`, `rolling`, `canary`, `blue-green`, `compose` |
| `rolled_back` | `true` with `status: failed` means switched servers were returned to the previous release |
| `waiting_reason`, `waiting_since` | Set while `waiting`, e.g. `"Waiting for 2 servers to finish preparing: web-1, web-2"` |

Terminal statuses: `succeeded`, `failed`, `cancelled`.

## `POST /api/v1/sites/{site}/deployments` — `deployments.create`

Body (all optional): `{"branch": "main", "commit": "<sha>"}`. Without a commit, the branch head is resolved through the git provider. Rate limited to 30/minute.

```bash
curl -X POST https://falak.example.com/api/v1/sites/shop/deployments \
  -H "Authorization: Bearer $FALAK_TOKEN" -H "Accept: application/json" -H "Content-Type: application/json" \
  -d '{"branch": "main", "commit": "a1b2c3d4e5f6"}'
```

`201 {"data": Deployment}`. The deployment starts immediately (`building`), queues behind the site's running deployment (`queued`), or waits for servers being prepared (`waiting`).

While a non-rollback deployment is `waiting`, every further trigger — this endpoint, the CLI, the UI, push-to-deploy, deploy hooks — **updates that deployment** (the latest branch/commit wins) and the response is that same deployment. It starts by itself once every preparing server is ready; servers whose preparation failed are skipped with a warning while another server is ready. It fails when the leader's preparation fails, no server can be prepared, or after `FALAK_DEPLOY_WAIT_TIMEOUT_MINUTES` (default 30).

## `GET /api/v1/sites/{site}/deployments` — `deployments.view`

Paginated, newest first.

## `GET /api/v1/deployments/{deployment}` — `deployments.view`

The deployment plus `targets` with their steps:

```json
{"targets": [{"id": "…", "server_id": "…", "server_name": "web-1", "role": "leader", "batch": 0,
  "status": "succeeded", "activated": true, "error": null,
  "steps": [{"key": "fetch:…", "kind": "fetch", "label": "fetch", "phase": "fetch", "rollback": false, "batch": 0,
             "status": "succeeded", "command_id": "…", "exit_code": 0, "error": null,
             "started_at": "…", "finished_at": "…", "duration_ms": 812}]}]}
```

| Field | Values |
|---|---|
| `targets[].status` | `pending`, `deploying`, `succeeded`, `failed`, `rolled_back`, `skipped` |
| `steps[].status` | `pending`, `running`, `succeeded`, `failed`, `skipped` |

## `GET /api/v1/deployments/{deployment}/output?after=<seq>` — `deployments.view`

Output lines with `seq > after` (up to 1000 per page), in order. Poll with `after = meta.next` until `meta.status` is terminal. `server` is `null` for build and orchestration lines.

```json
{"data": [{"seq": 1812, "at": "…", "server": "web-1", "server_id": "…", "step_id": "…",
           "phase": "migrate", "stream": "stdout", "data": "Migrating: …\n"}],
 "meta": {"next": 1812, "status": "deploying"}}
```

```bash title="Poll until done"
after=0
while :; do
  r=$(curl -s "https://falak.example.com/api/v1/deployments/$ID/output?after=$after" \
        -H "Authorization: Bearer $FALAK_TOKEN" -H "Accept: application/json")
  echo "$r" | jq -r '.data[].data' | tr -d '\r'
  after=$(echo "$r" | jq '.meta.next'); status=$(echo "$r" | jq -r '.meta.status')
  case "$status" in succeeded|failed|cancelled) echo "$status"; break;; esac
  sleep 2
done
```

## `POST /api/v1/deployments/{deployment}/cancel` — `deployments.create`

Cancels a deployment that is `queued`, `waiting`, or still `building` (nothing has touched the servers yet). `200 {"data": Deployment}`; `422` otherwise.

## `POST /api/v1/sites/{site}/rollback` — `deployments.rollback`

Body `{"release_id": "<ulid>"}` (optional; default: the newest retained release before the current one). `201 {"data": Deployment}` with `trigger: "rollback"`. `422` (`errors.release_id`) when the release is current, failed or pruned, or there is nothing to roll back to.

## `GET /api/v1/sites/{site}/releases` — `deployments.view`

Retained releases, current first:

```json
{"data": [{"id": "01k…", "commit": "…", "branch": "main", "message": "…", "author": "Ada",
           "deployment_id": "…", "build_id": "…", "image": null,
           "status": "active", "active": true, "can_rollback": false,
           "activated_at": "…", "created_at": "…"}]}
```

`status` is `active` or `inactive`. `image` is set for Docker sites.

The CLI implements this whole flow: `falak deploy <site> --wait` and `falak rollback <site> --wait`. See [CLI commands](/docs/cli/commands/).
