Skip to content

Update a state ​

PATCH/api/v2/workspaces/{slug}/projects/{project_id}/states/{pk}/

Change a state's name, color, description, group, position, or default flag. Work items already sitting in the state stay where they are — you are editing the state itself, not moving anything.

PATCH is partial. Send only the fields you want to change; anything you omit keeps its current value. Omitting a field is not the same as sending null.

Path Parameters ​

slug:requiredstring

The 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 the state belongs to.

pk:requiredstring (uuid)

The id of the state to update.

Body Parameters ​

Every field is optional — send the subset you are changing.

name:optionalstring

New display name, unique within the project. Maximum 255 characters. Renaming is safe for reporting: boards and charts key off group, not name.

color:optionalstring

Hex color used wherever the state is rendered, for example #3f76ff. Maximum 255 characters.

description:optionalstring

Free-form description of what the state means in this workflow.

group:optionalstring

Move the state to a different workflow group. This changes how every work item in the state is counted by boards, charts, and cycle progress, so switching a state from started to completed retroactively changes what those work items report as.

  • backlog — Not yet scheduled
  • unstarted — Scheduled but not begun
  • started — Actively in progress
  • completed — Finished successfully
  • cancelled — Closed without completion
  • triage — Awaiting intake review
sequence:optionalnumber

Ordering weight within the project. Lower values sort first. Set it to reposition the state in the workflow.

is_default:optionalboolean

Make this the project's default state — where work items land when no state_id is supplied. A project has exactly one default, so setting this to true clears the flag on the state that held it.

external_id:optionalstring

Your system's identifier for this state, for sync and import correlation. Maximum 255 characters.

external_source:optionalstring

The system external_id came from, for example github or jira. Maximum 255 characters.

Response shaping ​

fields:optionalstring

Comma-separated list of fields to return. Unrequested keys are omitted from the response, not returned as null, so absent means "not requested" and null means "actually null". id always comes back whether or not you name it.

Pass all for every requestable field. An unknown name is a 400 that lists the valid set and suggests the closest match, so a typo can't silently cost you the saving.

Requestable here: color, created_at, created_by_id, description, external_id, external_source, group, id, is_default, is_triage, name, sequence.

See Sparse fields.

Scopes ​

projects.states:write

Errors ​

StatusCodeCause
400invalid_requestA group outside the enum, or a field over its length limit.
401unauthorizedMissing or invalid credentials.
402payment_requiredThe feature this endpoint belongs to isn't enabled on your plan, or is switched off.
403forbiddenYour role or token scope can't update states.
404not_foundNo such state, project, or workspace — or it's outside your tenant.
406not_acceptableThe Accept header asks for a representation the API can't produce.
409conflictAnother state in the project already uses this name.
413payload_too_largeThe request body is over the size limit.
415unsupported_media_typeThe Content-Type isn't one this endpoint accepts.
429rate_limitedThrottled. Honor the Retry-After header before retrying.

Setting is_default moves the flag

A project has exactly one default state, so promoting a state with "is_default": true demotes whichever state held the flag before. To change which state is the default, promote the new one — that single request is the whole operation.

is_triage is not writable

is_triage is read-only. Plane creates and manages the triage state used by intake, so it isn't accepted in the request body. You can still assign the triage group to a state you own.

Update a state
bash
curl -X PATCH \
  "https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/states/f960d3c2-8524-4a41-b8eb-055ce4be2a7f/" \
  -H "X-Api-Key: $PLANE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Building",
  "color": "#f5a623"
}'
Response200
json
{
  "id": "f960d3c2-8524-4a41-b8eb-055ce4be2a7f",
  "name": "Building",
  "description": "Actively being worked on",
  "color": "#f5a623",
  "group": "started",
  "sequence": 25000,
  "is_default": false,
  "is_triage": false,
  "external_id": null,
  "external_source": null,
  "created_at": "2026-01-14T09:22:41.478363Z",
  "created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
}
Response400
json
{
  "type": "invalid_request",
  "code": "invalid_request",
  "detail": "The request body failed validation.",
  "errors": [
    {
      "field": "group",
      "code": "invalid_choice",
      "message": "\"in_review\" is not a valid choice."
    }
  ]
}