---
openapi: 3.0.3
info:
title: Store API
contact:
name: Spree Commerce
url: https://spreecommerce.org
email: [email protected]
description: |
Spree Store API v3 - Customer-facing storefront API for building headless commerce experiences.
## Authentication
The Store API uses two authentication methods:
### API Key (Required)
All requests must include a publishable API key in the `x-spree-api-key` header.
### JWT Bearer Token (For authenticated customers)
After login, include the JWT token in the `Authorization: Bearer <token>` header.
### Order Token (For guest checkout)
When creating an order, a `token` is returned. Include this in the `x-spree-token` header
for guest access to that specific order.
## Response Format
All responses are JSON. List endpoints return paginated responses with `data` and `meta` keys.
## Error Handling
Errors return a consistent format:
```json
{
"error": {
"code": "record_not_found",
"message": "Product not found"
}
}
```
version: v3
paths:
"/api/v3/store/customers/me/addresses":
get:
summary: List customer addresses
tags:
- Customers
security:
- api_key: []
bearer_auth: []
description: Returns all addresses in the customer address book
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
const addresses = await client.customer.addresses.list({}, {
token: '<token>',
})
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: 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: addresses found
content:
application/json:
example:
data:
- id: addr_EfhxLZ9ck8
first_name: John
last_name: Doe
full_name: John Doe
address1: 72 Lovely Street
address2: Northwest
postal_code: '10118'
city: New York
phone: 555-555-0199
company: Company
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: false
is_default_shipping: false
state_name: New York
- id: addr_gbHJdmfrXB
first_name: John
last_name: Doe
full_name: John Doe
address1: 71 Lovely Street
address2: Northwest
postal_code: '10118'
city: New York
phone: 555-555-0199
company: Company
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: true
is_default_shipping: false
state_name: New York
- id: addr_UkLWZg9DAJ
first_name: John
last_name: Doe
full_name: John Doe
address1: 70 Lovely Street
address2: Northwest
postal_code: '10118'
city: New York
phone: 555-555-0199
company: Company
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: false
is_default_shipping: true
state_name: New York
meta:
page: 1
limit: 25
count: 3
pages: 1
from: 1
to: 3
in: 3
previous:
next:
schema:
type: object
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Address"
meta:
"$ref": "#/components/schemas/PaginationMeta"
'401':
description: unauthorized
content:
application/json:
example:
error:
code: authentication_required
message: Authentication required
schema:
"$ref": "#/components/schemas/ErrorResponse"
post:
summary: Create an address
tags:
- Customers
security:
- api_key: []
bearer_auth: []
description: Adds a new address to the customer address book
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
const address = await client.customer.addresses.create({
first_name: 'John',
last_name: 'Doe',
address1: '123 Main St',
city: 'New York',
postal_code: '10001',
country_iso: 'US',
state_abbr: 'NY',
phone: '+1 555 123 4567',
}, {
token: '<token>',
})
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: address created
content:
application/json:
example:
id: addr_VqXmZF31wY
first_name: John
last_name: Doe
full_name: John Doe
address1: 123 Main St
address2:
postal_code: '10001'
city: New York
phone: "+1 555 123 4567"
company:
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: false
is_default_shipping: false
state_name: New York
schema:
"$ref": "#/components/schemas/Address"
'422':
description: validation error
content:
application/json:
example:
error:
code: validation_error
message: First Name can't be blank, Last Name can't be blank, Address
can't be blank, City can't be blank, Country can't be blank, and
Zip Code can't be blank
details:
firstname:
- can't be blank
lastname:
- can't be blank
address1:
- can't be blank
city:
- can't be blank
country:
- can't be blank
zipcode:
- can't be blank
schema:
"$ref": "#/components/schemas/ErrorResponse"
requestBody:
content:
application/json:
schema:
type: object
properties:
first_name:
type: string
example: John
last_name:
type: string
example: Doe
address1:
type: string
example: 123 Main St
address2:
type: string
example: Apt 4B
city:
type: string
example: New York
postal_code:
type: string
example: '10001'
phone:
type: string
example: "+1 555 123 4567"
company:
type: string
example: Acme Inc
country_iso:
type: string
example: US
description: ISO 3166-1 alpha-2 country code (e.g., "US", "DE")
state_abbr:
type: string
example: NY
description: ISO 3166-2 subdivision code without country prefix
(e.g., "CA", "NY")
state_name:
type: string
example: New York
description: State name - for countries without predefined states
is_default_billing:
type: boolean
example: true
description: Set as default billing address
is_default_shipping:
type: boolean
example: true
description: Set as default shipping address
required:
- first_name
- last_name
- address1
- city
- postal_code
- country_iso
"/api/v3/store/customers/me/addresses/{id}":
get:
summary: Get an address
tags:
- Customers
security:
- api_key: []
bearer_auth: []
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
const address = await client.customer.addresses.get('addr_abc123', {
token: '<token>',
})
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: 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: address found
content:
application/json:
example:
id: addr_EfhxLZ9ck8
first_name: John
last_name: Doe
full_name: John Doe
address1: 84 Lovely Street
address2: Northwest
postal_code: '10118'
city: New York
phone: 555-555-0199
company: Company
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: false
is_default_shipping: false
state_name: New York
schema:
"$ref": "#/components/schemas/Address"
'404':
description: address not found
content:
application/json:
example:
error:
code: record_not_found
message: Address not found
schema:
"$ref": "#/components/schemas/ErrorResponse"
patch:
summary: Update an address
tags:
- Customers
security:
- api_key: []
bearer_auth: []
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
const address = await client.customer.addresses.update('addr_abc123', {
city: 'Los Angeles',
}, {
token: '<token>',
})
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: address updated
content:
application/json:
example:
id: addr_EfhxLZ9ck8
first_name: John
last_name: Doe
full_name: John Doe
address1: 90 Lovely Street
address2: Northwest
postal_code: '10118'
city: Los Angeles
phone: 555-555-0199
company: Company
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: false
is_default_shipping: false
state_name: New York
schema:
"$ref": "#/components/schemas/Address"
requestBody:
content:
application/json:
schema:
type: object
properties:
first_name:
type: string
example: John
last_name:
type: string
example: Doe
address1:
type: string
example: 456 Oak Ave
city:
type: string
example: Los Angeles
is_default_billing:
type: boolean
example: true
description: Set as default billing address
is_default_shipping:
type: boolean
example: true
description: Set as default shipping address
delete:
summary: Delete an address
tags:
- Customers
security:
- api_key: []
bearer_auth: []
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
await client.customer.addresses.delete('addr_abc123', {
token: '<token>',
})
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: address deleted
'404':
description: address not found
content:
application/json:
example:
error:
code: record_not_found
message: Address not found
schema:
"$ref": "#/components/schemas/ErrorResponse"
"/api/v3/store/auth/login":
post:
summary: Login
tags:
- Authentication
security:
- api_key: []
description: Authenticates a customer with email/password and returns a JWT
token
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
const auth = await client.auth.login({
email: '[email protected]',
password: 'password123',
})
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: login successful
content:
application/json:
example:
token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6ImFjMTYxZjIyLTY2ODUtNDM0My1hZjhlLWFmNmZiY2Q4NzA3ZCIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5MzkwNzE2fQ.BuOWlcghPrLfW7-ka3a2yD1Giq5DAG-5amAPCOsJOvY
refresh_token: PZZGJT4udwGkyKEPgs4WRtus
user:
id: cus_UkLWZg9DAJ
email: [email protected]
first_name: Henriette
last_name: Stamm
phone:
accepts_email_marketing: false
full_name: Henriette Stamm
available_store_credit_total: '0'
display_available_store_credit_total: "$0.00"
addresses: []
default_billing_address:
default_shipping_address:
schema:
"$ref": "#/components/schemas/AuthResponse"
'401':
description: missing API key
content:
application/json:
example:
error:
code: invalid_token
message: Valid API key required
schema:
"$ref": "#/components/schemas/ErrorResponse"
requestBody:
content:
application/json:
schema:
type: object
properties:
provider:
type: string
example: email
description: 'Authentication provider (default: email)'
email:
type: string
format: email
example: [email protected]
password:
type: string
example: password123
required:
- email
- password
"/api/v3/store/auth/refresh":
post:
summary: Refresh token
tags:
- Authentication
security:
- api_key: []
description: Exchanges a refresh token for a new access JWT and rotated refresh
token. No Authorization header needed.
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
const auth = await client.auth.refresh({
refresh_token: 'rt_xxx',
})
parameters:
- name: x-spree-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: token refreshed
content:
application/json:
example:
token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6Ijg2NTFkMTJlLTRiMTItNDZhNi1hYjgzLTY4MjI1YWNhN2FhYyIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5MzkwNzE3fQ.mz2V3U-_6wrTzoLytYOOGc7mgH7eG71jQ_oA4mIHGtY
refresh_token: sRppucnbaakQTvpFCoJArcde
user:
id: cus_UkLWZg9DAJ
email: [email protected]
first_name: Richard
last_name: Larson
phone:
accepts_email_marketing: false
full_name: Richard Larson
available_store_credit_total: '0'
display_available_store_credit_total: "$0.00"
addresses: []
default_billing_address:
default_shipping_address:
schema:
"$ref": "#/components/schemas/AuthResponse"
'401':
description: missing or invalid refresh token
content:
application/json:
example:
error:
code: invalid_refresh_token
message: Invalid or expired refresh token
schema:
"$ref": "#/components/schemas/ErrorResponse"
requestBody:
content:
application/json:
schema:
type: object
properties:
refresh_token:
type: string
description: Refresh token from login response
required:
- refresh_token
"/api/v3/store/auth/logout":
post:
summary: Logout
tags:
- Authentication
security:
- api_key: []
bearer_auth: []
description: Revokes the refresh token, effectively logging the customer out.
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
await client.auth.logout({
refresh_token: 'rt_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: logout without refresh token (no-op)
requestBody:
content:
application/json:
schema:
type: object
properties:
refresh_token:
type: string
description: Refresh token to revoke
"/api/v3/store/carts":
get:
summary: List active carts
tags:
- Carts
security:
- api_key: []
bearer_auth: []
description: Returns all active (incomplete) carts for the authenticated user.
x-codeSamples:
- lang: javascript
label: Spree SDK
source: |-
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: '<api-key>',
})
const carts = await client.carts.list({
token: '<token>',
})
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
description: 'Page number (default: 1)'
schema:
type: integer
- name: limit
in: query
required: false
description: 'Number of results per page (default: 25, max: 100)'
schema:
type: integer
- name: sort
in: query
required: false
description: 'Sort order. Prefix with - for descending. Values: created_at,
-created_at, updated_at, -updated_at'
schema:
type: string
- name: q[created_at_gt]
in: query
required: false
description: Filter by created after date (ISO 8601)
schema:
type: string
- name: q[updated_at_gt]
in: query
required: false
description: Filter by updated after date (ISO 8601)
schema:
type: string
- name: expand
in: query
required: false
description: Comma-separated associations to expand (items, fulfillments,
payments, discounts, billing_address, shipping_address, gift_card, payment_methods).
Use "none" to skip associations.
schema:
type: string
- name: fields
in: query
required: false
description: Comma-separated list of fields to include (e.g., total,amount_due,item_count).
id is always included.
schema:
type: string
responses:
'200':
description: carts listed
content:
application/json:
example:
data:
- id: cart_gbHJdmfrXB
market_id:
number: R560405209
token: iqxaKurjyPCbwiuDRJwhMTLpUQs2SCohKfM
email: [email protected]
customer_note:
currency: USD
locale: en
total_quantity: 1
item_total: '10.0'
display_item_total: "$10.00"
adjustment_total: '0.0'
display_adjustment_total: "$0.00"
discount_total: '0.0'
display_discount_total: "$0.00"
tax_total: '0.0'
display_tax_total: "$0.00"
included_tax_total: '0.0'
display_included_tax_total: "$0.00"
additional_tax_total: '0.0'
display_additional_tax_total: "$0.00"
total: '110.0'
display_total: "$110.00"
gift_card_total: '0.0'
display_gift_card_total: "$0.00"
amount_due: '110.0'
display_amount_due: "$110.00"
delivery_total: '100.0'
display_delivery_total: "$100.00"
warnings: []
store_credit_total: '0.0'
display_store_credit_total: "$0.00"
covered_by_store_credit: false
current_step: address
completed_steps: []
requirements:
- step: payment
field: payment
message: Add a payment method
shipping_eq_billing_address: false
discounts: []
items:
- id: li_gbHJdmfrXB
variant_id: variant_gbHJdmfrXB
quantity: 1
currency: USD
name: Product 584574
slug: product-584574
options_text: ''
price: '10.0'
display_price: "$10.00"
total: '10.0'
display_total: "$10.00"
adjustment_total: '0.0'
display_adjustment_total: "$0.00"
additional_tax_total: '0.0'
display_additional_tax_total: "$0.00"
included_tax_total: '0.0'
display_included_tax_total: "$0.00"
discount_total: '0.0'
display_discount_total: "$0.00"
pre_tax_amount: '10.0'
display_pre_tax_amount: "$10.00"
discounted_amount: '10.0'
display_discounted_amount: "$10.00"
display_compare_at_amount: "$0.00"
compare_at_amount:
thumbnail_url:
option_values: []
digital_links: []
fulfillments:
- id: ful_gbHJdmfrXB
number: H60885401848
tracking: U10000
tracking_url:
cost: '100.0'
display_cost: "$100.00"
total: '100.0'
display_total: "$100.00"
discount_total: '0.0'
display_discount_total: "$0.00"
additional_tax_total: '0.0'
display_additional_tax_total: "$0.00"
included_tax_total: '0.0'
display_included_tax_total: "$0.00"
tax_total: '0.0'
display_tax_total: "$0.00"
status: pending
fulfillment_type: shipping
fulfilled_at:
items:
- item_id: li_gbHJdmfrXB
variant_id: variant_gbHJdmfrXB
quantity: 1
delivery_method:
id: dm_gbHJdmfrXB
name: UPS Ground
code: UPS_GROUND
stock_location:
id: sloc_UkLWZg9DAJ
state_abbr: NY
name: Milissa Kutch
address1: 1600 Pennsylvania Ave NW
city: Washington
zipcode: '20500'
country_iso: US
country_name: United States of America
state_text: NY
delivery_rates:
- id: dr_gbHJdmfrXB
delivery_method_id: dm_gbHJdmfrXB
name: UPS Ground
selected: true
cost: '100.0'
total: '100.0'
additional_tax_total: '0.0'
included_tax_total: '0.0'
tax_total: '0.0'
display_cost: "$100.00"
display_total: "$100.00"
display_additional_tax_total: "$0.00"
display_included_tax_total: "$0.00"
display_tax_total: "$0.00"
delivery_method:
id: dm_gbHJdmfrXB
name: UPS Ground
code: UPS_GROUND
payments: []
billing_address:
id: addr_uw2YK1rnl0
first_name: John
last_name: Doe
full_name: John Doe
address1: 105 Lovely Street
address2: Northwest
postal_code: '10118'
city: New York
phone: 555-555-0199
company: Company
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: false
is_default_shipping: false
state_name: New York
shipping_address:
id: addr_OIJLhNcSbf
first_name: John
last_name: Doe
full_name: John Doe
address1: 106 Lovely Street
address2: Northwest
postal_code: '10118'
city: New York
phone: 555-555-0199
company: Company
country_name: United States of America
country_iso: US
state_text: NY
state_abbr: NY
quick_checkout: false
is_default_billing: false
is_default_shipping: false
state_name: New York
payment_methods: []
gift_card:
market:
- id: cart_UkLWZg9DAJ
# --- truncated at 32 KB (369 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spree-commerce/refs/heads/main/openapi/spree-commerce-store-api-openapi.yml