> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squasher.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Releases API

> List the releases of each service and compare the health of one release with the release before it.

A release is one version of one service in one environment. Squasher builds releases from
deployment records and from the `service.version` that your telemetry sends. The Releases API lists
them and compares the health of one release with the release before it. See
[Services and releases](/features/services-and-releases) for how Squasher finds releases.

## Operations

| Operation | Method and path | Purpose |
| - | - | - |
| `releases.list` | `GET /v1/projects/{project_id}/releases` | List releases that served in a window, newest first. |
| `releases.get` | `GET /v1/projects/{project_id}/releases/{release_id}` | Read one release with its commits, deployments, and health comparison. |

Both operations need the `deployments:read` and `errors:read` scopes.

## Query parameters

`releases.list` takes these parameters. `releases.get` takes none.

| Parameter | Values | Default |
| - | - | - |
| `from` | ISO 8601 timestamp | 30 days before `to` |
| `to` | ISO 8601 timestamp | Now |
| `environment` | A `deployment.environment.name`, for example `production`. Empty (`environment=`): releases without an environment | All environments |
| `service_name` | A `service.name` | All services |
| `confidence` | `confirmed` or `inferred` | Both |
| `limit` | 1 to 100 | 50 |

The window is at most 90 days. A release is in the list when it served at any time in the window.

## Release IDs

A release ID starts with `rel_`. The same environment, service, and version always give the same
ID, so you can store an ID and read the release again later. Treat the ID as opaque text.

## List releases

```bash theme={null}
curl --get \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/releases" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --data-urlencode "service_name=checkout-api" \
  --data-urlencode "environment=production"
```

```json theme={null}
{
  "data": [
    {
      "id": "rel_WyJwcm9kdWN0aW9uIiwiY2hlY2tvdXQtYXBpIiwiMi40LjEiXQ",
      "service_name": "checkout-api",
      "environment": "production",
      "version": "2.4.1",
      "confidence": "confirmed",
      "started_at": "2026-10-10T16:02:11.000Z",
      "ended_at": null,
      "is_current": true,
      "first_seen": "2026-10-10T16:02:40.000Z",
      "last_seen": "2026-10-11T09:29:41.000Z",
      "commit_sha": "9f2c1e7",
      "comparison": "unchanged",
      "deployment_count": 1,
      "previous_release_id": "rel_WyJwcm9kdWN0aW9uIiwiY2hlY2tvdXQtYXBpIiwiMi40LjAiXQ"
    }
  ],
  "environments": ["production", "staging"],
  "services": ["checkout-api", "payments", "web"],
  "from": "2026-09-11T09:30:00.000Z",
  "to": "2026-10-11T09:30:00.000Z",
  "truncated": false
}
```

| Field | Description |
| - | - |
| `confidence` | `confirmed` when a deployment record names the version. `inferred` when only telemetry names it. |
| `started_at` | The deploy time of a confirmed release, else the first span or log of the version. |
| `start_approximate` | `true` when `started_at` is only the hour of the first span or log: Squasher keeps exact first times only for telemetry received after this feature shipped, and no deployment record gives the time. |
| `ended_at` | When the release last stopped serving. `null` while the release serves. |
| `is_current` | `true` for the release that serves now. |
| `first_seen` | The first span or log with this version. `null` when no telemetry names it. |
| `commit_sha` | The latest commit of the matching deployment records, else `null`. |
| `comparison` | `improved`, `regressed`, `unchanged`, or `insufficient_data`. Set on the first 25 releases of a list; `null` after them. |
| `previous_release_id` | The release of the same service and environment that served before this one. |
| `environments` | Environments with releases in the window, before the filters. |
| `services` | Services with releases in the window, before the filters. |
| `truncated` | `true` when more releases match than the response holds. |

## Read one release

```bash theme={null}
curl \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/releases/rel_WyJwcm9kdWN0aW9uIiwiY2hlY2tvdXQtYXBpIiwiMi40LjEiXQ" \
  --header "x-squasher-key: $SQUASHER_API_KEY"
```

```json theme={null}
{
  "release": {
    "id": "rel_WyJwcm9kdWN0aW9uIiwiY2hlY2tvdXQtYXBpIiwiMi40LjEiXQ",
    "service_name": "checkout-api",
    "environment": "production",
    "version": "2.4.1",
    "confidence": "confirmed",
    "started_at": "2026-10-10T16:02:11.000Z",
    "ended_at": null,
    "is_current": true,
    "commit_sha": "9f2c1e7",
    "commits": [{ "sha": "9f2c1e7", "branch": "main" }],
    "serving": [{ "started_at": "2026-10-10T16:02:11.000Z", "ended_at": null }],
    "deployments": [
      {
        "id": "4b0e7a51-2f7c-4c6e-9a43-1d2a8e5f6b70",
        "provider": "github",
        "deployment_id": "run-8812",
        "status": "ready",
        "url": "https://github.com/acme/checkout/actions/runs/8812",
        "started_at": "2026-10-10T15:58:02.000Z",
        "finished_at": "2026-10-10T16:02:11.000Z"
      }
    ]
  },
  "previous_release": {
    "id": "rel_WyJwcm9kdWN0aW9uIiwiY2hlY2tvdXQtYXBpIiwiMi40LjAiXQ",
    "version": "2.4.0"
  },
  "health": {
    "comparison": "regressed",
    "window": { "from": "2026-10-10T16:02:11.000Z", "to": "2026-10-11T16:02:11.000Z" },
    "previous_window": { "from": "2026-10-09T16:02:11.000Z", "to": "2026-10-10T16:02:11.000Z" },
    "current": {
      "request_count": 48210,
      "error_count": 731,
      "error_rate": 1.52,
      "p50_ms": 41,
      "p95_ms": 380,
      "p99_ms": 1210,
      "throughput_per_min": 33.5
    },
    "previous": {
      "request_count": 50122,
      "error_count": 150,
      "error_rate": 0.3,
      "p50_ms": 39,
      "p95_ms": 290,
      "p99_ms": 990,
      "throughput_per_min": 34.8
    },
    "deltas": { "error_rate_points": 1.22, "p95_percent": 31, "throughput_percent": -3.7 },
    "new_issues": {
      "count": 1,
      "items": [
        {
          "id": "0b7d3f8e-5a61-4c2b-8f9e-3c4d5e6f7a81",
          "short_id": "CHECKOUT-41",
          "title": "TypeError: Cannot read properties of undefined (reading 'total')",
          "first_seen": "2026-10-10T16:09:54.000Z"
        }
      ],
      "truncated": false
    },
    "series": []
  }
}
```

The JSON is shortened. `previous_release` has the same fields as a list item, and `series` has one
point for each bucket of the compared window. `serving` lists each time the release served, oldest
first.

## Serving and rollbacks

One release of a service and environment serves at a time.

* A release serves from its start until another release starts. A release keeps one ID: when an
  older version comes back (a rollback), it serves again and `serving` gets one more item.
* A deployment record of an older version after a newer one started is a rollback.
* Without a record, Squasher takes a rollback when the serving version stops sending telemetry for
  15 minutes or more while an older version keeps sending. The older version serves again from the
  end of those 15 minutes, the first time the rollback is known.
* When two versions overlap (a canary, a rolling deploy, or blue/green), the version that started
  later serves from its start. Version text does not set the order. At the same start time, a
  version with a deployment record wins, then the version seen last.

## Health comparison

Squasher compares a release with the release of the same service and environment that served
before it:

* Squasher compares the first time the release served with the time just before it, when the
  previous release served.
* Both windows have the same length: the shorter of the two serving times, and 24 hours at most.
  No window goes past a serving time.
* When that length is less than 5 minutes, or there is no previous release, `comparison` is
  `insufficient_data` and `previous` is `null`. `window` is then the release's own serving time.
* Each side needs at least 50 requests. With fewer, `comparison` is `insufficient_data`.

| `comparison` | When |
| - | - |
| `regressed` | The error rate rises by 1 percentage point or more, or p95 rises by 20% or more (and 5 ms or more). |
| `improved` | The error rate falls by 1 point or more, or p95 falls by 20% or more (and 5 ms or more). |
| `unchanged` | Neither of the above. |
| `insufficient_data` | No previous release, windows shorter than 5 minutes, or fewer than 50 requests on one side. |

`regressed` wins when one metric gets worse and another gets better. `deltas.error_rate_points` is
in percentage points. `deltas.p95_percent` and `deltas.throughput_percent` are in percent.

`new_issues` counts the issues of the service, in the same environment, that were first seen in
the compared window. It lists the 10 newest and counts up to 100. Issues without a service are not
counted.

The metrics cover the service and environment over time, not one version. During a rolling deploy,
both versions serve at the same time, so the first minutes mix both versions.

## Errors

| Status | When |
| - | - |
| `400` | A parameter is not valid, for example an unknown `confidence` or a `limit` above 100. |
| `403` | The key does not have both `deployments:read` and `errors:read` on the project. |
| `404` | `releases.get` only: the ID is not valid, or the release did not serve in about the last 120 days. |
| `422` | `from` is after `to`, or the window is longer than 90 days. |

## TypeScript client, CLI, and MCP

```typescript theme={null}
const releases = await client.releases.list({
  service_name: "checkout-api",
  confidence: "confirmed",
});
const release = await client.releases.get(releases.data[0].id);
```

```bash theme={null}
squasher releases list --project <project_id> --service checkout-api --environment production
squasher releases get --project <project_id> <release_id>
```

Add `--json` to print the full response. In MCP Code Mode, call `search("releases")` first, then
`execute` with `releases.list` or `releases.get`.

## Related guides

* [Services and releases](/features/services-and-releases)
* [Deployments API](/api-reference/deployments)
* [Services API](/api-reference/services)
* [Issues](/features/issues)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.