---
title: "Patch Sweep Point V1"
method: PATCH
path: "/v1/sweeps/{public_id}/points/{index}"
tags: ["v1", "sweeps"]
---

# Patch Sweep Point V1

`PATCH /v1/sweeps/{public_id}/points/{index}`

## Request

- Base URL: `https://thrustlab.com`
- URL: `https://thrustlab.com/v1/sweeps/{public_id}/points/{index}`
- Auth: HTTP bearer

Star/unstar a single sweep point. Ownership enforced via _load_owned_sweep
 before any mutation; out-of-range index → 404.

## Path parameters

- `public_id` string, required
- `index` integer, required

## Request body

- SweepPointPatch
  - `is_starred` boolean, required

## Response `200`

Successful Response

- SweepPointResource: A single sweep grid point. ``rotors`` is the full per-point solver result dict — keyed per-rotor ("1", "2"...) plus the "All"/"Battery" aggregates — mirroring ``SimulationResource.result``. Each per-rotor entry follows the canonical snake_case ``SimulationResultV1`` shape (wired at read time in a later wave); the schema below references that shape so an SDK/consumer sees the canonical per-rotor keys. NON-coercing rationale: the runtime type stays a raw ``dict[str, dict[str, Any]]`` — NOT a coercing per-rotor ``SimulationResultV1`` model. Coercing every rotor value through that model would re-introduce the 2026-06-02 aggregate-drop regression on sweep points, silently dropping the "All"/"Battery" aggregate-only fields (Max T_core, Cell voltages...). See the matching note on ``SimulationResource.result`` (serializers_simulations.py). The per-rotor snake shape is documented via the schema reference only; the values are never re-validated through a model.
  - `failed` boolean, required
  - `index` integer, required
  - `inputs` SweepPointInputs, required: ESC-13 item 4 — the operating condition this grid point was solved at. Previously typed ``dict[str, Any]``, which is the wire equivalent of saying nothing: an SDK user got an untyped bag and had to learn the key set by running a sweep and reading one. ESC-13 already made the RUNTIME blob self-describing (it is built from the point rather than from a hardcoded five-key literal, so a new axis appears the day it lands); this makes the CONTRACT say so too. ``extra="allow"`` is load-bearing, not laziness. Two families of key are generated per-sweep and cannot be enumerated in a static model: * ``tilt_<group_index>`` — group-targeted tilt is one grid dimension per MASKED rotor group, so the key set depends on the mask. * ``component_<axis>_<slots>`` — a component axis contributes its selected index under a name encoding the slots it spans (``component_motor_0``, or ``component_motor_0-2`` when synced). The propeller-label axes (2026-09-20) are declared below rather than left to ``extra``: there is one key per axis whatever the mask targets, because a label axis is ONE global grid dimension — the masked groups all run the same size at a point. Declaring those away would be worse than leaving the model untyped, because a strict model would DROP them at serialization — the same failure mode as the 2026-06-02 aggregate-drop that ``rotors`` is deliberately non-coercing to avoid. Every declared field is optional and permissively typed for the same reason: this model documents the shape, it does not police it.
    - `airspeed` number, nullable: Forward airspeed at this point, m/s.
    - `battery_charge_pct` number, nullable: Pack state of charge at this point, %.
    - `component` SweepPointComponentSelection[]: Components selected at this point, one entry per swept slot. Empty when no component axis is active.
      - `axis` string, required: Which component was swapped: "motor", "propeller" or "battery".
      - `id` string, nullable: Public component id of the selected component.
      - `name` string, nullable: Display name of the selected component.
      - `slot` integer, required: Rotor-group index the swap applied to (0 for a battery axis).
    - `density` number, nullable: Air density at this point, kg/m^3.
    - `esc_pwm_frequency_khz` number, nullable: ESC switching frequency at this point, kHz. Present only when an ESC PWM axis is swept.
    - `esc_timing` string, nullable: Six-step commutation timing preset at this point ("low", "medium", "high", "auto"). Present only when an ESC timing axis is swept — absent means each rotor group used its own persisted setting.
    - `grid_index` integer[], nullable: Multi-dimensional coordinate of this point in the sweep grid, one entry per axis in the order the axes were declared. The flat `index` on the point itself is the pagination counter, not this.
    - `prop_diameter_m` number, nullable: Propeller diameter at this point, metres. Present only when a `prop_diameter_m` axis is swept; it applies to every rotor group `sweep.label_sweep_mask` targets, and to no other.
    - `prop_num_blades` integer, nullable: Blade count at this point. Present only when a `prop_num_blades` axis is swept; it applies to every rotor group `sweep.label_sweep_mask` targets, and to no other.
    - `prop_pitch_m` number, nullable: Geometric propeller pitch at this point, metres. Present only when a `prop_pitch_m` axis is swept; it applies to every rotor group `sweep.label_sweep_mask` targets, and to no other.
    - `throttle` number, nullable: Commanded throttle % at this point. Always present. NOTE: this is the value of the throttle AXIS when one is swept; with no throttle axis it echoes rotor group 0's persisted throttle and applies to no other group (DM-6) — read the per-rotor results for what each group actually ran at.
    - `vertical_speed` number, nullable: Signed vertical speed at this point, m/s (positive = climb).
  - `is_starred` boolean, required
  - `object` 'sweep_point', required
  - `rotors` object, nullable, required: Per-point rotor results, keyed per-rotor ("1", "2", ...) plus the "All"/"Battery" aggregates. Each per-rotor entry follows the canonical snake_case SimulationResultV1 shape; NON-coercing at runtime so aggregate-only fields are never dropped.

## 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)
