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

# Find which retail chains carry a brand or category

> Which retail CHAINS carry a brand or a category, ranked by how many distinct priced products each lists, with that chain's average and median price. Answers 'who stocks this brand', 'where can I find it', and 'which retailers carry the most of this category'. Grouped on the retailer chain, never on the scrape lane - a lane like 'shopify' spans hundreds of storefronts, so grouping by it would answer 'which retailer' with 'shopify'. At least one of brand or category is required. Price statistics exclude rows the pipeline flagged as incoherent while the COUNTS keep them: a chain that genuinely carries the brand should not disappear because one of its prices is wrong. DISTINCT from share-of-shelf, which answers which BRANDS hold a category's shelf.



## OpenAPI

````yaml https://api.syntalic.com/openapi.json get /v1/marketing/retailer-assortment
openapi: 3.1.0
info:
  title: 'Syntalic — Data Analytics for Agentic Commerce '
  version: 1.0.0
  contact:
    name: Syntalic
    email: support@syntalic.com
    url: https://syntalic.com
  description: >-
    Competitive pricing data across US and Canadian e-commerce retailers
    (Amazon, Walmart, Target, Best Buy, Home Depot, etc.). Serves price
    comparisons, deal alerts, brand tracking, promotional intelligence, and
    market analytics to AI agents via x402 and MPP micropayments.
  x-guidance: >-
    This API has three endpoint groups organized by use case:


    **Shopper endpoints** ($0.01/query): Use these for price comparisons and
    deal hunting. Start with /v1/shopper/best-price?q=<product> to find the
    cheapest option across retailers. Use
    /v1/shopper/deal-finder?category=<category> to find discounted products. Use
    /v1/shopper/price-drop-alert?q=<product> to check for recent price drops.


    **Marketing endpoints** ($0.01/query): Use these for competitive analysis.
    /v1/marketing/competitive-landscape?category=<category> shows all products
    in a category with pricing. /v1/marketing/brand-tracker?brand=<brand> tracks
    a brand's pricing over time.
    /v1/marketing/share-of-shelf?category=<category> shows brand market share.


    **Analyst endpoints** ($0.02/query): Use these for market-level insights.
    /v1/analyst/inflation?category=<category> shows price trends over time.
    /v1/analyst/price-dispersion?category=<category> shows price spread across
    retailers.


    All endpoints accept an optional 'country' parameter (us or ca, defaults to
    us). Query parameters use 'q' for free-text search and 'category' for
    category-level queries.


    Marketing and analyst responses carry a `meta` block (served_from,
    freshness_seconds, schema_version) for staleness budgeting and a `resolved`
    block describing how the category input was matched against the taxonomy.
    Every response also sends an X-Data-Freshness-Hours header.


    **Free pre-payment rejection:** requests that cannot be served are rejected
    BEFORE any payment challenge — invalid params (400 INVALID_PARAMS),
    retailers that are not serving-eligible (404 RETAILER_NOT_SERVING_ELIGIBLE,
    with the catalog quality status and the serving_eligible_retailers list in
    error.details), and shopper queries that resolve to nothing in the catalog
    (404 NO_RESULTS). You only pay when the API can actually execute your query.
    Retailer values are case-insensitive (amazon == Amazon).
servers:
  - url: https://api.syntalic.com
security: []
paths:
  /v1/marketing/retailer-assortment:
    get:
      tags:
        - Marketing
      summary: Find which retail chains carry a brand or category
      description: >-
        Which retail CHAINS carry a brand or a category, ranked by how many
        distinct priced products each lists, with that chain's average and
        median price. Answers 'who stocks this brand', 'where can I find it',
        and 'which retailers carry the most of this category'. Grouped on the
        retailer chain, never on the scrape lane - a lane like 'shopify' spans
        hundreds of storefronts, so grouping by it would answer 'which retailer'
        with 'shopify'. At least one of brand or category is required. Price
        statistics exclude rows the pipeline flagged as incoherent while the
        COUNTS keep them: a chain that genuinely carries the brand should not
        disappear because one of its prices is wrong. DISTINCT from
        share-of-shelf, which answers which BRANDS hold a category's shelf.
      operationId: getRetailerAssortment
      parameters:
        - name: brand
          in: query
          required: false
          schema:
            type: string
            minLength: 1
          description: Brand name (e.g., Sony, Samsung, Nike)
          example: Apple
        - name: category
          in: query
          required: false
          schema:
            type: string
            minLength: 1
          description: >-
            Product category. Accepts a human-readable name (e.g. 'electronics',
            'beauty') or a taxonomy slug path (e.g. 'electronics/headphones');
            matched against the catalog's category tree (exact node, subtree, or
            path substring). Also accepts a GS1 GPC code (exactly 8 digits, e.g.
            '10001159') to filter by PRODUCT TYPE instead of by shelf placement
            — the same product type is shelved under different categories by
            different retailers, so a category filter answers from a fraction of
            the data while a GPC code spans them. Coarser codes
            (class/family/segment) match every brick beneath them. Resolve a
            phrase to a code with /v1/reference/classify?q=... ; when a code is
            used, resolved.match_source is 'gpc'.
          example: electronics
        - name: country
          in: query
          required: false
          schema:
            type: string
            enum:
              - us
              - ca
            default: us
          description: Country (us or ca)
          example: us
      responses:
        '200':
          description: Retailer assortment
          content:
            application/json:
              schema:
                type: object
                properties:
                  brand:
                    type: string
                    nullable: true
                  category:
                    type: string
                    nullable: true
                  country:
                    type: string
                  currency:
                    type: string
                  retailers:
                    type: array
                    items:
                      type: object
                      properties:
                        seller:
                          type: string
                        product_count:
                          type: integer
                        avg_price_usd:
                          type: number
                          nullable: true
                        median_price_usd:
                          type: number
                          nullable: true
                  coverage:
                    type: object
                    description: >-
                      How much data backed this answer. `sufficient` is false
                      when the slice is too thin to read as a market statement;
                      the count is always reported so you can judge for
                      yourself, and `note` explains an empty or thin result
                      rather than leaving you to infer it.
                    properties:
                      products:
                        type: integer
                        example: 42
                      sufficient:
                        type: boolean
                        example: true
                      note:
                        type: string
                      unpublished_note:
                        type: string
                        description: >-
                          Names columns that came back null on EVERY row because
                          the publish job writes them unpopulated, not because
                          the subjects lack the attribute. Never infer a zero or
                          an absence from a column named here.
                      sku_note:
                        type: string
                        description: >-
                          Present when `skus` is null on every row returned.
                          Read the column as unavailable for this run, not as a
                          stocking fact.
                      rank_note:
                        type: string
                        description: >-
                          Present when brands carry `tied_with`. Says how many,
                          and that the tie list is pairwise proximity rather
                          than an equivalence class.
                    additionalProperties: true
                  freshness:
                    type: object
                    description: >-
                      How current the underlying observations are.
                      `observedThrough` is the newest observation behind this
                      answer; `staleHours` is its age. Both null when nothing
                      was observed.
                    properties:
                      observedThrough:
                        type: string
                        format: date-time
                        nullable: true
                      staleHours:
                        type: number
                        nullable: true
                        example: 6.5
                    additionalProperties: true
                  quality:
                    type: object
                    additionalProperties: true
                    nullable: true
                  resolved:
                    type: object
                    properties:
                      input:
                        type: string
                      category_path:
                        type: string
                        nullable: true
                      department:
                        type: string
                        nullable: true
                      match_source:
                        type: string
                        nullable: true
                      match_confidence:
                        type: number
                        nullable: true
                      alternates:
                        type: array
                        items:
                          type: object
                          additionalProperties: true
                    additionalProperties: true
                  meta:
                    type: object
                    properties:
                      served_from:
                        type: string
                      freshness_seconds:
                        type: number
                      schema_version:
                        type: string
                      computed_at:
                        type: string
                        format: date-time
                      price_observed_at_min:
                        type: string
                        format: date-time
                        nullable: true
                      price_observed_at_max:
                        type: string
                        format: date-time
                        nullable: true
                    additionalProperties: true
        '400':
          description: >-
            Invalid query parameters or unsupported enum values. Rejected by
            preflight BEFORE the payment challenge — no payment is requested or
            charged for malformed requests.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                properties:
                  type:
                    type: string
                    format: uri-reference
                  title:
                    type: string
                    example: Bad Request
                  status:
                    type: integer
                    const: 400
                  detail:
                    type: string
                  instance:
                    type: string
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      details:
                        type: object
                        additionalProperties: true
                    additionalProperties: true
                additionalProperties: true
        '402':
          description: Payment challenge required before executing paid work
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                properties:
                  type:
                    type: string
                    format: uri-reference
                  title:
                    type: string
                    example: Payment Required
                  status:
                    type: integer
                    const: 402
                  detail:
                    type: string
                  instance:
                    type: string
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      details:
                        type: object
                        additionalProperties: true
                    additionalProperties: true
                additionalProperties: true
        '404':
          description: >-
            No matching result. error.code distinguishes the cases: NO_RESULTS
            (the query resolves to nothing in the catalog),
            RETAILER_NOT_SERVING_ELIGIBLE (the requested retailer exists but is
            not serving-eligible — error.details carries its catalog
            quality_status and the serving_eligible_retailers list to retry
            against), or NOT_PUBLISHED (a social rollup the current publish run
            does not compute yet — a gap in what we publish, not a finding about
            the category). Structurally-unservable requests are rejected by
            preflight before any payment challenge.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                properties:
                  type:
                    type: string
                    format: uri-reference
                  title:
                    type: string
                    example: Not Found
                  status:
                    type: integer
                    const: 404
                  detail:
                    type: string
                  instance:
                    type: string
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      details:
                        type: object
                        additionalProperties: true
                    additionalProperties: true
                additionalProperties: true
        '429':
          description: Rate limit exceeded
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                properties:
                  type:
                    type: string
                    format: uri-reference
                  title:
                    type: string
                    example: Too Many Requests
                  status:
                    type: integer
                    const: 429
                  detail:
                    type: string
                  instance:
                    type: string
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      details:
                        type: object
                        additionalProperties: true
                    additionalProperties: true
                additionalProperties: true
        '500':
          description: Unexpected server error
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                properties:
                  type:
                    type: string
                    format: uri-reference
                  title:
                    type: string
                    example: Internal Server Error
                  status:
                    type: integer
                    const: 500
                  detail:
                    type: string
                  instance:
                    type: string
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      details:
                        type: object
                        additionalProperties: true
                    additionalProperties: true
                additionalProperties: true

````