---
title: "Keep Run"
method: POST
path: "/api/runs/{run_id}/keep"
tags: ["runs"]
---

# Keep Run

`POST /api/runs/{run_id}/keep`

## Request

- Base URL: `https://api.retirementlab.app` (the document declares no server; this is the origin it was published from)
- URL: `https://api.retirementlab.app/api/runs/{run_id}/keep`
- Auth: HTTP bearer

## Path parameters

- `run_id` integer, required

## Request body

- KeepRunRequest
  - `name` string, required

## Response `201`

Successful Response

- ConfigDetail
  - `id` integer, required
  - `name` string, required
  - `label` string
  - `auto_label` string
  - `notes` string
  - `baseline_id` integer
  - `last_failure_probability` number
  - `display_order` integer, required
  - `simulation` SimulationConfigPayload, required: Simulation payload with all money values represented in full currency units.
    - `initial_year` integer, required
    - `initial_net_worth` number, required: Starting portfolio value in full local currency units.
    - `baseline_annual_expenses` number, required: Baseline annual spending in full local currency units.
    - `additional_expenses` SimulationExpensePayload[], required
      - `description` string, required
      - `cost` number, required: Expense amount in full local currency units.
      - `begin_year` integer, required: First year the expense applies (inclusive).
      - `end_year` integer, required: Last year the expense applies (inclusive). For a single-year expense, set begin_year == end_year. The API services layer converts to the engine's half-open ``[begin, end)`` interval.
      - `item_id` string, uuid
      - `seeded_from` string: Marker identifying a helper that generated this row (e.g. 'healthcare_defaults'). Absent on user-authored rows.
    - `additional_income` SimulationIncomePayload[], required
      - `description` string, required
      - `income` number, required: Income amount in full local currency units.
      - `begin_year` integer, required: First year the income applies (inclusive).
      - `end_year` integer, required: Last year the income applies (inclusive). For a single-year income, set begin_year == end_year. The API services layer converts to the engine's half-open ``[begin, end)`` interval.
      - `type` 'employment' | 'social_security' | 'public_pension' | 'private_pension' | 'rental' | 'other' | 'asset_sale'
      - `source_country` string
      - `claim_age` integer
      - `benefit_source` string
      - `cost_basis` number
      - `person` 'A' | 'B'
      - `item_id` string, uuid
      - `ss_benefit_basis_mode` 'fra_benefit' | 'ssa_estimate_at_age' | 'already_receiving'
      - `ss_monthly_benefit_basis` number
      - `ss_benefit_basis_age` integer
      - `ss_fra_age` integer
    - `country` string, required
    - `citizenship` string
    - `avg_return` number, required
    - `volatility` number, required
    - `approximate_yield_rate` number, required
    - `taxable_balance` number, required
    - `tax_deferred_balance` number, required
    - `tax_free_balance` number, required
    - `taxable_cost_basis` number, required
    - `accounts` SimulationAccountPayload[]
      - `wrapper_id` string, required
      - `balance` number, required: Account balance in full local currency units.
      - `cost_basis` number
      - `person` 'A' | 'B'
      - `item_id` string, uuid
      - `cross_border_tax_facts` CrossBorderTaxFactsPayload: Wrapper-tax facts the simulator cannot infer from a balance. Every field is optional: ``None`` (or absent) means the user has not asserted the fact yet. Empty payloads round-trip as ``None`` on the parent ``SimulationAccountPayload`` so existing scenarios stay backwards compatible.
        - `roth_contribution_basis` number
        - `qualified_roth_distribution` boolean
        - `canada_roth_election` boolean
        - `post_residency_contribution` boolean
        - `payment_form` 'lump_sum' | 'periodic'
      - `withdrawal_access` AccountAccessRulePayload
        - `mode` 'default' | 'available_now' | 'penalty_free_from' | 'locked_until'
        - `age` integer
        - `year` integer
        - `rule_of_55_eligible` boolean
      - `securities_holding_eligibility_override` 'eligible' | 'ineligible'
    - `withdrawal_order` 'taxable_first' | 'tax_deferred_first' | 'tax_free_first'
    - `tax_filing_status` 'single' | 'married_filing_jointly' | 'head_of_household'
    - `wealth_tax_region` string
    - `tax_regime` string
    - `subnational_region` string
    - `taxable_portfolio_source` 'domestic' | 'foreign'
    - `tax_regime_years_remaining` integer
    - `portfolio_dividend_qualified_pct` number
    - `portfolio_gains_longterm_pct` number
    - `primary_residence_value` number
    - `primary_residence_debt` number
    - `non_portfolio_property_value` number
    - `regime_eligibility_facts` object
    - `tax_profile_extended` object
    - `medicare_levy_applicable` boolean
    - `super_characterization` string
    - `remittance_basis` boolean
    - `tax_profile_explicit_fields` string[]
    - `horizon` integer
    - `n_scenarios` integer
    - `inflation` number
    - `tail_profile` 'none' | 'historical' | 'severe': Shape of each asset's annual returns. 'historical' (default): skew and tail weight fitted to long US histories; 'none': plain log-normal; 'severe': the heaviest stock-market tail the 1871-2024 record cannot rule out. Expected returns and volatilities are unchanged by the choice.
    - `market_turbulence` 'calmer' | 'historical' | 'rougher': How big each year's market ups and downs are. 'historical' (default): US stock volatility over 1871-2024; 'calmer': the calmest 30-year stretch on record (1871-1900); 'rougher': the roughest (1927-1956). Scales every asset's volatility; expected compound returns are unchanged.
    - `skewness_start` number: Deprecated and ignored; use tail_profile.
    - `skewness_factor` number: Deprecated and ignored; use tail_profile.
    - `minimum_ending_balance` number
    - `primary_heir_country` string
    - `retirement_year` integer
    - `annual_savings` number
    - `age` integer
    - `plan_to_age` integer
    - `person_b_retirement_year` integer
    - `person_b_age` integer
    - `person_b_plan_to_age` integer
    - `person_labels` string[]
    - `portfolio_preset` string
    - `portfolio_allocation` object[]
    - `glide_path` GlidePathWaypointPayload[]
      - `age` integer, required
      - `allocation` object[], required
      - `item_id` string, uuid
    - `rebalancing_mode` 'annual' | 'threshold' | 'none'
    - `rebalancing_threshold` number
    - `regime_aware` boolean
    - `simulation_mode` 'monte_carlo_regime' | 'monte_carlo_iid' | 'historical'
    - `withdrawal_strategy` string
    - `withdrawal_strategy_params` object
    - `return_assumption_preset` string
    - `return_overrides` object
    - `aca_subsidies_enabled` boolean
    - `household_size` integer
    - `aca_state` string
    - `medicare_enabled` boolean
    - `irmaa_enabled` boolean
    - `tax_loss_harvesting_enabled` boolean
    - `residency_schedule` object[]
    - `relocation_events` RelocationEventPayload[]
      - `year` integer, required
      - `to_country` string, required
      - `regime` string
      - `item_id` string, uuid
      - `sell_primary` boolean
      - `buy_primary_value` number
      - `buy_primary_mortgage` number
      - `fx_rate` number
      - `fx_source_currency` string
      - `fx_destination_currency` string
      - `fx_assumption_source` 'caller_supplied_fixed_rate'
    - `baseline_adjustments` BaselineAdjustmentPayload[]
      - `year` integer, required
      - `new_baseline` number, required
      - `reason` string
      - `item_id` string, uuid
      - `derived_from` string
    - `roth_conversions` RothConversionPayload[]
      - `year` integer, required
      - `amount` number, required
      - `from_wrapper_id` string, required
      - `to_wrapper_id` string, required
      - `item_id` string, uuid
      - `derived_from` string
    - `article24_relief` Article24ReliefFactsPayload: France-US tax treaty Article 24 portfolio relief facts. These are user-confirmed simulation facts, not a determination of legal eligibility — user-facing copy referencing this block must say "based on your inputs" and avoid advisory terms. ``eligibility_status`` defaults to ``"unknown"``, which must never silently activate relief downstream. A globally diversified portfolio can contain both qualifying and non-qualifying assets, so eligibility is recorded as fractions rather than a single domestic/foreign flag.
      - `schema_version` integer
      - `eligibility_status` 'unknown' | 'eligible' | 'ineligible'
      - `qualifying_investment_income_fraction` number
      - `qualifying_capital_gains_fraction` number
      - `us_source_or_asset_qualification_confirmed` boolean
      - `beneficial_ownership_confirmed` boolean
      - `us_reporting_compliance_confirmed` boolean
    - `puma_csm` PumaCsmAssumptionPayload: France PUMa cotisation subsidiaire maladie (CSM) eligibility assumption. A scenario-level state, separate from the per-adult ``puma_household_adults`` entries. ``"unknown"`` (the default) must never silently activate CSM liability downstream.
      - `eligibility_status` 'unknown' | 'eligible' | 'ineligible'
    - `puma_household_adults` PumaHouseholdAdultPayload[]
      - `household_relationship` 'self' | 'spouse' | 'pacs_partner' | 'other_adult'
      - `income_attribution` 'per_adult' | 'equal_household'
      - `person` 'A' | 'B'
      - `coverage_start_date` string, date
      - `coverage_end_date` string, date
      - `item_id` string, uuid
  - `inherited_pro_inputs` InheritedProInput[]
    - `field` string, required
    - `feature` 'country_sweep_3plus' | 'custom_portfolio_allocation' | 'custom_return_assumptions' | 'custom_withdrawal_access' | 'export_report' | 'glide_path' | 'historical_simulation' | 'member_daily_run_cap' | 'precision_tax_inputs' | 'rebalancing_options' | 'regime_aware' | 'roth_conversion_explorer' | 'scenario_cap' | 'simulation_resolution' | 'tax_loss_harvesting' | 'what_would_it_take' | 'withdrawal_order' | 'withdrawal_strategy', required
    - `display_value` string, required
  - `updated_at` string, date-time

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/retirementlab/apis/income-simulator-api.md) · [All operations](https://skmtc.dev/retirementlab/apis/income-simulator-api/llms.txt) · [OpenAPI document](https://skmtc.dev/retirementlab/apis/income-simulator-api/revisions/b0f00a0333fd?raw)
