---
title: "One stored book scan, with its full result"
method: GET
path: "/api/v1/book-scans/{id}"
tags: ["book-scan"]
---

# One stored book scan, with its full result

`GET /api/v1/book-scans/{id}`

## Request

- Base URL: `https://worthune.com`
- URL: `https://worthune.com/api/v1/book-scans/{id}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-Api-Key`

## Response `200`

The scan; `result` is null until it completes.

- object
  - `ok` unknown, required
  - `scan` object, required
    - `id` integer, required
    - `trigger` 'schedule' | 'manual', required
    - `runDate` string, nullable, required: UTC date of a scheduled scan; null for manual ones.
    - `status` 'queued' | 'running' | 'completed' | 'failed', required
    - `config` BookScanConfig, required: A stored sweep configuration. Unknown keys are rejected.
      - `profile` object: A pinned assumption profile (yours or the built-in illustration). Exactly one of profile and assumptions.
        - `id` string, required
        - `version` string, required
      - `assumptions` ProjectionAssumptions: Unknown keys are rejected — the accepted set is exactly: annualReturn, inflationRate, defaultIncomeGrowth, socialSecurityCola, returnsByWrapper.
        - `annualReturn` number, required: Nominal annual return applied to every account balance (one blended rate).
        - `inflationRate` number, required: Annual inflation applied to inflation-adjusted expense streams.
        - `defaultIncomeGrowth` number, required: Growth for income streams that carry no growthRate of their own.
        - `socialSecurityCola` number: COLA applied to COMPUTED social_security benefits from each benefit's start year. Defaults to inflationRate; pass 0 for a flat benefit.
        - `returnsByWrapper` object: Per-wrapper returns; unlisted wrappers keep the blended annualReturn.
          - `taxable` number: Return for taxable accounts, replacing annualReturn (and any sampled path) for that wrapper.
          - `traditional` number: Return for traditional accounts, replacing annualReturn (and any sampled path) for that wrapper.
          - `roth` number: Return for roth accounts, replacing annualReturn (and any sampled path) for that wrapper.
          - `hsa` number: Return for hsa accounts, replacing annualReturn (and any sampled path) for that wrapper.
          - `plan529` number: Return for plan529 accounts, replacing annualReturn (and any sampled path) for that wrapper.
          - `cash` number: Return for cash accounts, replacing annualReturn (and any sampled path) for that wrapper.
          - `annuity` number: Return for annuity accounts, replacing annualReturn (and any sampled path) for that wrapper.
      - `horizonYears` integer, required: Projection length; the start year is the UTC year of each run.
      - `strategies` string[]: Default: withdrawal-sequencing and ss-claiming, plus the strategies whose parameters you supply.
      - `taxRates` object
        - `marginalOrdinary` number, required
        - `qualifiedAndLtcg` number, required
      - `illustrativeCharacteristics` boolean
      - `ladderCandidates` object[]
        - `annualAmountUsd` number, required
        - `years` integer, required
      - `bracketFill` object: bracket-fill: rates to fill (default 12, 22, 24) and years to convert (default 10).
        - `fillToRatesPct` number[]
        - `years` integer
      - `charitableGiving` object: charitable-giving: the household's cash gifts each year (required for the strategy to run), other itemized deductions (default 0), the bunching cycle (default 2) and the IRA distributions a QCD can replace (default the first year's RMD).
        - `annualGivingUsd` number, required
        - `otherItemizedDeductionsUsd` number
        - `bunchYears` integer
        - `iraDistributionsUsd` number
      - `minOpportunityUsd` number: Queue floor (default $100).
      - `maxHouseholds` integer: Default 200; households beyond it are counted, never silently dropped.
    - `assumptionsSource` string, nullable, required
    - `specVersion` string, nullable, required
    - `summary` BookScanSummary, required
      - `householdsScanned` integer, required
      - `householdsTruncated` integer, required
      - `opportunities` integer, required
      - `opportunityUsd` number, required: Sum of queue entries — a triage total, not a forecast.
      - `topOpportunityUsd` number, required
      - `improvesRuin` integer, required
      - `skipped` integer, required
    - `error` string, nullable, required
    - `createdAt` string, date-time, required
    - `startedAt` string, date-time, nullable, required
    - `completedAt` string, date-time, nullable, required
    - `result` BookScanResult, required
      - `queue` BookScanOpportunity[], required: Ranked by opportunityUsd, desc.
        - `householdId` integer, required: On the keyless route: the 1-based position in the submitted households array.
        - `label` string, nullable
        - `advisorRef` string, nullable
        - `strategy` string, required
        - `alternativeId` string, required
        - `alternativeLabel` string, required
        - `opportunityUsd` number, required: Top alternative's endingNetWorthDelta vs its own baseline — a triage estimate.
        - `improvesRuin` boolean, required
        - `recordSha256` string, required
      - `advisorRollups` object[], required
        - `advisorRef` string, nullable, required
        - `households` integer, required
        - `opportunities` integer, required
        - `opportunityUsd` number, required
        - `topOpportunityUsd` number, required
        - `improvesRuin` integer, required
      - `skipped` object[], required
        - `householdId` integer, required
        - `strategy` string, required
        - `reason` string, required
      - `householdsScanned` integer, required
      - `householdsTruncated` integer, required: Households beyond the cap that were NOT scanned — never silent.
      - `strategiesRun` string[], required
      - `notes` string[], required

## Other responses

- `401`: No key presented (Authorization: Bearer wk_… or X-Api-Key).
- `402`: Unrecognized or revoked API key.
- `403`: The key predates organization support (contact support for a free rotation).
- `404`: No scan with this id in the key's organization.
- `429`: Hourly per-org stateful quota, a per-route durable limit, or the 120 requests/minute per-IP burst backstop.
- `503`: Billing is not configured on this deployment; household resources are disabled rather than served without tenancy (production fail-closed).

---

[API](https://skmtc.dev/worthune/apis/worthune-api.md) · [All operations](https://skmtc.dev/worthune/apis/worthune-api/llms.txt) · [OpenAPI document](https://skmtc.dev/worthune/apis/worthune-api/revisions/9f2241072555?raw)
