---
openapi: 3.0.3
info:
title: Admin API
contact:
name: Spree Commerce
url: https://spreecommerce.org
email: [email protected]
description: |
Spree Admin API v3 - Administrative API for managing products, orders, and store settings.
## Authentication
The Admin API requires a secret API key passed in the `x-spree-api-key` header.
Secret API keys can be generated in the Spree admin dashboard.
## Response Format
All responses are JSON. List endpoints return paginated responses with `data` and `meta` keys.
Single resource endpoints return a flat JSON object.
## Resource IDs
Every resource is identified by an opaque string ID (e.g. `prod_86Rf07xd4z`,
`variant_k5nR8xLq`, `or_UkLWZg9DAJ`). Use these IDs everywhere — URL paths,
request bodies, and Ransack filters all accept them directly.
## Error Handling
Errors return a consistent format:
```json
{
"error": {
"code": "validation_error",
"message": "Validation failed",
"details": { "name": ["can't be blank"] }
}
}
```
version: v3
paths:
"/api/v3/admin/admin_users":
get:
summary: List staff
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: |-
Returns admin users with at least one role assignment on the current store.
**Required scope:** `read_settings` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const { data: staff } = await client.adminUsers.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: staff found
content:
application/json:
example:
data:
- id: admin_UkLWZg9DAJ
email: [email protected]
first_name: Jamal
last_name: Doyle
full_name: Jamal Doyle
created_at: '2026-05-24T17:36:33.885Z'
updated_at: '2026-05-24T17:36:33.885Z'
roles:
- id: role_UkLWZg9DAJ
name: admin
meta:
page: 1
limit: 25
count: 1
pages: 1
from: 1
to: 1
in: 1
previous:
next:
"/api/v3/admin/admin_users/{id}":
get:
summary: Show a staff member
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: "**Required scope:** `read_settings` (for API-key authentication)."
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const staff = await client.adminUsers.get('admin_xxx')
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: staff member found
content:
application/json:
example:
id: admin_UkLWZg9DAJ
email: [email protected]
first_name: Mercedez
last_name: Bailey
full_name: Mercedez Bailey
created_at: '2026-05-24T17:36:34.235Z'
updated_at: '2026-05-24T17:36:34.235Z'
roles:
- id: role_UkLWZg9DAJ
name: admin
patch:
summary: Update a staff member
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: |-
Updates name fields and reassigns roles for the current store. `role_ids` is a complete replacement — roles not in the array are removed for this store.
**Required scope:** `write_settings` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const staff = await client.adminUsers.update('admin_xxx', {
first_name: 'Ada',
role_ids: ['role_xxx']
})
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: staff member updated
content:
application/json:
example:
id: admin_UkLWZg9DAJ
email: [email protected]
first_name: Renamed
last_name: Lindgren
full_name: Renamed Lindgren
created_at: '2026-05-24T17:36:34.526Z'
updated_at: '2026-05-24T17:36:34.545Z'
roles:
- id: role_UkLWZg9DAJ
name: admin
requestBody:
content:
application/json:
schema:
type: object
properties:
first_name:
type: string
example: Ada
last_name:
type: string
example: Lovelace
role_ids:
type: array
items:
type: string
delete:
summary: Remove a staff member from this store
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: |-
Removes the user's role assignments on the current store. The account is preserved — the user keeps access to any other stores.
**Required scope:** `write_settings` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
await client.adminUsers.delete('admin_xxx')
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: staff removed from store
"/api/v3/admin/api_keys":
get:
summary: List API keys
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: |-
Returns publishable and secret API keys for the current store. Secret keys are listed by `token_prefix` only — the plaintext token is delivered exactly once on create.
**Required scope:** `read_settings` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const { data: keys } = await client.apiKeys.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: API keys found
content:
application/json:
example:
data:
- id: key_UkLWZg9DAJ
name: Storefront key
key_type: publishable
token_prefix:
scopes: []
created_at: '2026-05-24T17:36:34.854Z'
updated_at: '2026-05-24T17:36:34.854Z'
revoked_at:
last_used_at:
plaintext_token: pk_wqTPmhFDQiJbhbgokeP9tPzK
created_by_email:
- id: key_gbHJdmfrXB
name: Backend integration
key_type: secret
token_prefix: sk_GAnG4mX7L
scopes:
- write_all
created_at: '2026-05-24T17:36:34.855Z'
updated_at: '2026-05-24T17:36:34.855Z'
revoked_at:
last_used_at:
plaintext_token:
created_by_email:
- id: key_EfhxLZ9ck8
name: occaecati
key_type: secret
token_prefix: sk_Zf75n9zm3
scopes:
- write_all
created_at: '2026-05-24T17:36:34.857Z'
updated_at: '2026-05-24T17:36:34.857Z'
revoked_at:
last_used_at:
plaintext_token:
created_by_email:
meta:
page: 1
limit: 25
count: 3
pages: 1
from: 1
to: 3
in: 3
previous:
next:
post:
summary: Create an API key
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: |-
Creates a publishable or secret API key. The plaintext token is included in the response **once** for secret keys; publishable keys expose their token on every read since they are intended for client-side use.
**Required scope:** `write_settings` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const key = await client.apiKeys.create({
name: 'Backend integration',
key_type: 'secret',
scopes: ['read_orders', 'write_orders']
})
// `key.plaintext_token` is available only on this response.
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: secret key created — plaintext token returned once
content:
application/json:
example:
id: key_VqXmZF31wY
name: CI key
key_type: secret
token_prefix: sk_ryCceerpp
scopes:
- read_orders
created_at: '2026-05-24T17:36:35.441Z'
updated_at: '2026-05-24T17:36:35.441Z'
revoked_at:
last_used_at:
plaintext_token: sk_ryCceerpp5vqodztxueeWXmc
created_by_email: [email protected]
'422':
description: validation error
content:
application/json:
example:
error:
code: validation_error
message: Name can't be blank and Scopes can't be blank
details:
name:
- can't be blank
scopes:
- can't be blank
requestBody:
content:
application/json:
schema:
type: object
required:
- name
- key_type
properties:
name:
type: string
example: Backend integration
key_type:
type: string
enum:
- publishable
- secret
scopes:
type: array
items:
type: string
example:
- read_orders
- write_orders
"/api/v3/admin/api_keys/{id}":
get:
summary: Show an API key
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: "**Required scope:** `read_settings` (for API-key authentication)."
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const key = await client.apiKeys.get('key_xxx')
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: API key found
content:
application/json:
example:
id: key_UkLWZg9DAJ
name: Storefront key
key_type: publishable
token_prefix:
scopes: []
created_at: '2026-05-24T17:36:35.723Z'
updated_at: '2026-05-24T17:36:35.723Z'
revoked_at:
last_used_at:
plaintext_token: pk_yXJtU7SvnfLbkPvuuiUnKaEo
created_by_email:
delete:
summary: Delete an API key
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: "**Required scope:** `write_settings` (for API-key authentication)."
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
await client.apiKeys.delete('key_xxx')
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: API key deleted
"/api/v3/admin/api_keys/{id}/revoke":
patch:
summary: Revoke an API key
tags:
- Configuration
security:
- api_key: []
bearer_auth: []
description: |-
Marks the key revoked. Future requests using its token will fail; the row is preserved for audit.
**Required scope:** `write_settings` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const key = await client.apiKeys.revoke('key_xxx')
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: API key revoked
content:
application/json:
example:
id: key_gbHJdmfrXB
name: Backend integration
key_type: secret
token_prefix: sk_q6euaWxod
scopes:
- write_all
created_at: '2026-05-24T17:36:36.279Z'
updated_at: '2026-05-24T17:36:36.554Z'
revoked_at: '2026-05-24T17:36:36.553Z'
last_used_at:
plaintext_token:
created_by_email:
"/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'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const { 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-05-24T17:36:36.570Z'
updated_at: '2026-05-24T17:36:36.570Z'
promotion_id: promo_UkLWZg9DAJ
order_id:
- id: coupon_gbHJdmfrXB
code: BBB222
state: unused
created_at: '2026-05-24T17:36:36.571Z'
updated_at: '2026-05-24T17:36:36.571Z'
promotion_id: promo_UkLWZg9DAJ
order_id:
meta:
page: 1
limit: 25
count: 2
pages: 1
from: 1
to: 2
in: 2
previous:
next:
"/api/v3/admin/custom_field_definitions":
get:
summary: List custom field definitions
tags:
- Custom Fields
security:
- api_key: []
bearer_auth: []
description: |-
Returns all defined custom fields. Filter by `?q[resource_type_eq]=Spree::Product` to narrow to one parent type.
**Required scope:** `read_custom_field_definitions` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const { data: definitions } = await client.customFieldDefinitions.list({
q: { resource_type_eq: 'Spree::Product' },
})
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
description: Comma-separated associations to expand. Use dot notation for
nested expand (max 4 levels).
schema:
type: string
- name: fields
in: query
required: false
description: Comma-separated list of fields to include (e.g., key,label,field_type).
id is always included.
schema:
type: string
responses:
'200':
description: definitions returned
content:
application/json:
example:
data:
- id: cfdef_UkLWZg9DAJ
namespace: specs
key: fabric
label: Title
field_type: short_text
resource_type: Spree::Product
storefront_visible: true
created_at: '2026-05-24T17:36:36.857Z'
updated_at: '2026-05-24T17:36:36.857Z'
- id: cfdef_gbHJdmfrXB
namespace: custom
key: order_notes
label: Order Notes
field_type: short_text
resource_type: Spree::Order
storefront_visible: true
created_at: '2026-05-24T17:36:36.857Z'
updated_at: '2026-05-24T17:36:36.857Z'
meta:
page: 1
limit: 25
count: 2
pages: 1
from: 1
to: 2
in: 2
previous:
next:
post:
summary: Create a custom field definition
tags:
- Custom Fields
security:
- api_key: []
bearer_auth: []
description: "**Required scope:** `write_custom_field_definitions` (for API-key
authentication)."
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const definition = await client.customFieldDefinitions.create({
namespace: 'specs',
key: 'origin',
label: 'Country of Origin',
field_type: 'short_text',
resource_type: 'Spree::Product',
storefront_visible: true,
})
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: definition created
content:
application/json:
example:
id: cfdef_EfhxLZ9ck8
namespace: specs
key: origin
label: Country of Origin
field_type: short_text
resource_type: Spree::Product
storefront_visible: true
created_at: '2026-05-24T17:36:37.407Z'
updated_at: '2026-05-24T17:36:37.407Z'
requestBody:
content:
application/json:
schema:
type: object
required:
- key
- field_type
- resource_type
properties:
namespace:
type: string
description: Defaults to `custom`
key:
type: string
label:
type: string
description: Human-readable name; defaults to titleized `key`
field_type:
type: string
description: Custom field type identifier (one of the registered
field-type class names).
resource_type:
type: string
description: Owner class, e.g. `Spree::Product`
storefront_visible:
type: boolean
description: 'When false, definition is admin-only (was `display_on:
back_end`)'
"/api/v3/admin/custom_field_definitions/{id}":
get:
summary: Show a custom field definition
tags:
- Custom Fields
security:
- api_key: []
bearer_auth: []
description: "**Required scope:** `read_custom_field_definitions` (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
- name: expand
in: query
required: false
description: Comma-separated associations to expand. Use dot notation for
nested expand (max 4 levels).
schema:
type: string
- name: fields
in: query
required: false
description: Comma-separated list of fields to include (e.g., key,label,field_type).
id is always included.
schema:
type: string
responses:
'200':
description: definition found
content:
application/json:
example:
id: cfdef_UkLWZg9DAJ
namespace: specs
key: fabric
label: Title
field_type: short_text
resource_type: Spree::Product
storefront_visible: true
created_at: '2026-05-24T17:36:37.410Z'
updated_at: '2026-05-24T17:36:37.410Z'
patch:
summary: Update a custom field definition
tags:
- Custom Fields
security:
- api_key: []
bearer_auth: []
description: "**Required scope:** `write_custom_field_definitions` (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: definition updated
content:
application/json:
example:
id: cfdef_UkLWZg9DAJ
namespace: specs
key: fabric
label: Fabric Composition
field_type: short_text
resource_type: Spree::Product
storefront_visible: false
created_at: '2026-05-24T17:36:37.685Z'
updated_at: '2026-05-24T17:36:37.959Z'
requestBody:
content:
application/json:
schema:
type: object
properties:
label:
type: string
storefront_visible:
type: boolean
delete:
summary: Delete a custom field definition
tags:
- Custom Fields
security:
- api_key: []
bearer_auth: []
description: |-
Deletes the definition and cascades to all custom field values referencing it.
**Required scope:** `write_custom_field_definitions` (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: definition deleted
"/api/v3/admin/customer_groups":
get:
summary: List customer groups
tags:
- Customers
security:
- api_key: []
bearer_auth: []
description: |-
Returns the customer groups configured for the current store. Groups
segment customers for targeted promotions (see the `customer_group`
promotion rule) and reporting. The list endpoint never embeds the
member list — fetch a single group with `?expand=customers` if you
need them inline, or query `/admin/customers?customer_group_id_in=…`
for paginated membership.
**Required scope:** `read_customers` (for API-key authentication).
x-codeSamples:
- lang: javascript
label: Spree Admin SDK
source: |-
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://your-store.com',
secretKey: 'sk_xxx',
})
const { data: groups } = await client.customerGroups.list({ page: 1, limit: 25 })
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
- name: Authorization
in: header
required: true
description: Bearer token for admin authentication
schema:
type: string
- name: page
in: query
required: false
description: Page number
schema:
type: integer
- name: limit
in: query
required: false
description: Number of records per page
schema:
type: integer
- name: q[name_cont]
in: query
required: false
description: Filter by name (contains)
schema:
type: string
- name: sort
in: query
required: false
description: Sort by field. Prefix with `-` for descending (e.g., `-created_at`).
schema:
type: string
- name: fields
in: query
required: false
description: Comma-separated list of fields to include. id is always included.
schema:
type: string
responses:
'200':
description: customer groups found
content:
application/json:
example:
data:
- id: cg_UkLWZg9DAJ
name: VIPs
description: Top spenders
customers_count: 0
created_at: '2026-05-24T17:36:38.239Z'
updated_at: '2026-05-24T17:36:38.239Z'
- id: cg_gbHJdmfrXB
name: Wholesale
description:
customers_count: 0
created_at: '2026-05-24T17:36:38.240Z'
updated_at: '2026-05-24T17:36:38.240Z'
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/CustomerGroup"
meta:
"$ref": "#/components/schemas/PaginationMeta"
required:
- data
- meta
'401':
description: unauthorized
content:
application/json:
# --- truncated at 32 KB (468 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spree-commerce/refs/heads/main/openapi/spree-commerce-admin-api-openapi.yml