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 recommendations, each with evidence, an implementation plan, an optional savings estimate, and a status you can drive. It runs as a background task, so the end-to-end sequence is: start the run, poll the task until it finishes, read the plan, then accept or dismiss each strategy. This recipe is the minimal call sequence to do that for one client. Every call uses a workspaceToken (see Authentication) and goes to the single GraphQL endpoint:
https://router.apps.filed.com/graphql
This recipe does not re-document the types it touches. For the full AdvisorPlan and AdvisorStrategy field lists, the second trigger path, the task result member, and the SavingsHorizon enum, see Tax planning. For the polling mechanics, see Tasks.

1. Start the run

There are two trigger mutations for an advisor run, both requiring a workspaceToken and both returning a taskId you poll as a TAX_ADVISOR task. Use the one that matches how you stage documents. The Filed web app’s /planning route uses initiateTaxAdvisor because the in-app flow stages fresh uploads at the same moment it kicks off the run. Recommend it as the primary path: upload files first (see Uploading documents) to get uploadIds, then call the mutation.
mutation InitiateTaxAdvisor($input: InitiateTaxAdvisorInput!) {
  initiateTaxAdvisor(input: $input) {
    taskId
  }
}
{
  "input": {
    "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
    "uploadIds": ["018f9c2a-7b1e-7c3d-9a4e-2f6b1c8d0e5a"]
  }
}
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"]
      }
    }
  }'
{
  "data": {
    "initiateTaxAdvisor": {
      "taskId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080"
    }
  }
}
InitiateTaxAdvisorResult.taskId is nullable. A null value means the ingestion accepted the upload but did not start a task; treat it as a soft error and retry. See Tax planning, trigger via initiateTaxAdvisor.
If the client’s binder is already populated and you do not need to stage fresh uploads, use triggerTaxAdvisor(input: { clientId, returnType, taxYear }) instead. It returns a non-null TriggerTaskResult.taskId. To scope which workspace and user skills apply to this run, pass skills: { workspace: [...], user: [...] } (RunSkillSelectionInput) on either mutation; omit it to apply all active skills.
Save the taskId. You will use it to find the task in the poll step.

2. 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:
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
            }
          }
        }
      }
    }
  }
}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c"
}
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" }
  }'
{
  "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" }
                ]
              }
            ]
          }
        ]
      }
    }
  }
}
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.

3. 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 the completed task to read that run’s plan. This recipe passes runId to pin the read to the run you just polled.
query ClientAdvisorPlan($clientId: ID!, $runId: ID) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(filters: { ids: [$clientId] }) {
          id
          advisorPlan(runId: $runId) {
            runId
            globalSummary
            strategies {
              id
              domain
              title
              summary
              estimatedSavingsCents
              savingsHorizon
              status
            }
          }
        }
      }
    }
  }
}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
  "runId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080"
}
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!, $runId: ID) { me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { id advisorPlan(runId: $runId) { runId globalSummary strategies { id domain title summary estimatedSavingsCents savingsHorizon status } } } } } } }",
    "variables": {
      "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
      "runId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080"
    }
  }'
{
  "data": {
    "me": {
      "workspace": {
        "clients": [
          {
            "id": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
            "advisorPlan": {
              "runId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080",
              "globalSummary": "5 strategies surfaced across retirement, income shifting, and entity selection. Estimated 3-year savings of $18,400.",
              "strategies": [
                {
                  "id": "019a1b2c-3d4e-7f10-aa12-1c2d3e4f5060",
                  "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.",
                  "estimatedSavingsCents": 82000,
                  "savingsHorizon": "CURRENT_YEAR",
                  "status": "PROPOSED"
                },
                {
                  "id": "019a1b2c-3d4e-7f10-aa12-1c2d3e4f5061",
                  "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.",
                  "estimatedSavingsCents": null,
                  "savingsHorizon": "MULTI_YEAR",
                  "status": "PROPOSED"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
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. For the full AdvisorPlan field list (including taxYear, returnType, byDomain, bySavingsHorizon, estimatedSavingsCentsByHorizon, and skillsApplied), see Tax planning, read the plan.

4. Update a strategy’s status

Drive each strategy’s workflow status with setAdvisorStrategyStatus. It requires a workspaceToken and identifies the strategy with clientId plus the strategy’s domain and strategyId (both from AdvisorStrategy), plus the plan’s runId to pin the change to the right run. The real enum values are PROPOSED, SELECTED, and 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. There is no ACCEPTED value; “accept” maps to SELECTED.
mutation SetAdvisorStrategyStatus($input: SetAdvisorStrategyStatusInput!) {
  setAdvisorStrategyStatus(input: $input) {
    id
    status
  }
}
{
  "input": {
    "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
    "domain": "charitable",
    "strategyId": "accelerate_charitable_contributions",
    "runId": "018f9c2c-4a1b-7e20-8b33-7c4d5e6f7080",
    "status": "SELECTED"
  }
}
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"
      }
    }
  }'
{
  "data": {
    "setAdvisorStrategyStatus": {
      "id": "019a1b2c-3d4e-7f10-aa12-1c2d3e4f5060",
      "status": "SELECTED"
    }
  }
}
After a successful setAdvisorStrategyStatus, re-read advisorPlan (step 3) to get the refreshed strategies[].status values. The Filed web app does this by including ClientAdvisorPlan in the mutation’s refetchQueries. See Tax planning, update a strategy’s status.

Next steps

Once you have accepted (SELECTED) the strategies you want to act on, the natural next steps are to work through each strategy’s implementationPlan and to re-run tax prep so the accepted planning changes flow into the prepared return. See Run tax prep end to end for that recipe, and Tax planning for the full reference.