Create a label
Add a label to a project. The new label is immediately available to every work item in that project, and to no other project.
Label names must be unique within a project — reusing one returns 409 conflict.
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:requiredstring (uuid)The project to add the label to.
Body Parameters
name:requiredstringDisplay name for the label, unique within the project. Maximum 255 characters.
color:optionalstringHex color used wherever the label is rendered, for example #e5484d. Maximum 255 characters. Send one if the label needs to be recognizable at a glance on a board.
description:optionalstringFree-form note about what the label is for and when to apply it.
parent_id:optionalstring (uuid)The label this one nests under, for grouping related tags such as Billing and Search beneath an Area label. The parent must be a label in the same project — an id from another project is a 400, not a silent link.
Omit it, or send null, for a top-level label.
sort_order:optionalnumberOrdering weight within the project. Lower values sort first. Assigned automatically when omitted, so send it only when you are recreating a specific order.
external_id:optionalstringYour system's identifier for this label, for sync and import correlation. Maximum 255 characters. Store it here and you can find the label later with ?external_id=, without keeping a map of Plane ids.
external_source:optionalstringThe system external_id came from, for example github or jira. Maximum 255 characters.
Scopes
projects.labels:write
Errors
| Status | Code | Cause |
|---|---|---|
400 | validation_error | name missing or over 255 characters, or a parent_id that isn't a label in this project. |
401 | unauthorized | Missing or invalid credentials. |
403 | forbidden | Your role or token scope can't create labels. |
404 | resource_not_found | No such workspace or project, or it's outside your tenant. |
409 | conflict | A label with this name already exists in the project. |
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/labels/" \
-H "X-Api-Key: $PLANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Regression",
"color": "#e5484d",
"description": "Worked before the last release",
"parent_id": "2b7d5e94-3c1a-4f60-9a8d-7e1c4b0f2d35"
}'import requests
response = requests.post(
"https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/labels/",
headers={"X-Api-Key": "your-api-key"},
json={
"name": "Regression",
"color": "#e5484d",
"description": "Worked before the last release",
"parent_id": "2b7d5e94-3c1a-4f60-9a8d-7e1c4b0f2d35",
},
)
print(response.json())const response = await fetch(
"https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/labels/",
{
method: "POST",
headers: {
"X-Api-Key": "your-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Regression",
color: "#e5484d",
description: "Worked before the last release",
parent_id: "2b7d5e94-3c1a-4f60-9a8d-7e1c4b0f2d35",
}),
}
);
const data = await response.json();{
"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"
}{
"type": "https://api.plane.so/errors/conflict",
"title": "Conflict",
"status": 409,
"code": "conflict",
"detail": "A label with this name already exists in the project."
}
