Skip to content

Project releases overview ​

A project release is a named, versioned deliverable with its own changelog. It is the same object as a workspace release, except that it belongs to one project. It can still hold work items from any project in the workspace. You manage it through the routes under /api/v2/workspaces/{slug}/projects/{project_id}/releases/.

Comments and links on a project release have their own routes, documented in Project release comments and Project release links.

Learn more about project releases

The project release object ​

Attributes ​

  • id string (uuid)

    Unique identifier for the release.

  • name string

    Display name. Maximum 255 characters. Names are unique across the whole workspace, so a project release can't reuse the name of a workspace release or of a release in another project.

  • project_id string (uuid)

    The project the release belongs to. Set from the route when you create the release and read-only after that. A workspace release returns null here.

  • description_id string (uuid)

    The id of the description record that holds the release body.

  • description_html string

    The release description as HTML. List rows leave it out unless you request it with ?fields=.

  • status string

    Where the release is in its lifecycle. One of unreleased (the default), released, or cancelled.

  • target_date string (date) or null

    The planned ship date, as YYYY-MM-DD. null until you set it.

  • release_date string (date) or null

    The date the release shipped, as YYYY-MM-DD. null until you set it.

  • lead_id string (uuid) or null

    The user who leads the release. Must be an active member of the workspace. null when the release has no lead.

  • tag_id string (uuid) or null

    The version tag, from the workspace release tag catalog. null when the release has no tag.

  • is_latest boolean

    Whether the release is marked as the latest one. Plane doesn't limit the flag to one release, so setting it doesn't clear it on other releases.

  • is_prerelease boolean

    Whether the release is marked as a pre-release.

  • external_id, external_source string or null

    Correlation fields for sync and import. Together they map a release to a record in another system. Both are null unless you set them.

  • label_ids array of string (uuid)

    The release labels applied to the release. Change them with Add or remove project release labels.

  • created_at string (date-time)

    When the release was created.

  • updated_at string (date-time)

    When the release was last updated.

  • created_by_id string (uuid)

    The user who created the release.

  • updated_by_id string (uuid) or null

    The user who last updated the release. null until someone updates it.

Response200
json
{
  "id": "3e8a1f52-7c4b-4d9e-a6f1-0b2c5d8e9f14",
  "name": "Mobile 4.2.0",
  "project_id": "4af68566-94a4-4eb3-94aa-50dc9427067b",
  "description_id": "5d2b7e91-4a3c-4f68-9e0d-1c7a8b2f6e35",
  "description_html": "<p>Offline mode and the new onboarding flow.</p>",
  "status": "unreleased",
  "target_date": "2026-02-27",
  "release_date": null,
  "lead_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
  "tag_id": "a41c9e07-2f5d-4b83-8c6e-9d1f0a3b7c52",
  "is_latest": false,
  "is_prerelease": false,
  "external_id": null,
  "external_source": null,
  "label_ids": ["7f3a2c19-8e4d-4b61-a5c7-2d9e0f1b8a46"],
  "created_at": "2026-01-14T09:22:41.478363Z",
  "updated_at": "2026-01-14T09:22:41.478363Z",
  "created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
  "updated_by_id": null
}

Endpoints ​

MethodPathDescription
GET/api/v2/workspaces/{slug}/projects/{project_id}/releases/List project releases
GET/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/Get a project release
POST/api/v2/workspaces/{slug}/projects/{project_id}/releases/Create a project release
PATCH/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/Update a project release
DELETE/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/Delete a project release
GET/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/changelog/Get a project release changelog
PATCH/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/changelog/Update a project release changelog
GET/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/labels/List a project release's labels
POST/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/labels/Add or remove project release labels
GET/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/work-items/List a project release's work items
POST/api/v2/workspaces/{slug}/projects/{project_id}/releases/{pk}/work-items/Add or remove project release work items

Project releases and workspace releases ​

Both kinds of release are the same object with the same fields. project_id tells them apart. It holds the project's id on a project release and null on a workspace release, and both the project routes and the workspace routes return it.

The two sets of routes never overlap:

  • The project routes return only releases in the project named in the path. A workspace release id, or the id of a release in another project, returns 404.
  • The workspace routes return only workspace releases. A project release id on /api/v2/workspaces/{slug}/releases/{pk}/ returns 404, and so do its comments and links on the workspace comment and link routes.
  • A release can't move between a project and the workspace, or to another project. The project comes from the path when you create the release, and no request body field changes it afterward.

Two things are shared across the workspace:

  • Release names. A project release can't reuse any release name already taken in the workspace.
  • Tags and labels. The v2 catalogs at /releases/tags/ and /releases/labels/ list only workspace-level tags and labels. Project-scoped ones, created in the app or through v1, don't appear there, but tag_id and adding a label still accept their ids, including tags and labels scoped to another project. List a project release's labels returns project-scoped labels too.

Plan gating ​

Every project release route, including the comment and link routes, needs the project releases entitlement on your plan. Without it, the API returns 402 payment_required. This entitlement is separate from the one for workspace releases, so having one doesn't give you the other.

The tag and label catalogs at /releases/tags/ and /releases/labels/ need the workspace releases entitlement. With only project releases on your plan, they return 402 payment_required.

The workspace Releases setting (is_release_enabled in workspace features) gates only the creation of workspace releases. While the setting is off, creating a workspace release returns 402 payment_required. Project release routes don't check the setting, and they don't check the project's own Releases feature toggle either.

Permissions ​

The API checks permissions against your role in the release's project. For the checks on a single release and on its comments and links, a workspace admin passes without a role in the project.

RequestNeedsWithout it
List project releasesView releases in the project403 forbidden
Create a project releaseCreate releases in the project403 forbidden
Get a project releaseView the release403 forbidden
Get the changelog, or list its labels or work itemsNo role checkNot checked. The work items list still leaves out work items you can't see
Update a release or its changelog, add or remove its labels or work itemsEdit the release403 forbidden
Delete a releaseDelete the release403 forbidden
List or get comments and linksView the release404 not_found
Create a comment or linkView and edit the release404 without view, 403 without edit
Update or delete a comment or linkEdit the release403 forbidden

An id that doesn't exist in the project always returns 404, before any role check runs. When you can't view a release, the status depends on what you read. A read of the release itself returns 403, while reads of its comments and links return 404, as if the release didn't exist. Reads of its changelog, labels, and work items run no role check and return 200.

Find the work items in a release ​

There are two ways to read a release's work items:

Use the child list for a quick read of everything in the release. Use the filter when you need to narrow, sort, or page through the set.

Response shaping ​

Every read that returns the release object accepts ?fields= for sparse responses and ?expand=lead,tag to embed the lead user and the tag next to their ids. See Sparse fields and Expanding relations. Errors follow the shared problem+json contract.

Changed from v1 ​

  • In v1, a project release's labels, work items, changelog, comments, and links were served on the workspace routes, under /api/v1/workspaces/{slug}/releases/{release_id}/. In v2 they live under the project route, and the workspace routes return 404 for a project release.
  • Adding and removing labels or work items is one POST with {"add": [...], "remove": [...]}, which returns {"added": [...], "removed": [...]}. v1 added with POST and removed with DELETE, passing label_ids or work_item_ids.
  • Listing a release's work items returns full work item objects. v1 returned only id, project_id, and name for each one.
  • v1 rejected work items from another project, and tags or labels scoped to another project, with 400 and RELEASE_WORK_ITEM_OUT_OF_SCOPE, RELEASE_TAG_OUT_OF_SCOPE, or RELEASE_LABEL_OUT_OF_SCOPE. v2 accepts any work item, tag, or label in the workspace.
  • v1 created project-scoped tags and labels when you passed project on create, and listed them with ?project_id=. v2 has no equivalent. Its tag and label catalogs create and list only workspace-level ones.

See Migrating from v1 for the full list.