---
title: "Create Dynamic V1"
method: POST
path: "/v1/dynamic-simulations"
tags: ["v1", "dynamic-simulations"]
---

# Create Dynamic V1

`POST /v1/dynamic-simulations`

## Request

- Base URL: `https://thrustlab.com`
- URL: `https://thrustlab.com/v1/dynamic-simulations`
- Auth: HTTP bearer

Submit a transient (time-domain) powertrain run.

Pro-gated (free -> 403 ``pro_required``); the schedule is validated and the
credit cost (the coulombic upfront estimate) reserved server-side
BEFORE the worker is dispatched. Returns ``202 Accepted`` with a
``dyn_``-prefixed resource; poll ``GET`` or stream progress via SSE.

## Headers

- `Idempotency-Key` string, required: Unique key (max 255 chars) making this POST safe to retry. Required on all v1 write requests; replays return the cached response.

## Request body

- DynamicCreateBody: Create body for ``POST /v1/dynamic-simulations``.
  - `ambient_temp_c` number
  - `battery_charge_pct` number
  - `battery_component_id` string, nullable
  - `battery_esc_wire_resistance_mohm` number
  - `battery_initial_temp_c` number, nullable
  - `battery_topology` PackTopologyIn
    - `bus_wire_resistance_mohm` number
    - `cross_charge_warning_acknowledged` boolean
    - `root` union, required
      - PackLeafIn
        - `battery_component_id` string, required
        - `branch_wire_resistance_mohm` number
        - `id` string, required
        - `initial_soc_pct` number, nullable
        - `kind` 'leaf'
      - PackSeriesIn
        - `children` union[], required
          - union
            - PackLeafIn
              - …
            - PackSeriesIn (recursive)
            - PackParallelIn
              - …
        - `kind` 'series'
      - PackParallelIn
        - `branches` union[], required
          - union
            - PackLeafIn
              - …
            - PackSeriesIn
              - …
            - PackParallelIn (recursive)
        - `kind` 'parallel'
        - `voltage_match_tolerance_v` number, required
    - `schema` 1
  - `density_kg_m3` number, required
  - `motor_initial_temp_c` number, nullable
  - `name` string, nullable
  - `project_id` string, nullable: Project to file this run in (raw UUID or proj_<ksuid>). Omit to use the account's default project, which is created if absent.
  - `propeller_model` 'fast' | 'full': Propeller model for this mission. Dynamic runs are Full-model only; 'fast' is refused rather than silently substituted.
  - `rotor_groups` DynamicRotorGroupIn[]
    - `count` integer
    - `esc_motor_wire_resistance_mohm` number
    - `esc_pwm_frequency_khz` number: ESC switching frequency (kHz)
    - `esc_resistance_mohm` number
    - `esc_sync_rectification` boolean: Synchronous rectification (comp_pwm); default ON
    - `esc_timing` 'low' | 'medium' | 'high' | 'auto': Six-step commutation advance preset (low 7.5°/medium 15°/high 22.5°/auto duty-scheduled); FOC ignores it
    - `esc_type` 'foc' | 'six_step': ESC commutation type. Selects K_volt, copper_mult, iron_mult, the six-step commutation-advance physics and the throttle->duty map — not a cosmetic flag. Single-sourced (ESC-7): app/constants_esc.py.
    - `label` string, required
    - `motor_component_id` string, nullable
    - `motor_cooling_source` 'cowling' | 'prop_exit_velocity' | 'custom': Per-rotor-group motor cooling mode. cowling = still air; prop_exit_velocity = forced convection from the prop slipstream (default); custom = fixed velocity or direct thermal resistance.
    - `motor_cooling_velocity_m_s` number, nullable: Custom motor cooling convection velocity (m/s); only used when motor_cooling_source=custom.
    - `motor_r_th` number, nullable: Custom direct motor thermal resistance override (K/W); only used when motor_cooling_source=custom.
    - `propeller_component_id` string, nullable
    - `propeller_label` PropellerLabel: The printed size of a propeller — everything the Fast model reads. This is the whole input the Fast model takes for a rotor: no station arrays, no section airfoils, nothing that has to be measured. It is accepted ONLY with ``propeller_model == "fast"``; the Full model needs blade geometry and refuses a label rather than silently switching models.
      - `camber_pct` number: Section camber as a percentage of chord. The default is the reference model's 3.2 % (zero-lift angle -3.5 deg), so a label with no camber given reproduces the published closed-form numbers.
      - `chord_ratio` number, nullable: Chord at 75 % radius divided by diameter. Required when family == 'custom'; rejected otherwise (the family preset is the value).
      - `diameter_m` number, required: Propeller diameter in metres.
      - `family` 'thin_electric' | 'sport' | 'slow_flyer' | 'multirotor' | 'custom', required: Planform family, which sets the chord ratio at 75 % radius (thin_electric 0.065, sport 0.07, slow_flyer 0.10, multirotor 0.11). Use 'custom' to give chord_ratio directly.
      - `max_rpm` integer, nullable
      - `num_blades` integer, required: Number of blades.
      - `pitch_m` number, required: Geometric pitch in metres.
      - `weight_g` number, nullable
  - `rotors` DynamicRotorIn[], nullable: One entry per rotor. Preferred over rotor_groups, and required for coaxial stacks: set coax_stack_id to the same non-zero value on the rotors that share an axis, give each a distinct coax_position_m, and set opposite rotation_sense values for a contra-rotating stack. Supply either rotors or rotor_groups, not both.
    - `coax_position_m` number: Position along the coaxial stack axis in metres, increasing downstream (in the direction the slipstream travels). The spacing between two rotors is the difference of their positions. Ignored when coax_stack_id is 0.
    - `coax_stack_id` integer: Coaxial stack this rotor belongs to. 0 (default) means the rotor is not stacked and is simulated in isolation. Rotors sharing a non-zero value form one contra-rotating or co-rotating stack.
    - `esc_motor_wire_resistance_mohm` number
    - `esc_pwm_frequency_khz` number: ESC switching frequency (kHz)
    - `esc_resistance_mohm` number
    - `esc_sync_rectification` boolean: Synchronous rectification (comp_pwm); default ON
    - `esc_timing` 'low' | 'medium' | 'high' | 'auto': Six-step commutation advance preset (low 7.5°/medium 15°/high 22.5°/auto duty-scheduled); FOC ignores it
    - `esc_type` 'foc' | 'six_step': ESC commutation type. Selects K_volt, copper_mult, iron_mult, the six-step commutation-advance physics and the throttle->duty map — not a cosmetic flag. Single-sourced (ESC-7): app/constants_esc.py.
    - `label` string, required
    - `motor_component_id` string, nullable
    - `motor_cooling_source` 'cowling' | 'prop_exit_velocity' | 'custom': Per-rotor-group motor cooling mode. cowling = still air; prop_exit_velocity = forced convection from the prop slipstream (default); custom = fixed velocity or direct thermal resistance.
    - `motor_cooling_velocity_m_s` number, nullable: Custom motor cooling convection velocity (m/s); only used when motor_cooling_source=custom.
    - `motor_r_th` number, nullable: Custom direct motor thermal resistance override (K/W); only used when motor_cooling_source=custom.
    - `propeller_component_id` string, nullable
    - `propeller_label` PropellerLabel: The printed size of a propeller — everything the Fast model reads. This is the whole input the Fast model takes for a rotor: no station arrays, no section airfoils, nothing that has to be measured. It is accepted ONLY with ``propeller_model == "fast"``; the Full model needs blade geometry and refuses a label rather than silently switching models.
      - `camber_pct` number: Section camber as a percentage of chord. The default is the reference model's 3.2 % (zero-lift angle -3.5 deg), so a label with no camber given reproduces the published closed-form numbers.
      - `chord_ratio` number, nullable: Chord at 75 % radius divided by diameter. Required when family == 'custom'; rejected otherwise (the family preset is the value).
      - `diameter_m` number, required: Propeller diameter in metres.
      - `family` 'thin_electric' | 'sport' | 'slow_flyer' | 'multirotor' | 'custom', required: Planform family, which sets the chord ratio at 75 % radius (thin_electric 0.065, sport 0.07, slow_flyer 0.10, multirotor 0.11). Use 'custom' to give chord_ratio directly.
      - `max_rpm` integer, nullable
      - `num_blades` integer, required: Number of blades.
      - `pitch_m` number, required: Geometric pitch in metres.
      - `weight_g` number, nullable
    - `rotation_sense` 1 | -1: Direction of rotation about the downstream axis: 1 or -1. Opposite values in one stack give a contra-rotating pair, which recovers swirl energy and is the usual choice. Only read by coaxial pairing — a single rotor's value does not affect its own performance.
  - `schedule` ScheduleIn, required: The control schedule — a ``segments`` list OR a per-rotor ``csv_text``. ``mode`` is the discriminator. ``segments`` is required for ``mode=segments``; ``csv_text`` (+ optional ``interpolation``) for ``mode=csv``. The cross-field requirement is enforced server-side by the schedule compiler (``validate_schedule``) so a malformed schedule 4xx's BEFORE any reservation.
    - `csv_text` string, nullable
    - `interpolation` 'linear' | 'hold', nullable
    - `mode` 'segments' | 'csv', required
    - `segments` SegmentIn[], nullable
      - `airspeed_ramp` 'step' | 'linear'
      - `airspeed_target` number
      - `duration_s` number, nullable
      - `per_group` object, required
      - `throttle_ramp` 'step' | 'linear'
      - `until_depleted` boolean
      - `vertical_speed_ramp` 'step' | 'linear'
      - `vertical_speed_target` number
  - `termination` TerminationIn, required: Run-termination policy: the SOC / cell-voltage depletion cutoffs and the fixed-duration vs until-depleted run mode.
    - `cell_voltage_cutoff_v` number, nullable
    - `max_duration_s` number, nullable
    - `mode` 'fixed' | 'until_depleted'
    - `soc_cutoff_pct` number

## Response `202`

Successful Response

- DynamicResource: The dynamic-simulation resource. ``result`` is populated only once the run is ``completed`` (the worker writes it); it stays ``None`` for queued/running/failed/canceled (the SweepResource optional-result idiom).
  - `battery_topology` object, nullable
  - `cancel_requested_at` string, nullable: When a cancel was requested for a RUNNING run. The status stays `running` until the worker stops at its next integration chunk boundary — at which point it keeps the results it has, refunds in full, and the run turns `canceled` with a partial `result`. Null when no cancel is pending, which includes every terminal run: the field reports a request in flight, not the history of one. A QUEUED run cancels immediately instead and never sets this.
  - `created_at` string, nullable: When the run was submitted.
  - `credits_cost` integer, required
  - `dispatched_at` string, nullable: When the run was handed to the worker queue. A dynamic run is dispatched at creation, so this always equals created_at — it is NOT the start of execution.
  - `display_labels` object, nullable
  - `error` object, nullable
  - `id` string, required
  - `input_snapshot` object, nullable
  - `is_starred` boolean
  - `name` string, nullable
  - `object` 'dynamic_simulation'
  - `progress` object, nullable: How far a running solve has got, refreshed at every integration chunk boundary: `fraction` (0-1, null when it cannot be estimated), `sim_time_s` reached, `sim_time_total_s` (null for a run to depletion, which has no fixed horizon — its fraction comes from the estimated duration and is capped at 0.99), `wall_s` of real time so far, and `updated_at`. Null before the first chunk completes.
  - `project_id` string, required
  - `result` object, nullable
  - `snapshot_version` integer
  - `solver_engine` string
  - `started_at` string, nullable: When a worker claimed the run and the solve began. Null until then. For a dynamic run this is the only field that shows how long it waited for a slot.
  - `status` 'queued' | 'running' | 'completed' | 'failed' | 'canceled', required

## Other responses

- `422`: Validation Error

---

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