# Deployments

A deployment is one commit, built and released to one environment. Each environment keeps its last 20; the last 10 successful ones stay available as rollback targets.

With an [API key](/reference/api/authentication) the organisation is inferred. Session tokens must add `targetOrganisationId` to every body.

## List deployments

```endpoint
POST /api/deployments
> An environment's deploy history, newest first.
permission: read:projects

param environmentId | string | required | The environment to read
param limit | number | 20 | How many to return
param offset | number | 0 | Skip this many
param targetOrganisationId | string | session only | Required when using a session token

response 200 | Deployments, newest first
[
  {
    "id": "dep_9f2a",
    "environment_id": "env_7Tz",
    "status": "healthy",
    "deployment_stage": "released",
    "commit_sha": "9f3c1ab",
    "commit_message": "Fix cart total rounding",
    "started_at": "2026-08-28T07:00:12.000Z",
    "completed_at": "2026-08-28T07:02:40.000Z"
  },
  {
    "id": "dep_7c11",
    "environment_id": "env_7Tz",
    "status": "failed",
    "commit_sha": "2b8e004",
    "commit_message": "Bump image deps",
    "started_at": "2026-08-27T16:41:03.000Z",
    "completed_at": "2026-08-27T16:43:55.000Z"
  }
]

code curl
curl -X POST https://api.light-cloud.com/api/deployments \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"environmentId": "env_7Tz", "limit": 5}'

code Node
const res = await fetch("https://api.light-cloud.com/api/deployments", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_CLOUD_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ environmentId: "env_7Tz", limit: 5 }),
});

if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);

const deployments = await res.json();
deployments.forEach((d) => console.log(d.commit_sha, d.status, d.commit_message));

code Python
import os
import requests

res = requests.post(
    "https://api.light-cloud.com/api/deployments",
    headers={"Authorization": f"Bearer {os.environ['LIGHT_CLOUD_API_KEY']}"},
    json={"environmentId": "env_7Tz", "limit": 5},
)
res.raise_for_status()

for d in res.json():
    print(d["commit_sha"], d["status"], d["commit_message"])

code Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.light-cloud.com/api/deployments"))
    .header("Authorization", "Bearer " + System.getenv("LIGHT_CLOUD_API_KEY"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(
        "{\"environmentId\":\"env_7Tz\",\"limit\":5}"))
    .build();

var response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());
```

## Retrieve a deployment

```endpoint
POST /api/deployments/get
> One deployment with its build logs. `status` moves through pending, building, deploying, then settles on healthy or failed; `deployment_stage` is the finer step within that.
permission: read:projects

param deploymentId | string | required | The deployment to read
param targetOrganisationId | string | session only | Required when using a session token

response 200 | A deployment
{
  "id": "dep_9f2a",
  "environment_id": "env_7Tz",
  "status": "healthy",
  "deployment_stage": "released",
  "commit_sha": "9f3c1ab",
  "commit_message": "Fix cart total rounding",
  "started_at": "2026-08-28T07:00:12.000Z",
  "completed_at": "2026-08-28T07:02:40.000Z",
  "deployment_logs": [
    "Building container image...",
    "Pushing to registry...",
    "Released to production"
  ]
}

code curl
curl -X POST https://api.light-cloud.com/api/deployments/get \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"deploymentId": "dep_9f2a"}'

code Node
const res = await fetch("https://api.light-cloud.com/api/deployments/get", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_CLOUD_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ deploymentId: "dep_9f2a" }),
});

const deployment = await res.json();
console.log(deployment.deployment_logs.join("\n"));

code Python
import os
import requests

res = requests.post(
    "https://api.light-cloud.com/api/deployments/get",
    headers={"Authorization": f"Bearer {os.environ['LIGHT_CLOUD_API_KEY']}"},
    json={"deploymentId": "dep_9f2a"},
)
res.raise_for_status()

print("\n".join(res.json()["deployment_logs"]))
```

> [!TIP]
> Poll [environment status](/reference/api/environments#retrieve-status) rather than this endpoint while a deploy runs. It is cheaper, and it is what the console does.

## Roll back

```endpoint
POST /api/deployments/rollback
> Re-releases an earlier deployment's existing artifact. Nothing is rebuilt, so it takes seconds and the result is byte-identical to what ran before. Only the last 10 successful deployments are eligible.
permission: update:projects

param environmentId | string | required | The environment to roll back
param deploymentId | string | required | The deployment to return to
param targetOrganisationId | string | session only | Required when using a session token

response 200 | The re-released deployment
{
  "id": "dep_7c11",
  "environment_id": "env_7Tz",
  "status": "deploying",
  "commit_sha": "2b8e004"
}

code curl
API=https://api.light-cloud.com
AUTH=(-H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" -H "Content-Type: application/json")

# The newest healthy deployment that is not the one currently released
last_good=$(curl -sS -X POST "$API/api/deployments" "${AUTH[@]}" \
  -d "{\"environmentId\":\"$ENV_ID\",\"limit\":10}" \
  | jq -r '[.[] | select(.status == "healthy")][1].id')

curl -sS -X POST "$API/api/deployments/rollback" "${AUTH[@]}" \
  -d "{\"environmentId\":\"$ENV_ID\",\"deploymentId\":\"$last_good\"}"

code Node
const API = "https://api.light-cloud.com";
const headers = {
  Authorization: `Bearer ${process.env.LIGHT_CLOUD_API_KEY}`,
  "Content-Type": "application/json",
};

const historyRes = await fetch(`${API}/api/deployments`, {
  method: "POST",
  headers,
  body: JSON.stringify({ environmentId, limit: 10 }),
});
const history = await historyRes.json();

// [0] is what is running now, so take the next healthy one
const lastGood = history.filter((d) => d.status === "healthy")[1];
if (!lastGood) throw new Error("No earlier healthy deployment to roll back to");

await fetch(`${API}/api/deployments/rollback`, {
  method: "POST",
  headers,
  body: JSON.stringify({ environmentId, deploymentId: lastGood.id }),
});

code Python
import os
import requests

API = "https://api.light-cloud.com"
headers = {"Authorization": f"Bearer {os.environ['LIGHT_CLOUD_API_KEY']}"}

history = requests.post(
    f"{API}/api/deployments",
    headers=headers,
    json={"environmentId": environment_id, "limit": 10},
).json()

healthy = [d for d in history if d["status"] == "healthy"]
if len(healthy) < 2:
    raise RuntimeError("No earlier healthy deployment to roll back to")

requests.post(
    f"{API}/api/deployments/rollback",
    headers=headers,
    json={"environmentId": environment_id, "deploymentId": healthy[1]["id"]},
).raise_for_status()
```

**Errors**

| Status | Cause |
| --- | --- |
| `400` | The deployment is older than the rollback window, or never succeeded |

```json
{ "message": "This deployment can no longer be rolled back to. Only the last 10 successful deployments are kept as rollback targets." }
```

> [!NOTE]
> A rollback does not change which branch the environment tracks. The next push to that branch deploys forwards again, over the rollback.

## Related

- [Environments](/reference/api/environments): Where deployments happen.
- [Deployments](/platform/deployments): How builds and releases work.
- [Observability](/platform/observability): Logs, metrics, and retention.
