Spree Commerce Pricing API

Prices and price lists for currency-, market-, and customer-group-specific pricing

OpenAPI Specification

spree-pricing-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Admin Account / Address Pricing 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: Pricing
  description: Prices and price lists for currency-, market-, and customer-group-specific pricing
paths:
  /api/v3/admin/price_lists:
    get:
      summary: List price lists
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Returns the price lists configured for the current store.


        **Required scope:** `read_products` (for API-key authentication).'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        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
        schema:
          type: string
      - name: q[status_eq]
        in: query
        required: false
        schema:
          type: string
      - name: sort
        in: query
        required: false
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: 'Comma-separated associations to embed. Supported: `price_rules`.'
        schema:
          type: string
      responses:
        '200':
          description: price lists found
          content:
            application/json:
              example:
                data:
                - id: pl_UkLWZg9DAJ
                  name: Wholesale
                  description: null
                  status: draft
                  position: 1
                  match_policy: all
                  starts_at: null
                  ends_at: null
                  deleted_at: null
                  created_at: '2026-06-12T17:24:52.444Z'
                  updated_at: '2026-06-12T17:24:52.444Z'
                  currently_active: false
                  products_count: 0
                  prices_count: 0
                  product_ids: []
                - id: pl_gbHJdmfrXB
                  name: Holiday
                  description: null
                  status: draft
                  position: 2
                  match_policy: all
                  starts_at: null
                  ends_at: null
                  deleted_at: null
                  created_at: '2026-06-12T17:24:52.447Z'
                  updated_at: '2026-06-12T17:24:52.447Z'
                  currently_active: false
                  products_count: 0
                  prices_count: 0
                  product_ids: []
                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/PriceList'
                  meta:
                    $ref: '#/components/schemas/PaginationMeta'
                required:
                - data
                - meta
    post:
      summary: Create a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Creates a new draft price list.


        **Required scope:** `write_products` (for API-key authentication).'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: price list created (server-to-server — rules + prices, no product_ids)
          content:
            application/json:
              example:
                id: pl_EfhxLZ9ck8
                name: EU wholesale
                description: null
                status: draft
                position: 3
                match_policy: all
                starts_at: null
                ends_at: null
                deleted_at: null
                created_at: '2026-06-12T17:24:53.499Z'
                updated_at: '2026-06-12T17:24:53.501Z'
                currently_active: false
                products_count: 1
                prices_count: 2
                product_ids:
                - prod_UkLWZg9DAJ
              schema:
                $ref: '#/components/schemas/PriceList'
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                  example: EU wholesale
                description:
                  type: string
                  nullable: true
                starts_at:
                  type: string
                  nullable: true
                  example: '2026-06-01T00:00:00Z'
                ends_at:
                  type: string
                  nullable: true
                  example: '2026-09-01T00:00:00Z'
                match_policy:
                  type: string
                  enum:
                  - all
                  - any
                  example: all
                position:
                  type: integer
                  example: 1
                product_ids:
                  type: array
                  items:
                    type: string
                  description: Prefixed product ids to seed the list with.
                  example:
                  - prod_aBc123
                rules:
                  type: array
                  description: STI-typed price rules to attach on create. Existing rules on the same payload via PATCH reconcile by id.
                  items:
                    type: object
                    required:
                    - type
                    properties:
                      type:
                        type: string
                        example: volume_rule
                      preferences:
                        type: object
                        additionalProperties: true
                prices:
                  type: array
                  description: 'Server-to-server alternative to `product_ids`: ship the exact per-variant prices the list should contain. Each row upserts on the unique key `(variant_id, currency, price_list_id)`. Mix-and-match with `product_ids` is supported but typically unnecessary — `prices` alone tells the server which variants belong to the list and what the override amount is.'
                  items:
                    type: object
                    required:
                    - variant_id
                    - currency
                    properties:
                      variant_id:
                        type: string
                        example: variant_xY9
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        nullable: true
                        example: '19.99'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '24.99'
  /api/v3/admin/price_lists/{id}:
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: Get a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: '**Required scope:** `read_products` (for API-key authentication).'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        schema:
          type: string
      responses:
        '200':
          description: price list found
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Wholesale
                description: null
                status: draft
                position: 1
                match_policy: all
                starts_at: null
                ends_at: null
                deleted_at: null
                created_at: '2026-06-12T17:24:53.806Z'
                updated_at: '2026-06-12T17:24:53.806Z'
                currently_active: false
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                $ref: '#/components/schemas/PriceList'
        '404':
          description: price list not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Price list not found
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    patch:
      summary: Update a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Updates a price list. The optional `rules:` array reconciles nested

        STI-typed price rules in a single round-trip — existing rules update

        by `id`, new rules build, missing rules destroy. Mirrors the

        promotion editor''s "save the whole thing on Save" pattern.



        **Required scope:** `write_products` (for API-key authentication).'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price list updated with nested rules
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Wholesale (Q3)
                description: null
                status: draft
                position: 1
                match_policy: all
                starts_at: null
                ends_at: null
                deleted_at: null
                created_at: '2026-06-12T17:24:55.427Z'
                updated_at: '2026-06-12T17:24:55.712Z'
                currently_active: false
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                $ref: '#/components/schemas/PriceList'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                  nullable: true
                starts_at:
                  type: string
                  nullable: true
                ends_at:
                  type: string
                  nullable: true
                match_policy:
                  type: string
                  enum:
                  - all
                  - any
                position:
                  type: integer
                product_ids:
                  type: array
                  items:
                    type: string
                  description: Prefixed product ids — reconciles list membership (adds + removes).
                  example:
                  - prod_aBc123
                rules:
                  type: array
                  items:
                    type: object
                    required:
                    - type
                    properties:
                      id:
                        type: string
                        nullable: true
                      type:
                        type: string
                        example: volume_rule
                      preferences:
                        type: object
                        additionalProperties: true
                prices:
                  type: array
                  description: Individual price overrides (the spreadsheet payload). Each row updates by `id` if shipped, otherwise upserts on the unique key `(variant_id, currency, price_list_id)`.
                  items:
                    type: object
                    oneOf:
                    - required:
                      - id
                    - required:
                      - variant_id
                      - currency
                    properties:
                      id:
                        type: string
                        example: price_aBc123
                      variant_id:
                        type: string
                        example: variant_xY9
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        nullable: true
                        example: '12.50'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '15.00'
    delete:
      summary: Delete a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Soft-deletes the price list. Associated prices are removed asynchronously.


        **Required scope:** `write_products` (for API-key authentication).'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: price list deleted
  /api/v3/admin/price_lists/{id}/activate:
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    patch:
      summary: Activate a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Transitions a draft / inactive list to `active`. If `starts_at` is

        in the future the list is marked `scheduled` instead, matching the

        legacy admin behaviour.



        **Required scope:** `write_products` (for API-key authentication).'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price list activated
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Wholesale
                description: null
                status: active
                position: 1
                match_policy: all
                starts_at: null
                ends_at: null
                deleted_at: null
                created_at: '2026-06-12T17:24:56.035Z'
                updated_at: '2026-06-12T17:24:56.320Z'
                currently_active: true
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                $ref: '#/components/schemas/PriceList'
  /api/v3/admin/price_lists/{id}/deactivate:
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    patch:
      summary: Deactivate a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: '**Required scope:** `write_products` (for API-key authentication).'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price list deactivated
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Price List 1
                description: null
                status: inactive
                position: 1
                match_policy: all
                starts_at: null
                ends_at: null
                deleted_at: null
                created_at: '2026-06-12T17:24:56.329Z'
                updated_at: '2026-06-12T17:24:56.617Z'
                currently_active: false
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                $ref: '#/components/schemas/PriceList'
  /api/v3/admin/prices:
    get:
      summary: List prices
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Generic prices endpoint covering both base prices and price-list

        overrides. Filter with Ransack: `q[price_list_id_eq]=…`,

        `q[currency_eq]=USD`, `q[price_list_id_null]=true` (base prices only).


        The admin spreadsheet uses this with server-side pagination so it

        scales past the metadata-PATCH path on `/price_lists/:id`.



        **Required scope:** `read_products` (for API-key authentication).'
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nconst { data: prices } = await client.prices.list({\n  price_list_id_eq: 'pl_xxx',\n  currency_eq: 'USD',\n  expand: ['variant'],\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        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[price_list_id_eq]
        in: query
        required: false
        schema:
          type: string
      - name: q[price_list_id_null]
        in: query
        required: false
        schema:
          type: boolean
      - name: q[currency_eq]
        in: query
        required: false
        schema:
          type: string
      - name: q[variant_id_eq]
        in: query
        required: false
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Comma-separated sort keys. Supports e.g. `variant_product_name,variant_id`.
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: 'Comma-separated associations to embed. Supported: `variant`.'
        schema:
          type: string
      responses:
        '200':
          description: prices found
          content:
            application/json:
              example:
                data:
                - 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
                  variant_id: variant_gbHJdmfrXB
                  created_at: '2026-06-12T17:24:56.681Z'
                  updated_at: '2026-06-12T17:24:56.681Z'
                - id: price_EfhxLZ9ck8
                  amount: '5.0'
                  amount_in_cents: 500
                  compare_at_amount: null
                  compare_at_amount_in_cents: null
                  currency: USD
                  display_amount: $5.00
                  display_compare_at_amount: null
                  price_list_id: pl_UkLWZg9DAJ
                  variant_id: variant_gbHJdmfrXB
                  created_at: '2026-06-12T17:24:56.685Z'
                  updated_at: '2026-06-12T17:24:56.685Z'
                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/Price'
                  meta:
                    $ref: '#/components/schemas/PaginationMeta'
                required:
                - data
                - meta
    post:
      summary: Create a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Creates a single price. Omit `price_list_id` to create a base price.

        For more than a handful of rows, prefer `POST /admin/prices/bulk_upsert`.



        **Required scope:** `write_products` (for API-key authentication).'
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nconst price = await client.prices.create({\n  variant_id: 'variant_xxx',\n  currency: 'USD',\n  amount: '19.99',\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: price created
          content:
            application/json:
              example:
                id: price_uw2YK1rnl0
                amount: '9.99'
                amount_in_cents: 999
                compare_at_amount: null
                compare_at_amount_in_cents: null
                currency: EUR
                display_amount: €9.99
                display_compare_at_amount: null
                price_list_id: null
                variant_id: variant_EfhxLZ9ck8
                created_at: '2026-06-12T17:24:57.494Z'
                updated_at: '2026-06-12T17:24:57.494Z'
              schema:
                $ref: '#/components/schemas/Price'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - variant_id
              - currency
              properties:
                variant_id:
                  type: string
                  example: variant_xY9
                currency:
                  type: string
                  example: USD
                amount:
                  type: string
                  nullable: true
                  example: '19.99'
                compare_at_amount:
                  type: string
                  nullable: true
                  example: '24.99'
                price_list_id:
                  type: string
                  nullable: true
                  example: pl_aBc123
  /api/v3/admin/prices/{id}:
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: Get a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: '**Required scope:** `read_products` (for API-key authentication).'
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nconst price = await client.prices.get('price_xxx')"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price found
          content:
            application/json:
              example:
                id: price_EfhxLZ9ck8
                amount: '5.0'
                amount_in_cents: 500
                compare_at_amount: null
                compare_at_amount_in_cents: null
                currency: USD
                display_amount: $5.00
                display_compare_at_amount: null
                price_list_id: pl_UkLWZg9DAJ
                variant_id: variant_gbHJdmfrXB
                created_at: '2026-06-12T17:24:57.574Z'
                updated_at: '2026-06-12T17:24:57.574Z'
              schema:
                $ref: '#/components/schemas/Price'
        '404':
          description: price not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Price not found
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    patch:
      summary: Update a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: '**Required scope:** `write_products` (for API-key authentication).'
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nconst price = await client.prices.update('price_xxx', {\n  amount: '12.34',\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price updated
          content:
            application/json:
              example:
                id: price_EfhxLZ9ck8
                amount: '12.34'
                amount_in_cents: 1234
                compare_at_amount: null
                compare_at_amount_in_cents: null
                currency: USD
                display_amount: $12.34
                display_compare_at_amount: null
                price_list_id: pl_UkLWZg9DAJ
                variant_id: variant_gbHJdmfrXB
                created_at: '2026-06-12T17:24:58.283Z'
                updated_at: '2026-06-12T17:24:58.593Z'
              schema:
                $ref: '#/components/schemas/Price'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: string
                  nullable: true
                compare_at_amount:
                  type: string
                  nullable: true
    delete:
      summary: Delete a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: 'Soft-deletes the price (acts_as_paranoid).


        **Required scope:** `write_products` (for API-key authentication).'
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nawait client.prices.delete('price_xxx')"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: price deleted
  /api/v3/admin/prices/bulk_upsert:
    post:
      summary: Bulk-upsert prices
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: "Upserts a batch of prices in a single SQL round trip.\n\nEach row either:\n* targets an existing price by `id`, OR\n* matches on the unique key `(variant_id, currency, price_list_id)` —\n  updating the existing row if one exists, creating one otherwise.\n\nModel callbacks (e.g. PriceHistory) are bypassed; this is a\nbulk-write fast path for the admin spreadsheet. The response\ncarries `price_count` — the number of rows touched.\n\n\n**Required scope:** `write_products` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nconst { price_count } = await client.prices.bulkUpsert({\n  prices: [\n    {\n      variant_id: 'variant_xxx',\n      currency: 'USD',\n      price_list_id: 'pl_xxx',\n      amount: '11.11',\n    },\n    {\n      variant_id: 'variant_yyy',\n      currency: 'USD',\n      price_list_id: 'pl_xxx',\n      amount: '22.22',\n    },\n  ],\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: prices upserted
          content:
            application/json:
              example:
                price_count: 2
              schema:
                type: object
                properties:
                  price_count:
                    type: integer
        '422':
          description: missing prices key
          content:
            application/json:
              example:
                error:
                  code: missing_prices
                  message: prices is required (send an empty array to no-op).
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - prices
              properties:
                prices:
                  type: array
                  items:
                    type: object
                    required:
                    - variant_id
                    - currency
                    properties:
                      id:
                        type: string
                        nullable: true
                        example: price_aBc123
                      variant_id:
                        typ

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