---
title: "List inventory"
method: GET
path: "/inventory"
tags: ["Inventory"]
---

# List inventory

`GET /inventory`

## Request

- Base URL: `https://api.ekho.com`
- URL: `https://api.ekho.com/inventory`
- Auth: HTTP bearer

Returns a cursor-paginated page of the units the token can see, ordered by id. A program owner's token returns every unit across its dealer network, including its own rooftop; a single dealership's token returns only its own. Archived and removed units are included, so a full sync can reconcile a removal. Year, make, model, category, and type describe the model rather than the unit, so they live on the always-present `catalog_vehicle` block rather than on the item itself.

## Query parameters

- `limit` integer: Page size, 1 to 100.
- `starting_after` string: Return the page after this resource id (newest first).
- `account_id` string: One account within the token's reach. An id outside it returns an empty page, not a 403.
- `listing_status` 'live' | 'off' | 'reserved' | 'not_ready' | 'archived': Filter the lead-generation lane to a single status.
- `online_sale_status` 'live' | 'off' | 'reserved' | 'not_ready' | 'archived': Filter the online-sale lane to a single status. Only one status filter per request.
- `condition` 'new' | 'used' | 'consigned'
- `vin` string: Exact match.
- `stock_number` string: Exact match.
- `expand[]` string[]: Repeatable. Expand `location` for the rooftop holding the unit and who to contact about it.

## Response `200`

A page of inventory units.

- object
  - `data` InventoryItem[], required
    - `id` string, required
    - `account_id` string, required: The account holding the unit. Joins to `/locations`.
    - `vin` string, nullable, required
    - `stock_number` string, nullable, required
    - `condition` 'new' | 'used' | 'consigned' | 'null', nullable, required: Null when the source never set one.
    - `listing_status` 'live' | 'off' | 'reserved' | 'not_ready' | 'archived', required: Whether the listing is live for lead generation.
    - `online_sale_status` 'live' | 'off' | 'reserved' | 'not_ready' | 'archived', required: Whether the unit can be bought online. `reserved` means mid-purchase.
    - `full_name` string, nullable, required: Full descriptive name, when one was built.
    - `color` string, nullable, required
    - `odometer` InventoryOdometer, nullable, required
      - `reading` number, required
      - `unit` string, required
    - `description` string, nullable, required
    - `images` string[], required: Dealer photography only.
    - `pricing` InventoryPricing, required: Base vehicle prices. Freight, PDI, assembly, doc fees, taxes and registration are all excluded, so neither field is an out-the-door price.
      - `advertised` number, nullable, required: What the unit is advertised at, before fees and taxes. Null for a unit the dealer has not priced.
      - `compare_at` number, nullable, required: The higher price a discount is shown against, struck through on a listing: the dealer's retail price when set, otherwise MSRP. Null when the unit carries neither, and null when the one it carries does not exceed `advertised`. Show `advertised` on its own whenever this is null.
    - `catalog_vehicle` InventoryCatalogVehicle, required: What model the unit is, plus the four catalog ids that place it. Always present; the ids are null for a unit the catalog has not been built for.
      - `manufacturer_id` string, nullable, required: Catalog id of the manufacturer, and the namespace the other ids are unique beneath.
      - `model_id` string, nullable, required: Catalog id of the model. Null while the unit sits outside the catalog.
      - `variant_id` string, nullable, required: Catalog id of the trim. Pass it with `style_id` to name this vehicle on `POST /carts/build-to-order`.
      - `style_id` string, nullable, required: Catalog id of the colour style. Pass it with `variant_id` to name this vehicle on `POST /carts/build-to-order`.
      - `name` string, nullable, required: A title for a unit whose `full_name` never got built.
      - `year` integer, nullable, required
      - `make` string, nullable, required
      - `model` string, nullable, required
      - `category` string, nullable, required: Golf Cart, Side-by-Side, ATV, and so on.
      - `type` string, nullable, required: Regulatory street-legal class, not a body descriptor. Values are like `LowSpeed`, `NonTitledVehicle`, `ATV`.
      - `img_url` string, nullable, required: The model's stock render, for a unit the dealer never photographed. Kept out of `images`, which stays dealer photography.
    - `location` InventoryLocation: Present on `expand[]=location`.
      - `account_id` string, required: The holding account. Joins to `/locations`.
      - `name` string, nullable, required: Rooftop name.
      - `phone` string, nullable, required: As stored, with no formatting guarantee.
      - `email` string, nullable, required
      - `address` object, nullable, required: Where the unit physically is.
        - `line1` string, required
        - `line2` string, nullable, required
        - `city` string, required
        - `state` string, required: Two-letter state code.
        - `zip` string, required
        - `country` string, nullable, required: ISO 3166-1 alpha-2; null implies US.
    - `created_at` integer, required: Epoch ms the unit entered inventory.
    - `updated_at` integer, required: Epoch ms of the last change.
    - `deleted_at` integer, nullable, required: Set when the unit left the dealer's source system. Removed units are returned, carrying `archived`, so a full sync can reconcile the removal.
  - `has_more` boolean, required: True when another page follows the returned one.
  - `next_cursor` string, nullable, required: Pass as `starting_after` to fetch the next page; null when `has_more` is false.

## Other responses

- `400`: The request was malformed or failed validation. `errors` itemizes every field at fault, so one response names them all; the fields in the example stand in for this request's own.
- `401`: Authentication is missing or invalid.
- `403`: The token lacks `inventory:read`.
- `429`: The rate limit has been exceeded.
- `500`: An unexpected error occurred.

## Changes

- **2026-09-18** `78c545d96a34`: 15 warning, 1 info
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `400`
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `401`
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `403`
  - added the new `external_id_in_use` enum value to the `code` response property for the response status `429`
  - …12 more
- **2026-09-17** `2a0b497bcf22`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/ekho/apis/ekho-api/changes/inventory/get.md)

---

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