> ## 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.

# Tax planning

> Start a tax advisor run, poll it to completion, read the plan and its strategies, and update a strategy's status

**Tax planning** (the advisor) reads a client's binder and produces an
`AdvisorPlan`: a global summary plus a list of `AdvisorStrategy` entries, each
one a discrete tax-saving recommendation with evidence, an implementation plan,
an estimated savings range, and a `status` you can drive. It runs as a
background task: you start it with a trigger mutation and follow the resulting
task to completion with the [tasks API](/apis/tasks).

Planning operations are reached through the [`me`](/apis/me) query resolved as a
`WorkspaceUser`, so they all require a **`workspaceToken`** (see
[Authentication](/guides/authentication)). All requests go to:

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

<Note>
  The advisor run is a polled background task. This page documents how to start a
  run, read the resulting plan, and update a strategy's status. For the polling
  pattern itself (listing tasks, reading `status`, and the `TaskResult` union),
  see [Tasks](/apis/tasks); this page does not re-explain it.
</Note>

## The `AdvisorPlan` type

`AdvisorPlan` is the shape returned by the `advisorPlan` field on
[`Client`](/apis/clients#the-client-type). It carries the run identifier, a
global summary, aggregate savings and skills-applied breakdowns, and the
individual strategies.

```graphql theme={null}
type AdvisorPlan {
  runId: ID!
  taxYear: Int
  returnType: String
  strategies: [AdvisorStrategy!]!
  byDomain: JSON!
  bySavingsHorizon: JSON!
  estimatedSavingsCentsByHorizon: JSON!
  globalSummary: String!
  skillsApplied: AppliedSkills!
}

type AppliedSkills {
  workspace: [String!]!
  user: [String!]!
}
```

<ResponseField name="runId" type="ID!">
  The advisor run this plan belongs to. Pass it back to
  `setAdvisorStrategyStatus` when updating a strategy from this plan.
</ResponseField>

<ResponseField name="taxYear" type="Int">
  The tax year the plan was prepared for, for example `2025`. May be `null` when
  the run has not finished populating the plan.
</ResponseField>

<ResponseField name="returnType" type="String">
  The return form as a free-form string (for example `"F1040"`). Note this is a
  `String`, not the `ReturnType` enum used by the trigger inputs.
</ResponseField>

<ResponseField name="strategies" type="[AdvisorStrategy!]!">
  The strategy recommendations. See [`AdvisorStrategy`](#the-advisorstrategy-type)
  for the field shape.
</ResponseField>

<ResponseField name="byDomain" type="JSON!">
  Aggregate counts of strategies grouped by domain (for example `retirement`,
  `income_shifting`). The exact keys depend on which strategies the run produced.
</ResponseField>

<ResponseField name="bySavingsHorizon" type="JSON!">
  Aggregate counts of strategies grouped by savings horizon. Horizon keys match
  the `SavingsHorizon` enum values (`CURRENT_YEAR`, `MULTI_YEAR`, `LIFETIME`,
  `EVENT_DRIVEN`).
</ResponseField>

<ResponseField name="estimatedSavingsCentsByHorizon" type="JSON!">
  Estimated total savings in USD cents, keyed by savings horizon. Treat the values
  as estimates, not guarantees.
</ResponseField>

<ResponseField name="globalSummary" type="String!">
  A human-readable summary of the whole plan, suitable to show at the top of a
  plan view.
</ResponseField>

<ResponseField name="skillsApplied" type="AppliedSkills!">
  Which workspace and user skills were applied to this run. Each field is a list
  of skill names.

  ```graphql theme={null}
  type AppliedSkills {
    workspace: [String!]!
    user: [String!]!
  }
  ```
</ResponseField>

## The `AdvisorStrategy` type

Each entry in `AdvisorPlan.strategies` is an `AdvisorStrategy`: one
recommendation the advisor surfaced from the binder, with the evidence it built
on, a step-by-step implementation plan, an optional savings estimate, and a
`status` you control with
[`setAdvisorStrategyStatus`](#update-a-strategys-status).

```graphql theme={null}
type AdvisorStrategy {
  id: ID!
  strategyId: String!
  domain: String!
  title: String!
  summary: String!
  applicabilityEvidence: String!
  sourceSubdocIds: [String!]!
  implementationPlan: [String!]!
  estimatedSavingsCents: Int
  savingsMethod: String
  savingsHorizon: SavingsHorizon!
  assumptions: String
  status: AdvisorStrategyStatus!
}

enum AdvisorStrategyStatus {
  PROPOSED
  SELECTED
  DISMISSED
}

enum SavingsHorizon {
  CURRENT_YEAR
  MULTI_YEAR
  LIFETIME
  EVENT_DRIVEN
}
```

<ResponseField name="id" type="ID!">
  The strategy's stable row identifier for this plan.
</ResponseField>

<ResponseField name="strategyId" type="String!">
  The logical strategy key shared across runs and clients (for example
  `accelerate_charitable_contributions`). Use this, together with `domain` and
  `runId`, to address a strategy in
  [`setAdvisorStrategyStatus`](#update-a-strategys-status).
</ResponseField>

<ResponseField name="domain" type="String!">
  The strategy's domain (for example `retirement`, `income_shifting`,
  `entity_selection`). Used together with `strategyId` to address a strategy.
</ResponseField>

<ResponseField name="title" type="String!">
  A short, human-readable strategy title.
</ResponseField>

<ResponseField name="summary" type="String!">
  A one-paragraph summary of the strategy and its expected effect.
</ResponseField>

<ResponseField name="applicabilityEvidence" type="String!">
  The evidence from the binder that made the advisor surface this strategy. Quote
  or paraphrase this when explaining a recommendation to a client.
</ResponseField>

<ResponseField name="sourceSubdocIds" type="[String!]!">
  The binder sub-document IDs the evidence was drawn from. Cross-reference these
  with the [clients API](/apis/clients) to surface the source documents.
</ResponseField>

<ResponseField name="implementationPlan" type="[String!]!">
  Ordered, human-readable steps to implement the strategy.
</ResponseField>

<ResponseField name="estimatedSavingsCents" type="Int">
  Optional estimated tax savings in USD cents. `null` when the strategy does not
  produce a direct dollar estimate.
</ResponseField>

<ResponseField name="savingsMethod" type="String">
  How the estimate was computed, when `estimatedSavingsCents` is present.
</ResponseField>

<ResponseField name="savingsHorizon" type="SavingsHorizon!">
  When the savings are expected to land: `CURRENT_YEAR`, `MULTI_YEAR`, `LIFETIME`,
  or `EVENT_DRIVEN`.
</ResponseField>

<ResponseField name="assumptions" type="String">
  Free-text assumptions behind the estimate, when relevant.
</ResponseField>

<ResponseField name="status" type="AdvisorStrategyStatus!">
  The strategy's workflow status: `PROPOSED` (the advisor surfaced it, no action
  taken), `SELECTED` (the firm accepted it), or `DISMISSED` (the firm rejected
  it). Drive it with
  [`setAdvisorStrategyStatus`](#update-a-strategys-status).
</ResponseField>

## Start an advisor run

There are two trigger mutations for an advisor run. Both return a `taskId` you
poll as a `TAX_ADVISOR` task, both require a **`workspaceToken`**, and both
create a task whose result member is `TaskTaxAdvisorResult`. Pick the one that
matches how you stage documents:

* [`triggerTaxAdvisor`](#trigger-via-triggertaxadvisor) (the `ai` subgraph) takes
  the client, return type, and tax year directly. Use it when the documents are
  already in the client's binder.
* [`initiateTaxAdvisor`](#trigger-via-initiatetaxadvisor) (the `platform`
  subgraph) also takes `uploadIds`, ingesting them into the binder in the same
  call. This is the mutation the Filed web app's `/planning` route actually
  uses.

<Note>
  The Filed web app's planning flow (`src/routes/.../planning/`) calls
  `initiateTaxAdvisor`, not `triggerTaxAdvisor`, because the in-app flow stages
  fresh uploads at the same moment it kicks off the run. Both mutations exist
  live and resolve to the same `TAX_ADVISOR` task type; pick the one that matches
  your ingestion path.
</Note>

### Trigger via `triggerTaxAdvisor`

`triggerTaxAdvisor` starts an advisor run for a client whose binder is already
populated. It lives in the `ai` subgraph and requires a **`workspaceToken`**.

```graphql theme={null}
mutation TriggerTaxAdvisor($input: TriggerTaxAdvisorInput!) {
  triggerTaxAdvisor(input: $input) {
    taskId
  }
}
```

#### Input: `TriggerTaxAdvisorInput`

```graphql theme={null}
input TriggerTaxAdvisorInput {
  clientId: ID!
  returnType: ReturnType!
  taxYear: Int!
  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!]
}
```

<ParamField path="clientId" type="ID!" required>
  The client to plan for.
</ParamField>

<ParamField path="returnType" type="ReturnType!" required>
  The return form: `F1040`, `F1041`, `F1065`, `F1120`, `F1120S`, or `F990` (see
  [clients](/apis/clients#the-client-type)).
</ParamField>

<ParamField path="taxYear" type="Int!" required>
  The tax year to plan for, for example `2025`.
</ParamField>

<ParamField path="skills" type="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.
</ParamField>

#### Returns: `TriggerTaskResult`

```graphql theme={null}
type TriggerTaskResult {
  taskId: ID!
}
```

<ResponseField name="taskId" type="ID!">
  The ID of the started `TAX_ADVISOR` [task](/apis/tasks). Poll it until `status`
  is no longer `RUNNING`, then read `advisorPlan` and, optionally, the task's
  `result` as `TaskTaxAdvisorResult`.
</ResponseField>

<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 TriggerTaxAdvisor($input: TriggerTaxAdvisorInput!) { triggerTaxAdvisor(input: $input) { taskId } }",
      "variables": {
        "input": {
          "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
          "returnType": "F1040",
          "taxYear": 2025
        }
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "triggerTaxAdvisor": {
        "taskId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080"
      }
    }
  }
  ```
</ResponseExample>

### Trigger via `initiateTaxAdvisor`

`initiateTaxAdvisor` starts an advisor run and attaches already-staged uploads
to the client's binder in the same call. It lives in the `platform` subgraph
and requires a **`workspaceToken`**. Stage the files first with the [upload
endpoint](/guides/uploading-documents); this is the mutation the Filed web app
uses for the `/planning` route.

```graphql theme={null}
mutation InitiateTaxAdvisor($input: InitiateTaxAdvisorInput!) {
  initiateTaxAdvisor(input: $input) {
    taskId
  }
}
```

#### Input: `InitiateTaxAdvisorInput`

```graphql theme={null}
input InitiateTaxAdvisorInput {
  clientId: ID!
  uploadIds: [String!]!
  skills: RunSkillSelectionInput
}
```

<ParamField path="clientId" type="ID!" required>
  The client to plan for.
</ParamField>

<ParamField path="uploadIds" type="[String!]!" required>
  One or more upload IDs from the [upload endpoint](/guides/uploading-documents).
  The advisor ingests these into the client's binder as part of starting the run.
</ParamField>

<ParamField path="skills" type="RunSkillSelectionInput">
  Optional. Override which workspace and user skills apply to this run. Same
  shape as [`triggerTaxAdvisor`](#trigger-via-triggertaxadvisor).
</ParamField>

#### Returns: `InitiateTaxAdvisorResult`

```graphql theme={null}
type InitiateTaxAdvisorResult {
  taskId: ID
}
```

<ResponseField name="taskId" type="ID">
  The ID of the started `TAX_ADVISOR` [task](/apis/tasks). Poll it until `status`
  is no longer `RUNNING`, then read `advisorPlan`. `null` when the ingestion
  accepted the upload but did not start a task; treat that as a soft error and
  retry.
</ResponseField>

<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 InitiateTaxAdvisor($input: InitiateTaxAdvisorInput!) { initiateTaxAdvisor(input: $input) { taskId } }",
      "variables": {
        "input": {
          "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
          "uploadIds": ["018f9c2a-7b1e-7c3d-9a4e-2f6b1c8d0e5a"]
        }
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "initiateTaxAdvisor": {
        "taskId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080"
      }
    }
  }
  ```
</ResponseExample>

## Poll the task to completion

There is no `task(id:)` query. Poll the task you just started by listing the
client's `TAX_ADVISOR` 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 PollTaxAdvisor($clientId: ID!) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          tasks(type: TAX_ADVISOR, limit: 1) {
            id
            status
            startedAt
            completedAt
            errorMessage
            subTasks {
              type
              status
            }
          }
        }
      }
    }
  }
}
```

<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 PollTaxAdvisor($clientId: ID!) { me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { tasks(type: TAX_ADVISOR, 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": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080",
                  "status": "RUNNING",
                  "startedAt": "2026-07-04T11:02:00.000Z",
                  "completedAt": null,
                  "errorMessage": null,
                  "subTasks": [
                    { "type": "BUILD_ADVISOR_MANIFEST", "status": "COMPLETED" },
                    { "type": "RUN_ADVISOR_AGENT", "status": "RUNNING" }
                  ]
                }
              ]
            }
          ]
        }
      }
    }
  }
  ```
</ResponseExample>

<Tip>
  Poll on an interval (for example every few seconds) until `status` is no longer
  `RUNNING`. `COMPLETED` means the run succeeded and `advisorPlan` is now
  readable; `FAILED` means it did not, and `errorMessage` (plus
  `subTasks[].errorMessage`) explains which stage failed. Typical advisor
  sub-task types are `BUILD_ADVISOR_MANIFEST`, `RUN_ADVISOR_AGENT`,
  `LOCATE_ADVISOR_REFERENCES`, and `EXPORT_ADVISOR`.
</Tip>

## Read the plan

Read the plan through `Client.advisorPlan`. There is no top-level `advisorPlan`
query; reach it through `me { ... on WorkspaceUser { workspace { clients(...) {
advisorPlan } } } }` (see [clients](/apis/clients)). Call it without a `runId`
to read the client's current plan, or pass the `runId` from a specific task to
read that run's plan.

```graphql theme={null}
query ClientAdvisorPlan($clientId: ID!, $runId: ID) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          id
          advisorPlan(runId: $runId) {
            runId
            taxYear
            returnType
            globalSummary
            estimatedSavingsCentsByHorizon
            skillsApplied {
              workspace
              user
            }
            strategies {
              id
              strategyId
              domain
              title
              summary
              applicabilityEvidence
              sourceSubdocIds
              implementationPlan
              estimatedSavingsCents
              savingsMethod
              savingsHorizon
              assumptions
              status
            }
          }
        }
      }
    }
  }
}
```

<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 ClientAdvisorPlan($clientId: ID!) { me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { id advisorPlan { runId taxYear returnType globalSummary estimatedSavingsCentsByHorizon skillsApplied { workspace user } strategies { id strategyId domain title summary applicabilityEvidence sourceSubdocIds implementationPlan estimatedSavingsCents savingsMethod savingsHorizon assumptions status } } } } } } }",
      "variables": { "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c" }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "me": {
        "workspace": {
          "clients": [
            {
              "id": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
              "advisorPlan": {
                "runId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080",
                "taxYear": 2025,
                "returnType": "F1040",
                "globalSummary": "5 strategies surfaced across retirement, income shifting, and entity selection. Estimated 3-year savings of $18,400.",
                "estimatedSavingsCentsByHorizon": {
                  "CURRENT_YEAR": 420000,
                  "MULTI_YEAR": 1840000,
                  "LIFETIME": 0,
                  "EVENT_DRIVEN": 0
                },
                "skillsApplied": {
                  "workspace": ["advisor_evidence_qa"],
                  "user": []
                },
                "strategies": [
                  {
                    "id": "019a1b2c-3d4e-7f10-aa12-1c2d3e4f5060",
                    "strategyId": "accelerate_charitable_contributions",
                    "domain": "charitable",
                    "title": "Bunch charitable contributions into 2025",
                    "summary": "Combine two years of charitable giving into 2025 to exceed the standard deduction and itemize this year.",
                    "applicabilityEvidence": "Client has donated $4,200 and $4,800 in each of the last two years per binder sub-doc sd_8842 and sd_8843.",
                    "sourceSubdocIds": ["sd_8842", "sd_8843"],
                    "implementationPlan": [
                      "Confirm intended 2025 and 2026 giving totals with the client.",
                      "Move 2026 contributions into December 2025.",
                      "Rebuild the itemized deduction worksheet."
                    ],
                    "estimatedSavingsCents": 82000,
                    "savingsMethod": "marginal_rate_x_deduction_delta",
                    "savingsHorizon": "CURRENT_YEAR",
                    "assumptions": "Marginal rate stays at 24%; no further AGI-limit changes.",
                    "status": "PROPOSED"
                  },
                  {
                    "id": "019a1b2c-3d4e-7f10-aa12-1c2d3e4f5061",
                    "strategyId": "roth_conversion_window",
                    "domain": "retirement",
                    "title": "Roth convert up to the 24% bracket cap",
                    "summary": "Convert traditional IRA funds to Roth up to the top of the 24% bracket this year.",
                    "applicabilityEvidence": "Client has $120,000 in traditional IRA assets and taxable income is temporarily lower this year per sd_7101.",
                    "sourceSubdocIds": ["sd_7101"],
                    "implementationPlan": [
                      "Model the bracket headroom for the current year.",
                      "Convert up to the cap.",
                      "Withhold or pay estimated tax on the conversion."
                    ],
                    "estimatedSavingsCents": null,
                    "savingsMethod": null,
                    "savingsHorizon": "MULTI_YEAR",
                    "assumptions": "Future marginal rate is 32% or higher.",
                    "status": "PROPOSED"
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }
  ```
</ResponseExample>

<Note>
  `advisorPlan` returns `null` while the run is still `RUNNING`, or when the
  client has no advisor run yet. Treat `null` as "no plan to show", and keep
  polling the task until `status` is `COMPLETED` before re-reading.
</Note>

## Update a strategy's status

`setAdvisorStrategyStatus` moves a strategy between `PROPOSED`, `SELECTED`, and
`DISMISSED`. It lives in the `ai` subgraph and requires a
**`workspaceToken`**. Identify the strategy with `clientId` plus the strategy's
`domain` and `strategyId` (both from `AdvisorStrategy`), and pass the plan's
`runId` so the status change is recorded against the right run.

```graphql theme={null}
mutation SetAdvisorStrategyStatus($input: SetAdvisorStrategyStatusInput!) {
  setAdvisorStrategyStatus(input: $input) {
    id
    status
  }
}
```

### Input: `SetAdvisorStrategyStatusInput`

```graphql theme={null}
input SetAdvisorStrategyStatusInput {
  clientId: ID!
  domain: String!
  strategyId: String!
  status: AdvisorStrategyStatus!
  runId: ID
}

enum AdvisorStrategyStatus {
  PROPOSED
  SELECTED
  DISMISSED
}
```

<ParamField path="clientId" type="ID!" required>
  The client the plan belongs to.
</ParamField>

<ParamField path="domain" type="String!" required>
  The strategy's `domain` (from `AdvisorStrategy.domain`).
</ParamField>

<ParamField path="strategyId" type="String!" required>
  The strategy's logical key (from `AdvisorStrategy.strategyId`), not the row
  `id`.
</ParamField>

<ParamField path="status" type="AdvisorStrategyStatus!" required>
  The new status: `PROPOSED`, `SELECTED`, or `DISMISSED`. Use `SELECTED` for
  strategies the firm accepts, `DISMISSED` for those it rejects, and `PROPOSED`
  to revert either back to the advisor's original state.
</ParamField>

<ParamField path="runId" type="ID">
  The plan's `runId` (from `AdvisorPlan.runId`). Optional in the schema but
  recommended: it pins the status change to a specific run, which matters when a
  client has more than one advisor run on file.
</ParamField>

### Returns: `AdvisorStrategy`

The mutation returns the updated `AdvisorStrategy`, typically just `id` and
`status`. The full type is documented
[above](#the-advisorstrategy-type).

<ResponseField name="id" type="ID!">
  The strategy row identifier that was updated.
</ResponseField>

<ResponseField name="status" type="AdvisorStrategyStatus!">
  The strategy's new status.
</ResponseField>

<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 SetAdvisorStrategyStatus($input: SetAdvisorStrategyStatusInput!) { setAdvisorStrategyStatus(input: $input) { id status } }",
      "variables": {
        "input": {
          "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
          "domain": "charitable",
          "strategyId": "accelerate_charitable_contributions",
          "runId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080",
          "status": "SELECTED"
        }
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "setAdvisorStrategyStatus": {
        "id": "019a1b2c-3d4e-7f10-aa12-1c2d3e4f5060",
        "status": "SELECTED"
      }
    }
  }
  ```
</ResponseExample>

<Tip>
  After a successful `setAdvisorStrategyStatus`, re-read
  [`advisorPlan`](#read-the-plan) to get the refreshed `strategies[].status`
  values. The Filed web app does this by including `ClientAdvisorPlan` in the
  mutation's `refetchQueries`.
</Tip>

## Task result member: `TaskTaxAdvisorResult`

When a `TAX_ADVISOR` task reaches `status: COMPLETED`, its `result` field
resolves to `TaskTaxAdvisorResult`. This is the same data the
[`advisorPlan`](#read-the-plan) field exposes as `AdvisorPlan`, just delivered
through the task poll. Most callers prefer `advisorPlan` for its richer
`strategies` list; `TaskTaxAdvisorResult` is useful when you are already
polling the task and want the high-level summary in the same response.

```graphql theme={null}
type TaskTaxAdvisorResult {
  taxYear: Int!
  returnType: ReturnType!
  summary: String!
  strategyTotal: Int!
  byDomain: JSON!
  bySavingsHorizon: JSON!
  estimatedSavingsCentsByHorizon: JSON!
}
```

Select it with an inline fragment on the task's `result`, alongside the
`TaskUnknownResult` fallback:

```graphql theme={null}
query TaxAdvisorResult($clientId: ID!) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          tasks(type: TAX_ADVISOR, limit: 1) {
            id
            status
            completedAt
            result {
              __typename
              ... on TaskTaxAdvisorResult {
                taxYear
                returnType
                summary
                strategyTotal
                byDomain
                bySavingsHorizon
                estimatedSavingsCentsByHorizon
              }
              ... on TaskUnknownResult {
                message
              }
            }
          }
        }
      }
    }
  }
}
```

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