# List deployments

Source: https://www.jawsdeploy.net/rest-api/deployments-list | Section: Deployments

Page through the deployments of a workspace, a project or a single release - and poll for what has changed.

`GET /api/deployment/list`

Returns one page of deployments, most recently changed first.

**Scope is required, and it is exactly one of** `workspaceId`, `projectId` or `releaseId`. Sending none of them, or more than one, is a `400` - there is no unscoped read of every deployment in the organization. Adding `version` to a `projectId` narrows the read to that one release, resolved the same way [Get a release](https://www.jawsdeploy.net/rest-api/releases-details) resolves it.

Each entry is a summary: what was deployed where, by whom, when it last changed, and its status and error counts. The **logs are not here** - those are on [Get deployment status](https://www.jawsdeploy.net/rest-api/deployments-status), one deployment at a time.

One deployment targets exactly one environment. A [deploy](https://www.jawsdeploy.net/rest-api/releases-deploy) or [promote](https://www.jawsdeploy.net/rest-api/releases-promote) that named three environments produced three deployments, and all three appear here separately.

A workspace-wide read shows the projects this service account may see and **silently leaves the rest out**. Asking about a workspace is a fair question even when part of it is none of your business, so widening the scope never turns into a permission error over one project. Naming a project or a release you may not see is a different matter, and is refused.

Optionally narrow any scope to selected environments with `environmentIds` or `environmentNames`. Omit both to keep the existing unfiltered behavior. See the environment filtering notes below.

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `workspaceId` | query | string | no | Every deployment of every project in this workspace that you are allowed to see. Give exactly one of `workspaceId`, `projectId` or `releaseId`. |
| `projectId` | query | string | no | Every deployment of this project. Give exactly one of the three scope parameters. |
| `releaseId` | query | string | no | Every deployment of this one release. Give exactly one of the three scope parameters. |
| `version` | query | string | no | Narrows a `projectId` read to the release carrying this version. Only valid together with `projectId` - on its own it is a `400`. Matched exactly first, then as a SemVer equivalent, so `6.1` finds `6.1.0`. |
| `changedSince` | query | string | no | ISO 8601 date and time, e.g. `2026-09-02T14:05:00Z`. Only deployments that changed strictly after it are returned, and the sort flips to oldest change first. See below. |
| `max` | query | integer | no | Deployments per page. Defaults to `100` and is clamped to the range 1-500 rather than rejected. |
| `cursor` | query | string | no | Continuation token from the previous response's `nextCursor`. Omit it to read the first page. See below. |
| `environmentIds` | query | array<string> | no | Optional environment IDs. Repeat the query key for multiple values, for example `environmentIds=env_prod&environmentIds=env_stage`. Matches any listed environment within the scoped workspace. Cannot be combined with `environmentNames`. See below. |
| `environmentNames` | query | array<string> | no | Optional environment names. Repeat the query key for multiple values, for example `environmentNames=Production&environmentNames=Staging`. Matches any listed name within the scoped workspace, case-insensitively. URL-encode names, for example `environmentNames=Pre%20Production`. Cannot be combined with `environmentIds`. See below. |

### Polling for what has changed

`changedSince` is the field to build a reporter on. Only deployments whose `changedUtc` is strictly after it come back, so the same value never hands you the same row twice.

**The sort direction flips with it, deliberately.**

- **Without `changedSince`** you are browsing, and the most recent change comes first.
- **With `changedSince`** you are catching up, and the *oldest* change comes first - so you walk forward through what happened and can stop anywhere with a coherent position behind you.

The loop is: take the highest `changedUtc` in what you were given, hand it back as the next `changedSince`, repeat. Use the value from the response rather than your own clock; the timestamps are the server's, and your clock is not.

Ordering is by when a deployment last changed rather than when it was created, because the column a page boundary sits on has to be the column the filter uses. That column is written when the row is created, refreshed while the deployment runs, and updated on every status transition. For rows written before every writer set it, `changedUtc` falls back to the creation date, so a deployment always has a place in the timeline.

Keep `changedSince` on **every** request of the same walk. Dropping it midway flips the direction, and the cursor you are holding is then read the other way round.

### Paging

Paging is by cursor, exactly as on [List releases](https://www.jawsdeploy.net/rest-api/releases-list). Read the first page without `cursor`, hand each response's `nextCursor` back as the next `cursor`, and keep going until it comes back `null`.

A short page is not the last page - only a `null` cursor is. The token is opaque, and one that does not decode is refused with `400` rather than quietly restarting you at page one.

### Field casing

This endpoint answers in lower camel case - `deploymentId`, `errorCount` - as every listing in this reference does. [Get deployment status](https://www.jawsdeploy.net/rest-api/deployments-status) is the exception: its `status` object and log entries are Pascal case (`Status`, `ErrorCount`). The two shapes describe the same deployment and cannot share a parser.

### Status values

`status` is one of `Queued`, `Validating`, `AwaitingSlot`, `Running`, `Completed`, `Failed` or `Cancelled`.

`Completed`, `Failed` and `Cancelled` are terminal - a deployment in one of them will not change again. The other four are transient, and a deployment can move between `AwaitingSlot` and `Validating` more than once before it runs.

`Completed` means the engine reached the end of the step list, not that the deployed work was healthy. That is the separate question `errorCount` answers, and [Get deployment status](https://www.jawsdeploy.net/rest-api/deployments-status) covers both in full.

### Filtering by environment

Keep exactly one scope parameter (`workspaceId`, `projectId` or `releaseId`). Environment filters also work with `projectId` plus `version` and with `changedSince`. They narrow that scope and do not replace it.

Supply **either** `environmentIds` **or** `environmentNames`, repeating the query key once per value. Do not send a comma-separated list. A deployment matches **any** of the supplied environments. Both IDs and names are trimmed and compared case-insensitively, and duplicate values are ignored.

Every value must resolve to a non-deleted environment in the scoped workspace. For a project or release scope, this is the workspace that owns the project. Use [List environments](https://www.jawsdeploy.net/rest-api/environments-list) to find IDs and names. Disabled environments are still valid filters, so you can read their deployment history. Any invalid value rejects the whole request with `400`. A valid filter with no matching deployments returns an empty `deployments` array.

Filtering happens **before pagination**. When following `nextCursor`, keep the same scope, environment filters and `changedSince` value on every page. If you change the filters, start again without a cursor.

## Response fields

| Field | Type | Description |
|---|---|---|
| `workspaceId` | string | Echoed back when you asked by workspace, otherwise `null`. |
| `projectId` | string | Echoed back when you asked by project, otherwise `null`. |
| `releaseId` | string | The release you asked by - or, for a `projectId` and `version` read, the release that version resolved to. `null` otherwise. That makes this the cheapest way to turn a version into a release id. |
| `deployments` | object[] | One page of deployments. Empty array when nothing matches - including when a workspace holds no project you may see, which is not an error. |
| `deployments[].deploymentId` | string | Pass it to [Get deployment status](https://www.jawsdeploy.net/rest-api/deployments-status) or [Cancel a deployment](https://www.jawsdeploy.net/rest-api/deployments-cancel). |
| `deployments[].status` | string (enum) | `Queued`, `Validating`, `AwaitingSlot`, `Running`, `Completed`, `Failed` or `Cancelled`. See below. |
| `deployments[].projectId` | string | The project the deployed release belongs to. |
| `deployments[].projectName` | string | That project's name as it reads now. |
| `deployments[].releaseId` | string | The release that was deployed. Read it with [Get a release](https://www.jawsdeploy.net/rest-api/releases-details). |
| `deployments[].releaseVersion` | string | That release's version. |
| `deployments[].environmentId` | string | The one environment this deployment targeted. |
| `deployments[].environmentName` | string | That environment's name, or `null` when it no longer resolves. |
| `deployments[].createdUtc` | string | When the deployment was created, ISO 8601 with offset. |
| `deployments[].deploymentDateUtc` | string | When it is due to run. The same as `createdUtc` for an immediate deploy, later for one scheduled with `deploymentDateUnixMillis`. |
| `deployments[].completeUtc` | string | When it finished, or `null` while it has not. |
| `deployments[].changedUtc` | string | When it last changed - created, started, retried, finished or cancelled. **This is the field the list is ordered and filtered by**, and the one to feed back as `changedSince`. |
| `deployments[].errorCount` | integer | Error-level log entries recorded so far. It only grows, and it counts log lines rather than failed steps. A `Completed` deployment can still have a non-zero count. |
| `deployments[].warningCount` | integer | The same count for warning-level entries. |
| `deployments[].automated` | boolean | `true` when a lifecycle started this deployment on its own, rather than a person or a pipeline asking for it. |
| `deployments[].createdBy` | object | Who started it: `userId`, `name`, `email`. `null` for an automated deployment, or when the creator no longer resolves. |
| `nextCursor` | string | Pass back as `cursor` to read the next page. `null` means this page was the last one. |

## Errors

| Status | Meaning |
|---|---|
| 400 | None of `workspaceId`, `projectId` and `releaseId` was given, or more than one was - the response reads `give exactly one of workspaceId, projectId or releaseId`. |
| 400 | `version` was sent without `projectId` - the response reads `version only applies together with projectId`. |
| 400 | `changedSince` is not an ISO 8601 date and time. The message names the format it wanted, e.g. `2026-09-02T14:05:00Z`. |
| 400 | `cursor` is not a token this endpoint issued - the response reads `invalid cursor`. |
| 400 | Invalid `workspaceId`, `projectId` or `releaseId`, or no release with that `version` exists for the project. A resource in another organization is reported the same way as one that does not exist. |
| 401 | Missing or invalid Basic auth credentials, or the service account lacks permission to view deployments of the project or release you named. A workspace read never fails this way - projects you cannot see are left out of the page instead. |
| 400 | Both environment filters were supplied - `give only one of environmentIds or environmentNames`. |
| 400 | An environment filter contains an empty or whitespace-only value - `environment filters must not contain blank values`. |
| 400 | At least one environment is unknown, deleted, or outside the scoped workspace - `one or more environments are invalid for this workspace`. The whole request is rejected, even if other values match. Environments in another organization produce the same error. |

Example request:

```
GET /api/deployment/list?projectId=prj_abc123&changedSince=2026-09-02T14:05:00Z&max=50 HTTP/1.1
Host: app.jawsdeploy.net
Authorization: Basic <base64(serviceAccountId:apiKey)>

// or every deployment of one release:
GET /api/deployment/list?releaseId=rel_9f4c HTTP/1.1

// or everything in a workspace you can see:
GET /api/deployment/list?workspaceId=ws_abc HTTP/1.1

// Project deployments in either environment, filtered before paging:
GET /api/deployment/list?projectId=prj_abc123&environmentIds=env_prod&environmentIds=env_stage&max=50 HTTP/1.1

// One release, selected by project and version, in either named environment:
GET /api/deployment/list?projectId=prj_abc123&version=2.5.3&environmentNames=Production&environmentNames=Pre%20Production HTTP/1.1

// Poll a workspace for changes in Production:
GET /api/deployment/list?workspaceId=ws_abc&environmentNames=Production&changedSince=2026-09-02T14:05:00Z HTTP/1.1

// Filter a release directly by environment ID:
GET /api/deployment/list?releaseId=rel_9f4c&environmentIds=env_prod HTTP/1.1
```

Example response:

```
{
  "workspaceId": null,
  "projectId": "prj_abc123",
  "releaseId": null,
  "deployments": [
    {
      "deploymentId": "dep_a1b2c3",
      "status": "Completed",
      "projectId": "prj_abc123",
      "projectName": "Acme Web",
      "releaseId": "rel_9f4c",
      "releaseVersion": "2.5.3",
      "environmentId": "env_prod",
      "environmentName": "Production",
      "createdUtc": "2026-09-05T09:20:01.004+00:00",
      "deploymentDateUtc": "2026-09-05T09:20:01.004+00:00",
      "completeUtc": "2026-09-05T09:24:47.881+00:00",
      "changedUtc": "2026-09-05T09:24:47.881+00:00",
      "errorCount": 0,
      "warningCount": 2,
      "automated": false,
      "createdBy": {
        "userId": "usr_ci",
        "name": "Build agent",
        "email": "ci@example.com"
      }
    }
  ],
  "nextCursor": "NjM4OTM5MzUwODgxMDAwMDAwfGRlcF9hMWIyYzM="
}
```

