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

# Resolve product query to nearby store availability

> Accepts a natural-language product query plus a geographic anchor and optional filtering constraints (certifications, allergens, substances, price, nutrients) and returns ranked product matches with real-time nearby store availability.

**Ranking** is a blend of semantic similarity to ``query``, proximity to ``location.latitude``/``location.longitude`` (within ``radius_km``), and constraint compliance. Each result carries a list of ``StoreAvailabilityOut`` rows sorted closest-first.

**Constraints** in the payload are merged with the authenticated user's saved preferences (explicit payload wins on conflict); a missing ``constraints`` key means use the user's preferences as-is.

**Empty results** return ``200`` with ``results: []`` — the endpoint does not 404 when nothing matches.



## OpenAPI

````yaml /openapi/openapi-agent.json post /agent/api/v1/resolve
openapi: 3.1.0
info:
  title: Agentic Commerce API
  version: 1.0.0
  description: >
    Structured API for AI shopping assistants (ChatGPT, Gemini, Perplexity) to
    resolve product availability at nearby stores via tool use. Accepts
    natural-language product queries with geographic context and returns ranked
    results with real-time store availability.


    ## Authentication


    All endpoints require an API key passed via the `X-API-Key` HTTP header,
    unless otherwise noted.


    ```

    X-API-Key: csb_<body>_<checksum>

    ```


    Generate API keys in **Settings > API Keys** in your dashboard, or via the
    Account API.

    Session-based (cookie) authentication is also accepted for browser-based
    access.


    ## Rate Limits


    | Tier        | Requests / minute | Requests / day |

    |-------------|-------------------|----------------|

    | Default     | 300               | 10,000         |

    | Custom      | Contact us        | Contact us     |


    Rate-limit headers are included on every response so callers can
    self-throttle without

    hitting our 429s ("informed governor"):


    - `RateLimit-Policy` — every active window, e.g. `300;w=60, 10000;w=86400`

    - `RateLimit-Limit` — quota for the **most-restrictive** currently-active
    window

    - `RateLimit-Remaining` — requests left in that window

    - `RateLimit-Reset` — seconds until that window resets (relative; clock-skew
    safe)


    Legacy `X-RateLimit-*` aliases are also emitted for back-compat.
    `X-RateLimit-Reset`

    keeps the absolute Unix-timestamp shape to avoid breaking existing
    consumers.


    When rate-limited, you receive `429 Too Many Requests` with a
    `retry_after_seconds` field

    in the error envelope and a `Retry-After` header.


    ## Pagination


    List endpoints return paginated results in this envelope:


    ```json

    {
      "data": [...],
      "pagination": {
        "page": 1,
        "page_size": 25,
        "total_count": 342,
        "total_pages": 14,
        "has_next": true,
        "has_previous": false
      }
    }

    ```


    Use `?page=2&page_size=50` query parameters. Maximum page size is 100.


    ## Error Responses


    All errors conform to [RFC 9457 Problem
    Details](https://www.rfc-editor.org/rfc/rfc9457)

    with `Content-Type: application/problem+json`:


    ```json

    {
      "type": "https://closient.com/docs/errors/not_found",
      "title": "Not Found",
      "status": 404,
      "detail": "The requested resource was not found.",
      "error_code": "not_found",
      "retryable": false,
      "timestamp": "2026-03-31T12:00:00+00:00"
    }

    ```


    Common error codes: `unauthorized` (401), `forbidden` (403), `not_found`
    (404),

    `validation_error` (422), `rate_limited` (429), `internal_error` (500).
  termsOfService: https://www.closient.com/terms/
servers:
  - url: https://www.closient.com
security: []
tags:
  - name: Resolve
    description: Resolve product queries to nearby store availability.
  - name: Products
    description: Retrieve detailed product information by GTIN.
  - name: Availability
    description: Check store availability for a known product.
externalDocs:
  description: Closient Documentation
  url: https://docs.closient.com
paths:
  /agent/api/v1/resolve:
    post:
      tags:
        - Resolve
      summary: Resolve product query to nearby store availability
      description: >-
        Accepts a natural-language product query plus a geographic anchor and
        optional filtering constraints (certifications, allergens, substances,
        price, nutrients) and returns ranked product matches with real-time
        nearby store availability.


        **Ranking** is a blend of semantic similarity to ``query``, proximity to
        ``location.latitude``/``location.longitude`` (within ``radius_km``), and
        constraint compliance. Each result carries a list of
        ``StoreAvailabilityOut`` rows sorted closest-first.


        **Constraints** in the payload are merged with the authenticated user's
        saved preferences (explicit payload wins on conflict); a missing
        ``constraints`` key means use the user's preferences as-is.


        **Empty results** return ``200`` with ``results: []`` — the endpoint
        does not 404 when nothing matches.
      operationId: apps_agent_api_resolve_resolve
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolveIn'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResolveOut'
        '400':
          description: Bad Request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ErrorOut'
        '404':
          description: Not Found
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ErrorOut'
        '405':
          description: Method Not Allowed
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ErrorOut'
        '422':
          description: Unprocessable Content
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ErrorOut'
        '429':
          description: Too Many Requests
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ErrorOut'
      security:
        - APIKeyHeaderAuth: []
        - OAuthTokenAuth: []
        - CookieGatedSessionAuth: []
        - {}
components:
  schemas:
    ResolveIn:
      description: |-
        Input for the product resolution endpoint.

        Encapsulates a free-form shopper question, a geographic anchor, and
        optional constraints. The agent API combines these with the
        authenticated user's saved preferences (explicit payload wins on
        conflict) to produce ranked product matches with nearby store
        availability.
      examples:
        - constraints:
            certifications:
              - USDA Organic
            exclude_major_allergens: true
            price_max: 8.99
          limit: 5
          location:
            latitude: 40.7128
            longitude: -74.006
          query: organic almond milk
          radius_km: 10
      properties:
        query:
          description: >-
            Natural-language product query as the shopper would phrase it (e.g.
            'organic almond milk', 'gluten-free pasta sauce'). The resolver runs
            hybrid semantic + lexical search; brand and category hints in the
            query are used for ranking.
          maxLength: 500
          minLength: 1
          title: Query
          type: string
        location:
          $ref: '#/components/schemas/LocationIn'
          description: >-
            Shopper's geographic anchor for proximity ranking. Stores within
            ``radius_km`` of this point are considered for availability.
        constraints:
          anyOf:
            - $ref: '#/components/schemas/ConstraintsIn'
            - type: 'null'
          description: >-
            Optional product-filter constraints. Merged with the authenticated
            user's saved preferences (explicit payload wins on conflict). Null
            means use the user's preferences as-is.
        radius_km:
          default: 10
          description: >-
            Search radius in kilometers from ``location``. Stores beyond this
            distance are excluded from availability. Capped at 100 km.
          exclusiveMinimum: 0
          maximum: 100
          title: Radius Km
          type: number
        limit:
          default: 5
          description: >-
            Maximum number of distinct product results to return. Each product
            may carry multiple ``StoreAvailabilityOut`` entries — this bound is
            on the **product** count, not the per-store availability list.
          maximum: 25
          minimum: 1
          title: Limit
          type: integer
      required:
        - query
        - location
      title: ResolveIn
      type: object
    ResolveOut:
      description: |-
        Response from the ``POST /resolve`` endpoint.

        Top-level container holds the ranked product matches; the ranking is
        a blend of semantic similarity to ``query``, proximity to
        ``location``, and constraint compliance.
      examples:
        - results:
            - availability:
                - distance_km: 0.42
                  in_stock: true
                  retailer: Whole Foods
              product:
                brand: Acme
                gtin: '00012345600012'
                name: Acme Trail Mix
        - results: []
      properties:
        results:
          default: []
          description: >-
            Matched products with their nearby store availability, ranked
            best-match first. Empty list when nothing matches the query and
            constraints; the endpoint does not 404 on no-match.
          items:
            $ref: '#/components/schemas/ResolveResultOut'
          title: Results
          type: array
      title: ResolveOut
      type: object
    ErrorOut:
      title: ErrorOut
      type: object
      description: RFC 9457 Problem Details error body.
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        error_code:
          type: string
        retryable:
          type: boolean
        timestamp:
          type: string
          format: date-time
      required:
        - type
        - title
        - status
        - detail
      examples:
        - type: https://closient.com/docs/errors/not_found
          title: Not Found
          status: 404
          detail: The requested resource was not found.
          error_code: not_found
          retryable: false
          timestamp: '2026-03-31T12:00:00+00:00'
    LocationIn:
      description: Geographic coordinates for proximity-based search.
      examples:
        - latitude: 40.7128
          longitude: -74.006
      properties:
        latitude:
          description: >-
            Latitude in decimal degrees (WGS84 / EPSG:4326). Positive values are
            north of the equator; negative are south. Required for proximity
            ranking.
          maximum: 90
          minimum: -90
          title: Latitude
          type: number
        longitude:
          description: >-
            Longitude in decimal degrees (WGS84 / EPSG:4326). Positive values
            are east of the prime meridian; negative are west. Required for
            proximity ranking.
          maximum: 180
          minimum: -180
          title: Longitude
          type: number
      required:
        - latitude
        - longitude
      title: LocationIn
      type: object
    ConstraintsIn:
      description: |-
        Product filtering constraints for the resolve endpoint.

        All filters are ANDed together and applied **in addition to** any
        constraints derived from the authenticated user's saved preferences
        (the explicit payload wins on conflict). Empty lists / null values
        mean "no filter on this dimension".
      examples:
        - allergen_free:
            - Peanuts
          category_path: Food, Beverages & Tobacco > Beverages
          certifications:
            - USDA Organic
          claims:
            - Vegan
          exclude_major_allergens: true
          nutrients_max:
            SODIUM: 140
          nutrients_min:
            PROTEIN: 20
          price_max: 9.99
      properties:
        certifications:
          default: []
          description: >-
            Required certification labels — products must have **all** listed
            certifications. Match is case-sensitive against
            ``Certification.label`` (e.g. 'USDA Organic', 'Fair Trade
            Certified'). Empty list means no filter.
          items:
            type: string
          title: Certifications
          type: array
        substances_exclude:
          default: []
          description: >-
            Substance names to exclude — products containing **any** of these
            are removed from results. Match is case-insensitive against
            ``Substance.name`` (e.g. 'BPA', 'Phthalates', 'High Fructose Corn
            Syrup').
          items:
            type: string
          title: Substances Exclude
          type: array
        substances_include:
          default: []
          description: >-
            Substance names that must be present — products are included only if
            they contain **all** listed substances. Use for positive ingredient
            filters (e.g. 'Almonds', 'Olive Oil').
          items:
            type: string
          title: Substances Include
          type: array
        claims:
          default: []
          description: >-
            Required claim labels — products must have **all** listed claims.
            Match is case-sensitive against ``Claim.label`` (e.g. 'Vegan',
            'Non-GMO', 'Gluten-Free'). Empty list means no filter.
          items:
            type: string
          title: Claims
          type: array
        allergen_free:
          default: []
          description: >-
            Allergens that must not be present — products containing **any** of
            these (as a substance flagged ``is_major_allergen`` or matching by
            name) are removed (e.g. 'Peanuts', 'Tree Nuts', 'Dairy').
          items:
            type: string
          title: Allergen Free
          type: array
        exclude_major_allergens:
          default: false
          description: >-
            If true, exclude products containing any substance flagged
            ``is_major_allergen`` (FDA top-9 / EU 14). Combined with
            ``allergen_free`` via OR: a product is excluded if it matches
            **either** filter.
          title: Exclude Major Allergens
          type: boolean
        price_max:
          anyOf:
            - minimum: 0
              type: number
            - type: 'null'
          description: >-
            Maximum price in USD. Offers with ``price > price_max`` are
            excluded; offers with no price set are kept (so listings without a
            price still appear). Null means no price ceiling.
          title: Price Max
        category_path:
          anyOf:
            - maxLength: 500
              type: string
            - type: 'null'
          description: >-
            Google Product Taxonomy category-path **prefix** to filter by (e.g.
            'Food, Beverages & Tobacco > Beverages'). Matches any descendant
            category. Null means no category filter.
          title: Category Path
        nutrients_min:
          additionalProperties:
            type: number
          description: >-
            Minimum nutrient amounts (per serving) keyed by ``NutrientType``
            value (e.g. ``{'PROTEIN': 20}`` requires >= 20g protein). Products
            without nutrition facts are **excluded** when this filter is
            non-empty. Units are the canonical ``NutrientUnit`` for that
            nutrient (typically g/mg/kcal).
          title: Nutrients Min
          type: object
        nutrients_max:
          additionalProperties:
            type: number
          description: >-
            Maximum nutrient amounts (per serving) keyed by ``NutrientType``
            value (e.g. ``{'SODIUM': 140, 'CALORIES': 200}`` excludes products
            with > 140mg sodium or > 200kcal). Products without nutrition facts
            are **excluded** when this filter is non-empty.
          title: Nutrients Max
          type: object
      title: ConstraintsIn
      type: object
    ResolveResultOut:
      description: A single product result with its nearby store availability.
      examples:
        - availability:
            - address: 123 Main St, Springfield, IL
              currency: USD
              distance_km: 0.42
              in_stock: true
              price: '5.99'
              retailer: Whole Foods
          product:
            brand: Acme
            gtin: '00012345600012'
            name: Acme Organic Trail Mix 200g
      properties:
        product:
          $ref: '#/components/schemas/ProductOut'
          description: Product summary information.
        availability:
          default: []
          description: >-
            Nearby store availability for this product, sorted by
            ``distance_km`` ascending (closest first). Empty when no in-stock
            offer is within ``radius_km`` of the user's location.
          items:
            $ref: '#/components/schemas/StoreAvailabilityOut'
          title: Availability
          type: array
      required:
        - product
      title: ResolveResultOut
      type: object
    ProductOut:
      description: |-
        Summary product information returned in resolve results.

        Lightweight projection used for the ``resolve`` list view — see
        :class:`ProductDetailOut` for the full per-product detail (substances,
        certification metadata, claim provenance) returned by the
        ``products/{gtin}`` detail endpoint.
      examples:
        - brand: Acme Beverages
          category: Food, Beverages & Tobacco > Beverages > Milk
          certifications:
            - USDA Organic
            - Non-GMO Project Verified
          claims:
            - Vegan
            - Gluten-Free
          description: Creamy organic almond milk, unsweetened.
          gtin: '00012345678905'
          image_url: https://cdn.closient.com/products/00012345678905/hero.jpg
          name: Organic Almond Milk
          net_content: 500ml
      properties:
        gtin:
          description: >-
            GTIN-14 identifier (always 14 digits, zero-padded). Input
            GTIN-8/12/13 values are normalized to GTIN-14 by the resolver.
          maxLength: 14
          minLength: 14
          pattern: ^\d{14}$
          title: Gtin
          type: string
        name:
          description: Product name as it appears on the package or marketing copy.
          title: Name
          type: string
        brand:
          description: Brand name (the consumer-facing brand, not the manufacturer).
          title: Brand
          type: string
        description:
          description: >-
            Marketing description of the product. May be empty when no
            description is on file; never null.
          title: Description
          type: string
        image_url:
          description: >-
            Absolute HTTPS URL of the product hero image. Empty string when no
            image is on file; never null.
          title: Image Url
          type: string
        category:
          description: >-
            Google Product Taxonomy full category path (e.g. 'Food, Beverages &
            Tobacco > Beverages > Milk'). Empty string when no category is
            assigned.
          title: Category
          type: string
        certifications:
          default: []
          description: >-
            Active certification labels held by this product (label-only
            summary; see :class:`ProductDetailOut` for full validity /
            verification metadata).
          items:
            type: string
          title: Certifications
          type: array
        claims:
          default: []
          description: >-
            Active claim labels held by this product (label-only summary; see
            :class:`ProductDetailOut` for full source / validity metadata).
          items:
            type: string
          title: Claims
          type: array
        net_content:
          description: >-
            Net content with unit as a single human-readable string (e.g.
            '500ml', '1kg', '12 fl oz'). Empty string when unknown.
          title: Net Content
          type: string
      required:
        - gtin
        - name
        - brand
        - description
        - image_url
        - category
        - net_content
      title: ProductOut
      type: object
    StoreAvailabilityOut:
      description: |-
        Store-level availability information for a product.

        Returned both as ``ResolveResultOut.availability`` items (resolve flow)
        and as the top-level list from ``GET /products/{gtin}/availability``.
        Stores are sorted by distance ascending (closest first).
      examples:
        - address: 270 Greenwich St, New York, NY, 10007
          distance_km: 1.23
          last_verified: '2026-04-30T14:22:00Z'
          price: $4.99
          stock_confidence: active
          stock_status: In Stock
          store: Whole Foods Tribeca
      properties:
        store:
          description: >-
            Store / branch name as the shopper would recognize it (e.g. 'Whole
            Foods Tribeca'). Sourced from ``Place.name``.
          title: Store
          type: string
        address:
          description: >-
            Comma-joined street address ('line 1, city, region, postal_code').
            Components missing on the underlying ``Place`` are omitted from the
            joined string.
          title: Address
          type: string
        distance_km:
          description: >-
            Great-circle distance from the user's location to this store, in
            kilometers, rounded to 2 decimals. Zero when the distance could not
            be computed.
          minimum: 0
          title: Distance Km
          type: number
        stock_status:
          $ref: '#/components/schemas/StockStatusDisplayEnum'
          description: >-
            Customer-facing stock label derived from the underlying offer
            status. Use this when surfacing availability to a shopper. See
            ``stock_confidence`` for the machine-readable wire value.
        stock_confidence:
          $ref: '#/components/schemas/OfferStatusEnum'
          description: >-
            Wire value of the underlying ``InStoreOffer.status``
            (``apps.retailers.models.OfferStatus``). Use this for programmatic
            decisions; see ``stock_status`` for the display label.
        price:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Pre-formatted price string with currency symbol (e.g. '$4.99'). Null
            when no price is on file for this store.
          title: Price
        last_verified:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            ISO 8601 timestamp of the last inventory verification on the
            underlying ``InStoreOffer.quantity_updated_at``. Null when the offer
            has never had a quantity update.
          title: Last Verified
      required:
        - store
        - address
        - distance_km
        - stock_status
        - stock_confidence
      title: StoreAvailabilityOut
      type: object
    StockStatusDisplayEnum:
      description: |-
        Customer-facing stock label rendered alongside ``stock_confidence``.

        Derived from :class:`apps.retailers.models.OfferStatus` via a fixed
        presentation map in :mod:`apps.agent.services.resolve`. Distinct from
        the raw ``OfferStatusEnum`` (the wire/machine value) — the display
        string is what an AI assistant should surface to a shopper, while
        ``stock_confidence`` is what it should reason about programmatically.
      enum:
        - In Stock
        - Discontinued
        - Seasonal
        - Out of Stock
        - Unknown
      title: StockStatusDisplayEnum
      type: string
    OfferStatusEnum:
      enum:
        - active
        - discontinued
        - seasonal
        - out_of_stock
      title: OfferStatusEnum
      type: string
  securitySchemes:
    APIKeyHeaderAuth:
      type: apiKey
      in: header
      name: X-API-Key
    OAuthTokenAuth:
      type: http
      scheme: bearer
    CookieGatedSessionAuth:
      type: apiKey
      in: cookie
      name: sessionid

````