# Create a release

Source: https://www.jawsdeploy.net/rest-api/releases-create | Section: Releases

Snapshot package versions and the current deployment plan into a new release.

`POST /api/release`

Creates a new release for a project. A release locks in the project's deployment plan (steps), the chosen package versions, and the project channel - everything needed to redeploy the same thing later.

If `version` is omitted, the server proposes the next version using the project's release versioning rules. If `packageVersions` is omitted, the latest version of every project package is selected by default.

If `channelName` is omitted the project's default channel is used (unless `ignoreDefaultChannel = true`).

### Channel version rules

If the resolved channel has [version rules](https://www.jawsdeploy.net/guides/channel-version-rules), they are enforced here, and they shape the defaults:

- **The proposed version respects the channel.** When `version` is omitted the proposal is seeded from the releases already in that channel - so a stable and a prerelease stream keep independent numbering - then snapped up to the minimum of the channel's version range and given the channel's default prerelease tag.
- **Default package versions respect the channel.** For any package not named in `packageVersions`, the newest version the channel *allows* is pinned, rather than the newest version that exists.
- **Explicit values are validated, never silently corrected.** A `version` or a pinned package version the channel disallows fails the request with a message naming the channel and the reason.

The channel and its rules are always loaded server-side from the channel resolved for this request, so a caller cannot influence which rules apply.

## Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `projectId` | body | string | yes | ID of the project to create the release for. |
| `channelName` | body | string | no | Channel name to bind the release to. Defaults to the project's default channel. The channel's version rules are enforced on this request. |
| `ignoreDefaultChannel` | body | boolean | no | Set to `true` to skip the project's default channel when `channelName` is omitted. The release is then created without a channel, and no channel rules apply. |
| `version` | body | string | no | Explicit SemVer version. Defaults to the next proposed version for the resolved channel. Must satisfy the channel's release version rule. |
| `notes` | body | string | no | Free-form release notes. |
| `packageVersions` | body | object | no | Map of `packageId -> version` to pin specific package versions. Each pinned version must satisfy whichever channel package rule governs that package. Packages left out default to the newest version the channel allows. |
| `metadata` | body | object | no | Free-form JSON object carried with the release - work items, the commit it was built from, a ticket reference. Stored as given and returned by every release read. See below. |

### Release metadata

`metadata` is a free-form JSON document the release carries. Jaws stores it and gives it back on every release read - [List releases](https://www.jawsdeploy.net/rest-api/releases-list) and [Get a release](https://www.jawsdeploy.net/rest-api/releases-details) both return it - and never interprets a single field of it. That is the whole contract, which is why the only rules are about shape and size.

- It must be a **JSON object**. An array, a string, a number or a boolean at the top level is refused with `metadata must be a JSON object`. An object is the only shape that stays extensible: a caller that starts with a `buildUrl` can add `workItems` later without either side renegotiating.
- `{}` is accepted and stored. Omitting the field, or sending JSON `null`, means the release has no metadata, and `metadata` reads back as `null`.
- The serialized document must be at most **64 KB** - 65536 bytes of UTF-8. A larger one is refused with a message naming the size it actually was.

Everything inside is carried through untouched: nesting to any depth, nulls, booleans, numbers and array order all come back as they went in. No field is dropped, renamed or validated, so there is no schema to keep in step with Jaws.

Two things are **not** preserved, because the document is stored in a JSON column: the order of an object's keys, and whitespace. Compare metadata field by field rather than by string equality, and do not expect to read the document back byte for byte.

Metadata belongs to the release from the moment it is created. No endpoint edits it afterwards, so anything a pipeline learns after the release was cut has to go somewhere else.

## Errors

| Status | Meaning |
|---|---|
| 400 | Invalid `projectId`, invalid `channelName`, or pinned packages with versions that don't exist. |
| 400 | `version` is not allowed in the resolved channel - the message names the channel and whether the version range or the prerelease tag rejected it. |
| 400 | One or more pinned package versions are not allowed in the resolved channel - the message lists each rejected `packageId @ version` with the reason. |
| 400 | No available version of a project package satisfies the channel's rules, so there is nothing to pin for it. Push a compliant package version, or create the release in a different channel. |
| 401 | Missing or invalid Basic auth credentials, or the service account lacks the required role. |
| 400 | Validation failed - the response includes `errorcode = InvalidParameter` and (where applicable) a `validationErrors` map. |
| 400 | `metadata` is not a JSON object - the response reads `metadata must be a JSON object`. No release is created. |
| 400 | `metadata` is larger than 64 KB once serialized - the message names the size it actually was. No release is created. |

Example request:

```
POST /api/release HTTP/1.1
Host: app.jawsdeploy.net
Authorization: Basic <base64(serviceAccountId:apiKey)>
Content-Type: application/json

{
  "projectId": "prj_abc123",
  "channelName": "Beta",
  "version": "2.5.3-beta1",
  "notes": "Build #4821 from main",
  "packageVersions": {
    "Acme.Web": "2.5.3-beta1",
    "Acme.Worker": "2.5.3-beta1"
  },
  "metadata": {
    "buildUrl": "https://ci.example/build/4821",
    "commit": "3f9a1c2",
    "workItems": [
      { "id": "JAWS-14", "title": "Fix the retry loop" }
    ]
  }
}
```

Example response:

```
{
  "releaseId": "rel_9f4c..."
}
```

