---
title: "Run a book scan now"
method: POST
path: "/api/v1/book-scans"
tags: ["book-scan"]
---

# Run a book scan now

`POST /api/v1/book-scans`

## Request

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

Sweeps the org's active households on the job queue under the saved schedule's configuration, or under `config` when sent. Answers 202 at once; the result lands at the scan's href and is announced with book.scan.completed. Every scanned household counts as active this month.

## Request body

- object
  - `config` BookScanConfig: 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.

## Response `202`

Filed and queued.

- object
  - `ok` unknown, required
  - `scan` StoredBookScan, 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
  - `href` string, required
  - `note` string, required

## Other responses

- `400`: Malformed JSON, a body of the wrong shape, or a top-level field that fails its check.
- `401`: No key presented (Authorization: Bearer wk_… or X-Api-Key).
- `402`: Unrecognized or revoked API key.
- `403`: The key's role is below the operation's floor (viewer < developer < owner), the key predates organization support, or the plan lacks the feature. On a sandbox key, also: the cap of 5 active households on create and import, the cap of 1 active Lodestar mandate, and the white-label surfaces (tenant config, embed tokens) and narration or mapping drafts on Worthune's model (they run on your own: a model assigned at /api/v1/model-policy, or x-model-key), which the sandbox does not carry.
- `422`: Invalid config, or no config sent and none saved.
- `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)
