Skip to main content
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. Planning operations are reached through the me query resolved as a WorkspaceUser, so they all require a workspaceToken (see Authentication). All requests go to:
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; this page does not re-explain it.

The AdvisorPlan type

AdvisorPlan is the shape returned by the advisorPlan field on Client. It carries the run identifier, a global summary, aggregate savings and skills-applied breakdowns, and the individual strategies.
ID!
The advisor run this plan belongs to. Pass it back to setAdvisorStrategyStatus when updating a strategy from this plan.
Int
The tax year the plan was prepared for, for example 2025. May be null when the run has not finished populating the plan.
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.
[AdvisorStrategy!]!
The strategy recommendations. See AdvisorStrategy for the field shape.
JSON!
Aggregate counts of strategies grouped by domain (for example retirement, income_shifting). The exact keys depend on which strategies the run produced.
JSON!
Aggregate counts of strategies grouped by savings horizon. Horizon keys match the SavingsHorizon enum values (CURRENT_YEAR, MULTI_YEAR, LIFETIME, EVENT_DRIVEN).
JSON!
Estimated total savings in USD cents, keyed by savings horizon. Treat the values as estimates, not guarantees.
String!
A human-readable summary of the whole plan, suitable to show at the top of a plan view.
AppliedSkills!
Which workspace and user skills were applied to this run. Each field is a list of skill names.

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.
ID!
The strategy’s stable row identifier for this plan.
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.
String!
The strategy’s domain (for example retirement, income_shifting, entity_selection). Used together with strategyId to address a strategy.
String!
A short, human-readable strategy title.
String!
A one-paragraph summary of the strategy and its expected effect.
String!
The evidence from the binder that made the advisor surface this strategy. Quote or paraphrase this when explaining a recommendation to a client.
[String!]!
The binder sub-document IDs the evidence was drawn from. Cross-reference these with the clients API to surface the source documents.
[String!]!
Ordered, human-readable steps to implement the strategy.
Int
Optional estimated tax savings in USD cents. null when the strategy does not produce a direct dollar estimate.
String
How the estimate was computed, when estimatedSavingsCents is present.
SavingsHorizon!
When the savings are expected to land: CURRENT_YEAR, MULTI_YEAR, LIFETIME, or EVENT_DRIVEN.
String
Free-text assumptions behind the estimate, when relevant.
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.

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

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.

Input: TriggerTaxAdvisorInput

ID!
required
The client to plan for.
ReturnType!
required
The return form: F1040, F1041, F1065, F1120, F1120S, or F990 (see clients).
Int!
required
The tax year to plan for, for example 2025.
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

ID!
The ID of the started TAX_ADVISOR task. Poll it until status is no longer RUNNING, then read advisorPlan and, optionally, the task’s result as TaskTaxAdvisorResult.

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; this is the mutation the Filed web app uses for the /planning route.

Input: InitiateTaxAdvisorInput

ID!
required
The client to plan for.
[String!]!
required
One or more upload IDs from the upload endpoint. The advisor ingests these into the client’s binder as part of starting the run.
RunSkillSelectionInput
Optional. Override which workspace and user skills apply to this run. Same shape as triggerTaxAdvisor.

Returns: InitiateTaxAdvisorResult

ID
The ID of the started TAX_ADVISOR task. 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.

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; the short version:
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.

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

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.

Input: SetAdvisorStrategyStatusInput

ID!
required
The client the plan belongs to.
String!
required
The strategy’s domain (from AdvisorStrategy.domain).
String!
required
The strategy’s logical key (from AdvisorStrategy.strategyId), not the row id.
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.
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.

Returns: AdvisorStrategy

The mutation returns the updated AdvisorStrategy, typically just id and status. The full type is documented above.
ID!
The strategy row identifier that was updated.
AdvisorStrategyStatus!
The strategy’s new status.
After a successful setAdvisorStrategyStatus, re-read advisorPlan to get the refreshed strategies[].status values. The Filed web app does this by including ClientAdvisorPlan in the mutation’s refetchQueries.

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 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.
Select it with an inline fragment on the task’s result, alongside the TaskUnknownResult fallback:
TaskTaxAdvisorResult is one member of the TaskResult union. The other tax members are TaskTaxPrepResult (returned for TAX_PREP tasks, see tax prep) and TaskTaxReviewResult (returned for TAX_REVIEW tasks). See Tasks, task result for the full union and the inline-fragment pattern used to select it.