API Advanced Search for Work Items

Hello! I am trying to get a custom list of work items via API. In particular, I’m looking to make use of the “Advanced search work items” endpoint detailed in the docs here: Advanced search work items | Plane

One of the optional parameters is a “filters” JSON. I’m looking for any kind of documentation anywhere on the shape of the data that JSON expects. In particular, I want to see how the format of “filter by cycle” and “filter by states” is passed in.

My use case is as follows:

Given a specific cycle, I want to parse the data for that cycle and export a rich-text-copyable list that includes the data in the following format: [PROJ-1234] Some Deployed Feature Name Here

  1. [PROJ-1234] => Work item shortname ID (not the long alphanumeric unique key) including a hyperlink to that work item’s URL
  2. Some Deployed feature Name Here => Work item title

I thought I’d achieve this by doing an advanced issue search that includes the valid states (various categories of Completed), as well as the cycle and project to look within.

The other possible approach is brute force and inelegant. If Advanced Search will not work for this, I think the approach would have to be:

  1. GET cycles for a project, select one by ID
  2. GET work items for a cycle by cycle_id, store all the work item IDs
  3. GET work item details one by one for each of those IDs
  4. Filter by desired status based on the output in #3, concatenate the shortname for the export URL and line item

Obviously the first approach sounds simpler, can anybody let me know if this is possible via API? I know I can set up a VIEW with filters on the Plane UI, but I want an API solution that can make rich-text-doc exportable summaries weekly without the manual work of compiling them.

The filters documentation is indeed missing examples — we’re aware and will be updating the docs with this information.

In the meantime, here’s what you need:

Filter Syntax for Advanced Search Work Items

The POST /api/v1/workspaces/<slug>/work-items/advanced-search/ endpoint accepts a JSON body with a filters key. The filters use a rich JSON grammar with logical operators (and, or, not).

Request Shape

{
  "filters": { ... },
  "project_id": "<optional project UUID>",
  "workspace_search": true,
  "limit": 25
}

Your Use Case: Cycle + Completed States

To get all completed work items in a specific cycle and project — this is a single API call:

{
  "filters": {
    "and": [
      { "cycle_id": "<your-cycle-uuid>" },
      { "state_group__in": ["completed"] }
    ]
  },
  "project_id": "<your-project-uuid>",
  "limit": 100
}

If you also want “cancelled” items or need to be more specific with individual state IDs:

{
  "filters": {
    "and": [
      { "cycle_id": "<your-cycle-uuid>" },
      { "state_group__in": ["completed", "cancelled"] }
    ]
  },
  "project_id": "<your-project-uuid>",
  "limit": 100
}

Or filter by specific state UUIDs instead of state groups:

{
  "filters": {
    "and": [
      { "cycle_id": "<your-cycle-uuid>" },
      {
        "state_id__in": [
          "<done-state-uuid>",
          "<deployed-state-uuid>"
        ]
      }
    ]
  },
  "project_id": "<your-project-uuid>",
  "limit": 100
}

All Available Filter Fields

Filter Key Description Example Value
state_id / state_id__in Filter by specific state UUID(s) "<uuid>" / ["<uuid>", ...]
state_group / state_group__in Filter by state group name "completed" / ["completed", "cancelled"]
cycle_id / cycle_id__in Filter by cycle UUID(s) "<uuid>" / ["<uuid>", ...]
module_id / module_id__in Filter by module UUID(s) "<uuid>"
assignee_id / assignee_id__in Filter by assignee UUID(s) "<uuid>"
label_id / label_id__in Filter by label UUID(s) "<uuid>"
project_id / project_id__in Filter by project UUID(s) "<uuid>"
priority / priority__in Filter by priority "high" / ["high", "urgent"]
created_by_id / created_by_id__in Filter by creator UUID(s) "<uuid>"
is_archived Include/exclude archived items false
start_date Exact / range / comparison "2025-01-01"
target_date / target_date__range Target date or range ["2025-01-01", "2025-01-31"]
created_at__gte / created_at__lte Created date comparisons "2025-01-01"
type_id / type_id__in Filter by work item type "<uuid>"

Valid state_group values: backlog, unstarted, started, completed, cancelled

Valid priority values: urgent, high, medium, low, none

Logical Operators

You can nest and, or, and not:

{
  "and": [
    { "cycle_id": "<uuid>" },
    { "not": { "state_group": "cancelled" } },
    {
      "or": [
        { "priority": "high" },
        { "priority": "urgent" }
      ]
    }
  ]
}

Building Your Export

The response includes sequence_id and project_identifier, so you can construct the display identifier as {project_identifier}-{sequence_id} (e.g., PROJ-1234) and the name field gives you the title. No brute-force multi-step approach needed — one POST call gets you everything.

We’ll be updating the API documentation to include this filter syntax and examples so future users won’t have to dig for it..