# List releases

Source: https://www.jawsdeploy.net/rest-api/releases-list | Section: Releases

Page through a project's releases, newest first, with the notes and metadata of each one.

`GET /api/release`

Returns one page of the releases of a project, newest first.

Every entry carries the release's identity, its notes and the [metadata document](https://www.jawsdeploy.net/rest-api/releases-create) attached when it was created, so a pipeline polling for what has been built does not have to read each release individually to see them.

What is deliberately **not** here is the snapshot - the package versions, steps, variables and lifecycle phases a release locked in. That is what [Get a release](https://www.jawsdeploy.net/rest-api/releases-details) returns. The deployments of a release are not here either: a release can be deployed any number of times, so its deployments are a paged list of their own - [List deployments](https://www.jawsdeploy.net/rest-api/deployments-list).

Ordering is by **creation date**, newest first, with the release ID breaking ties between two releases created in the same microsecond. It is not version order: SemVer ordering cannot be expressed in SQL, and a page boundary has to mean the same thing to the server as it does to the caller. A release cut out of version sequence - a hotfix on an older line, say - therefore still appears at the top of the first page.

Deleted releases are never returned.

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `projectId` | query | string | yes | ID of the project whose releases to list, from [List projects](https://www.jawsdeploy.net/rest-api/projects-list). |
| `max` | query | integer | no | Releases per page. Defaults to `100` and is clamped to the range 1-500 rather than rejected, so an out-of-range value still returns a page. |
| `cursor` | query | string | no | Continuation token from the previous response's `nextCursor`. Omit it to read the first page. See below. |

### Paging

Paging is by cursor, not by row offset. Read the first page without `cursor`, then hand each response's `nextCursor` back as the `cursor` of the next request, and keep going until `nextCursor` comes back `null`.

That `null` is the only signal that you have read everything. Do not stop on a short page and do not compare the row count against the `max` you asked for - neither tells you whether more releases follow.

A cursor rather than a page number, because a build server keeps creating releases while you page and each new one arrives at the *top* of this list. A numbered window would shift underneath you on every arrival, handing you some releases twice and skipping others entirely. A cursor names the last row you actually read, so the next page continues from there whatever has appeared in front of it.

The token is opaque. Hand it back as you received it rather than building or reading one - it encodes a position, and the encoding is free to change. A token that does not decode is rejected with `400` rather than ignored, because serving page one to a caller that believes it asked for page nine is the worse failure.

## Response fields

| Field | Type | Description |
|---|---|---|
| `projectId` | string | The project the page belongs to, echoing the one you asked for. |
| `releases` | object[] | One page of releases, newest first. Empty array when the project has no releases - not an error. |
| `releases[].releaseId` | string | The release's id. Pass it to [Get a release](https://www.jawsdeploy.net/rest-api/releases-details) or [Deploy a release](https://www.jawsdeploy.net/rest-api/releases-deploy). |
| `releases[].projectId` | string | The project the release belongs to. |
| `releases[].version` | string | The release version, as it was stored. Note that this list is *not* ordered by it. |
| `releases[].notes` | string | The release notes, or `null` when none were given. |
| `releases[].metadata` | object | The free-form document attached at creation, exactly as it was stored, or `null` when none was attached. Jaws never reads into it - see [Create a release](https://www.jawsdeploy.net/rest-api/releases-create). |
| `releases[].created` | string | When the release was created, ISO 8601 with offset. This is the field the list is ordered by. |
| `releases[].createdBy` | object | Who created the release: `userId`, `name` and `email`. The service account's own user for a release cut by a pipeline. `null` when the creator no longer resolves. |
| `releases[].channelId` | string | The channel the release is bound to, or `null` for a release created without one. |
| `releases[].channelName` | string | Name of that channel, or `null`. |
| `releases[].lifecycleName` | string | Name of the lifecycle the channel binds the release to, or `null` when the release is not phase-controlled. |
| `nextCursor` | string | Pass back as `cursor` to read the next page. `null` means this page was the last one. |

## Errors

| Status | Meaning |
|---|---|
| 400 | Missing or invalid `projectId`. A project in another organization is reported the same way as one that does not exist, so an id cannot be probed for existence. |
| 400 | `cursor` is not a token this endpoint issued - the response reads `invalid cursor`. Nothing is returned; ask again from the page you last read. |
| 401 | Missing or invalid Basic auth credentials, or the service account lacks permission to view releases of this project. |

Example request:

```
GET /api/release?projectId=prj_abc123&max=50 HTTP/1.1
Host: app.jawsdeploy.net
Authorization: Basic <base64(serviceAccountId:apiKey)>
```

Example response:

```
{
  "projectId": "prj_abc123",
  "releases": [
    {
      "releaseId": "rel_9f4c",
      "projectId": "prj_abc123",
      "version": "2.5.3",
      "notes": "Build #4821 from main",
      "metadata": {
        "buildUrl": "https://ci.example/build/4821",
        "commit": "3f9a1c2",
        "workItems": [
          { "id": "JAWS-14", "title": "Fix the retry loop" }
        ]
      },
      "created": "2026-09-05T09:14:22.418+00:00",
      "createdBy": {
        "userId": "usr_ci",
        "name": "Build agent",
        "email": "ci@example.com"
      },
      "channelId": "chn_stable",
      "channelName": "Stable",
      "lifecycleName": "Default lifecycle"
    }
  ],
  "nextCursor": "NjM4OTM5MzI0NjI0MTgwMDAwfHJlbF85ZjRj"
}
```

