Documentation Index
Fetch the complete documentation index at: https://spreecommerce.org/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
A product represents something you sell. Each product has one or more variants — the actual purchasable items with their own SKU, price, and inventory. For example, a “T-Shirt” product might have variants for each size and color combination. Products are organized into categories — a flexible hierarchy for grouping products. Categories can be filtered, sorted, and searched via the Store API.Product names, descriptions, slugs, and SEO fields are translatable.
Product Attributes
| Attribute | Description | Translatable |
|---|---|---|
name | Product name | Yes |
description | Full product description | Yes |
slug | URL-friendly identifier (e.g., spree-tote) | Yes |
status | draft, active, or archived | No |
available_on | Date the product becomes available for sale | No |
discontinue_on | Date the product is no longer available | No |
meta_title | Custom SEO title | Yes |
meta_description | SEO description | Yes |
meta_keywords | SEO keywords | Yes |
purchasable | Whether the product can be added to cart | No |
in_stock | Whether any variant has stock available | No |
price | Default variant’s price in the current currency | No |
thumbnail_url | URL to the product’s first image — always returned, no expand needed | No |
tags | Array of tag strings for filtering | No |
Listing Products
Getting a Product
Product Filters
Get available filter options for building a faceted search UI. Returns price ranges, option values, and categories with counts:Variants
Variants are the purchasable units of a product. Each variant has its own SKU, price, inventory, and images, and is defined by a unique combination of option values.| Attribute | Description |
|---|---|
sku | Unique stock keeping unit |
barcode | Barcode (UPC, EAN, etc.) |
price | Price in the current currency |
original_price | Compare-at price for showing discounts |
weight, height, width, depth | Dimensions for shipping calculations |
in_stock | Whether stock is available |
backorderable | Whether the variant can be ordered when out of stock |
option_values | The option values that define this variant (e.g., Size: Small, Color: Red) |
Master Variant
Every product has a master variant that holds default pricing and inventory. If a product has no option types (e.g., a book with no size/color), the master variant is the only purchasable variant.Regular Variants
When a product has option types, each unique combination of option values creates a variant. For example, a T-shirt with sizes (S, M, L) and colors (Red, Green) has 6 variants:| SKU | Size | Color |
|---|---|---|
TEE-S-R | Small | Red |
TEE-S-G | Small | Green |
TEE-M-R | Medium | Red |
TEE-M-G | Medium | Green |
TEE-L-R | Large | Red |
TEE-L-G | Large | Green |
default_variant_id points to the first non-master variant (or the master variant if none exist).
Option Types and Option Values
Option types define the axes of variation for a product (e.g., Size, Color, Material). Option values are the specific choices within each type (e.g., Small, Medium, Large). A product must have at least one option type to have multiple variants. Option types and their values are included in the product response when requested:Option type
name and presentation fields are translatable.Media
Media can be attached to the product (via the master variant) or to individual variants. When displaying a product, show the images for the selected variant, falling back to the product-level images.Thumbnails
Every product response includes athumbnail_url field — the URL to the first image, ready to use without any expands. Similarly, each variant includes a thumbnail_url URL and an media_count counter.
Use these fields for product listing pages to avoid loading all images:
All Images
On the product detail page, expandmedia and variants to get the full set of images. Images are ordered by position:
| Field | Available on | Always returned | Description |
|---|---|---|---|
thumbnail_url | Product | Yes | URL to the product’s first media |
thumbnail_url | Variant | Yes | URL to the variant’s first media |
media_count | Variant | Yes | Number of media |
media | Product, Variant | No | Full image array (requires ?expand=media) |
Prices
Each variant can have multiple prices — one per currency, plus additional prices from Price Lists that apply conditionally based on market, geography, customer segment, or quantity. The API automatically returns the correct price based on the current currency and market context:| Field | Description |
|---|---|
price | Current selling price |
original_price | Compare-at price (for showing strikethrough discounts) |
Categories
Categories provide a flexible way to organize products into hierarchical trees. Internally, Spree uses Taxonomies (category trees) and Taxons (nodes within those trees), but the Store API exposes them simply as Categories. For example:- Categories → Clothing → T-Shirts, Dresses
- Brands → Nike, Adidas, Puma
- Collections → Summer 2025, Best Sellers
Category
name and description fields are translatable.Publications and Sales Channels
A product is visible on a Channel only when aProductPublication record joins the two. Publications carry an optional time window so a product can be scheduled to go live and come down without code or manual toggles.
| Publication state | What customers see |
|---|---|
| No publication exists | Product is not on this channel — invisible |
| Publication has no dates set | Live now and indefinitely |
published_at is in the future | Scheduled — not yet visible |
unpublished_at is in the past | Hidden — was visible, now sunset |
| Within the window | Live |
status (draft / active / archived) is the outer gate: a Draft or Archived product is hidden on every channel regardless of its publication window. Only active products consult publication state.
Reading publications
Publications appear in the API underproduct_publications when expanded; the same data is available through the channels association as a flat list of joined channels.
Response
Writing publications
Two write surfaces serve different shapes:-
Per-product, full-set —
PATCH /api/v3/admin/products/{id}with aproduct_publicationsarray. The array represents the complete desired state; channels absent from the payload are detached. -
Per-channel, bulk —
POST /api/v3/admin/channels/{id}/add_productsandPOST /api/v3/admin/channels/{id}/remove_productsfor publishing or unpublishing many products at once. Idempotent: re-publishing an already-published product is a no-op for its window unlesspublished_at/unpublished_atare explicitly passed.
spree_product_publications table — pick whichever matches your call site.
Listing products on a specific channel
Storefronts andclient.products.list() calls return only products published on the resolved channel (live within the publication window, with the product itself active). To scope a Store SDK request to a non-default channel — e.g. a POS app querying for the POS catalog — set the channel code on the client or per-request:
q[channels_id_in][]=ch_xxx. See Sales Channels for the resolution rules.
Auto-publish on the default channel
When a product is created via the dashboard, it is auto-published on the store’s default channel (the only channel wheredefault = true). The Admin API does not auto-publish — supply product_publications: [{ channel_id }] on create or call add_products afterwards.
See Sales Channels for the full channel lifecycle, including default-channel resolution and the X-Spree-Channel header.
Related Documentation
- Sales Channels — Channels, publications, and order attribution
- Pricing — Price Lists, Price Rules, and market-specific pricing
- Inventory — Stock management and backorders
- Media — Image management
- Translations — Translating product content
- Search & Filtering — Full-text search and Ransack filtering
- Querying — API filtering, sorting, and pagination

