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

# List products

> Returns a paginated list of active, publicly visible products for the store.

**Pagination** uses `limit` / `offset` query parameters.  Default page size is 20; maximum is 100.

**Filtering** by category UUID narrows to a single category.  **Search** (`search` param) matches against product name and description.



## OpenAPI

````yaml /LeyyowPublicAPI(v2).yaml get /products
openapi: 3.0.3
info:
  title: Leyyow Public API
  version: 1.0.0 (v2)
  description: >-
    The Leyyow Public API lets you build custom storefronts on top of any Leyyow
    merchant store.


    ## Authentication


    Every request must carry a merchant API key as a Bearer token:


    ```

    Authorization: Bearer lyw_<your-secret-key>

    ```


    Keys are scoped to a single store.  All responses contain only data that
    belongs to the store that issued the key.


    ## Rate limits


    | Throttle group | Limit |

    |---|---|

    | Catalogue endpoints (per key) | 1 000 / hour |

    | Catalogue endpoints (per IP) | 200 / hour |

    | Order creation (per key) | 50 / hour |

    | Shipping quotes (per key) | 100 / hour |


    When a limit is exceeded the API returns HTTP 429 with a `Retry-After`
    header indicating how many seconds to wait.


    ## Store scoping


    The `X-Store-Id` header is ignored.  Store identity is derived entirely from
    the API key — there is no way to access a different store's data using the
    same key.
servers:
  - url: /api/public/v1
    description: Leyyow Public API v1
security: []
paths:
  /products:
    get:
      tags:
        - Catalogue
      summary: List products
      description: >-
        Returns a paginated list of active, publicly visible products for the
        store.


        **Pagination** uses `limit` / `offset` query parameters.  Default page
        size is 20; maximum is 100.


        **Filtering** by category UUID narrows to a single category.  **Search**
        (`search` param) matches against product name and description.
      operationId: products_list
      parameters:
        - in: query
          name: category
          schema:
            type: string
          description: Filter by category UID (UUID string).
        - in: query
          name: limit
          schema:
            type: integer
          description: 'Number of results per page (default: 20, max: 100).'
        - in: query
          name: offset
          schema:
            type: integer
          description: Starting position in the result set.
        - in: query
          name: search
          schema:
            type: string
          description: Full-text search on product name and description.
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedPublicProductList'
              examples:
                ProductList:
                  value:
                    count: 123
                    next: http://api.example.org/accounts/?offset=400&limit=100
                    previous: http://api.example.org/accounts/?offset=200&limit=100
                    results:
                      - count: 42
                        next: >-
                          https://api.leyyow.com/api/public/v1/products?limit=20&offset=20
                        previous: null
                        results:
                          - uid: 018e1234-0000-7000-a000-000000000010
                            name: Classic Ankara Dress
                            description: Hand-stitched ankara dress with custom embroidery.
                            story: null
                            category: 018e1234-0000-7000-a000-000000000050
                            category_name: Dresses
                            brand: Remi's Boutique
                            unit: piece
                            is_variable: true
                            price: 15000.00 - 22000.00
                            variants:
                              - uid: 018e1234-0000-7000-a000-000000000020
                                name: Small / Blue
                                sku: RB-ANKD-S-BLU
                                price: '15000.00'
                                is_default: true
                                weight: '0.50'
                                length: null
                                width: null
                                height: null
                                attributes:
                                  - uid: ...
                                    attribute: ...
                                    value: ...
                                    attribute_name: Size
                                    attribute_value: Small
                                  - uid: ...
                                    attribute: ...
                                    value: ...
                                    attribute_name: Colour
                                    attribute_value: Blue
                            images:
                              - uid: 018e1234-0000-7000-a000-000000000030
                                image: >-
                                  https://cdn.leyyow.com/products/classic-ankara-dress/front.jpg
                                alt_text: Classic Ankara Dress — front view
                                is_primary: true
                                sort_order: 0
                                created_at: '2025-01-15T10:00:00Z'
                                updated_at: '2025-01-15T10:00:00Z'
                            created_at: '2025-01-15T10:00:00Z'
                  summary: Product list
          description: Paginated list of products.
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/_Error'
              examples:
                InvalidKey:
                  value:
                    detail: Invalid or revoked API key.
                    error_code: AUTHENTICATION_FAILED
                  summary: Invalid key
          description: Authentication failed — key missing, invalid, or revoked.
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/_Error'
              examples:
                RateLimited:
                  value:
                    detail: Rate limit exceeded. Please retry in 120 seconds.
                    error_code: ENDPOINT_THROTTLED
                  summary: Rate limited
          description: >-
            Rate limit exceeded.  Retry after the number of seconds indicated in
            the `Retry-After` response header.


            | Throttle group | Limit |

            |---|---|

            | Catalogue endpoints — per API key | 1 000 / hour |

            | Catalogue endpoints — per IP address | 200 / hour |

            | Order creation — per API key | 50 / hour |

            | Shipping quotes — per API key | 100 / hour |
      security:
        - MerchantAPIKey: []
components:
  schemas:
    PaginatedPublicProductList:
      type: object
      required:
        - count
        - results
      properties:
        count:
          type: integer
          example: 123
        next:
          type: string
          nullable: true
          format: uri
          example: http://api.example.org/accounts/?offset=400&limit=100
        previous:
          type: string
          nullable: true
          format: uri
          example: http://api.example.org/accounts/?offset=200&limit=100
        results:
          type: array
          items:
            $ref: '#/components/schemas/PublicProduct'
    _Error:
      type: object
      properties:
        detail:
          type: string
        error_code:
          type: string
      required:
        - detail
    PublicProduct:
      type: object
      properties:
        uid:
          type: string
          format: uuid
          readOnly: true
        name:
          type: string
          readOnly: true
        description:
          type: string
          readOnly: true
        story:
          type: string
          readOnly: true
          description: Extended product story/description
        category:
          type: string
          format: uuid
          readOnly: true
          nullable: true
        category_name:
          type: string
          readOnly: true
        brand:
          type: string
          readOnly: true
        unit:
          type: string
          readOnly: true
          description: Unit of measurement (e.g. kg, bottles, packs). Free text.
        is_variable:
          type: boolean
          readOnly: true
        price:
          type: string
          readOnly: true
        variants:
          type: string
          readOnly: true
        images:
          type: string
          readOnly: true
        created_at:
          type: string
          format: date-time
          readOnly: true
      required:
        - brand
        - category
        - category_name
        - created_at
        - description
        - images
        - is_variable
        - name
        - price
        - story
        - uid
        - unit
        - variants
  securitySchemes:
    MerchantAPIKey:
      type: http
      scheme: bearer
      bearerFormat: lyw_<secret>
      description: >-
        Authenticate using a Leyyow merchant API key.


        Include the key in every request as a Bearer token:


        ```

        Authorization: Bearer lyw_<your-secret-key>

        ```


        Keys are scoped to a single store. All endpoints return data belonging
        to the store that issued the key — there is no `X-Store-Id` override.


        Keys are created in the Leyyow merchant dashboard under **Settings →
        Developer → API Keys**.

````