Add or remove project release labels
Apply labels to a project release and take labels off it in one request. The v2 release label catalog lists only workspace-level labels. Project-scoped labels, created in the app or through v1, don't appear there, but this endpoint accepts their ids too, including labels scoped to another project.
The API runs remove first, then add, and returns what changed:
removedlists the ids fromremovethat were on the release. The API ignores ids that weren't on it.addedlists every id fromaddthat matched a release label in the workspace, workspace-level or project-scoped, including labels the release already had. The API skips ids that don't match a label and doesn't return an error for them.
Compare added with what you sent to find ids that were skipped. To read the labels on the release afterward, use List a project release's labels, or read label_ids on the release.
Path parameters
slug:requiredstringThe workspace slug. It appears in your Plane URLs. In https://app.plane.so/my-team/projects/, the slug is my-team.
project_id:requiredstringThe project the release belongs to. Accepts the project UUID or its bare identifier, for example ENG.
pk:requiredstring (uuid)The id of the release to change.
Body parameters
add:optionalarray of string (uuid)Ids of release labels to apply. Defaults to an empty array.
remove:optionalarray of string (uuid)Ids of release labels to take off. Defaults to an empty array.
Scopes
releases:write
Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_request | add or remove isn't an array, or an entry isn't a UUID. |
401 | unauthorized | Missing or invalid credentials. |
402 | payment_required | Project releases aren't enabled on your plan. |
403 | forbidden | Your role in the project can't edit this release, or your token scope doesn't allow this. |
404 | not_found | No release with this id in this project, or no such workspace or project. |
406 | not_acceptable | The Accept header asks for a representation the API can't produce. |
409 | governance_migration_in_progress | A governance migration is running in this workspace, so writes are paused. Retry after it finishes. |
413 | payload_too_large | The request body is over the size limit. |
415 | unsupported_media_type | The Content-Type isn't one this endpoint accepts. |
429 | rate_limited | Throttled. Honor the Retry-After header before retrying. |
curl -X POST \
"https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/releases/3e8a1f52-7c4b-4d9e-a6f1-0b2c5d8e9f14/labels/" \
-H "X-Api-Key: $PLANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"add": ["0e6b4d83-1a7c-4f29-b8e5-3c2a9f7d1b60"],
"remove": ["7f3a2c19-8e4d-4b61-a5c7-2d9e0f1b8a46"]
}'import requests
response = requests.post(
"https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/releases/3e8a1f52-7c4b-4d9e-a6f1-0b2c5d8e9f14/labels/",
headers={"X-Api-Key": "your-api-key"},
json={
"add": ["0e6b4d83-1a7c-4f29-b8e5-3c2a9f7d1b60"],
"remove": ["7f3a2c19-8e4d-4b61-a5c7-2d9e0f1b8a46"],
},
)
print(response.json())const response = await fetch(
"https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/releases/3e8a1f52-7c4b-4d9e-a6f1-0b2c5d8e9f14/labels/",
{
method: "POST",
headers: {
"X-Api-Key": "your-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
add: ["0e6b4d83-1a7c-4f29-b8e5-3c2a9f7d1b60"],
remove: ["7f3a2c19-8e4d-4b61-a5c7-2d9e0f1b8a46"],
}),
},
);
const data = await response.json();{
"added": ["0e6b4d83-1a7c-4f29-b8e5-3c2a9f7d1b60"],
"removed": ["7f3a2c19-8e4d-4b61-a5c7-2d9e0f1b8a46"]
}
