Preview a governance change
Count the work items a governance mode change would move, without changing anything. The response is a preview object with a total and a per_state breakdown of the states those work items sit in now.
Call it before Update work item type governance so you know what acknowledge: true will do and which states need a state_mapping. The call writes nothing and is safe to repeat.
What the preview counts depends on the mode:
anyalways returns{"total": 0, "per_state": []}. Widening the choice keeps every existing pick valid.constrainedcounts work items in projects whose pick uses a workflow thatworkflow_idsleaves out. Those projects would fall back to the workspace default workflow, so the preview counts their work items in states that workflow doesn't contain.requiredcounts the work items in states the mandated workflow doesn't contain, across every project with a pick for the type.
The preview never counts drafts or work items in triage group states. It does count archived work items.
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.
type_id:requiredstring (uuid)The work item type. It can be any type in the workspace.
Body Parameters
mode:requiredstringThe mode to preview. One of any, constrained, or required.
workflow_ids:optionalarray of string (uuid)Required when mode is constrained. The allowlist to preview. The preview leaves out ids that aren't active catalog workflows. Unlike the PATCH, it doesn't return an error for them.
required_workflow_id:optionalstring (uuid)Required when mode is required. The workflow to preview as the mandate. The preview doesn't check that the workflow is active. An unknown workflow, or one with no states, previews as total: 0.
Scopes
workspaces.workflows:write
Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_request | mode missing or outside the enum, workflow_ids missing for constrained, or required_workflow_id missing for required. |
401 | unauthorized | Missing or invalid credentials. |
402 | payment_required | Workspace governance isn't on your plan. |
403 | forbidden | Your role or token scope can't edit workspace workflows. |
404 | not_found | No such work item type in this workspace. |
406 | not_acceptable | The Accept header asks for a representation the API can't produce. |
409 | states_managed_at_project | The workspace doesn't have governance turned on. |
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/work-item-types/d1e7a4c9-2b58-4f36-9a0e-7c3b5d81f240/governance/preview/" \
-H "X-Api-Key: $PLANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mode": "required",
"required_workflow_id": "e6b2d9f1-48a7-4c3e-9f50-1d7a8c2b6e93"
}'import requests
response = requests.post(
"https://api.plane.so/api/v2/workspaces/my-team/work-item-types/d1e7a4c9-2b58-4f36-9a0e-7c3b5d81f240/governance/preview/",
headers={"X-Api-Key": "your-api-key"},
json={
"mode": "required",
"required_workflow_id": "e6b2d9f1-48a7-4c3e-9f50-1d7a8c2b6e93",
},
)
print(response.json())const response = await fetch(
"https://api.plane.so/api/v2/workspaces/my-team/work-item-types/d1e7a4c9-2b58-4f36-9a0e-7c3b5d81f240/governance/preview/",
{
method: "POST",
headers: {
"X-Api-Key": "your-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
mode: "required",
required_workflow_id: "e6b2d9f1-48a7-4c3e-9f50-1d7a8c2b6e93",
}),
},
);
const data = await response.json();{
"total": 12,
"per_state": [
{
"state_id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"count": 9
},
{
"state_id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"count": 3
}
]
}{
"total": 0,
"per_state": []
}Sum per_state by state_id
per_state has one entry per state for each affected project, so a state shared by several projects appears more than once. Add up the count values for each state_id to build a mapping form, then send the mapping as state_mapping on the PATCH.

