---
title: "Publish an immutable profile version"
method: POST
path: "/api/v1/assumption-profiles"
tags: ["assumption-profiles"]
---

# Publish an immutable profile version

`POST /api/v1/assumption-profiles`

## Request

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

No update or delete path exists: a changed number is a new version, so a run pinned to id@version can never drift.

## Request body

- object
  - `id` string, required: Kebab-case, 3–64 chars, e.g. "firm-cma-2026".
  - `version` string, required: Semver.
  - `label` string, required
  - `assumptions` ProjectionAssumptions, required: 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.
  - `provenance` string, required: Who stands behind these assumptions and as of when — required.

## Response `201`

Published.

- object
  - `ok` unknown, required
  - `profile` object, required
    - `id` string, required
    - `version` string, required
    - `label` string, required
    - `assumptions` ProjectionAssumptions, required: 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.
    - `provenance` 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.
- `409`: id@version already exists and is immutable — publish a new version.
- `422`: Validation failed (id, version, label, provenance, or assumptions).
- `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)
