Skip to main content

Building a task queue

Task management is in preview and available in the v1alpha2 API. Requests, responses, and activity-log payloads described in this guide may change without notice.

ListManualTasks is the endpoint behind the portal's Task Manager, and the one you use to build an equivalent queue in your own system. This page covers the request shape, the filter and ordering fields it supports, the enrichment calls needed to render a useful row, and the caveats specific to querying tasks as an integration rather than as a portal user.

Listing tasks

GET /v1alpha2/{parent}/manualTasks

parent accepts two shapes:

  • organizations/{organization}/teams/{team}/checks/{check} — tasks for one check.
  • organizations/{organization}/teams/{team}/checks/- — all tasks across every check in the team. This is the wildcard form a task queue is built on.
curl -X GET "https://api.thirdfort.dev/client/api/v1alpha2/organizations/{org_id}/teams/{team_id}/checks/-/manualTasks?filter=task_type+%3D+%22REVIEW%22&page_size=25" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Filtering

The filter parameter follows AIP-160. Supported fields:

On the task itself:

  • status, assignee, task_type, display_name, parent
  • create_time, update_time, due_time
  • source — how the task came into being (for example source = "AUTO_OM_HIT" for tasks spawned by an ongoing-monitoring hit)

On the check the task belongs to (and that check's subject):

  • check.created_by — the actor resource name that created the check (for checks created by an integration, the integration's own name)
  • check.client_reference — the client-supplied reference on the check
  • check.composite_status — the check's at-a-glance lifecycle status
  • check.subject.given_name, check.subject.family_name, check.subject.name (check.subject.name matches the concatenation of given and family name)

Examples from the proto contract:

status = "PENDING"
assignee = "organizations/123/users/456"
status = "PENDING" AND assignee = ""
task_type = "INCOME_VERIFICATION"
create_time > "2023-01-01T00:00:00Z"
due_time < "2024-01-01T00:00:00Z"
check.created_by = "organizations/123/users/456"
check.client_reference = "ABC-123"
check.subject.family_name = "Smith"

Ordering

order_by takes comma-separated <field> [asc|desc] clauses, applied in order. Supported fields: create_time, update_time, due_time, check.subject.name (NULLS LAST — checks with no individual subject sort to the end), and check.composite_status (sorted in lifecycle order, so ascending reads as natural progression).

Leave order_by empty for the default: create_time ASC, assignee NULLS LAST, name ASC. When you supply your own clauses, that default tiebreaker is dropped in favour of name ASC alone — you get exactly the order you asked for, with name (the task's unique key) only breaking ties.

Pagination and counts

Pagination is opaque: pass next_page_token from the previous response as page_token on the next request. A page token is pinned to the filter and order_by it was minted under — replaying it against a different filter or order is rejected. Set include_total_size = true to get a total_size count across all pages (an extra COUNT(*), so only ask for it when you need a badge or total, such as a per-tab count).

Portal tab recipes

The portal's Task Manager renders five tabs. These filter expressions are recipes that reproduce the same view — a starting point, not a guaranteed contract. Only the fields listed above are officially supported filter expressions; treat anything beyond that as subject to change.

TabFilter expression
Needs actionstatus = "PENDING" AND task_type = "REVIEW"
Monitoringsource = "AUTO_OM_HIT"
Overdue(status = "PENDING" OR status = "IN_PROGRESS") AND due_time < "<now>"
In progresstask_type = "WAITING" AND check.created_by = "<your user or integration resource name>"
All livestatus = "PENDING" OR status = "IN_PROGRESS"

Substitute <now> with the current timestamp in RFC 3339 format, and <your user or integration resource name> with the caller's own resource name (see the check.created_by nuance below).

Enriching the queue

ListManualTasks returns the task; it does not return the check's subject, reference, or risk detail. Building a queue view means joining that in with a small number of batched calls, one per page rather than one per row.

Check context: BatchGetChecks

GET /v1alpha2/{parent}/checks:batchGet

parent is the team (organizations/{organization}/teams/{team}); names takes up to 100 check resource names, all belonging to that team, and returns them in the same order as requested. Use it to pull related_subjects, client_reference, and composite_status for the checks behind a page of tasks.

Risk pills: BatchGetRiskSummaries

GET /v1alpha2/{parent}/riskSummaries:batchGet

parent is the organisation; names takes up to 100 RiskSummary resource names (.../checks/{check}/riskSummary). Each summary aggregates the check's currently-visible risk indicators by domain (screening, identity, source of funds, address, client alert, bank statements), giving you the per-domain severity pills a queue row typically shows without fetching every underlying finding.

Risk detail: ListRiskIndicators

GET /v1alpha2/{parent}/riskIndicators

Scoped to a single check. Use this when a row is expanded and you need the individual indicators (domain, severity, presentation category) behind the summary pill, rather than the aggregate.

Resolving reviewer names

Task and check fields carry bare user resource names (organizations/{organization}/users/{user}), not display names. Resolve them via the stable, public ListUsers:

GET /v1/{parent}/users
curl -X GET "https://api.thirdfort.dev/client/api/v1/organizations/{org_id}/users?page_size=100" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

parent is the organisation. Supported filter fields are email, display_name, and state (ACTIVE, INACTIVE, INVITED, DELETED). Page through the organisation's users with page_token, and build a name → display_name map once per sync rather than resolving one user at a time. This is the same lookup used for assignee, creator_name, requester_name, and the activity-log actor fields described in Observing outcomes.

The check.created_by nuance

For checks your integration created, check.created_by is the integration's own resource name (partners/{partner}/integrations/{id} or organizations/{organization}/integrations/{id}), not the name of any human. This is useful precisely because of that: filtering check.created_by = "<your integration's resource name>" scopes a queue to only the checks your integration created, which is normally what you want when building a queue for your own system rather than the whole team's.

check.on_behalf_of — the human a check was created for — is not a supported filter field today. If you need to find work belonging to a specific person the check was created on behalf of, filter checks separately (via ListChecks) and cross-reference by check name.

Filtering to reviews only

ListManualTasks returns every task type on a check or team, not just reviews — a check may also carry WAITING, DOCUMENT_REVIEW, INCOME_VERIFICATION, and other internally-managed task types in the same response. If your queue only cares about review decisions, add task_type = "REVIEW" to every query.