Spree Store API

Customer-facing REST API for browsing products, managing carts, placing orders, and handling checkout. Documented with OpenAPI 3.0.

OpenAPI Specification

spree-store-api.yaml Raw ↑
---
openapi: 3.0.3
info:
  title: Store API
  contact:
    name: Spree Commerce
    url: https://spreecommerce.org
    email: [email protected]
  description: |
    Spree Store API v3 - Customer-facing storefront API for building headless commerce experiences.

    ## Authentication

    The Store API uses two authentication methods:

    ### API Key (Required)
    All requests must include a publishable API key in the `x-spree-api-key` header.

    ### JWT Bearer Token (For authenticated customers)
    After login, include the JWT token in the `Authorization: Bearer <token>` header.

    ### Order Token (For guest checkout)
    When creating an order, a `token` is returned. Include this in the `x-spree-token` header
    for guest access to that specific order.

    ## Response Format

    All responses are JSON. List endpoints return paginated responses with `data` and `meta` keys.

    ## Error Handling

    Errors return a consistent format:
    ```json
    {
      "error": {
        "code": "record_not_found",
        "message": "Product not found"
      }
    }
    ```
  version: v3
paths:
  "/api/v3/store/auth/login":
    post:
      summary: Login
      tags:
      - Authentication
      security:
      - api_key: []
      description: |
        Authenticates a customer and returns a JWT access token + refresh token.

        Dispatches by the `provider` field to a strategy registered in
        `Spree.store_authentication_strategies`. When `provider` is omitted it
        defaults to `email`, which uses the built-in email/password strategy.

        To plug in a third-party identity provider (Auth0, Okta, Firebase, a
        custom JWT issuer, SAML, etc.), register a `Spree::Authentication::Strategies::BaseStrategy`
        subclass under a provider key, then send `{ "provider": "<your_key>", ... }`
        with the fields your strategy requires. The endpoint returns the same
        Spree-issued JWT + refresh token regardless of which strategy authenticated
        the request.
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          const auth = await client.auth.login({
            email: '[email protected]',
            password: 'password123',
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: login successful
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjY0NjcwM2Q0LWY5ZjAtNDlmMi05ZmZkLTA3YTZhY2I5YWZkZiIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjE1fQ.jlz2KHxYkB1Dd9ucl26zy6E5M7dFB5q9g-Qw0YjsX50
                refresh_token: MQ9QZ1ToR8QocZoDd4ggC8yN
                user:
                  id: cus_UkLWZg9DAJ
                  email: [email protected]
                  first_name: Colette
                  last_name: Hegmann
                  phone:
                  accepts_email_marketing: false
                  full_name: Colette Hegmann
                  available_store_credit_total: '0'
                  display_available_store_credit_total: "$0.00"
                  addresses: []
                  default_billing_address:
                  default_shipping_address:
              schema:
                "$ref": "#/components/schemas/AuthResponse"
        '401':
          description: missing API key
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
              - title: EmailPasswordLogin
                description: Built-in email/password authentication (default when
                  `provider` is omitted).
                type: object
                properties:
                  provider:
                    type: string
                    enum:
                    - email
                    default: email
                  email:
                    type: string
                    format: email
                    example: [email protected]
                  password:
                    type: string
                    example: password123
                required:
                - email
                - password
              - title: ProviderLogin
                description: |
                  Provider-dispatched login. The `provider` key selects a registered
                  strategy class; the remaining fields are forwarded to the strategy's
                  `authenticate` method. Required fields depend on the registered strategy
                  — consult its documentation.
                type: object
                properties:
                  provider:
                    type: string
                    example: auth0
                    description: Registered provider key (anything other than `email`).
                    not:
                      enum:
                      - email
                required:
                - provider
                additionalProperties: true
  "/api/v3/store/auth/refresh":
    post:
      summary: Refresh token
      tags:
      - Authentication
      security:
      - api_key: []
      description: Exchanges a refresh token for a new access JWT and rotated refresh
        token. No Authorization header needed.
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          const auth = await client.auth.refresh({
            refresh_token: 'rt_xxx',
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: token refreshed
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjNmZjU3NWU0LTVmNmItNDVjOC04MzIzLTIzMDMyMzVjZTkzMiIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjE2fQ.OuCk-UNe-asA8DvK2yKMkp94BQz9PN_Z7_SnReeIRYE
                refresh_token: qLuZDRo8LqywXFThqPM5V2Ug
                user:
                  id: cus_UkLWZg9DAJ
                  email: [email protected]
                  first_name: Debi
                  last_name: Tillman
                  phone:
                  accepts_email_marketing: false
                  full_name: Debi Tillman
                  available_store_credit_total: '0'
                  display_available_store_credit_total: "$0.00"
                  addresses: []
                  default_billing_address:
                  default_shipping_address:
              schema:
                "$ref": "#/components/schemas/AuthResponse"
        '401':
          description: missing or invalid refresh token
          content:
            application/json:
              example:
                error:
                  code: invalid_refresh_token
                  message: Invalid or expired refresh token
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                refresh_token:
                  type: string
                  description: Refresh token from login response
              required:
              - refresh_token
  "/api/v3/store/auth/logout":
    post:
      summary: Logout
      tags:
      - Authentication
      security:
      - api_key: []
      description: Revokes the submitted refresh token. The refresh token itself is
        the credential — no Authorization header is required, so a client with an
        expired access JWT can still log out.
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          await client.auth.logout({
            refresh_token: 'rt_xxx',
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: logout without refresh token (no-op)
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                refresh_token:
                  type: string
                  description: Refresh token to revoke
  "/api/v3/store/password_resets":
    post:
      summary: Request a password reset
      tags:
      - Authentication
      security:
      - api_key: []
      description: Sends a password reset email if an account exists for the given
        email address. Always returns 202 Accepted to prevent email enumeration.
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          await client.passwordResets.create({
            email: '[email protected]',
            redirect_url: 'https://myshop.com/reset-password',
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '202':
          description: email not found (same response to prevent enumeration)
          content:
            application/json:
              example:
                message: If an account exists for that email, password reset instructions
                  have been sent.
              schema:
                type: object
                properties:
                  message:
                    type: string
        '401':
          description: missing API key
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  example: [email protected]
                  description: Email address of the account to reset
                redirect_url:
                  type: string
                  format: uri
                  example: https://myshop.com/reset-password
                  description: URL to redirect the user to after clicking the reset
                    link. Validated against the store's allowed origins.
              required:
              - email
  "/api/v3/store/password_resets/{token}":
    patch:
      summary: Reset password with token
      tags:
      - Authentication
      security:
      - api_key: []
      description: Resets the password using a token received via email. Returns a
        JWT token on success (auto-login).
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          const auth = await client.passwordResets.update(
            'reset-token-from-email',
            {
              password: 'newsecurepassword',
              password_confirmation: 'newsecurepassword',
            }
          )
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: token
        in: path
        required: true
        description: Password reset token from the email
        schema:
          type: string
      responses:
        '200':
          description: password reset successful
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjU1YjA5Yzc4LTUzMTYtNDRjYy05ZjJiLThmN2E2MzViMmRlNSIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjI4fQ.FX2Te4WfdAu3kN_fvvfHsH92_axvIZTI1d8Zmw8R1mE
                refresh_token: Be2HUCjiJVRjgidFuYU7GRRh
                user:
                  id: cus_UkLWZg9DAJ
                  email: [email protected]
                  first_name: Randa
                  last_name: O'Hara
                  phone:
                  accepts_email_marketing: false
                  full_name: Randa O'Hara
                  available_store_credit_total: '0'
                  display_available_store_credit_total: "$0.00"
                  addresses: []
                  default_billing_address:
                  default_shipping_address:
              schema:
                "$ref": "#/components/schemas/AuthResponse"
        '422':
          description: password confirmation mismatch
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Password confirmation doesn't match Password
                  details:
                    password_confirmation:
                    - doesn't match Password
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
        '401':
          description: missing API key
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
                  minLength: 6
                  example: newsecurepassword
                password_confirmation:
                  type: string
                  example: newsecurepassword
              required:
              - password
              - password_confirmation
  "/api/v3/store/categories":
    get:
      summary: List categories
      tags:
      - Product Catalog
      security:
      - api_key: []
      description: Returns a paginated list of categories for the current store
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          const categories = await client.categories.list({
            page: 1,
            limit: 25,
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,slug,price).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: categories found
          content:
            application/json:
              example:
                data:
                - id: ctg_UkLWZg9DAJ
                  name: taxonomy_3
                  permalink: taxonomy-3
                  position: 0
                  depth: 0
                  meta_title:
                  meta_description:
                  meta_keywords:
                  children_count: 1
                  parent_id:
                  description: ''
                  description_html: ''
                  image_url:
                  square_image_url:
                  is_root: true
                  is_child: false
                  is_leaf: false
                - id: ctg_gbHJdmfrXB
                  name: taxon_3
                  permalink: taxonomy-3/taxon-3
                  position: 0
                  depth: 1
                  meta_title:
                  meta_description:
                  meta_keywords:
                  children_count: 1
                  parent_id: ctg_UkLWZg9DAJ
                  description: ''
                  description_html: ''
                  image_url:
                  square_image_url:
                  is_root: false
                  is_child: true
                  is_leaf: false
                - id: ctg_EfhxLZ9ck8
                  name: taxon_4
                  permalink: taxonomy-3/taxon-3/taxon-4
                  position: 0
                  depth: 2
                  meta_title:
                  meta_description:
                  meta_keywords:
                  children_count: 0
                  parent_id: ctg_gbHJdmfrXB
                  description: ''
                  description_html: ''
                  image_url:
                  square_image_url:
                  is_root: false
                  is_child: true
                  is_leaf: true
                meta:
                  page: 1
                  limit: 25
                  count: 3
                  pages: 1
                  from: 1
                  to: 3
                  in: 3
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Category"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/store/categories/{id}":
    get:
      summary: Get a category
      tags:
      - Product Catalog
      security:
      - api_key: []
      description: Returns a single category by permalink or prefix ID
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          const category = await client.categories.get('categories/clothing/shirts', {
            expand: ['children'],
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Category permalink (e.g., clothing/shirts) or prefix ID (e.g.,
          ctg_abc123)
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Expand associations (children, parent, ancestors, custom_fields)
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,slug,price).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: category found by prefix ID
          content:
            application/json:
              example:
                id: ctg_gbHJdmfrXB
                name: taxon_12
                permalink: taxonomy-9/taxon-12
                position: 0
                depth: 1
                meta_title:
                meta_description:
                meta_keywords:
                children_count: 1
                parent_id: ctg_UkLWZg9DAJ
                description: ''
                description_html: ''
                image_url:
                square_image_url:
                is_root: false
                is_child: true
                is_leaf: false
              schema:
                "$ref": "#/components/schemas/Category"
        '404':
          description: category from other store not accessible
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Category not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/store/products":
    get:
      summary: List products
      tags:
      - Product Catalog
      security:
      - api_key: []
      description: Returns a paginated list of active products for the current store
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          const products = await client.products.list({
            page: 1,
            limit: 25,
            sort: 'price',
            name_cont: 'shirt',
            price_gte: 20,
            price_lte: 100,
            with_option_value_ids: ['optval_abc', 'optval_def'],
            expand: ['variants', 'media'],
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        description: Publishable API key
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: 'Page number (default: 1)'
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: 'Number of items per page (default: 25, max: 100)'
        schema:
          type: integer
      - name: sort
        in: query
        required: false
        description: 'Sort order. Prefix with - for descending. Values: price, -price,
          best_selling, name, -name, -available_on, available_on'
        schema:
          type: string
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name containing string
        schema:
          type: string
      - name: q[in_category]
        in: query
        required: false
        description: Filter by category prefixed ID (includes descendants)
        schema:
          type: string
      - name: q[in_categories][]
        in: query
        required: false
        description: Filter by multiple category prefixed IDs (OR logic, includes
          descendants)
        schema:
          type: string
      - name: q[price_gte]
        in: query
        required: false
        description: Filter by minimum price
        schema:
          type: number
      - name: q[price_lte]
        in: query
        required: false
        description: Filter by maximum price
        schema:
          type: number
      - name: q[with_option_value_ids][]
        in: query
        required: false
        description: Filter by option value prefix IDs (e.g., optval_abc). Pass multiple
          values for OR logic.
        schema:
          type: string
      - name: q[in_stock]
        in: query
        required: false
        description: Filter to only in-stock products
        schema:
          type: boolean
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (variants, media, categories,
          option_types)
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,slug,price).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: products found
          content:
            application/json:
              example:
                data:
                - id: prod_UkLWZg9DAJ
                  name: Product 1421251
                  slug: product-1421251
                  meta_title:
                  meta_description:
                  meta_keywords:
                  variant_count: 1
                  available_on: '2025-05-26T16:14:22.402Z'
                  purchasable: true
                  in_stock: false
                  backorderable: true
                  available: true
                  description: A comfortable cotton t-shirt.
                  description_html: "<p>A <strong>comfortable</strong> cotton t-shirt.</p>"
                  default_variant_id: variant_gbHJdmfrXB
                  thumbnail_url:
                  tags: []
                  price:
                    id: price_gbHJdmfrXB
                    amount: '19.99'
                    amount_in_cents: 1999
                    compare_at_amount:
                    compare_at_amount_in_cents:
                    currency: USD
                    display_amount: "$19.99"
                    display_compare_at_amount:
                    price_list_id:
                  original_price:
                - id: prod_gbHJdmfrXB
                  name: Product 1435220
                  slug: product-1435220
                  meta_title:
                  meta_description:
                  meta_keywords:
                  variant_count: 0
                  available_on: '2025-05-26T16:14:22.472Z'
                  purchasable: true
                  in_stock: false
                  backorderable: true
                  available: true
                  description: Architecto dignissimos nemo inventore incidunt enim.
                    Odit accusamus repellat error saepe culpa unde eius. Cupiditate
                    officiis voluptatem autem perferendis qui vitae omnis sunt. Debitis
                    dolor tempore ad impedit itaque reprehenderit delectus. Doloremque
                    laudantium iure recusandae iusto debitis laborum consequuntur.
                    Impedit eum optio commodi tempora cum quidem. Facere voluptatum
                    nam possimus veritatis nostrum explicabo dolore ex. Adipisci iure
                    unde nobis itaque amet nesciunt voluptatibus impedit. Numquam
                    in accusantium magni itaque exercitationem. Quas vero maxime voluptatem
                    rem impedit inventore. Esse perferendis asperiores ea expedita
                    aut tenetur soluta. Enim accusantium dolor adipisci impedit. Error
                    maxime neque accusamus facere provident eum. Cum officia velit
                    asperiores quod cupiditate fugiat. Possimus tenetur aut consequuntur
                    iusto cumque quas. Ab velit ullam qui pariatur veritatis omnis.
                    Accusantium vero occaecati explicabo neque animi commodi. Necessitatibus
                    perspiciatis iste culpa totam quibusdam voluptate distinctio.
                    Quod aliquam ut et autem. Saepe ut asperiores et quisquam perspiciatis
                    molestiae. Vel recusandae sunt nemo et accusamus veniam ducimus.
                    Laborum modi quasi perferendis culpa laboriosam quaerat magnam.
                    Facere at tempora iusto ex magni aliquam modi debitis.
                  description_html: |-
                    Architecto dignissimos nemo inventore incidunt enim. Odit accusamus repellat error saepe culpa unde eius. Cupiditate officiis voluptatem autem perferendis qui vitae omnis sunt. Debitis dolor tempore ad impedit itaque reprehenderit delectus. Doloremque laudantium iure recusandae iusto debitis laborum consequuntur.
                    Impedit eum optio commodi tempora cum quidem. Facere voluptatum nam possimus veritatis nostrum explicabo dolore ex. Adipisci iure unde nobis itaque amet nesciunt voluptatibus impedit. Numquam in accusantium magni itaque exercitationem. Quas vero maxime voluptatem rem impedit inventore.
                    Esse perferendis asperiores ea expedita aut tenetur soluta. Enim accusantium dolor adipisci impedit. Error maxime neque accusamus facere provident eum. Cum officia velit asperiores quod cupiditate fugiat. Possimus tenetur aut consequuntur iusto cumque quas.
                    Ab velit ullam qui pariatur veritatis omnis. Accusantium vero occaecati explicabo neque animi commodi. Necessitatibus perspiciatis iste culpa totam quibusdam voluptate distinctio. Quod aliquam ut et autem. Saepe ut asperiores et quisquam perspiciatis molestiae.
                    Vel recusandae sunt nemo et accusamus veniam ducimus. Laborum modi quasi perferendis culpa laboriosam quaerat magnam. Facere at tempora iusto ex magni aliquam modi debitis.
                  default_variant_id: variant_EfhxLZ9ck8
                  thumbnail_url:
                  tags: []
                  price:
                    id: price_EfhxLZ9ck8
                    amount: '19.99'
                    amount_in_cents: 1999
                    compare_at_amount:
                    compare_at_amount_in_cents:
                    currency: USD
                    display_amount: "$19.99"
                    display_compare_at_amount:
                    price_list_id:
                  original_price:
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Product"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized - invalid or missing API key
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/store/products/{id}":
    get:
      summary: Get a product
      tags:
      - Product Catalog
      security:
      - api_key: []
      description: Returns a single product by slug or prefix ID
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: |-
          import { createClient } from '@spree/sdk'

          const client = createClient({
            baseUrl: 'https://your-store.com',
            publishableKey: '<api-key>',
          })

          const product = await client.products.get('spree-tote', {
            expand: ['variants', 'media'],
          })
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        description: Publishable API key
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Product slug (e.g., spree-tote) or prefix ID (e.g., product_abc123)
        schema:
 

# --- truncated at 32 KB (372 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spree/refs/heads/main/openapi/spree-store-api.yaml