> ## Documentation Index
> Fetch the complete documentation index at: https://docs.incentives.leap.energy/llms.txt
> Use this file to discover all available pages before exploring further.

# Search device catalog

> Find the catalog `device_id` for a product, or browse the catalog when you have no search term. Use it to map your product catalog to Leap's programmatically instead of by hand. A query parameter this endpoint does not recognise returns 400 rather than being ignored, so a misspelled filter fails loudly.



## OpenAPI

````yaml /api-reference/specs/gcs-devices.json get /beta/incentives/devices/search
openapi: 3.0.1
info:
  title: Leap Incentives — Devices
  description: >-
    API for managing program definitions, requirement catalog, field groups, and
    partner data preferences
  contact:
    email: apiteam@leap.energy
  version: '0.1'
servers:
  - url: https://api.leap.energy
    description: Production
  - url: https://api.staging.leap.energy
    description: Staging
security:
  - BearerAuth: []
tags:
  - name: devices
paths:
  /beta/incentives/devices/search:
    get:
      tags:
        - devices
      summary: Search device catalog
      description: >-
        Find the catalog `device_id` for a product, or browse the catalog when
        you have no search term. Use it to map your product catalog to Leap's
        programmatically instead of by hand. A query parameter this endpoint
        does not recognise returns 400 rather than being ignored, so a
        misspelled filter fails loudly.
      operationId: searchDevices
      parameters:
        - name: q
          in: query
          required: false
          description: >
            Free-text query over manufacturer, model name and model number. Omit
            it to browse rather than search.
          schema:
            type: string
            minLength: 1
        - name: category
          in: query
          required: false
          description: >
            Device category, addressed by its stable `name` (case-insensitive):
            hvac, ev_charger, solar_storage, water_heater, smart_thermostat,
            weatherization, vehicle, meter, panel_make_ready, solar_panel.
            Address a category by name: the category's own id is specific to one
            Leap environment and is not accepted here. An unknown name is a 400
            naming the categories that exist.
          schema:
            type: string
        - name: subcategory
          in: query
          required: false
          description: >
            Exact (case-insensitive) match on the device's `subcategory`. The
            stored vocabulary is uncontrolled today, so treat this as a filter
            on values you have already seen in `subcategory` on a response, not
            as an enum.
          schema:
            type: string
        - name: ids
          in: query
          required: false
          description: >
            Resolves specific catalog devices by id: a comma-separated list of
            catalog device UUIDs, at most 100 per request. Combines with the
            other filters by AND, so `ids` plus `category` returns only the
            named devices that also sit in that category.


            Intended for resolving already-attached customer devices, where the
            caller holds device UUIDs and needs the full catalog record for each
            one. An id that matches no device currently in the catalog is simply
            absent from the results rather than an error, so match the responses
            back to the ids you asked for. A malformed UUID, an empty value, or
            more than 100 ids is a 400.
          schema:
            type: array
            maxItems: 100
            items:
              type: string
              pattern: >-
                ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
          style: form
          explode: false
        - name: page_size
          in: query
          required: false
          description: >
            Rows per page, 1 to 500. Defaults to `limit` when only `limit` is
            given, else to 20. Cannot be combined with `limit`.
          schema:
            type: integer
            minimum: 1
            maximum: 500
        - name: page_token
          in: query
          required: false
          description: >
            Opaque cursor from a previous response's `next_page_token`. Only
            valid when replayed with the same `q`, `category` and `subcategory`;
            replaying it against different filters is a 400. Cannot be combined
            with `offset`.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: >
            Legacy alias for `page_size`, kept so existing callers keep working.
            The ceiling was raised from 50 to 500.
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 500
        - name: offset
          in: query
          required: false
          description: >
            Legacy row offset, kept so existing callers keep working. Prefer
            `page_token`.
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        '200':
          description: Ranked page of matching devices.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceSearchResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  schemas:
    DeviceSearchResponse:
      type: object
      required:
        - results
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/PartnerDeviceResponse'
        next_offset:
          type: integer
          nullable: true
          description: >
            Offset for the next page, or null when this is the last page. Kept
            for callers still paging with limit + offset.
        next_page_token:
          type: string
          nullable: true
          description: >
            Cursor for the next page, or null when this is the last page. Pass
            it back as `page_token`. Present alongside `next_offset` whichever
            paging style the request used, so a caller can switch.
    PartnerDeviceResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        device_category_id:
          type: string
          format: uuid
          description: >-
            Leap's identifier for the device's category. It is specific to one
            Leap environment, so key on `device_category` instead when you store
            or compare categories.
        device_category:
          type: string
          description: >-
            The device's category name, and the stable way to address a
            category: `hvac`, `ev_charger`, `solar_storage`, `water_heater`,
            `smart_thermostat`, `weatherization`, `vehicle`, `meter`,
            `panel_make_ready`, `solar_panel`. It is the same value the
            `category` query parameter takes, so you can bucket a page of
            results without a second call.
        manufacturer:
          type: string
        model_number:
          type: string
        model_name:
          type: string
        description:
          type: string
        subcategory:
          type: string
        is_active:
          type: boolean
        date_available:
          type: string
          format: date
        date_discontinued:
          type: string
          format: date
        manufacture_year:
          type: integer
        charger_level:
          type: string
        charging_power_kw:
          type: number
        connector_types:
          type: array
          items:
            type: string
        seer2_rating:
          type: number
        eer2_rating:
          type: number
        hspf2_rating:
          type: number
        ceer_rating:
          type: number
        capacity_tons:
          type: number
        capacity_btu:
          type: integer
        capacity_kw:
          type: number
        msrp:
          type: number
        is_energy_star_certified:
          type: boolean
        is_ul_listed:
          type: boolean
        is_networked:
          type: boolean
        is_ocpp_compliant:
          type: boolean
        battery_capacity_kwh:
          type: number
        battery_chemistry:
          type: string
        is_mobile_plugin_charger:
          type: boolean
      description: >-
        One device in Leap's catalog. Send its `id` as the `device_id` on a
        lookup. Specification fields such as `capacity_kw` or `seer2_rating` are
        populated where Leap holds data for that device type, and are null
        otherwise.
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - message
          properties:
            message:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  error_code:
                    type: string
                  reason:
                    type: string
  responses:
    BadRequest:
      description: Malformed or invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: You are not authorized to perform this operation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: You do not have permission to perform this operation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: >
        The shared per-partner rate limit for /incentives endpoints was exceeded
        (`error_code: RATE_LIMIT_EXCEEDED`). Back off and retry after the number
        of seconds indicated by the `Retry-After` header.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalServerError:
      description: An internal server error occurred
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Your Leap API key as a Bearer token. Send it in the `Authorization`
        header: `Authorization: Bearer <api-key>`.

````