> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apps.filed.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Run tax prep end to end

> Start a tax prep run for a client, poll it to completion, and read the review items it produces

Tax prep extracts forms from a client's binder, reconciles them, optionally
enters them into tax software, and produces a list of review items. It runs as a
background task, so the end-to-end sequence is: start the run, poll the task
until it finishes, then read the result. This recipe is the minimal call
sequence to do that for one client.

Every call uses a **`workspaceToken`** (see [Authentication](/guides/authentication))
and goes to the single GraphQL endpoint:

```
https://router.apps.filed.com/graphql
```

```mermaid theme={null}
flowchart LR
  A["Client with<br/>ingested binder"] -->|"triggerTaxPrep"| B["TAX_PREP task"]
  B -->|"poll tasks(type: TAX_PREP)"| C{"status"}
  C -->|RUNNING| B
  C -->|COMPLETED| D["TaskTaxPrepResult"]
  D -->|reviewItemCount| E["Quick check"]
  D -->|reviewItems| F["Per-item detail"]
  F -->|"next"| G["Review and sign off"]
```

This recipe does not re-document the types it touches. For the full input
shape, the backoffice re-trigger/status operations, and the complete
`TaskTaxPrepResult` field list, see [Tax prep](/apis/tax-prep). For the polling
mechanics, see [Tasks](/apis/tasks).

## 1. Start the run

Start a tax prep run with
[`triggerTaxPrep`](/apis/tax-prep#start-a-tax-prep-run). The only required
fields are the client's `clientId` and the `returnType` you want to prepare (it
must match the client's `returnType`, see
[Clients](/apis/clients#the-client-type)). The mutation returns a `taskId` you
poll in the next step.

```graphql theme={null}
mutation TriggerTaxPrep($input: TriggerTaxPrepInput!) {
  triggerTaxPrep(input: $input) {
    taskId
  }
}
```

```json theme={null}
{
  "input": {
    "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
    "returnType": "F1040"
  }
}
```

<RequestExample>
  ```bash cURL theme={null}
  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"
        }
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "triggerTaxPrep": {
        "taskId": "018f9c2b-7c4d-7e10-9a22-6b3c4d5e6f70"
      }
    }
  }
  ```
</ResponseExample>

Save the `taskId`. You will use it to find the task in the poll step.

<Tip>
  To scope which workspace and user skills apply to this run, pass
  `skills: { workspace: [...], user: [...] }` (`RunSkillSelectionInput`). Omit it
  to apply all active skills. See [Tax prep, start a run](/apis/tax-prep#start-a-tax-prep-run)
  for the full input.
</Tip>

## 2. 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](/apis/tasks#check-a-single-tasks-status); the short version:

```graphql theme={null}
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
            }
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c"
}
```

<RequestExample>
  ```bash cURL theme={null}
  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" }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "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" }
                  ]
                }
              ]
            }
          ]
        }
      }
    }
  }
  ```
</ResponseExample>

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.

## 3. 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. 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`, and branching on
`__typename` keeps your client from throwing on the unexpected member.

```graphql theme={null}
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
              }
            }
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c"
}
```

<RequestExample>
  ```bash cURL theme={null}
  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" }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "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."
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    }
  }
  ```
</ResponseExample>

## 4. Use the review items

Two reads cover most needs:

* **Quick check**: read `reviewItemCount` for a single "how much needs attention"
  number before paging through the items.
* **Per-item detail**: read `reviewItems`, each with `severity`, `category`, and
  `description`. `severity` is a free-form `String!` (not an enum), so sort and
  group it in your client as you see fit.

<Note>
  `TaskTaxPrepResult` is one member of the `TaskResult` union. The other tax
  members are `TaskTaxReviewResult` (returned for `TAX_REVIEW` tasks) and
  `TaskTaxAdvisorResult` (returned for `TAX_ADVISOR` tasks). See
  [Tasks, task result](/apis/tasks#task-result) for the full union and the
  inline-fragment pattern used to select it.
</Note>

## Next steps

Once review items exist, the natural next step is to work through them and
record sign-offs on the sheets and rows that produced each item. See
[Review and sign off](/guides/recipes/review-and-sign-off) for that recipe.
