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

# Search products

> Finds Etsy products (other sellers' listings) by words, category, price, estimated sales, reviews, listing date, maker and shop country, sorted by relevance or a field. Returns product summaries with Alura's sales estimates; the totals stop counting at 10,000 and paging stops after 10,000 results. Only active listings are searched. Shops that opted out of Alura never appear. Costs 10 API credits per page with results; an empty page is free.

Cost: 10 API credits per page.



## OpenAPI

````yaml /openapi.json get /v1/research/products
openapi: 3.1.0
info:
  title: Alura API
  version: 1.0.0
  description: Etsy market research for scripts and AI assistants.
servers:
  - url: https://api.alura.io
security:
  - apiKey: []
paths:
  /v1/research/products:
    get:
      summary: Search products
      description: >-
        Finds Etsy products (other sellers' listings) by words, category, price,
        estimated sales, reviews, listing date, maker and shop country, sorted
        by relevance or a field. Returns product summaries with Alura's sales
        estimates; the totals stop counting at 10,000 and paging stops after
        10,000 results. Only active listings are searched. Shops that opted out
        of Alura never appear. Costs 10 API credits per page with results; an
        empty page is free.


        Cost: 10 API credits per page.
      operationId: research.products.search
      parameters:
        - name: q
          in: query
          required: false
          description: >-
            Words to find in the title, tags, materials, category or shop name;
            every word must match.
          schema:
            description: >-
              Words to find in the title, tags, materials, category or shop
              name; every word must match.
            type: string
            example: mug
        - name: category_id
          in: query
          required: false
          description: >-
            An Etsy category ID (see /v1/categories); matches the category and
            every category under it.
          schema:
            type: string
            pattern: ^[1-9][0-9]{0,9}$
            description: >-
              An Etsy category ID (see /v1/categories); matches the category and
              every category under it.
        - name: price_min
          in: query
          required: false
          description: Lowest price in USD.
          schema:
            description: Lowest price in USD.
            type: string
            pattern: ^\d{1,9}(\.\d{1,2})?$
        - name: price_max
          in: query
          required: false
          description: Highest price in USD.
          schema:
            description: Highest price in USD.
            type: string
            pattern: ^\d{1,9}(\.\d{1,2})?$
            example: '30'
        - name: est_sales_min
          in: query
          required: false
          description: >-
            Fewest estimated lifetime sales.


            Estimate: see the methodology (version 2026-10) at
            https://docs.alura.io/methodology/sales-estimates.
          schema:
            description: Fewest estimated lifetime sales.
            type: string
            pattern: ^\d{1,10}$
        - name: est_sales_max
          in: query
          required: false
          description: >-
            Most estimated lifetime sales.


            Estimate: see the methodology (version 2026-10) at
            https://docs.alura.io/methodology/sales-estimates.
          schema:
            description: Most estimated lifetime sales.
            type: string
            pattern: ^\d{1,10}$
        - name: est_monthly_sales_min
          in: query
          required: false
          description: >-
            Fewest estimated sales per month (average).


            Estimate: see the methodology (version 2026-10) at
            https://docs.alura.io/methodology/sales-estimates.
          schema:
            description: Fewest estimated sales per month (average).
            type: string
            pattern: ^\d{1,10}$
        - name: est_monthly_sales_max
          in: query
          required: false
          description: >-
            Most estimated sales per month (average).


            Estimate: see the methodology (version 2026-10) at
            https://docs.alura.io/methodology/sales-estimates.
          schema:
            description: Most estimated sales per month (average).
            type: string
            pattern: ^\d{1,10}$
        - name: reviews_min
          in: query
          required: false
          description: Fewest reviews.
          schema:
            description: Fewest reviews.
            type: string
            pattern: ^\d{1,10}$
        - name: listed_after
          in: query
          required: false
          description: Listed on Etsy at or after this time.
          schema:
            description: Listed on Etsy at or after this time.
            type: string
            pattern: >-
              ^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2}))?$
        - name: listed_before
          in: query
          required: false
          description: Listed on Etsy at or before this time.
          schema:
            description: Listed on Etsy at or before this time.
            type: string
            pattern: >-
              ^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2}))?$
        - name: who_made
          in: query
          required: false
          description: Who made the product.
          schema:
            type: string
            enum:
              - i_did
              - someone_else
              - collective
            description: Who made the product.
        - name: when_made
          in: query
          required: false
          description: When the product was made.
          schema:
            type: string
            enum:
              - made_to_order
              - 2020_2025
              - 2020_2024
              - 2020_2023
              - 2010_2019
              - 2006_2009
              - 2000_2005
              - before_2006
              - 1990s
              - 1980s
              - 1970s
              - 1960s
              - 1950s
              - 1940s
              - 1930s
              - 1920s
              - 1910s
              - 1900s
              - 1800s
              - 1700s
              - before_1700
            description: When the product was made.
        - name: is_digital
          in: query
          required: false
          description: '`true`: digital downloads only; `false`: physical products only.'
          schema:
            description: '`true`: digital downloads only; `false`: physical products only.'
            type: string
            enum:
              - 'true'
              - 'false'
        - name: is_personalizable
          in: query
          required: false
          description: Whether the seller offers personalization.
          schema:
            description: Whether the seller offers personalization.
            type: string
            enum:
              - 'true'
              - 'false'
        - name: free_shipping
          in: query
          required: false
          description: Whether shipping is free.
          schema:
            description: Whether shipping is free.
            type: string
            enum:
              - 'true'
              - 'false'
        - name: shop_country
          in: query
          required: false
          description: The shop's country, as an ISO 3166-1 alpha-2 code (`US`).
          schema:
            description: The shop's country, as an ISO 3166-1 alpha-2 code (`US`).
            type: string
            pattern: ^[A-Za-z]{2}$
        - name: sort
          in: query
          required: false
          description: >-
            `relevance` (default: best match for `q`, else most estimated
            sales), or a field. Sorting by a field leaves out products where
            that value is unknown. `est_revenue` orders by Alura's stored
            lifetime revenue, which values each sale at the price when it was
            estimated; `est_lifetime_revenue_usd` values every sale at today's
            price, so products whose price changed can appear out of order by
            that value.


            Estimate: see the methodology (version 2026-10) at
            https://docs.alura.io/methodology/sales-estimates.
          schema:
            default: relevance
            description: >-
              `relevance` (default: best match for `q`, else most estimated
              sales), or a field. Sorting by a field leaves out products where
              that value is unknown. `est_revenue` orders by Alura's stored
              lifetime revenue, which values each sale at the price when it was
              estimated; `est_lifetime_revenue_usd` values every sale at today's
              price, so products whose price changed can appear out of order by
              that value.
            type: string
            enum:
              - relevance
              - est_sales
              - est_monthly_sales
              - est_revenue
              - price
              - newest
              - reviews
              - listing_score
            example: est_sales
        - name: order
          in: query
          required: false
          description: >-
            `desc` (default) or `asc`. Not accepted with `sort=relevance`, which
            is always best match first.
          schema:
            type: string
            enum:
              - asc
              - desc
            description: >-
              `desc` (default) or `asc`. Not accepted with `sort=relevance`,
              which is always best match first.
        - name: limit
          in: query
          required: false
          description: 'Page size: default 25, at most 100.'
          schema:
            type: integer
            minimum: 1
            maximum: 100
        - name: cursor
          in: query
          required: false
          description: >-
            The `next_cursor` of the previous page. Bound to the query, the
            workspace and the key.
          schema:
            type: string
        - name: fields
          in: query
          required: false
          description: >-
            Comma-separated dotted paths to return; `id`, `object` and `as_of`
            always come back.
          schema:
            type: string
      responses:
        '200':
          description: OK
          headers:
            Request-Id:
              $ref: '#/components/headers/Request-Id'
            Alura-Credits-Cost:
              $ref: '#/components/headers/Alura-Credits-Cost'
            Alura-Credits-Remaining:
              $ref: '#/components/headers/Alura-Credits-Remaining'
          content:
            application/json:
              schema:
                type: object
                properties:
                  object:
                    type: string
                    const: list
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        object:
                          type: string
                          const: research.product
                        id:
                          type: string
                          description: Etsy ID, as a string.
                        title:
                          type:
                            - string
                            - 'null'
                        url:
                          type: string
                          description: The listing on Etsy.
                        shop:
                          type: object
                          properties:
                            id:
                              type: string
                              description: Etsy ID, as a string.
                            name:
                              type:
                                - string
                                - 'null'
                          required:
                            - id
                            - name
                          additionalProperties: false
                        price:
                          anyOf:
                            - type: object
                              properties:
                                amount:
                                  type: string
                                  description: >-
                                    Decimal string in the listing's own
                                    currency.
                                currency:
                                  type: string
                                  description: ISO 4217 code.
                                usd:
                                  description: >-
                                    The same price in USD, as a decimal string;
                                    null when no exchange rate is known.
                                  type:
                                    - string
                                    - 'null'
                              required:
                                - amount
                                - currency
                                - usd
                              additionalProperties: false
                              description: The listing's current price.
                            - type: 'null'
                        image_url:
                          description: The primary image (570px wide).
                          type:
                            - string
                            - 'null'
                        category:
                          anyOf:
                            - type: object
                              properties:
                                id:
                                  anyOf:
                                    - type: string
                                      description: Etsy ID, as a string.
                                    - type: 'null'
                                path:
                                  type: array
                                  items:
                                    type: string
                              required:
                                - id
                                - path
                              additionalProperties: false
                            - type: 'null'
                        sales:
                          type: object
                          properties:
                            est_lifetime:
                              type:
                                - number
                                - 'null'
                              description: >-
                                Estimate: see the methodology (version 2026-10)
                                at
                                https://docs.alura.io/methodology/sales-estimates.
                            est_monthly_avg:
                              type:
                                - number
                                - 'null'
                              description: >-
                                Estimate: see the methodology (version 2026-10)
                                at
                                https://docs.alura.io/methodology/sales-estimates.
                            est_lifetime_revenue_usd:
                              type:
                                - number
                                - 'null'
                              description: >-
                                Estimate: see the methodology (version 2026-10)
                                at
                                https://docs.alura.io/methodology/sales-estimates.
                          required:
                            - est_lifetime
                            - est_monthly_avg
                            - est_lifetime_revenue_usd
                          additionalProperties: false
                          description: >-
                            Estimates (methodology:
                            https://docs.alura.io/methodology/sales-estimates).
                            Revenue is valued at the current price.
                        reviews:
                          type: object
                          properties:
                            count:
                              anyOf:
                                - type: integer
                                - type: 'null'
                            average:
                              description: null when there are no reviews.
                              type:
                                - number
                                - 'null'
                          required:
                            - count
                            - average
                          additionalProperties: false
                        favorites:
                          anyOf:
                            - type: integer
                            - type: 'null'
                        listing_score:
                          anyOf:
                            - type: integer
                            - type: 'null'
                          description: Alura's 0-100 listing score.
                        listed_at:
                          anyOf:
                            - type: string
                              description: ISO 8601, UTC.
                            - type: 'null'
                        as_of:
                          anyOf:
                            - type: string
                              description: ISO 8601, UTC.
                            - type: 'null'
                          description: >-
                            When this data was last updated. In search results:
                            when Alura's search copy of the product was last
                            synced (an approximation for older copies; null when
                            unknown), which can differ from the product detail's
                            `as_of`. In a bulk get by `ids`: the product
                            detail's `as_of`.
                      required:
                        - object
                        - id
                        - title
                        - url
                        - shop
                        - price
                        - image_url
                        - category
                        - sales
                        - reviews
                        - favorites
                        - listing_score
                        - listed_at
                        - as_of
                      additionalProperties: false
                  has_more:
                    type: boolean
                  next_cursor:
                    type:
                      - string
                      - 'null'
                  total:
                    type: object
                    properties:
                      value:
                        type: integer
                      relation:
                        type: string
                        enum:
                          - eq
                          - gte
                    required:
                      - value
                      - relation
                    additionalProperties: false
                required:
                  - object
                  - data
                  - has_more
                  - next_cursor
                  - total
                additionalProperties: false
              example:
                object: list
                data:
                  - object: research.product
                    id: '4524717183'
                    title: Personalized Name Mug, Custom Coffee Mug
                    url: https://www.etsy.com/listing/4524717183
                    shop:
                      id: '48911633'
                      name: MugCo
                    price:
                      amount: '24.99'
                      currency: EUR
                      usd: '27.10'
                    image_url: >-
                      https://i.etsystatic.com/48911633/r/il/0a1b2c/4524717183/il_570xN.4524717183_mug1.jpg
                    category:
                      id: '1062'
                      path:
                        - Home & Living
                        - Kitchen & Dining
                        - Drink & Barware
                        - Drinkware
                        - Mugs
                    sales:
                      est_lifetime: 6400
                      est_monthly_avg: 210
                      est_lifetime_revenue_usd: 173440
                    reviews:
                      count: 842
                      average: 4.9
                    favorites: 3120
                    listing_score: 86
                    listed_at: '2023-04-02T10:11:00.000Z'
                    as_of: '2026-10-13T08:05:00.000Z'
                has_more: false
                next_cursor: null
                total:
                  value: 1
                  relation: eq
        '400':
          $ref: '#/components/responses/Problem400'
        '401':
          $ref: '#/components/responses/Problem401'
        '402':
          $ref: '#/components/responses/Problem402'
        '403':
          $ref: '#/components/responses/Problem403'
        '404':
          $ref: '#/components/responses/Problem404'
        '405':
          $ref: '#/components/responses/Problem405'
        '429':
          $ref: '#/components/responses/Problem429'
        '500':
          $ref: '#/components/responses/Problem500'
        '503':
          $ref: '#/components/responses/Problem503'
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >-
            curl
            "https://api.alura.io/v1/research/products?q=mug&price_max=30&sort=est_sales"
            \
              -H "Authorization: Bearer $ALURA_API_KEY"
        - lang: typescript
          label: TypeScript
          source: >-
            const res = await
            fetch('https://api.alura.io/v1/research/products?q=mug&price_max=30&sort=est_sales',
            {
              headers: {
                Authorization: `Bearer ${process.env.ALURA_API_KEY}`,
              },
            });

            console.log(await res.json());
        - lang: python
          label: Python
          source: |-
            import json
            import os
            import urllib.request

            request = urllib.request.Request(
                "https://api.alura.io/v1/research/products?q=mug&price_max=30&sort=est_sales",
                headers={
                    "Authorization": f"Bearer {os.environ['ALURA_API_KEY']}",
                },
            )
            with urllib.request.urlopen(request) as response:
                print(json.load(response))
components:
  headers:
    Request-Id:
      description: '`req_` + ULID; quote it when reporting a problem.'
      schema:
        type: string
    Alura-Credits-Cost:
      description: API credits this call cost.
      schema:
        type: integer
    Alura-Credits-Remaining:
      description: >-
        API credits left in the workspace's monthly allowance, counting calls
        still in flight. Absent when it cannot be read right now.
      schema:
        type: integer
  responses:
    Problem400:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/invalid_request
            title: Invalid request
            status: 400
            code: invalid_request
            detail: Invalid request
            suggestion: Fix the request as the detail says, then send it again.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem401:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/unauthorized
            title: Unauthorized
            status: 401
            code: unauthorized
            detail: Unauthorized
            suggestion: 'Send a valid API key as `Authorization: Bearer alura_sk_...`.'
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem402:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/credits_exhausted
            title: API credits exhausted
            status: 402
            code: credits_exhausted
            detail: API credits exhausted
            suggestion: Upgrade the plan or wait for the monthly reset.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem403:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/plan_required
            title: Plan required
            status: 403
            code: plan_required
            detail: Plan required
            suggestion: Upgrade the workspace plan to use this operation.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem404:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/not_found
            title: Not found
            status: 404
            code: not_found
            detail: Not found
            suggestion: Check the ID, or search for it first.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem405:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/method_not_allowed
            title: Method not allowed
            status: 405
            code: method_not_allowed
            detail: Method not allowed
            suggestion: Use one of the methods in the Allow header.
            retryable: false
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem429:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/rate_limited
            title: Rate limited
            status: 429
            code: rate_limited
            detail: Rate limited
            suggestion: Wait for Retry-After, then retry.
            retryable: true
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem500:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/internal_error
            title: Internal error
            status: 500
            code: internal_error
            detail: Internal error
            suggestion: Retry; if it keeps failing, report the request_id.
            retryable: true
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
    Problem503:
      description: Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://docs.alura.io/errors/credits_unavailable
            title: API credits unavailable
            status: 503
            code: credits_unavailable
            detail: API credits unavailable
            suggestion: Retry shortly.
            retryable: true
            request_id: req_01JQ5W3H8M2N4P6R8T0V2X4Z6B
  schemas:
    Problem:
      type: object
      description: RFC 9457 problem details.
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        code:
          type: string
          description: A code from the error catalog; new codes may be added.
          x-extensible-enum:
            - invalid_request
            - unknown_parameter
            - invalid_cursor
            - cursor_window_exceeded
            - id_type_mismatch
            - invalid_keyword
            - unauthorized
            - credits_exhausted
            - plan_required
            - insufficient_scope
            - workspace_required
            - workspace_locked
            - browser_refused
            - role_required
            - impersonation_refused
            - recent_sign_in_required
            - not_found
            - not_found_on_etsy
            - shop_opted_out
            - method_not_allowed
            - conflict
            - key_limit_reached
            - idempotency_processing
            - unprocessable
            - rate_limited
            - throttled
            - daily_credit_cap_exceeded
            - credits_reserved
            - fetch_limit_reached
            - internal_error
            - upstream_unavailable
            - credits_unavailable
            - service_unavailable
            - fetch_unavailable
            - upstream_timeout
        detail:
          type: string
        suggestion:
          type: string
        retryable:
          type: boolean
        request_id:
          type: string
        upgrade_url:
          type: string
          format: uri
          description: 'credits_exhausted and plan_required: where to upgrade the plan.'
        credits_needed:
          type: integer
          description: 'API credit refusals: what the call needed.'
        credits_remaining:
          type: integer
          description: >-
            API credit refusals: what is left (of the month, or of the day for
            daily_credit_cap_exceeded).
        resets_at:
          type: string
          format: date-time
          description: >-
            credits_exhausted and daily_credit_cap_exceeded: when the limit
            resets.
      required:
        - type
        - title
        - status
        - code
        - detail
        - suggestion
        - retryable
        - request_id
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: 'An API key: `Authorization: Bearer alura_sk_...`.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.