Spree Commerce Promotions API
Promotions, promotion rules, promotion actions, and coupon codes
Promotions, promotion rules, promotion actions, and coupon codes
openapi: 3.0.3
info:
title: Admin Account / Address Promotions 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: Promotions
description: Promotions, promotion rules, promotion actions, and coupon codes
paths:
/api/v3/admin/promotions/{promotion_id}/coupon_codes:
parameters:
- name: promotion_id
in: path
required: true
schema:
type: string
get:
summary: List coupon codes for a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: 'Returns the auto-generated coupon codes for a multi-code promotion. Single-code promotions store the code on the promotion itself; this endpoint returns an empty list for them.
**Required scope:** `read_promotions` (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: coupons } = await client.promotions.couponCodes.list('promo_UkLWZg9DAJ')"
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: coupon codes found
content:
application/json:
example:
data:
- id: coupon_UkLWZg9DAJ
code: AAA111
state: unused
created_at: '2026-06-12T17:23:52.481Z'
updated_at: '2026-06-12T17:23:52.481Z'
promotion_id: promo_UkLWZg9DAJ
order_id: null
- id: coupon_gbHJdmfrXB
code: BBB222
state: unused
created_at: '2026-06-12T17:23:52.483Z'
updated_at: '2026-06-12T17:23:52.483Z'
promotion_id: promo_UkLWZg9DAJ
order_id: null
meta:
page: 1
limit: 25
count: 2
pages: 1
from: 1
to: 2
in: 2
previous: null
next: null
/api/v3/admin/promotions/{promotion_id}/promotion_actions:
parameters:
- name: promotion_id
in: path
required: true
schema:
type: string
get:
summary: List actions for a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: '**Required scope:** `read_promotions` (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: actions } = await client.promotions.actions.list('promo_UkLWZg9DAJ')"
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: actions found
content:
application/json:
example:
data:
- id: pact_UkLWZg9DAJ
created_at: '2026-06-12T17:25:08.639Z'
updated_at: '2026-06-12T17:25:08.639Z'
type: free_shipping
promotion_id: promo_UkLWZg9DAJ
preferences: {}
preference_schema: []
label: Free shipping
calculator: null
line_items: null
meta:
page: 1
limit: 25
count: 1
pages: 1
from: 1
to: 1
in: 1
previous: null
next: null
post:
summary: Create an action on a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: 'Adds a new action to a promotion. The `type` is the wire shorthand from `GET /promotion_actions/types` (e.g. `free_shipping`, `create_item_adjustments`). Fully-qualified Ruby class names are also accepted for backward compatibility.
**Required scope:** `write_promotions` (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 action = await client.promotions.actions.create('promo_UkLWZg9DAJ', {\n type: 'free_shipping',\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: action created
content:
application/json:
example:
id: pact_UkLWZg9DAJ
created_at: '2026-06-12T17:25:09.232Z'
updated_at: '2026-06-12T17:25:09.232Z'
type: free_shipping
promotion_id: promo_UkLWZg9DAJ
preferences: {}
preference_schema: []
label: Free shipping
calculator: null
line_items: null
'422':
description: unknown action type
content:
application/json:
example:
error:
code: unknown_promotion_action_type
message: Unknown type
requestBody:
content:
application/json:
schema:
type: object
properties:
type:
type: string
example: free_shipping
preferences:
type: object
additionalProperties: true
required:
- type
/api/v3/admin/promotions/{promotion_id}/promotion_actions/{id}:
parameters:
- name: promotion_id
in: path
required: true
schema:
type: string
- name: id
in: path
required: true
schema:
type: string
delete:
summary: Delete an action from a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: '**Required scope:** `write_promotions` (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: action deleted
/api/v3/admin/promotions/{promotion_id}/promotion_rules:
parameters:
- name: promotion_id
in: path
required: true
schema:
type: string
get:
summary: List rules for a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: '**Required scope:** `read_promotions` (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: rules } = await client.promotions.rules.list('promo_UkLWZg9DAJ')"
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: rules found
content:
application/json:
example:
data:
- id: prorule_UkLWZg9DAJ
created_at: '2026-06-12T17:25:09.944Z'
updated_at: '2026-06-12T17:25:09.944Z'
type: currency
promotion_id: promo_UkLWZg9DAJ
preferences:
currency: USD
preference_schema:
- key: currency
type: string
default: null
label: Currency
product_ids: null
category_ids: null
customer_ids: null
meta:
page: 1
limit: 25
count: 1
pages: 1
from: 1
to: 1
in: 1
previous: null
next: null
post:
summary: Create a rule on a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: 'Adds a new rule to a promotion. The `type` is the wire shorthand from `GET /promotion_rules/types` (e.g. `currency`, `item_total`, `product`). Fully-qualified Ruby class names are also accepted for backward compatibility.
**Required scope:** `write_promotions` (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 rule = await client.promotions.rules.create('promo_UkLWZg9DAJ', {\n type: 'currency',\n preferences: { currency: 'EUR' },\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: rule created with preferences
content:
application/json:
example:
id: prorule_UkLWZg9DAJ
created_at: '2026-06-12T17:25:10.546Z'
updated_at: '2026-06-12T17:25:10.546Z'
type: currency
promotion_id: promo_UkLWZg9DAJ
preferences:
currency: EUR
preference_schema:
- key: currency
type: string
default: null
label: Currency
product_ids: null
category_ids: null
customer_ids: null
'422':
description: unknown rule type
content:
application/json:
example:
error:
code: unknown_promotion_rule_type
message: Unknown type
requestBody:
content:
application/json:
schema:
type: object
properties:
type:
type: string
example: currency
preferences:
type: object
additionalProperties: true
required:
- type
/api/v3/admin/promotions/{promotion_id}/promotion_rules/{id}:
parameters:
- name: promotion_id
in: path
required: true
schema:
type: string
- name: id
in: path
required: true
schema:
type: string
patch:
summary: Update a rule's preferences
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: '**Required scope:** `write_promotions` (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: rule updated
content:
application/json:
example:
id: prorule_UkLWZg9DAJ
created_at: '2026-06-12T17:25:10.853Z'
updated_at: '2026-06-12T17:25:11.135Z'
type: currency
promotion_id: promo_UkLWZg9DAJ
preferences:
currency: GBP
preference_schema:
- key: currency
type: string
default: null
label: Currency
product_ids: null
category_ids: null
customer_ids: null
requestBody:
content:
application/json:
schema:
type: object
properties:
preferences:
type: object
additionalProperties: true
delete:
summary: Delete a rule from a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: '**Required scope:** `write_promotions` (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: rule deleted
/api/v3/admin/promotions:
get:
summary: List promotions
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: 'Returns the store''s promotions, including manual coupon and automatic promotions.
**Required scope:** `read_promotions` (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: promotions } = await client.promotions.list()"
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: promotions found
content:
application/json:
example:
data:
- id: promo_UkLWZg9DAJ
name: Summer Sale
description: null
code: summer
starts_at: '2026-06-12T17:25:11.475Z'
expires_at: null
usage_limit: null
match_policy: all
path: null
kind: coupon_code
multi_codes: false
number_of_codes: null
code_prefix: null
promotion_category_id: null
metadata: {}
created_at: '2026-06-12T17:25:11.477Z'
updated_at: '2026-06-12T17:25:11.479Z'
action_ids: []
rule_ids: []
meta:
page: 1
limit: 25
count: 1
pages: 1
from: 1
to: 1
in: 1
previous: null
next: null
post:
summary: Create a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: 'Creates a new promotion. `code` is required for single-code coupon promotions;
pass `multi_codes: true` with `number_of_codes` to auto-generate a batch.
Rules and actions can be created in the same request by passing arrays of
`{ type, preferences, ... }` rows. The server reconciles to the desired set:
new rows are built, existing rows (by `id`) are updated, omitted rows are removed.
**Required scope:** `write_promotions` (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\n// Single coupon code, no rules/actions\nconst promotion = await client.promotions.create({\n name: 'Black Friday',\n code: 'BLACKFRIDAY',\n starts_at: '2026-11-29T00:00:00Z',\n expires_at: '2026-12-01T00:00:00Z',\n})\n\n// One-shot: promotion + rules + actions in a single request\nconst blackFriday = await client.promotions.create({\n name: 'Black Friday',\n code: 'BLACKFRIDAY',\n kind: 'coupon_code',\n starts_at: '2026-11-29T00:00:00Z',\n expires_at: '2026-12-01T00:00:00Z',\n match_policy: 'all',\n rules: [\n {\n type: 'currency',\n preferences: { currency: 'USD' },\n },\n {\n type: 'item_total',\n preferences: { amount_min: 100, operator_min: 'gte' },\n },\n {\n type: 'product',\n preferences: { match_policy: 'any' },\n product_ids: ['prod_abc123', 'prod_def456'],\n },\n ],\n actions: [\n {\n type: 'create_item_adjustments',\n calculator: {\n type: 'percent_on_line_item',\n preferences: { percent: 25 },\n },\n },\n { type: 'free_shipping' },\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:
'201':
description: promotion created with rules and actions
content:
application/json:
example:
id: promo_gbHJdmfrXB
name: Black Friday
description: null
code: blackfriday-os
starts_at: '2026-06-12T17:25:12.469Z'
expires_at: null
usage_limit: null
match_policy: all
path: null
kind: coupon_code
multi_codes: false
number_of_codes: null
code_prefix: null
promotion_category_id: null
metadata: {}
created_at: '2026-06-12T17:25:12.471Z'
updated_at: '2026-06-12T17:25:12.495Z'
action_ids:
- pact_UkLWZg9DAJ
- pact_gbHJdmfrXB
rule_ids:
- prorule_UkLWZg9DAJ
- prorule_gbHJdmfrXB
- prorule_EfhxLZ9ck8
'422':
description: invalid params
content:
application/json:
example:
error:
code: validation_error
message: Name can't be blank and Code can't be blank
details:
name:
- can't be blank
code:
- can't be blank
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
code:
type: string
nullable: true
description:
type: string
nullable: true
starts_at:
type: string
format: date-time
nullable: true
expires_at:
type: string
format: date-time
nullable: true
usage_limit:
type: integer
nullable: true
match_policy:
type: string
enum:
- all
- any
kind:
type: string
enum:
- coupon_code
- automatic
multi_codes:
type: boolean
number_of_codes:
type: integer
nullable: true
code_prefix:
type: string
nullable: true
promotion_category_id:
type: string
nullable: true
rules:
type: array
items:
type: object
properties:
type:
type: string
example: currency
preferences:
type: object
additionalProperties: true
product_ids:
type: array
items:
type: string
category_ids:
type: array
items:
type: string
customer_ids:
type: array
items:
type: string
required:
- type
actions:
type: array
items:
type: object
properties:
type:
type: string
example: free_shipping
preferences:
type: object
additionalProperties: true
calculator:
type: object
properties:
type:
type: string
example: flat_percent_item_total
preferences:
type: object
additionalProperties: true
required:
- type
required:
- name
/api/v3/admin/promotions/{id}:
get:
summary: Show a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: '**Required scope:** `read_promotions` (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: id
in: path
required: true
schema:
type: string
responses:
'200':
description: promotion found
content:
application/json:
example:
id: promo_UkLWZg9DAJ
name: Summer Sale
description: null
code: summer
starts_at: '2026-06-12T17:25:12.804Z'
expires_at: null
usage_limit: null
match_policy: all
path: null
kind: coupon_code
multi_codes: false
number_of_codes: null
code_prefix: null
promotion_category_id: null
metadata: {}
created_at: '2026-06-12T17:25:12.805Z'
updated_at: '2026-06-12T17:25:12.806Z'
action_ids: []
rule_ids: []
patch:
summary: Update a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: 'Updates a promotion. The `rules` and `actions` arrays are treated as
a *desired set* — rows with `id` update in place, rows without `id` are
built fresh, and any existing row not present in the array is destroyed.
Pass `rules: []` or `actions: []` to clear them.
**Required scope:** `write_promotions` (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\n// Basic field update\nawait client.promotions.update(promotionId, {\n description: 'Updated description',\n})\n\n// One-shot: rewrite rules + actions in a single request\nawait client.promotions.update(promotionId, {\n name: 'Holiday Sale',\n rules: [\n // Update an existing rule by id — `preferences` overwrite the prior set\n {\n id: 'prorule_existing',\n type: 'currency',\n preferences: { currency: 'EUR' },\n },\n // Add a new rule\n {\n type: 'item_total',\n preferences: { amount_min: 50, operator_min: 'gte' },\n },\n ],\n actions: [\n // Swap calculator type on an existing action\n {\n id: 'proaction_existing',\n type: 'create_item_adjustments',\n calculator: {\n type: 'percent_on_line_item',\n preferences: { percent: 15 },\n },\n },\n ],\n})\n\n// Remove all rules/actions\nawait client.promotions.update(promotionId, {\n rules: [],\n actions: [],\n})"
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
- name: Authorization
in: header
required: true
schema:
type: string
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: rules and actions cleared with empty arrays
content:
application/json:
example:
id: promo_UkLWZg9DAJ
name: Summer Sale
description: null
code: summer
starts_at: '2026-06-12T17:25:13.717Z'
expires_at: null
usage_limit: null
match_policy: all
path: null
kind: coupon_code
multi_codes: false
number_of_codes: null
code_prefix: null
promotion_category_id: null
metadata: {}
created_at: '2026-06-12T17:25:13.718Z'
updated_at: '2026-06-12T17:25:14.003Z'
action_ids: []
rule_ids: []
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
description:
type: string
nullable: true
code:
type: string
nullable: true
starts_at:
type: string
format: date-time
nullable: true
expires_at:
type: string
format: date-time
nullable: true
usage_limit:
type: integer
nullable: true
match_policy:
type: string
enum:
- all
- any
kind:
type: string
enum:
- coupon_code
- automatic
promotion_category_id:
type: string
nullable: true
rules:
type: array
items:
type: object
properties:
id:
type: string
nullable: true
description: Pass to update an existing rule; omit to build a new one
type:
type: string
example: currency
preferences:
type: object
additionalProperties: true
product_ids:
type: array
items:
type: string
category_ids:
type: array
items:
type: string
customer_ids:
type: array
items:
type: string
required:
- type
actions:
type: array
items:
type: object
properties:
id:
type: string
nullable: true
type:
type: string
example: free_shipping
preferences:
type: object
additionalProperties: true
calculator:
type: object
properties:
type:
type: string
example: flat_percent_item_total
preferences:
type: object
additionalProperties: true
required:
- type
delete:
summary: Delete a promotion
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: '**Required scope:** `write_promotions` (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: id
in: path
required: true
schema:
type: string
responses:
'204':
description: promotion deleted
/api/v3/admin/promotion_actions/types:
get:
summary: List available promotion action types
tags:
- Promotions
security:
- api_key: []
bearer_auth: []
description: 'Returns the registered Spree::PromotionAction subclasses with their preference schemas. Used by admin UIs to populate the "Add action" picker and render generic preference forms.
**Required scope:** `read_promotions` (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: actionTypes } = await client.promotionActions.types()"
parameters:
- name: x-
# --- truncated at 32 KB (69 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spree/refs/heads/main/openapi/spree-promotions-api-openapi.yml