Skip to main content
Tax prep is the pipeline that extracts forms from a client’s binder, reconciles them, optionally enters them into tax software, and produces a set of review items. It is a background task: you start it with the triggerTaxPrep mutation and follow the resulting task to completion with the tasks API. Tax prep operations are reached through the me query resolved as a WorkspaceUser, so the trigger mutation and the task poll both require a workspaceToken (see Authentication). The two backoffice operations on this page (retriggerTaxPrepStep and setTaxPrepTaskStatus) require a user token instead, called out below. All requests go to:
https://router.apps.filed.com/graphql
Tax prep runs as a polled background task. This page documents how to start a run and read its result. For the polling pattern itself (listing tasks, reading status, subTasks, and the TaskResult union), see Tasks; this page does not re-explain it.

The TaskTaxPrepResult type

When a TAX_PREP task reaches status: COMPLETED, its result field resolves to TaskTaxPrepResult. It carries a summary plus document and form counts, and the individual review items the run produced.
type TaskTaxPrepResult {
  taxYear: Int!
  returnType: ReturnType!
  summary: String!
  documentCount: Int!
  extractedFormCount: Int!
  reviewItemCount: Int!
  reviewItems: [TaxPrepReviewItem!]!
}

type TaxPrepReviewItem {
  severity: String!
  category: String!
  description: String!
}

enum ReturnType {
  F1040
  F1041
  F1065
  F1120
  F1120S
  F990
}
taxYear
Int!
The tax year the run was prepared for, for example 2025.
returnType
ReturnType!
The return form: F1040, F1041, F1065, F1120, F1120S, or F990 (see ReturnType).
summary
String!
A human-readable summary of the prepared return.
documentCount
Int!
Number of documents processed from the client’s binder.
extractedFormCount
Int!
Number of forms extracted from those documents.
reviewItemCount
Int!
Number of review items produced. Use this as a quick “needs attention” count before paging through reviewItems.
reviewItems
[TaxPrepReviewItem!]!
The review items. Each has severity, category, and description (all String!).
TaskTaxPrepResult is one member of the TaskResult union. The other tax members are TaskTaxReviewResult (returned for TAX_REVIEW tasks, with issue counts by severity and form) and TaskTaxAdvisorResult (returned for TAX_ADVISOR tasks). See Tasks, task result for the full union and the inline-fragment pattern used to select it.

Start a tax prep run

triggerTaxPrep starts a tax prep run for a client and returns the taskId you poll. It requires a workspaceToken.
mutation TriggerTaxPrep($input: TriggerTaxPrepInput!) {
  triggerTaxPrep(input: $input) {
    taskId
  }
}

Input: TriggerTaxPrepInput

input TriggerTaxPrepInput {
  taskId: ID
  clientId: ID!
  returnType: ReturnType!
  software: String
  softwareClientId: String
  softwareClientVersion: String
  runDataEntry: Boolean
  forceReconcile: Boolean
  force: Boolean
  skills: RunSkillSelectionInput
}

"""
Per-run selection of tenant (firm + user) skills. Omitted = all active skills
apply; an empty list censors every skill in that scope.
"""
input RunSkillSelectionInput {
  workspace: [String!]
  user: [String!]
}
clientId
ID!
required
The client to prepare the return for.
returnType
ReturnType!
required
The return form to prepare. Must match the client’s returnType (see clients).
taskId
ID
Optional. Pass an existing tax prep task ID to target an in-flight or prior run rather than starting a brand-new one. Omit for a fresh run.
software
String
The tax software provider key, as exposed by the workspace’s connected tax software integrations. Required only when runDataEntry is true.
softwareClientId
String
The client identifier inside the tax software. Required only when runDataEntry is true.
softwareClientVersion
String
The tax software client version string, when relevant to the integration.
runDataEntry
Boolean
When true, the pipeline continues past extraction and reconciliation into data entry, writing the prepared return back to the tax software. Requires software and softwareClientId.
forceReconcile
Boolean
When true, re-run reconciliation even if a prior reconcile already succeeded.
force
Boolean
When true, start a fresh run even if another tax prep task for this client is already RUNNING.
skills
RunSkillSelectionInput
Optional. Override which workspace and user skills apply to this run. Omit to apply all active skills; pass an empty list for a scope to censor every skill in that scope.

Returns: TriggerTaskResult

type TriggerTaskResult {
  taskId: ID!
}
taskId
ID!
The ID of the started TAX_PREP task. Poll it until status is no longer RUNNING, then read result as TaskTaxPrepResult.
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{
    "query": "mutation TriggerTaxPrep($input: TriggerTaxPrepInput!) { triggerTaxPrep(input: $input) { taskId } }",
    "variables": {
      "input": {
        "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
        "returnType": "F1040",
        "runDataEntry": false
      }
    }
  }'
{
  "data": {
    "triggerTaxPrep": {
      "taskId": "018f9c2b-7c4d-7e10-9a22-6b3c4d5e6f70"
    }
  }
}

Poll the task to completion

There is no task(id:) query. Poll the task you just started by listing the client’s TAX_PREP tasks and reading the entry whose id matches the taskId returned above. The polling mechanics are documented on Tasks; the short version:
query PollTaxPrep($clientId: ID!) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          tasks(type: TAX_PREP, limit: 1) {
            id
            status
            startedAt
            completedAt
            errorMessage
            subTasks {
              type
              status
            }
          }
        }
      }
    }
  }
}
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{
    "query": "query PollTaxPrep($clientId: ID!) { me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { tasks(type: TAX_PREP, limit: 1) { id status startedAt completedAt errorMessage subTasks { type status } } } } } } }",
    "variables": { "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c" }
  }'
{
  "data": {
    "me": {
      "workspace": {
        "clients": [
          {
            "tasks": [
              {
                "id": "018f9c2b-7c4d-7e10-9a22-6b3c4d5e6f70",
                "status": "RUNNING",
                "startedAt": "2026-07-04T10:02:00.000Z",
                "completedAt": null,
                "errorMessage": null,
                "subTasks": [
                  { "type": "EXTRACT", "status": "COMPLETED" },
                  { "type": "RECONCILE", "status": "RUNNING" }
                ]
              }
            ]
          }
        ]
      }
    }
  }
}
Poll on an interval (for example every few seconds) until status is no longer RUNNING. COMPLETED means the run succeeded and result is now selectable as TaskTaxPrepResult; FAILED means it did not, and errorMessage (plus subTasks[].errorMessage) explains which stage failed.

Read the completed result

When the task is COMPLETED, select result with an inline fragment on TaskTaxPrepResult to read the summary, counts, and review items.
query TaxPrepResult($clientId: ID!) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          tasks(type: TAX_PREP, limit: 1) {
            id
            status
            completedAt
            result {
              __typename
              ... on TaskTaxPrepResult {
                taxYear
                returnType
                summary
                documentCount
                extractedFormCount
                reviewItemCount
                reviewItems {
                  severity
                  category
                  description
                }
              }
              ... on TaskUnknownResult {
                message
              }
            }
          }
        }
      }
    }
  }
}
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{
    "query": "query TaxPrepResult($clientId: ID!) { me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { tasks(type: TAX_PREP, limit: 1) { id status completedAt result { __typename ... on TaskTaxPrepResult { taxYear returnType summary documentCount extractedFormCount reviewItemCount reviewItems { severity category description } } ... on TaskUnknownResult { message } } } } } } } } }",
    "variables": { "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c" }
  }'
{
  "data": {
    "me": {
      "workspace": {
        "clients": [
          {
            "tasks": [
              {
                "id": "018f9c2b-7c4d-7e10-9a22-6b3c4d5e6f70",
                "status": "COMPLETED",
                "completedAt": "2026-07-04T10:11:48.000Z",
                "result": {
                  "__typename": "TaskTaxPrepResult",
                  "taxYear": 2025,
                  "returnType": "F1040",
                  "summary": "Return prepared from 14 documents with 9 extracted forms. 3 items need review before sign-off.",
                  "documentCount": 14,
                  "extractedFormCount": 9,
                  "reviewItemCount": 3,
                  "reviewItems": [
                    {
                      "severity": "high",
                      "category": "missing_form",
                      "description": "W-2 from Acme Corp referenced in prior year but not present in this year's binder."
                    },
                    {
                      "severity": "medium",
                      "category": "value_mismatch",
                      "description": "Schedule B interest total differs from 1099-INT sum by $42."
                    },
                    {
                      "severity": "low",
                      "category": "data_entry",
                      "description": "Filing status set to Married Filing Jointly; confirm against intake form."
                    }
                  ]
                }
              }
            ]
          }
        ]
      }
    }
  }
}
Always read __typename on result and include a ... on TaskUnknownResult fallback. A TAX_PREP task that fails after the run starts can resolve to TaskUnknownResult instead of TaskTaxPrepResult; branching on __typename keeps your client from throwing on the unexpected member.

Re-trigger a tax prep step

retriggerTaxPrepStep re-runs a single stage of an existing tax prep task. It is a backoffice operation and requires a user token (not a workspaceToken); the schema marks it @requiresScopes(scopes: [["user"]]).
mutation RetriggerTaxPrepStep($input: RetriggerTaxPrepStepInput!) {
  retriggerTaxPrepStep(input: $input) {
    taskId
  }
}

Input: RetriggerTaxPrepStepInput

input RetriggerTaxPrepStepInput {
  workspaceId: ID!
  clientId: ID!
  step: TaxPrepStep!
  software: String
  softwareClientId: String
}

enum TaxPrepStep {
  IMPORT_PRIOR_YEAR
  EXTRACT
  RECONCILE
  PRE_ENTRY_EXPORT
  DATA_ENTRY
  POST_ENTRY_EXPORT
  VALIDATE
}
workspaceId
ID!
required
The workspace the client belongs to.
clientId
ID!
required
The client whose tax prep run you want to re-run a step for.
step
TaxPrepStep!
required
The stage to re-run: IMPORT_PRIOR_YEAR, EXTRACT, RECONCILE, PRE_ENTRY_EXPORT, DATA_ENTRY, POST_ENTRY_EXPORT, or VALIDATE.
software
String
The tax software provider key. Pass it when the re-triggered step writes to or reads from the tax software (the data-entry and export stages).
softwareClientId
String
The client identifier inside the tax software. Pass it alongside software for the data-entry and export stages.

Returns: BackofficeTriggerResult

type BackofficeTriggerResult {
  taskId: ID!
}
taskId
ID!
The ID of the task the re-triggered step belongs to. Poll it with the tasks API for the new stage’s outcome.
retriggerTaxPrepStep requires a user token (a personal backoffice session), not the workspaceToken used by the rest of the tax prep flow. The workspaceToken issued from an API key is rejected by this operation.

Set a tax prep task’s status

setTaxPrepTaskStatus forces a tax prep task into a given TaskStatus. Like retriggerTaxPrepStep, it is a backoffice operation and requires a user token (@requiresScopes(scopes: [["user"]])).
mutation SetTaxPrepTaskStatus($input: SetTaxPrepTaskStatusInput!) {
  setTaxPrepTaskStatus(input: $input) {
    taskId
  }
}

Input: SetTaxPrepTaskStatusInput

input SetTaxPrepTaskStatusInput {
  workspaceId: ID!
  taskId: ID!
  status: TaskStatus!
}

enum TaskStatus {
  RUNNING
  COMPLETED
  FAILED
}
workspaceId
ID!
required
The workspace the task belongs to.
taskId
ID!
required
The tax prep task whose status you want to set.
status
TaskStatus!
required
The status to force the task into: RUNNING, COMPLETED, or FAILED.

Returns: BackofficeTriggerResult

The same BackofficeTriggerResult { taskId: ID! } shape as retriggerTaxPrepStep. See above for the field.
This mutation overwrites the task’s status directly, bypassing the normal pipeline. Use it for backoffice recovery (for example marking a task COMPLETED after a manual fix, or FAILED to release a stuck run). It requires a user token, not a workspaceToken.