---
title: "Assign a mandate to a household"
method: POST
path: "/api/v1/mandates"
tags: ["lodestar"]
---

# Assign a mandate to a household

`POST /api/v1/mandates`

## Request

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

A standing assignment: an objective, pinned constraints (a profile { id, version } or literal assumptions, never an implicit default) and an approval policy. Lodestar works it when a deadline approaches, the household changes, rules or your assumption profile change, a scheduled review comes due, or on request, and files proposals for an approver. One mandate per type per household until it ends. Each cycle's sweep counts the household as active for the month.

## Request body

- object
  - `householdId` integer: Required for household types; omitted for rules-change.
  - `type` 'strategy-watch' | 'tax-optimization' | 'rules-change': Default strategy-watch. tax-optimization pursues minimize-lifetime-tax; rules-change needs Growth or above.
  - `objective` object, required
    - `target` 'maximize-ending-net-worth' | 'minimize-lifetime-tax', required
    - `statement` string
  - `constraints` Constraints, required (unresolved $ref)
  - `approvalPolicy` object
    - `approvers` 'approver-or-owner'
    - `expiresAfterDays` integer
  - `status` 'draft' | 'active': Default active.

## Response `201`

Created.

- object
  - `ok` unknown, required
  - `mandate` Mandate, required
    - `id` integer, required
    - `householdId` integer, nullable, required: null for a book mandate (rules-change).
    - `scope` 'household' | 'book', required
    - `type` 'strategy-watch' | 'tax-optimization' | 'rules-change', required: strategy-watch and tax-optimization work one household; rules-change works the book (Growth and above).
    - `typeVersion` string, required
    - `objective` object, required
      - `target` 'maximize-ending-net-worth' | 'minimize-lifetime-tax', required
      - `statement` string, required
    - `constraints` object, required
      - `profile` object: Pinned assumption profile; 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: The horizon starts in the UTC year of each cycle.
      - `strategies` string[]: Default: every strategy the type runs.
      - `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
      - `maxHouseholds` integer: rules-change only: households per book cycle (default 1,000; the rest are reported).
      - `materialityFloorUsd` number: Default 1,000. A candidate below it is not proposed unless it removes or delays a ruin year.
      - `cooldownDays` integer: Default 30, per strategy, after a proposal is approved, rejected or expires.
      - `maxOpenProposals` integer: Default 3.
      - `reviewCadence` 'none' | 'monthly' | 'quarterly': Default quarterly.
      - `planner` 'on' | 'off': Household mandates. Default off. "on" runs each cycle through the organization's planner model when one is assigned and certified for this mandate type (and the deployment allows it); otherwise the cycle is deterministic, and its outcome says why. The planner chooses among proposals the gate would pass, never adds one.
    - `approvalPolicy` object, required
      - `approvers` 'approver-or-owner', required
      - `expiresAfterDays` integer, required: Default 30; a proposal with a deadline expires at the deadline when that is sooner.
    - `status` 'draft' | 'active' | 'paused' | 'ended', required
    - `version` integer, required
    - `lastReviewPeriod` string, nullable
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `endedAt` string, date-time, nullable
  - `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.
- `404`: No such active household in your organization.
- `409`: The household already has a mandate of this type.
- `422`: Invalid fields, each with its path; or the pinned profile does not resolve.
- `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)
