Workspace workflows overview
In a workspace with governance turned on, the workspace owns states and workflows instead of each project. It keeps a catalog of both:
- Catalog states are workspace-level states that belong to no project. You manage them with workspace states.
- Catalog workflows arrange catalog states into a chain and define the moves between them. They are the subject of this page.
Projects don't copy a catalog workflow. They resolve to one, so a change to a catalog workflow applies to every project that uses it.
A catalog workflow is made of four parts, each with its own endpoints:
- The chain is the ordered list of catalog states that work items using the workflow can be in. One of them is the default for new work items. See Workspace workflow states.
- Transitions are the allowed moves between chain states, including approval flows and their approvers. See Workspace workflow transitions.
- Hooks are scripts or webhooks that run before or after a move through a transition. See Workspace workflow hooks.
- The activity feed is the change history of the workflow. See Workspace workflow activities.
How work items resolve to a workflow
A pick binds one project and one work item type to a catalog workflow. For every project and work item type, Plane resolves one effective workflow, in this order:
- The workflow the work item type mandates, when the type's governance mode is
required. - The workflow the workspace pinned for this project and type.
- The project's own pick for the type.
- Otherwise, the workspace default workflow, the catalog workflow with
is_default: true.
Work items without a type use the project's pick for typeless work items, or the workspace default. You set governance modes, allowlists, and pins per work item type with work item type governance, and a project's picks with work item type workflows. Get workspace workflow usage shows which projects and types resolve to a workflow today.
Ungoverned workspaces
Every catalog endpoint, including the states, transitions, activities, and hooks under a workflow, returns 409 states_managed_at_project in an ungoverned workspace. There, each project owns its workflows. Use the project workflows instead.
The permission check runs before the governance check, so a caller without access gets 403, not 409, and learns nothing about how the workspace is configured.
Learn more about workspace governance
Learn more about workflows and approvals
The workspace workflow object
Attributes
idstring (uuid)Unique identifier for the catalog workflow.
namestringDisplay name, unique among the workspace's catalog workflows. Maximum 255 characters.
descriptionstringFree-form description. Nullable.
is_activebooleanWhether the workflow's rules are enforced. A new workflow starts inactive, and activation needs at least one state in the chain. Work items that resolve to the workflow use its states whether or not it is active.
is_defaultbooleanWhether this is the workspace default workflow, the one a project and work item type fall back to when nothing else applies. One catalog workflow is the default. Read-only.
states_countintegerNumber of states in the chain.
projects_countintegerNumber of distinct projects with a pick that points at the workflow.
work_item_types_countintegerNumber of distinct work item types with a pick that points at the workflow.
statesarray of objectThe chain, ordered by
sequence. Detail only. Each entry has:id: the catalog state id. The workspace workflow state object calls thisstate_id.allow_issue_creation,is_default,sequence,type: the chain settings for the state.transitions: the transitions that start from the state. Each hasid,transition_state_id,rejection_state_id,member_ids,required_approvals,pre_rules, andpost_rules.
pre_rulesandpost_ruleslist the transition's enabled hooks in run order, each withid,handler_name,rule_type(validationforpre,actionforpost), andconfig. Asend_webhookrule shows a maskedconfig.secret.referenced_resourcesobjectLookup maps for every id the chain names. Detail only.
statesmaps each catalog state id (chain members, transition targets, and rejection targets) to itsid,name,color,group,sequence,default,project_id, andworkspace_id.usersmaps each approver id toid,display_name,avatar_url,is_bot,first_name,last_name, andworkspace_id.project_idsarray of stringProjects with a pick that points at the workflow. Detail only.
work_item_type_idsarray of stringWork item types with a pick that points at the workflow. Detail only.
created_atstring (date-time)When the workflow was created.
updated_atstring (date-time)When the workflow was last updated.
created_by_idstring (uuid)The user who created the workflow.
updated_by_idstring (uuid)The user who last updated the workflow.
The list carries counts and the detail carries the chain
List rows omit states, referenced_resources, project_ids, and work_item_type_ids. Those four take extra queries to build, so only Get a workspace workflow and the write responses return them.
{
"id": "9c1f0b3d-6d2e-4c9a-8b41-2f7e5a0d6c88",
"name": "Delivery",
"description": "Engineering delivery flow with a review gate",
"is_active": true,
"is_default": false,
"states_count": 4,
"projects_count": 2,
"work_item_types_count": 1,
"states": [
{
"id": "2c4d16f8-9b3e-4a52-8d71-1f0e6c9a5b48",
"allow_issue_creation": true,
"is_default": true,
"sequence": 10000.0,
"type": "transition",
"transitions": [
{
"id": "8d2f6a41-5c3e-4b97-a1d0-7e9c4b2f8a63",
"transition_state_id": "f960d3c2-8524-4a41-b8eb-055ce4be2a7f",
"rejection_state_id": null,
"member_ids": [],
"required_approvals": null,
"pre_rules": [],
"post_rules": []
}
]
},
{
"id": "f960d3c2-8524-4a41-b8eb-055ce4be2a7f",
"allow_issue_creation": true,
"is_default": false,
"sequence": 20000.0,
"type": "transition",
"transitions": [
{
"id": "d7a3f5c9-0b2e-4d81-b6f4-9e1c3a5d7b20",
"transition_state_id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"rejection_state_id": null,
"member_ids": [],
"required_approvals": null,
"pre_rules": [
{
"id": "9a1c5e37-8b2d-4f60-a4e9-6c3b7d0f1e28",
"handler_name": "run_script",
"rule_type": "validation",
"config": {
"script_id": "5d8e2a6c-3f1b-4a97-8c04-2e9b7d1f6a35",
"execution_variables": {
"min_estimate": "1"
}
}
}
],
"post_rules": [
{
"id": "e4b7c9a2-3d1f-4e68-8a52-9f0c6b3d7e15",
"handler_name": "send_webhook",
"rule_type": "action",
"config": {
"url": "https://hooks.example.com/plane",
"headers": [
{
"key": "X-Team",
"is_secret": false,
"value": "platform"
}
],
"secret": "plane_wh_••••7c1d"
}
}
]
}
]
},
{
"id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"allow_issue_creation": false,
"is_default": false,
"sequence": 30000.0,
"type": "approval",
"transitions": [
{
"id": "4b6e1d93-2a7f-4c58-9e30-1d8b5f7a2c46",
"transition_state_id": "7b1e9d40-3c86-4f2a-9a5d-8e2b0c47d613",
"rejection_state_id": "f960d3c2-8524-4a41-b8eb-055ce4be2a7f",
"member_ids": ["a3f92c71-6e4b-4d08-9b5a-1c7e3d9f2b84"],
"required_approvals": 1,
"pre_rules": [],
"post_rules": []
}
]
},
{
"id": "7b1e9d40-3c86-4f2a-9a5d-8e2b0c47d613",
"allow_issue_creation": false,
"is_default": false,
"sequence": 40000.0,
"type": "transition",
"transitions": []
}
],
"referenced_resources": {
"states": {
"2c4d16f8-9b3e-4a52-8d71-1f0e6c9a5b48": {
"id": "2c4d16f8-9b3e-4a52-8d71-1f0e6c9a5b48",
"name": "Backlog",
"color": "#8b8d98",
"group": "backlog",
"sequence": 15000.0,
"default": false,
"project_id": null,
"workspace_id": "b1c4e7a2-5d8f-4a3b-9c6e-0f2d4a7b8c91"
},
"f960d3c2-8524-4a41-b8eb-055ce4be2a7f": {
"id": "f960d3c2-8524-4a41-b8eb-055ce4be2a7f",
"name": "In Progress",
"color": "#3f76ff",
"group": "started",
"sequence": 25000.0,
"default": false,
"project_id": null,
"workspace_id": "b1c4e7a2-5d8f-4a3b-9c6e-0f2d4a7b8c91"
},
"b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53": {
"id": "b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53",
"name": "In Review",
"color": "#f5a623",
"group": "started",
"sequence": 35000.0,
"default": false,
"project_id": null,
"workspace_id": "b1c4e7a2-5d8f-4a3b-9c6e-0f2d4a7b8c91"
},
"7b1e9d40-3c86-4f2a-9a5d-8e2b0c47d613": {
"id": "7b1e9d40-3c86-4f2a-9a5d-8e2b0c47d613",
"name": "Done",
"color": "#26a05f",
"group": "completed",
"sequence": 45000.0,
"default": false,
"project_id": null,
"workspace_id": "b1c4e7a2-5d8f-4a3b-9c6e-0f2d4a7b8c91"
}
},
"users": {
"a3f92c71-6e4b-4d08-9b5a-1c7e3d9f2b84": {
"id": "a3f92c71-6e4b-4d08-9b5a-1c7e3d9f2b84",
"display_name": "priya",
"avatar_url": null,
"is_bot": false,
"first_name": "Priya",
"last_name": "Raman",
"workspace_id": "b1c4e7a2-5d8f-4a3b-9c6e-0f2d4a7b8c91"
}
}
},
"project_ids": ["4af68566-94a4-4eb3-94aa-50dc9427067b", "d1e8a3c5-7f2b-4a96-8e04-3b6c9d1f5a27"],
"work_item_type_ids": ["2d9d1a97-5c6f-4a1e-9d5b-8c2f7e30b6a4"],
"created_at": "2026-01-14T09:22:41.478363Z",
"updated_at": "2026-01-15T11:04:52.660219Z",
"created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
"updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
}Build a workflow
- Create the workflow with Create a workspace workflow. It starts as an inactive draft with an empty chain.
- Attach catalog states with Add states to a workspace workflow.
- Choose where new work items land with Mark a workspace workflow state as default.
- Add the allowed moves with Create a workspace workflow transition, and hooks on them with Create a workspace workflow hook.
- Activate the workflow by sending
{"is_active": true}to Update a workspace workflow.
To set the whole chain, its order, and its default in one request, send states and default_state_id to Update a workspace workflow in place of steps 2 and 3.
Plan features
Some operations need a plan feature. When the feature is off, they return 402 payment_required.
| Operation | Plan feature |
|---|---|
| List and get workspace workflows, and get usage | None |
| Create and update a workspace workflow, and every state, transition, activity, and hook endpoint under one | Workflows |
| Create a second or later catalog workflow | Multiple workflows |
| Delete a workspace workflow | Multiple workflows |
Set a chain state's type to approval, or create or update a transition that starts from an approval state | Workflow approvals |
Create or update a run_script hook | Plane Runner |
Create or update a send_webhook hook | Webhook transition conditions |
Guards on removing states and deleting workflows
Three 409 codes protect work items and the records that reference a workflow:
workflow_state_orphans: removing states from a chain would leave work items in a state outside it. Plane counts the work items in every project and work item type whose pick points at the workflow. The count includes archived work items and excludes drafts and work items in triage. Send astate_mappingfrom each stranded state to a state that stays in the chain. The body'sorphansmember lists the stranded states with counts per project. Update a workspace workflow and Remove a state from a workspace workflow return it.workflow_state_dependencies: a transition still starts from, targets, or rejects to the state you're removing. Delete those transitions first. Remove a state from a workspace workflow returns it.workflow_in_use: the workflow is the workspace default, or a project pick, a pin, or a type allowlist references it. Delete a workspace workflow returns it.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v2/workspaces/{slug}/workflows/ | List workspace workflows |
GET | /api/v2/workspaces/{slug}/workflows/{pk}/ | Get a workspace workflow |
POST | /api/v2/workspaces/{slug}/workflows/ | Create a workspace workflow |
PATCH | /api/v2/workspaces/{slug}/workflows/{pk}/ | Update a workspace workflow |
DELETE | /api/v2/workspaces/{slug}/workflows/{pk}/ | Delete a workspace workflow |
GET | /api/v2/workspaces/{slug}/workflows/{pk}/usage/ | Get workspace workflow usage |
Response shaping
Every endpoint that returns the workspace workflow object accepts ?fields= for sparse responses. See Sparse fields. On the list, naming a detail-only field (states, referenced_resources, project_ids, or work_item_type_ids) is a 400. Errors follow the shared problem+json contract.
Changed from v1
- In an ungoverned workspace, the catalog returns
409 states_managed_at_project. v1 returns400with its own error body. - Deleting a workflow that is in use returns
409 workflow_in_use. v1 returns400. - The orphan report is a problem+json body with the code
workflow_state_orphans, and the report sits underorphans. v1 returns the bare report. - List rows add
description,created_at,updated_at,created_by_id, andupdated_by_id, and dropworkspace_idandproject_id. The detail reportscreated_by_idandupdated_by_idin place ofcreated_byandupdated_by. - Chain states have read routes, and the transition and activity lists are paginated.
See Migrating from v1 for the full list.

