Skip to content

Filtering tasks

GET /public/v1/tasks returns every task in the scope (the same set as the project’s table view in the web app) and narrows it down with query-parameter filters. This page shows how the filters combine and gives copy-paste recipes for common queries.

All examples assume:

Terminal window
BASE="https://api.bordio.com/public/v1"
AUTH='Authorization: Bearer brd_sk_live_...'
PROJECT="proj_6594a1b2c3d4e5f6a7b8c9d1"
  • Different parameters → AND. Every parameter you add narrows the result.
  • Multiple values in one parameter → OR. Values are comma-separated: priority=high,critical matches either.
  • Parameters you omit don’t restrict anything — no filters means all tasks.
Parameter Values Notes
priority CSV of lowest, low, medium, high, critical and/or none none = tasks with no priority set
task_status_id CSV of task_status_… ids Get ids from Definitions
state open | closed Groups statuses by their state — no need to enumerate them. With view=by_task it means “is there work to do”
task_type_id CSV of task_type_… ids
assignee_id CSV of user_… ids and/or none none = tasks with no assignee
date_from YYYY-MM-DD or ISO-8601 datetime Inclusive lower bound on the day the task is scheduled for — the date field, not the deadline
date_to YYYY-MM-DD or ISO-8601 datetime Inclusive upper bound on the same day. Setting either bound orders the list by date, oldest first
due_date_from YYYY-MM-DD or ISO-8601 datetime Inclusive lower bound of the due-date range
due_date_to YYYY-MM-DD or ISO-8601 datetime Inclusive upper bound of the due-date range
due_date none Only tasks without a due date; incompatible with the range bounds
tag_id CSV of tag_… ids Matches tasks that have any of the tags
view by_task | by_date Changes what counts as one record — see Repeating tasks in a listing
closed_since YYYY-MM-DD or ISO-8601 datetime Only tasks completed at or after this moment, most recently completed first

The special value none matches tasks that have no assignee:

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&assignee_id=none" -H "$AUTH"

Tasks assigned to a specific person — or to nobody

Section titled “Tasks assigned to a specific person — or to nobody”

none can be mixed with user ids in the same CSV; within one parameter the values are OR-ed:

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&assignee_id=user_6594a1b2c3d4e5f6a7b8c9d1,none" -H "$AUTH"

Tasks with no priority — or low priority

Section titled “Tasks with no priority — or low priority”

Priority is optional, so priority accepts the special value none for tasks where it isn’t set. Like every CSV value it OR-s with the rest — “no priority or low” is one parameter:

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&priority=none,low" -H "$AUTH"
Terminal window
curl "$BASE/tasks?project_id=$PROJECT&state=open&priority=high,critical" -H "$AUTH"

state is the easiest way to split open vs closed work. If you need specific statuses (“In progress” but not “New”), use task_status_id with ids from the definitions endpoints.

Both bounds are inclusive; date-only values expand to the start / end of that day (UTC):

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&due_date_from=2026-07-01&due_date_to=2026-07-31" -H "$AUTH"

You can also pass just one bound — for example, everything due from today onward (due_date_from alone), or an “overdue” view — open tasks whose deadline has already passed:

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&state=open&due_date_to=2026-07-17" -H "$AUTH"

A range can never match a task that has no due date, so this is a separate filter:

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&due_date=none" -H "$AUTH"
Terminal window
curl "$BASE/tasks?project_id=$PROJECT&tag_id=tag_65dcc9c66f2e4e001ab18859,tag_66446ff2dc01cb59f6cbf7a6" -H "$AUTH"

Open, high-priority, assigned to nobody, due this month:

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&state=open&priority=high&assignee_id=none&due_date_from=2026-07-01&due_date_to=2026-07-31" -H "$AUTH"

Filters compose with pagination as usual — limit and cursor apply to the filtered result (see Conventions).

By default a listing returns your one-off tasks plus the individual occurrences of repeating tasks that already exist — the ones somebody edited, completed or rescheduled. One repeating task can therefore appear as several rows, and an occurrence nobody has touched yet does not appear at all.

Pass view=by_task to list tasks instead: a repeating task comes back as a single row carrying its rule and the occurrence to work on next, and its occurrences are not listed separately.

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&view=by_task" -H "$AUTH"

The response gains kind, series_id, series_chain_id, recurrence_summary and current_occurrence; see Recurring tasks. Without view the set of records is unchanged, so existing integrations keep working — but new ones should pass it explicitly.

Pass view=by_date with a date range to list occurrences: every day a repeating task falls on is its own row, next to the one-off tasks scheduled in those days.

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&view=by_date&date_from=2026-09-01&date_to=2026-09-30" -H "$AUTH"

The range is required here and cannot exceed 31 days, results run from the start of the range, and closed_since cannot be combined with it (400). Details and the full list of rules: Listing occurrences day by day.

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&view=by_task&state=open" -H "$AUTH"

In this view state answers “is there work to do”: a one-off task by its own status, a repeating task by its occurrences — open while one is still open, closed once none are left. A repeating task whose occurrences have run out drops out of the list even though the status it starts occurrences in is a perfectly normal “To do”.

Terminal window
curl "$BASE/tasks?project_id=$PROJECT&closed_since=2026-07-28" -H "$AUTH"

Completed work is a different question, so it is a different request. Each completed occurrence is its own record — that is what “we did the standup on Tuesday” means — so this listing is not combined with view=by_task; doing so returns 400 validation_error. Results are ordered by completion time, most recent first, and paginate like any other listing.

closed_since also rejects state=open with 400 for the same reason it rejects view=by_task: the request contradicts itself, and an empty page would read as “nothing was completed” rather than “you asked for something impossible”.

due_date_from / due_date_to / due_date — why three parameters?

Section titled “due_date_from / due_date_to / due_date — why three parameters?”

They answer two different questions:

  • due_date_from / due_date_to select tasks whose due date falls into a range. Use either bound alone or both together.
  • due_date=none selects tasks that have no due date at all. No range can express “the field is empty”, which is why it’s a separate parameter rather than a magic range value.

Because “has no due date” and “due date within a range” are mutually exclusive, combining due_date=none with either bound returns 400 validation_error.

  • A malformed value (unknown priority, bad id format, non-date) → 400 validation_error.
  • A well-formed id that matches nothing (foreign workspace’s tag, deleted status) → not an error: it simply matches no tasks, so you get an empty page.
  • The exception is project_id: a project outside your key’s scope → 404 not_found_error.