Work item type governance overview
In a workspace with workspace governance turned on, workflows live in the workspace catalog instead of in each project. Governance decides, for every project and work item type, which catalog workflow applies and who chose it. You set the rules per work item type with the routes in this group.
This page explains the model once. The endpoint pages link back here.
Learn more about workspace governance · Learn more about workflows
How a project's workflow is decided
Each active pair of a project and a work item type has one pick, the catalog workflow that project uses for that type. Plane writes the pick when the type is activated in the project, and every governance change below keeps it valid. When a pair has no pick, the workspace default workflow applies.
The type's governance mode controls who may change the pick:
| Mode | Who chooses the workflow | The project's own pick |
|---|---|---|
any | The project, from any active catalog workflow. This is the default for every type. | Allowed. |
constrained | The project, from the type's allowlist of catalog workflows. | Allowed inside the allowlist. A workflow outside it returns 400 workflow_outside_allowlist. |
required | The workspace. Plane writes one mandated workflow into the pick of every project that uses the type. | Refused with 403 workflow_mandated. |
A pin works alongside the mode. It fixes the workflow for the projects you name. Creating a pin writes those projects' picks and marks them as set by the workspace, so a pinned project's attempt to set its own pick returns 403 workflow_assigned_by_workspace. Pins work under any and constrained. Under required, the mandate already decides, so creating a pin returns 409 workflow_pins_unavailable.
The mode is also on the work item type itself as the read-only governance_mode field. See Work item types.
To see which workflow resolved for each type in one project, and where that answer came from, use Work item type workflows.
The governance object
GET and PATCH on /work-item-types/{type_id}/governance/ return this object.
Attributes
modestringThe type's governance mode. One of
any,constrained, orrequired.required_workflow_idstring (uuid) or nullThe mandated workflow when
modeisrequired, otherwisenull.allowlistarray of objectsThe workflows the type is tied to. Under
constrained, this is the allowlist. Underrequired, it holds the one mandated workflow. Underany, it is empty. Each entry has these fields:workflow_idstring (uuid). The catalog workflow.namestring or null. The workflow's name.lockedboolean.truewhile at least one project's pick uses this workflow for the type. A locked workflow can't leave the allowlist unless you sendacknowledge: true.in_use_by_project_idsarray of string (uuid). The projects whose pick uses this workflow for the type.
Project ids, not names
in_use_by_project_ids carries ids only. Someone who can read workspace governance isn't necessarily a member of every project listed, so resolve the ids you're allowed to see with the projects endpoints.
{
"mode": "constrained",
"required_workflow_id": null,
"allowlist": [
{
"workflow_id": "a1f4c7e2-3b98-4d61-8e25-6c0b9d7f3a14",
"name": "Standard delivery",
"locked": true,
"in_use_by_project_ids": [
"4af68566-94a4-4eb3-94aa-50dc9427067b",
"7c19e5b3-2d84-4f6a-b0e7-93a1c5d8f246"
]
},
{
"workflow_id": "e6b2d9f1-48a7-4c3e-9f50-1d7a8c2b6e93",
"name": "Regulated release",
"locked": false,
"in_use_by_project_ids": []
}
]
}The pin object
Attributes
idstring (uuid)Unique identifier for the pin.
project_idstring (uuid)The project whose workflow the pin fixes.
workflow_idstring (uuid)The catalog workflow the project is pinned to.
work_item_type_idstring (uuid)The work item type the pin applies to.
created_atstring (date-time)When the pin was created.
updated_atstring (date-time)When the pin was last updated. Pinning a project that already has a pin for the type moves that pin to the new workflow.
{
"id": "0b6d3f92-7e15-4a48-9c27-5f8e1a4d6b30",
"project_id": "4af68566-94a4-4eb3-94aa-50dc9427067b",
"workflow_id": "e6b2d9f1-48a7-4c3e-9f50-1d7a8c2b6e93",
"work_item_type_id": "d1e7a4c9-2b58-4f36-9a0e-7c3b5d81f240",
"created_at": "2026-01-14T09:22:41.478363Z",
"updated_at": "2026-01-14T09:22:41.478363Z"
}The preview object
Every dry run in this group returns the same shape. It counts the work items a change would move, broken down by the state they sit in now.
Attributes
totalintegerThe number of work items the change would move.
per_statearray of objectsOne entry per current state and affected project, so the same
state_idcan appear more than once when several projects are affected. Each entry hasstate_id(string (uuid)), the state the work items sit in now, andcount(integer).
{
"total": 12,
"per_state": [
{
"state_id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"count": 9
},
{
"state_id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"count": 3
}
]
}Changing the mode
Send the new mode to Update work item type governance. What happens depends on the direction.
- To
any. Plane clears the allowlist. Pins stay, because a pin is valid underany. No pick changes and no work item moves. - To
constrained. Sendworkflow_ids, the new allowlist. Every id must be an active catalog workflow. If a workflow that some project's pick uses would leave the allowlist, the request returns409 workflow_allowlist_excludes_in_useand lists those workflows. Send the same body withacknowledge: trueto go ahead. Plane then removes the affected projects' picks and deletes any pin that points outside the new allowlist. Those projects fall back to the workspace default workflow. - To
required. Sendrequired_workflow_id, an active catalog workflow. Withoutacknowledge: true, the request is a dry run. It returns200with apreviewobject and changes nothing. Withacknowledge: true, Plane writes the mandated workflow into every project pick for the type and deletes every pin for the type, so returning toanyorconstrainedlater can't bring an old pin back.
acknowledge confirms a consequence you have already seen. Call Preview a governance change first to see how many work items would move.
The orphan gate
A change that moves projects onto a different workflow can leave work items in states the new workflow doesn't contain. Before Plane applies such a change, it counts those work items. If any exist and your state_mapping doesn't cover every one of their states, the request returns 409 workflow_state_orphans and writes nothing.
state_mapping is an object that maps a current state id to a state id in the target workflow:
{
"state_mapping": {
"b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53": "f960d3c2-8524-4a41-b8eb-055ce4be2a7f"
}
}The target workflow depends on the change. It is the workspace default workflow when a constrained change strands projects, the mandated workflow for required, or the workflow you pick with Update a work item type workflow.
The 409 body carries an orphans report. Its inner orphans array lists each stranded state with state_id, state_name, count, and a per_project breakdown. invalid_targets lists mapping values that aren't in the target workflow. Plane ignores a mapping key that isn't a valid UUID, so that state shows up as uncovered.
{
"type": "conflict",
"code": "workflow_state_orphans",
"detail": "This change strands work items outside the target workflow; supply a state_mapping that covers them.",
"orphans": {
"error": "Some work items are in states that are not part of the new chain — map every affected state to a state in it.",
"code": "orphaned_states",
"orphans": [
{
"state_id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"state_name": "In Review",
"count": 12,
"per_project": [
{ "project_id": "4af68566-94a4-4eb3-94aa-50dc9427067b", "count": 9 },
{ "project_id": "7c19e5b3-2d84-4f6a-b0e7-93a1c5d8f246", "count": 3 }
]
}
],
"invalid_targets": []
}
}Once the gate passes, Plane moves each stranded work item to its mapped state and records an activity entry on the work item. These rules decide which work items count:
- Archived work items count and move. Draft work items don't.
- Work items in a
triagegroup state never move. - A change that moves more than 500 work items in one project finishes in the background, so the response can arrive before every work item has moved.
Pins
Create workflow pins pins one workflow across several projects in one call. Each pin also writes the project's pick, so the project starts using the pinned workflow immediately. Plane moves work items that are outside the pinned workflow to its default state.
Deleting a pin removes only the marker. The project keeps the workflow the pin set, and its own pick endpoint accepts changes again.
Governed workspaces only
Most of these routes work only under governance. In an ungoverned workspace, every route in this group except the two pin reads returns 409 states_managed_at_project. Workflows there belong to each project, so see Workflows instead.
Every route in this group also needs the workspace governance feature on your plan and returns 402 payment_required without it.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v2/workspaces/{slug}/work-item-types/{type_id}/governance/ | Get work item type governance |
PATCH | /api/v2/workspaces/{slug}/work-item-types/{type_id}/governance/ | Update work item type governance |
POST | /api/v2/workspaces/{slug}/work-item-types/{type_id}/governance/preview/ | Preview a governance change |
GET | /api/v2/workspaces/{slug}/work-item-types/{type_id}/governance/pins/ | List workflow pins |
GET | /api/v2/workspaces/{slug}/work-item-types/{type_id}/governance/pins/{pk}/ | Get a workflow pin |
POST | /api/v2/workspaces/{slug}/work-item-types/{type_id}/governance/pins/ | Create workflow pins |
DELETE | /api/v2/workspaces/{slug}/work-item-types/{type_id}/governance/pins/{pk}/ | Delete a workflow pin |
The project side of the same model is in Work item type workflows. The catalog workflows themselves are in Workspace workflows.
Changed from v1
- The orphan gate returns
409 workflow_state_orphans. v1 returns400for the same condition. allowlist[].in_use_by_project_idscarries project ids. v1 returns project names.- In an ungoverned workspace, these routes return
409 states_managed_at_projectin the standard error shape.
See Migrating from v1 for the full list.
Response shaping
The pin reads accept ?fields= for sparse responses. See Sparse fields. The governance object and the preview object don't. Errors follow the shared problem+json contract.

