Skip to main content
A task is a background job Filed runs for a workspace: binder ingestion, tax prep, tax review, tax advisor, or chat. Mutations like createClient and addClientDocuments return a taskId; you use the tasks API to follow that work to completion. Tasks are reached through the me query as a WorkspaceUser, so authenticate with a workspaceToken (see Authentication). All requests go to:
https://router.apps.filed.com/graphql

The Task type

type Task {
  id: ID!
  type: TaskType!
  status: TaskStatus!
  startedAt: String!
  completedAt: String
  errorMessage: String
  attributes: [TaskAttribute!]!
  subTasks: [SubTask!]!
  result: TaskResult!
  client: ClientShortDetails
  triggeredBy: UserShortDetails
}

enum TaskType {
  BINDER
  TAX_PREP
  TAX_REVIEW
  TAX_ADVISOR
  CHAT
}

enum TaskStatus {
  RUNNING
  COMPLETED
  FAILED
}
id
ID!
The task’s unique identifier. This is the value returned as taskId by the mutations that start work.
type
TaskType!
What kind of work this is: BINDER, TAX_PREP, TAX_REVIEW, TAX_ADVISOR, or CHAT.
status
TaskStatus!
RUNNING, COMPLETED, or FAILED. Poll this to know when work finishes.
startedAt
String!
ISO 8601 timestamp of when the task started.
completedAt
String
ISO 8601 timestamp of when the task finished. null while RUNNING.
errorMessage
String
A human-readable error message when status is FAILED. null otherwise.
attributes
[TaskAttribute!]!
Arbitrary name/value metadata pairs describing the task.
subTasks
[SubTask!]!
The individual stages of the task, each with its own status. Use these for granular progress while a task is RUNNING.
result
TaskResult!
The typed result of the task, resolved by type. See Task result.
client
ClientShortDetails
The client this task belongs to (id, name), when applicable.
triggeredBy
UserShortDetails
The user who started the task (id, name, email).

Supporting types

type TaskAttribute {
  name: String!
  value: String!
}

type SubTask {
  id: ID!
  type: SubTaskType!
  status: TaskStatus!
  startedAt: String!
  completedAt: String
  errorMessage: String
  errorCode: DataEntryErrorCode
}

type ClientShortDetails {
  id: ID!
  name: String!
}

type UserShortDetails {
  id: ID!
  name: String!
  email: String!
  emailHash: String
}
SubTask.type
SubTaskType!
The stage, for example CONVERT_DOCUMENTS, CLASSIFY_SUBDOCS, EXTRACT_SUBDOCS, or EXPORT_AND_INDEX. The full set of stages depends on the parent task’s type.
SubTask.errorCode
DataEntryErrorCode
A machine-readable code when a data-entry stage fails, for example INVALID_CREDENTIALS, CLIENT_NOT_FOUND, or TIMEOUT. null otherwise.

List tasks

Read workspace.tasks to list tasks across the whole workspace. Filter, page, and sort with the arguments below.
query ListTasks($filters: TaskFilters, $sortBy: SortBy, $limit: Int, $offset: Int) {
  me {
    ... on WorkspaceUser {
      workspace {
        tasks(filters: $filters, sortBy: $sortBy, limit: $limit, offset: $offset) {
          id
          type
          status
          startedAt
          completedAt
          client {
            id
            name
          }
          triggeredBy {
            id
            name
          }
        }
      }
    }
  }
}

Arguments

input TaskFilters {
  type: TaskType
  status: TaskStatus
  triggeredBy: ID
  search: String
}

input SortBy {
  field: String!
  order: SortByOrder!   # ASC | DESC
}
filters.type
TaskType
Return only tasks of this type.
filters.status
TaskStatus
Return only tasks in this status (RUNNING, COMPLETED, FAILED).
filters.triggeredBy
ID
Return only tasks started by this user.
Free-text search over task metadata.
sortBy
SortBy
Sort order, for example { "field": "startedAt", "order": "DESC" }.
limit
Int
Maximum number of tasks to return.
offset
Int
Number of tasks to skip, for pagination.
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{
    "query": "query ListTasks($filters: TaskFilters, $sortBy: SortBy, $limit: Int) { me { ... on WorkspaceUser { workspace { tasks(filters: $filters, sortBy: $sortBy, limit: $limit) { id type status startedAt completedAt client { id name } triggeredBy { id name } } } } } }",
    "variables": {
      "filters": { "type": "BINDER", "status": "RUNNING" },
      "sortBy": { "field": "startedAt", "order": "DESC" },
      "limit": 20
    }
  }'
{
  "data": {
    "me": {
      "workspace": {
        "tasks": [
          {
            "id": "018f9c2b-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
            "type": "BINDER",
            "status": "RUNNING",
            "startedAt": "2026-07-04T09:15:00.000Z",
            "completedAt": null,
            "client": {
              "id": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
              "name": "Jane Taxpayer"
            },
            "triggeredBy": {
              "id": "019f0fb6-26e9-74b7-a842-cb43a2a41682",
              "name": "Jane Preparer"
            }
          }
        ]
      }
    }
  }
}

Check a single task’s status

There is no task(id:) query. To follow one task (for example the taskId returned by createClient or addClientDocuments), list the tasks for its client with client.tasks and read the entry whose id matches. Because a client’s task list is small and typed, this is the reliable way to poll a specific task.
query ClientTaskStatus($clientId: ID!, $type: TaskType) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          tasks(type: $type) {
            id
            status
            startedAt
            completedAt
            errorMessage
            subTasks {
              type
              status
            }
          }
        }
      }
    }
  }
}
Client.tasks accepts these arguments:
tasks(type: TaskType, status: TaskStatus, triggeredBy: ID, limit: Int): [Task!]!
type
TaskType
Narrow to one task type, for example BINDER to watch document ingestion.
limit
Int
Cap the number of tasks returned (for example 1 for the most recent).
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{
    "query": "query ClientTaskStatus($clientId: ID!, $type: TaskType) { me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { tasks(type: $type) { id status startedAt completedAt errorMessage subTasks { type status } } } } } } }",
    "variables": { "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c", "type": "BINDER" }
  }'
{
  "data": {
    "me": {
      "workspace": {
        "clients": [
          {
            "tasks": [
              {
                "id": "018f9c2b-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
                "status": "COMPLETED",
                "startedAt": "2026-07-04T09:15:00.000Z",
                "completedAt": "2026-07-04T09:17:42.000Z",
                "errorMessage": null,
                "subTasks": [
                  { "type": "CONVERT_DOCUMENTS", "status": "COMPLETED" },
                  { "type": "CLASSIFY_SUBDOCS", "status": "COMPLETED" },
                  { "type": "EXTRACT_SUBDOCS", "status": "COMPLETED" },
                  { "type": "EXPORT_AND_INDEX", "status": "COMPLETED" }
                ]
              }
            ]
          }
        ]
      }
    }
  }
}
Poll on an interval (for example every few seconds) until status is no longer RUNNING. COMPLETED means the work succeeded; FAILED means it did not, and errorMessage explains why. subTasks show which stage is currently running.

Task result

Every task carries a typed result. TaskResult is a union whose concrete type is determined by the task’s type. Select fields with an inline fragment on the member you expect, and read __typename to know which one you got.
union TaskResult =
    TaskUnknownResult
  | TaskTaxPrepResult
  | TaskTaxReviewResult
  | TaskTaxAdvisorResult
TaskUnknownResult
object
The fallback result, including for BINDER and CHAT tasks.
type TaskUnknownResult {
  message: String!
}
TaskTaxPrepResult
object
Returned for TAX_PREP tasks: a summary plus document/form counts and the individual review items.
type TaskTaxPrepResult {
  taxYear: Int!
  returnType: ReturnType!
  summary: String!
  documentCount: Int!
  extractedFormCount: Int!
  reviewItemCount: Int!
  reviewItems: [TaxPrepReviewItem!]!
}

type TaxPrepReviewItem {
  severity: String!
  category: String!
  description: String!
}
TaskTaxReviewResult
object
Returned for TAX_REVIEW tasks: a summary plus issue breakdowns by severity and by form.
type TaskTaxReviewResult {
  taxYear: Int!
  returnType: ReturnType!
  summary: String!
  issueCountBySeverity: IssueCountBySeverity!
  issueCountByForm: [FormIssueCount!]!
}

type IssueCountBySeverity {
  critical: Int!
  high: Int!
  medium: Int!
  low: Int!
}

type FormIssueCount {
  form: String!
  count: Int!
}
TaskTaxAdvisorResult
object
Returned for TAX_ADVISOR tasks: a summary plus strategy counts. The by* fields are JSON maps.
type TaskTaxAdvisorResult {
  taxYear: Int!
  returnType: ReturnType!
  summary: String!
  strategyTotal: Int!
  byDomain: JSON!
  bySavingsHorizon: JSON!
  estimatedSavingsCentsByHorizon: JSON!
}
Because the members share taxYear, returnType, and summary, you can select those on each fragment and branch on __typename:
query TaskResult($clientId: ID!) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          tasks(type: TAX_PREP, limit: 1) {
            id
            status
            result {
              __typename
              ... on TaskTaxPrepResult {
                summary
                documentCount
                extractedFormCount
                reviewItems {
                  severity
                  category
                  description
                }
              }
              ... on TaskTaxReviewResult {
                summary
                issueCountBySeverity {
                  critical
                  high
                  medium
                  low
                }
                issueCountByForm {
                  form
                  count
                }
              }
              ... on TaskUnknownResult {
                message
              }
            }
          }
        }
      }
    }
  }
}