openapi: 3.0.3 info: title: Admin Account / Address Product Catalog API contact: name: Spree Commerce url: https://spreecommerce.org email: hello@spreecommerce.org description: "Spree Admin API v3 - Administrative API for managing products, orders, and store settings.\n\n## Authentication\n\nThe Admin API requires a secret API key passed in the `x-spree-api-key` header.\nSecret API keys can be generated in the Spree admin dashboard.\n\n## Response Format\n\nAll responses are JSON. List endpoints return paginated responses with `data` and `meta` keys.\nSingle resource endpoints return a flat JSON object.\n\n## Resource IDs\n\nEvery resource is identified by an opaque string ID (e.g. `prod_86Rf07xd4z`,\n`variant_k5nR8xLq`, `or_UkLWZg9DAJ`). Use these IDs everywhere — URL paths,\nrequest bodies, and Ransack filters all accept them directly.\n\n## Error Handling\n\nErrors return a consistent format:\n```json\n{\n \"error\": {\n \"code\": \"validation_error\",\n \"message\": \"Validation failed\",\n \"details\": { \"name\": [\"can't be blank\"] }\n }\n}\n```\n" version: v3 servers: - url: http://{defaultHost} variables: defaultHost: default: localhost:3000 tags: - name: Product Catalog description: Products and categories paths: /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'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '',\n})\n\nconst categories = await client.categories.list({\n page: 1,\n limit: 25,\n})" 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: null meta_description: null meta_keywords: null children_count: 1 parent_id: null description: '' description_html: '' image_url: null square_image_url: null 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: null meta_description: null meta_keywords: null children_count: 1 parent_id: ctg_UkLWZg9DAJ description: '' description_html: '' image_url: null square_image_url: null 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: null meta_description: null meta_keywords: null children_count: 0 parent_id: ctg_gbHJdmfrXB description: '' description_html: '' image_url: null square_image_url: null 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: null next: null 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'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '',\n})\n\nconst category = await client.categories.get('categories/clothing/shirts', {\n expand: ['children'],\n})" 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: null meta_description: null meta_keywords: null children_count: 1 parent_id: ctg_UkLWZg9DAJ description: '' description_html: '' image_url: null square_image_url: null 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'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '',\n})\n\nconst products = await client.products.list({\n page: 1,\n limit: 25,\n sort: 'price',\n name_cont: 'shirt',\n price_gte: 20,\n price_lte: 100,\n with_option_value_ids: ['optval_abc', 'optval_def'],\n expand: ['variants', 'media'],\n})" 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: null meta_description: null meta_keywords: null 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:

A comfortable cotton t-shirt.

default_variant_id: variant_gbHJdmfrXB thumbnail_url: null tags: [] price: id: price_gbHJdmfrXB amount: '19.99' amount_in_cents: 1999 compare_at_amount: null compare_at_amount_in_cents: null currency: USD display_amount: $19.99 display_compare_at_amount: null price_list_id: null original_price: null - id: prod_gbHJdmfrXB name: Product 1435220 slug: product-1435220 meta_title: null meta_description: null meta_keywords: null 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: null tags: [] price: id: price_EfhxLZ9ck8 amount: '19.99' amount_in_cents: 1999 compare_at_amount: null compare_at_amount_in_cents: null currency: USD display_amount: $19.99 display_compare_at_amount: null price_list_id: null original_price: null meta: page: 1 limit: 25 count: 2 pages: 1 from: 1 to: 2 in: 2 previous: null next: null 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'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '',\n})\n\nconst product = await client.products.get('spree-tote', {\n expand: ['variants', 'media'],\n})" 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: type: string - name: expand in: query required: false description: Comma-separated associations to expand 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: product without prior_price expanded does not include field content: application/json: example: id: prod_UkLWZg9DAJ name: Product 1702106 slug: product-1702106 meta_title: null meta_description: null meta_keywords: null variant_count: 1 available_on: '2025-05-26T16:14:24.749Z' purchasable: true in_stock: false backorderable: true available: true description: A comfortable cotton t-shirt. description_html:

A comfortable cotton t-shirt.

default_variant_id: variant_gbHJdmfrXB thumbnail_url: null tags: [] price: id: price_gbHJdmfrXB amount: '19.99' amount_in_cents: 1999 compare_at_amount: null compare_at_amount_in_cents: null currency: USD display_amount: $19.99 display_compare_at_amount: null price_list_id: null original_price: null prior_price: id: _AXs1igzRC6 amount: '9.99' amount_in_cents: 999 currency: USD display_amount: $9.99 recorded_at: '2026-05-11T16:14:24Z' schema: $ref: '#/components/schemas/Product' '404': description: draft product not visible content: application/json: example: error: code: record_not_found message: Product not found schema: $ref: '#/components/schemas/ErrorResponse' /api/v3/store/products/filters: get: summary: Get product filters tags: - Product Catalog security: - api_key: [] description: 'Returns available filters for products with their options and counts. Use this endpoint to build filter UIs for product listing pages. The filters are context-aware - when a category_id is provided, only filters relevant to products in that category are returned. ' x-codeSamples: - lang: javascript label: Spree SDK source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n baseUrl: 'https://your-store.com',\n publishableKey: '',\n})\n\nconst filters = await client.products.filters({\n category_id: 'ctg_abc123',\n})" parameters: - name: x-spree-api-key in: header required: true description: Publishable API key schema: type: string - name: category_id in: query required: false description: Scope filters to products in this category (prefix ID) schema: type: string - name: q[name_cont] in: query required: false description: Filter by name containing string schema: type: string responses: '200': description: filters scoped to category content: application/json: example: filters: - id: price type: price_range min: 19.99 max: 19.99 currency: USD - id: availability type: availability options: - id: in_stock count: 2 - id: out_of_stock count: 0 - id: opt_UkLWZg9DAJ type: option name: size label: Size kind: dropdown options: - id: optval_UkLWZg9DAJ name: small label: S position: 1 color_code: null image_url: null count: 1 - id: categories type: category options: - id: ctg_EfhxLZ9ck8 name: Shirts permalink: taxonomy-27/taxon-34/shirts count: 2 sort_options: - id: manual - id: best_selling - id: price - id: -price - id: -available_on - id: available_on - id: name - id: -name default_sort: manual total_count: 2 schema: type: object properties: filters: type: array description: Available filters (price_range, availability, option, category) items: type: object sort_options: type: array description: Available sort options items: type: object properties: id: type: string required: - id default_sort: type: string description: Default sort option ID total_count: type: integer description: Total products matching current filters required: - filters - sort_options - default_sort - total_count '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' components: schemas: Price: type: object properties: id: type: string amount: type: string nullable: true amount_in_cents: type: number nullable: true compare_at_amount: type: string nullable: true compare_at_amount_in_cents: type: number nullable: true currency: type: string nullable: true display_amount: type: string nullable: true display_compare_at_amount: type: string nullable: true price_list_id: type: string nullable: true required: - id - amount - amount_in_cents - compare_at_amount - compare_at_amount_in_cents - currency - display_amount - display_compare_at_amount - price_list_id x-typelizer: true OptionValue: type: object properties: id: type: string option_type_id: type: string name: type: string label: type: string position: type: number color_code: type: string nullable: true option_type_name: type: string option_type_label: type: string image_url: type: string nullable: true required: - id - option_type_id - name - label - position - color_code - option_type_name - option_type_label - image_url x-typelizer: true PriceHistory: type: object properties: id: type: string amount: type: string amount_in_cents: type: number currency: type: string display_amount: type: string recorded_at: type: string required: - id - amount - amount_in_cents - currency - display_amount - recorded_at x-typelizer: true OptionType: type: object properties: id: type: string name: type: string label: type: string position: type: number kind: type: string required: - id - name - label - position - kind x-typelizer: true Category: type: object properties: id: type: string name: type: string permalink: type: string position: type: number depth: type: number meta_title: type: string nullable: true meta_description: type: string nullable: true meta_keywords: type: string nullable: true children_count: type: number parent_id: type: string nullable: true description: type: string description_html: type: string image_url: type: string nullable: true square_image_url: type: string nullable: true is_root: type: boolean is_child: type: boolean is_leaf: type: boolean parent: $ref: '#/components/schemas/Category' children: type: array items: $ref: '#/components/schemas/Category' ancestors: type: array items: $ref: '#/components/schemas/Category' custom_fields: type: array items: $ref: '#/components/schemas/CustomField' required: - id - name - permalink - position - depth - meta_title - meta_description - meta_keywords - children_count - parent_id - description - description_html - image_url - square_image_url - is_root - is_child - is_leaf x-typelizer: true PaginationMeta: type: object properties: page: type: integer example: 1 limit: type: integer example: 25 count: type: integer example: 100 description: Total number of records pages: type: integer example: 4 description: Total number of pages from: type: integer example: 1 description: Index of first record on this page to: type: integer example: 25 description: Index of last record on this page in: type: integer example: 25 description: Number of records on this page previous: type: integer nullable: true example: null description: Previous page number next: type: integer nullable: true example: 2 description: Next page number required: - page - limit - count - pages - from - to - in Product: type: object properties: id: type: string name: type: string slug: type: string meta_title: type: string nullable: true meta_description: type: string nullable: true meta_keywords: type: string nullable: true variant_count: type: number available_on: type: string nullable: true purchasable: type: boolean in_stock: type: boolean backorderable: type: boolean available: type: boolean description: type: string nullable: true description_html: type: string nullable: true default_variant_id: type: string thumbnail_url: type: string nullable: true tags: type: array items: type: string price: $ref: '#/components/schemas/Price' original_price: allOf: - $ref: '#/components/schemas/Price' nullable: true primary_media: $ref: '#/components/schemas/Media' media: type: array items: $ref: '#/components/schemas/Media' variants: type: array items: $ref: '#/components/schemas/Variant' default_variant: $ref: '#/components/schemas/Variant' option_types: type: array items: $ref: '#/components/schemas/OptionType' categories: type: array items: $ref: '#/components/schemas/Category' custom_fields: type: array items: $ref: '#/components/schemas/CustomField' prior_price: allOf: - $ref: '#/components/schemas/PriceHistory' nullable: true required: - id - name - slug - meta_title - meta_description - meta_keywords - variant_count - available_on - purchasable - in_stock - backorderable - available - description - description_html - default_variant_id - thumbnail_url - tags - price - original_price x-typelizer: true ErrorResponse: type: object properties: error: type: object properties: code: type: string example: record_not_found message: type: string example: Record not found details: type: object description: Field-specific validation errors nullable: true example: name: - is too short - is required email: - is invalid required: - code - message required: - error example: error: code: validation_error message: Validation failed details: name: - is too short email: - is invalid Media: type: object properties: id: type: string product_id: type: string nullable: true variant_ids: type: array items: type: string position: type: number alt: type: string nullable: true media_type: type: string focal_point_x: type: number nullable: true focal_point_y: type: number nullable: true external_video_url: type: string nullable: true original_url: type: string nullable: true mini_url: type: string nullable: true small_url: type: string nullable: true medium_url: type: string nullable: true large_url: type: string nullable: true xlarge_url: type: string nullable: true og_image_url: type: string nullable: true required: - id - product_id - variant_ids - position - alt - media_type - focal_point_x - focal_point_y - external_video_url - original_url - mini_url - small_url - medium_url - large_url - xlarge_url - og_image_url x-typelizer: true Variant: type: object properties: id: type: string product_id: type: string sku: type: string nullable: true options_text: type: string track_inventory: type: boolean media_count: type: number thumbnail_url: type: string nullable: true purchasable: type: boolean in_stock: type: boolean backorderable: type: boolean weight: type: number nullable: true height: type: number nullable: true width: type: number nullable: true depth: type: number nullable: true price: $ref: '#/components/schemas/Price' original_price: allOf: - $ref: '#/components/schemas/Price' nullable: true primary_media: $ref: '#/components/schemas/Media' media: type: array items: $ref: '#/components/schemas/Media' option_values: type: array items: $ref: '#/components/schemas/OptionValue' custom_fields: type: array items: $ref: '#/components/schemas/CustomField' prior_price: allOf: - $ref: '#/components/schemas/PriceHistory' nullable: true required: - id - product_id - sku - options_text - track_inventory - media_count - thumbnail_url - purchasable - in_stock - backorderable - weight - height - width - depth - price - original_price - option_values x-typelizer: true CustomField: type: object properties: id: type: string label: type: string type: type: string deprecated: true field_type: type: string enum: - short_text - long_text - rich_text - number - boolean - json key: type: string value: type: object required: - id - label - type - field_type - key - value x-typelizer: true securitySchemes: api_key: type: apiKey name: x-spree-api-key in: header description: Secret API key for admin access bearer_auth: type: http scheme: bearer bearerFormat: JWT description: JWT token for admin user authentication x-tagGroups: - name: Authentication tags: - Authentication - name: Products & Catalog tags: - Products - Variants - Option Types - Custom Fields - Channels - name: Pricing tags: - Pricing - Markets - name: Orders & Fulfillment tags: - Orders - Payments - Fulfillments - Refunds - name: Customers tags: - Customers - Customer Groups - name: Promotions & Gift Cards tags: - Promotions - Gift Cards - name: Data tags: - Exports - name: Configuration tags: - Settings - Stock Locations - Payment Methods - Staff - API Keys - Allowed Origins - Webhooks