Labels overview
A label is a tag you attach to work items to slice a project by something the workflow doesn't already model, such as bug, needs-design, or customer-escalation. In most workspaces, a label belongs to exactly one project, so two projects can both have a bug label and they are separate records with separate ids. A workspace with governance turned on keeps its labels in a workspace catalog instead. See Workspace governance.
Work items reference labels by id through label_ids, and you filter work items with label_id. Nothing on the label object tells you which work items carry it — that relationship is read from the work item side.
To tag projects rather than work items, use project labels, a separate workspace-level catalog.
The label object
Attributes
idstring (uuid)Unique identifier for the label. This is the value you send in a work item's
label_ids.namestringDisplay name, unique within the project. Maximum 255 characters.
descriptionstringFree-form note about what the label is for. Useful when a team needs a convention written down next to the tag.
colorstringHex color used wherever the label is rendered, for example
#e5484d.sort_ordernumberOrdering weight within the project. Lower values sort first. Assigned automatically when you don't send one.
parent_idstring (uuid) or nullThe label this one nests under, letting you build groups such as an
Arealabel withBillingandSearchbeneath it.nullfor a top-level label.external_id,external_sourcestring or nullCorrelation fields for sync and import. Together they let you map a label to a record in another system and find it again later — list labels filtered by both to look one up without storing Plane ids yourself.
created_atstring (date-time)When the label was created.
updated_atstring (date-time)When the label was last updated.
created_by_idstring (uuid) or nullThe user who created the label.
nullfor labels created by an integration or by the system.updated_by_idstring (uuid) or nullThe user who last updated the label.
nulluntil someone updates the label.
Nesting is metadata, not inheritance
parent_id groups labels for display and filtering. Applying a child label to a work item does not also apply its parent.
{
"id": "9c1f0b3d-6d2e-4c9a-8b41-2f7e5a0d6c88",
"name": "Regression",
"description": "Worked before the last release",
"color": "#e5484d",
"sort_order": 65535,
"parent_id": "2b7d5e94-3c1a-4f60-9a8d-7e1c4b0f2d35",
"external_id": null,
"external_source": null,
"created_at": "2026-01-14T09:22:41.478363Z",
"created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
}Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v2/workspaces/{slug}/projects/{project_id}/labels/ | List labels |
GET | /api/v2/workspaces/{slug}/projects/{project_id}/labels/{pk}/ | Get a label |
POST | /api/v2/workspaces/{slug}/projects/{project_id}/labels/ | Create a label |
PATCH | /api/v2/workspaces/{slug}/projects/{project_id}/labels/{pk}/ | Update a label |
DELETE | /api/v2/workspaces/{slug}/projects/{project_id}/labels/{pk}/ | Delete a label |
POST | /api/v2/workspaces/{slug}/projects/{project_id}/labels/upsert/ | Upsert a label |
POST | /api/v2/workspaces/{slug}/projects/{project_id}/labels/bulk-create/ | Bulk create labels |
POST | /api/v2/workspaces/{slug}/projects/{project_id}/labels/bulk-update/ | Bulk update labels |
POST | /api/v2/workspaces/{slug}/projects/{project_id}/labels/bulk-delete/ | Bulk delete labels |
Names are unique per project
A project cannot hold two labels with the same name. Creating a duplicate, or renaming a label onto a name already in use, returns 409 conflict.
If you are importing labels from another system, treat the 409 as "this already exists" rather than an error: list the project's labels filtered by external_id and external_source first, and update the match instead of creating it again.
Deleting labels
DELETE returns 204 with an empty body. The label is removed from every work item that carried it — the work items themselves are untouched.
Deletes are not reversible through the API
There is no undelete endpoint. If you need the association back, recreate the label and reapply it with label_ids on each work item.
Workspace governance
In a workspace with workspace governance turned on, these routes are read-only:
- List and get return the workspace's catalog labels, plus any labels the project still holds from before governance was turned on.
- Create, update, delete, upsert, and bulk create return
400 workspace_managedand change nothing. - Bulk update and bulk delete answer
200, and each row fails withcodeworkspace_managed.
The 400 body uses v1's error shape, with error and code keys, instead of the problem format the rest of v2 uses. Branch on code. The v2 API has no workspace label routes.
{
"error": "This resource is managed at the workspace level",
"code": "workspace_managed"
}The governance check runs after the role check and before Plane looks up the label, so on update and delete an unknown label id also returns this 400. On create it runs before body validation, so a governed workspace answers 400 workspace_managed even when the body is invalid.
Changed from v1
parentis nowparent_id, on both reads and writes.created_byis nowcreated_by_id.updated_byis nowupdated_by_id.- Reads no longer return
projectorworkspace. The project is already in the request path. - Reads now return
external_idandexternal_source, which v1 accepted on writes but did not surface on the label object. - Lists return the offset envelope —
data,next,previous,total_count— instead of v1'sresultswith cursor keys. See List labels. - The
expandandfieldsquery parameters are not available on labels.
See Migrating from v1 for the full list.

