list_work_packages
Retrieve and filter OpenProject work packages by project, status, assignee, priority, version, or date range, with sorting, grouping, and sum totals—no free-text query needed.
Instructions
List work packages with structured filters and no free-text query requirement.
project accepts a numeric ID, exact identifier/slug, or project name; the parameter is named project, not project_id. There is no generic filters=[...] parameter; each filter is its own named argument (version, status, assignee, the date filters, etc.), listed below.
version_status filters by the status of a work package's assigned version: one of 'open', 'closed', or 'locked'. It requires OpenProject 16.4 or newer. A work package with several target versions matches version and version_status when any one of them matches.
assignee filters by any user (username, id, or "me"). assignee_me takes precedence.
status/priority filter by exact OpenProject status/priority name or numeric ID (case-insensitive), not meta-values like 'open'/'closed'; set open_only=true to restrict results to not-closed work packages instead.
Date filters accept YYYY-MM-DD format:
created_on/updated_on/due_on: exact date match
created_between/updated_between/due_between: inclusive date range [start, end] Cannot specify both _on and _between for the same field.
overdue_only=true restricts results to work packages with due_date before today that are not closed (OpenProject's own overdue? predicate; there is no dedicated overdue API filter, this composes a relative date filter with the open-status meta-filter). due_within_days=N restricts to due_date in [today, today+N days]. Neither can be combined with each other or with due_on/due_between (all four constrain the same field).
sort_by and group_by are checked against OpenProject's real sortable and groupable work-package columns (the parameters list them with the release each newer column needs); an unknown field raises a ValueError listing the valid set instead of only failing once OpenProject itself rejects the request. A column the instance's release lacks is rejected by OpenProject and the error names the release it needs. Dates, hours, subject, id and the other columns without a value per group sort fine but cannot be grouped by.
select restricts each result row to the given fields (e.g. ["id", "subject", "status"]); an invalid name returns the allowed set. Common fields: id, display_id, subject, type, status, priority, assignee, project, version, parent_id, parent_display_id, start_date, due_date, estimated_time, spent_time, created_at, updated_at, author, category, description, schedule_manually, derived_start_date, derived_due_date, percentage_done, derived_percentage_done, readonly, has_project_attributes, ignore_non_working_days, custom_fields, custom_fields_truncated, custom_comments, custom_comments_truncated. custom_fields/custom_comments are selectable/hideable only as a whole field, not by individual custom-field key (per-key filtering is OPENPROJECT_HIDE_CUSTOM_FIELDS' concern, not select's). parent_display_id is only populated on OpenProject 17.5+ (semantic mode); it stays null on older/classic instances even when parent_id is set.
total is the real matching count only when the query is provably restricted to OPENPROJECT_READ_PROJECTS server-side: scope is unrestricted, an explicit project was given, or (no project, restricted scope) a server-side filter for the resolved allowed project IDs was sent. Otherwise total falls back to this page's item count, and next_offset/truncated are based on whether this page came back full rather than the server's own total, so nothing here ever reveals how many matches exist in projects you can't see. Because of this, total can read 0 while next_offset is still non-null (a restrictive scope filtered out every match on this page, but the raw server page was full); that is not an inconsistency, keep paging via next_offset rather than stopping on a low/zero total. Page until next_offset is null either way.
include_sums=true adds server-computed aggregates instead of requiring client-side pagination and summation: groups (one entry per group_by value, with count and a sums dict of OpenProject's fixed summable fields: estimated_time, story_points, percentage_done, remaining_time, overall_costs, labor_costs, material_costs, plus any custom fields, as raw server-formatted values, e.g. ISO 8601 durations and currency strings) and total_sums (the same shape, across all matches). groups is only populated when group_by is also set; total_sums is populated either way (a sum over the whole filtered result set even without grouping). Same scope-safety rule as total above: groups/total_sums come back null whenever the query cannot be proven restricted to OPENPROJECT_READ_PROJECTS server-side. A group named after a version, sprint or backlog bucket defined in a project that OPENPROJECT_READ_PROJECTS does not cover keeps its count and sums under the label [outside read scope].
Version rollup recipe: group_by="status", version="", include_sums=true returns per-status progress/time sums for one version's work packages, replacing manual pagination + client-side summation.
custom_fields is a dict keyed by the RAW OpenProject key (e.g. "customField12") -- never a friendly name -- with values normalized by shape: plain scalars pass through; link-typed values (list/user/version format) become title-only strings (or a list of titles for a multi-value field), matching every other link field in this response; multi- paragraph "text"-format values are capped like description (this call's effective text_limit); a scalar string/link/date-format value is independently capped at ~255 characters. custom_fields_truncated is true when the dict was capped at 50 entries and/or any individual entry's value was itself capped. custom_comments (keyed the same way, holding a field's freeform comment text) and custom_comments_truncated follow the identical shape and caps, independently -- in practice custom_comments is always empty/null for work packages on OpenProject's stock CE behavior: only Projects opt into per-custom-field comments, work packages do not, so this field is present for forward compatibility only. Combined worst case is roughly 250 KB for custom_fields per work package, always finite regardless of how many custom fields exist or how large their values are. get_work_packages (batch) and list_my_open_work_packages return the same custom_fields/custom_comments shape and caps, since they reuse this same normalization. OPENPROJECT_HIDE_CUSTOM_FIELDS hides individual custom_fields entries by matching ONLY the raw key/wildcard (e.g. "customField12", "customField*") -- unlike the write path, which also accepts the custom field's friendly name, a read-side hide pattern written as a friendly name has no effect.
custom_field_filters filters results by custom field value(s) -- a dict keyed by "cf_" or "customField" (both forms accepted transparently and always normalized to "cf_" on the wire; "cf_" is CustomField#column_name, the actual OpenProject filter key, distinct from "customField" which is the JSON/PATCH key used by custom_fields above -- do not confuse the two). Each entry's value is {"operator": "", "values": [...]}, e.g. {"cf_12": {"operator": "=", "values": ["42"]}}. Learn a field's cf_ id from any prior get_work_package call's custom_fields dict keys (strip the "customField" prefix). Only raw cf_/customField keys are accepted -- friendly-name resolution is not supported (a list/search call has no single project+type context to resolve a name against safely; a friendly name is only meaningful for the write path's per-call project+type schema probe). At most 20 custom-field filters per call, at most 100 values per filter, each value at most 1000 characters.
Legal operators depend on the field's format on this instance -- see docs/filters.md's "Custom-Field Filters" section for the full format-to-operator matrix, verified against OpenProject CE source. This tool validates the key shape and the operator symbol locally (a recognized custom-field operator, not necessarily legal for this specific field's format) and rejects hidden fields (OPENPROJECT_HIDE_CUSTOM_FIELDS) before any network call; an operator/value that is syntactically valid but illegal for the field's actual format is rejected by OpenProject itself with a clear error (surfaced as a ValueError here, not a raw HTTP passthrough) rather than validated client-side against a live schema -- this keeps list/search calls at their existing single-request cost (no per-call schema probe). user/version-format custom-field filters additionally require project to be set (OpenProject only considers project-scoped custom fields of these two formats filterable at all; this is not checked locally -- a global, no-project user/version CF filter fails server-side with an unhelpful "filter not available" error, see docs/filters.md's "Global (no-project) filtering constraint" section).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | ||
| limit | No | Page size, capped at OPENPROJECT_MAX_PAGE_SIZE. | |
| due_on | No | ||
| offset | No | 1-based page number; pass the previous result's next_offset. | |
| select | No | Fields to return; a requested unset field comes back as null. Allowed: assignee, author, category, created_at, custom_comments, custom_comments_truncated, custom_fields, custom_fields_truncated, derived_due_date, derived_estimated_time, derived_percentage_done, derived_remaining_time, derived_start_date, description, description_length, description_truncated, display_id, due_date, duration, estimated_time, has_description, has_project_attributes, id, ignore_non_working_days, parent_display_id, parent_id, percentage_done, priority, project, project_phase, readonly, remaining_time, responsible, schedule_manually, spent_time, sprint, start_date, status, subject, target_versions, type, updated_at, version. | |
| status | No | ||
| project | No | Project identifier, id, or name; a unique part of a name or identifier also matches. | |
| sort_by | No | Sort criteria as "field:direction" or "field-direction" (e.g. ["status:desc", "priority-asc"]); the direction defaults to asc. Fields: assigned_to, assignee, author, backlog_bucket, category, created_at, done_ratio, due_date, duration, estimated_hours, estimated_time, id, observed_in_versions, percentage_done, position, priority, project, project_phase, remaining_hours, remaining_time, responsible, sprint, start_date, status, story_points, subject, target_versions, type, updated_at, version, or a custom field's cf_<id>. Newer columns need an OpenProject release: project_phase 16.1+, sprint 17.4+, backlog_bucket 17.6+, target_versions 17.8+, observed_in_versions 17.9+; target_versions is version under its newer name. sprint and backlog_bucket also need the Backlogs module in a project where you may view sprints. | |
| version | No | ||
| assignee | No | ||
| group_by | No | One field to group the results by: assigned_to, assignee, author, backlog_bucket, category, done_ratio, observed_in_versions, percentage_done, priority, project, project_phase, responsible, sprint, status, target_versions, type, version, or a custom field's cf_<id>. Newer columns need an OpenProject release: project_phase 16.1+, sprint 17.4+, backlog_bucket 17.6+, target_versions 17.8+, observed_in_versions 17.9+; target_versions is version under its newer name. sprint and backlog_bucket also need the Backlogs module in a project where you may view sprints. | |
| priority | No | ||
| open_only | No | ||
| created_on | No | ||
| updated_on | No | ||
| assignee_me | No | ||
| due_between | No | ||
| include_sums | No | ||
| overdue_only | No | ||
| version_status | No | ||
| created_between | No | ||
| due_within_days | No | ||
| updated_between | No | ||
| custom_field_filters | No |