---
title: "List Public Propellers"
method: GET
path: "/v1/public/propellers"
tags: ["v1", "public"]
---

# List Public Propellers

`GET /v1/public/propellers`

## Request

- Base URL: `https://thrustlab.com`
- URL: `https://thrustlab.com/v1/public/propellers`
- Auth: none required

Unauthenticated curated-propeller list, paged and licensed like /motors.

Carries the same datasheet an authenticated caller reads. A propeller's
per-station geometry (radius, chord, twist, thickness, section airfoils) is
not part of that datasheet and is returned by no endpoint, under any filter
or ordering.

Numeric fields are filterable with bracket syntax — `?kv[gte]=900&kv[lte]=1100`
— and the bounds are inclusive. Discrete fields take `[in]` with a
comma-separated list — `?brand[in]=T-Motor,Hobbywing`. A bracket filter naming a
field this type does not have is a 400 `unknown_filter` listing the fields it
does have, so a typo cannot quietly return the whole catalog.

Carries `license` because there is no bulk export: a consumer reading the open
database page by page has to learn the terms from the response, and this is the
only place left that can tell it.

## Query parameters

- `limit` integer
- `starting_after` string, nullable: Where the next page starts — the `next_starting_after` the previous page returned. Under the default ordering (`sort_by=name`, `sort_order=asc`) that is the last component's `id`, and a component `id` is accepted under any ordering. Under any other ordering it is an opaque cursor bound to that `sort_by`/`sort_order`, and replaying it against a different ordering is a 400 `invalid_cursor`. Omit for the first page.
- `search` string, nullable: Case-insensitive substring match on the component name.
- `q` string, nullable: Alias for `search`. If both are supplied, `search` wins. Length-capped identically.
- `brand` string[], nullable: Restrict to these brands. Repeat the parameter for several (`?brand=T-Motor&brand=Hobbywing`). `brand[in]=a,b` does the same.
- `sort_by` string: Sort key. `name` (the default) on every type, plus — motor: R (or resistance), iq_max (or current_max), kv, n (or poles), weight; battery: c_rating, energy_density, series_cells, total_capacity_mAh (or capacity), weight_g (or weight); propeller: diameter, inertia, maxRPM (or max_rpm), num_blades, pd_ratio, pitch, weight. Either spelling of a field works, here and in the bracket filters. `pd_ratio` is a propeller's pitch divided by its diameter; `energy_density` is a pack's NOMINAL specific energy in Wh/kg (capacity x 3.7 V per cell x series cells / mass), a label figure for ranking packs against each other, not a measurement.
- `sort_order` string: `asc` or `desc`.

## Response `200`

Successful Response

- PublicComponentList: A page of the open catalog.
  - `data` PublicComponent[], required
    - `curve_pack_cells` integer, nullable: The field gives the cell count of the stand-in battery pack used for a motor's published curves. It is null on propellers, batteries and motors with no published curves.
    - `id` string, required: Public component id (comp_<ksuid>).
    - `name` string, required
    - `slug` string, nullable: The row's URL segment — the one GET /v1/public/{type}/by-slug/{slug} resolves. Null only for a row minted before the column existed; a client should fall back to the id rather than derive a slug of its own, because the minting rule is the server's.
    - `source` string, nullable: Where the row came from. Published, not hidden: a dataset whose rows cannot be attributed is one a reader has to take on trust.
    - `spec_json` object, required: The datasheet. The same projection an authenticated caller reads. A propeller's station arrays are digitised blade geometry and are not part of it.
    - `type` 'motor' | 'propeller' | 'battery', required
    - `updated_at` string, nullable: When the row was last touched (ISO 8601).
  - `has_more` boolean, required: True when a further page exists; page with starting_after.
  - `license` string, required: The licence this data is published under. Stated on the response because there is no bulk export to carry it.
  - `next_starting_after` string, nullable: Pass as starting_after to fetch the next page. Null on the last page, so a client can loop until it disappears. Under the default ordering it is the last component's id; under any other ordering it is an opaque cursor bound to that sort.
  - `object` 'list'

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