# Create an allowed origin
Source: https://spreecommerce.org/docs/api-reference/admin-api/allowed-origins/create-an-allowed-origin
/api-reference/admin.yaml post /api/v3/admin/allowed_origins
Adds an origin to the admin CORS allowlist. The value must be a bare
`scheme://host[:port]` (no path, query, or fragment) and use `http` or
`https`.
**Required scope:** `write_settings` (for API-key authentication).
# Delete an allowed origin
Source: https://spreecommerce.org/docs/api-reference/admin-api/allowed-origins/delete-an-allowed-origin
/api-reference/admin.yaml delete /api/v3/admin/allowed_origins/{id}
Removes an origin from the admin CORS allowlist. After deletion the
admin SPA running at that origin will no longer be able to call the
admin API from a browser.
**Required scope:** `write_settings` (for API-key authentication).
# Get an allowed origin
Source: https://spreecommerce.org/docs/api-reference/admin-api/allowed-origins/get-an-allowed-origin
/api-reference/admin.yaml get /api/v3/admin/allowed_origins/{id}
Returns a single allowed origin by prefixed ID.
**Required scope:** `read_settings` (for API-key authentication).
# List allowed origins
Source: https://spreecommerce.org/docs/api-reference/admin-api/allowed-origins/list-allowed-origins
/api-reference/admin.yaml get /api/v3/admin/allowed_origins
Returns the CORS allowlist for the current store. Each entry is a
bare `scheme://host[:port]` permitted to call the admin API from a
browser. Backs the `Rack::Cors` allowlist and the CSRF boundary of
the admin cookie session (see
`docs/plans/5.5-admin-auth-cookie-refresh.md`).
**Required scope:** `read_settings` (for API-key authentication).
# Update an allowed origin
Source: https://spreecommerce.org/docs/api-reference/admin-api/allowed-origins/update-an-allowed-origin
/api-reference/admin.yaml patch /api/v3/admin/allowed_origins/{id}
Updates an existing allowed origin.
**Required scope:** `write_settings` (for API-key authentication).
# Create an API key
Source: https://spreecommerce.org/docs/api-reference/admin-api/api-keys/create-an-api-key
/api-reference/admin.yaml post /api/v3/admin/api_keys
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).
# Delete an API key
Source: https://spreecommerce.org/docs/api-reference/admin-api/api-keys/delete-an-api-key
/api-reference/admin.yaml delete /api/v3/admin/api_keys/{id}
**Required scope:** `write_settings` (for API-key authentication).
# List API keys
Source: https://spreecommerce.org/docs/api-reference/admin-api/api-keys/list-api-keys
/api-reference/admin.yaml get /api/v3/admin/api_keys
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).
# Revoke an API key
Source: https://spreecommerce.org/docs/api-reference/admin-api/api-keys/revoke-an-api-key
/api-reference/admin.yaml patch /api/v3/admin/api_keys/{id}/revoke
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).
# Show an API key
Source: https://spreecommerce.org/docs/api-reference/admin-api/api-keys/show-an-api-key
/api-reference/admin.yaml get /api/v3/admin/api_keys/{id}
**Required scope:** `read_settings` (for API-key authentication).
# Authenticate Admin API requests with keys and JWTs
Source: https://spreecommerce.org/docs/api-reference/admin-api/authentication
Authenticate Spree Admin API requests using secret API keys for server-to-server calls or JWT bearer tokens for interactive admin sessions.
The Admin API supports two authentication methods: **secret API keys** for server-to-server integrations, and **JWT bearer tokens** for admin SPA / interactive sessions. Every request must include credentials — there is no public surface.
Secret API keys grant full administrative access to your store. **Never embed them in client-side code, mobile apps, or public repositories.** Use them only from secure server environments.
## Secret API key
Pass the key via the `X-Spree-Api-Key` header:
```typescript SDK theme={"theme":"night-owl"}
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'https://store.example.com',
secretKey: 'sk_xxx',
})
// The SDK automatically sends the secret key with every request
const { data: products } = await client.products.list()
```
```bash cURL theme={"theme":"night-owl"}
curl -X GET 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx'
```
Secret API keys are prefixed with `sk_`. Create them in the Spree admin under **Settings → API Keys** or via the Spree CLI:
```bash theme={"theme":"night-owl"}
spree api-key create --type secret # Create a new secret key
spree api-key list # List existing keys
spree api-key revoke # Revoke a key
```
If you omit the API key, the API returns `401 Unauthorized`:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "authentication_required",
"message": "Authentication required"
}
}
```
## JWT bearer token (admin user)
For interactive admin sessions (the Spree admin SPA, custom dashboards, etc.) authenticate as an admin user and use the returned JWT token for subsequent requests.
### Login
```typescript SDK theme={"theme":"night-owl"}
const { token, user } = await client.auth.login({
email: 'admin@example.com',
password: 'secret123',
})
// Reuse the JWT for subsequent requests. setToken is sticky — every
// later call on `client` carries the bearer header automatically.
client.setToken(token)
const orders = await client.orders.list()
```
```bash cURL theme={"theme":"night-owl"}
curl -X POST 'https://store.example.com/api/v3/admin/auth/login' \
-H 'X-Spree-Api-Key: sk_xxx' \
-H 'Content-Type: application/json' \
-d '{"email": "admin@example.com", "password": "secret123"}'
```
### Token refresh
JWT tokens expire after 1 hour by default. Refresh them with the current token:
```typescript SDK theme={"theme":"night-owl"}
const { token } = await client.auth.refresh({ token: currentToken })
```
```bash cURL theme={"theme":"night-owl"}
curl -X POST 'https://store.example.com/api/v3/admin/auth/refresh' \
-H 'X-Spree-Api-Key: sk_xxx' \
-H 'Authorization: Bearer '
```
## Permissions
Authorization works differently depending on which credentials you use.
### Secret API keys: scopes
Each secret API key carries a list of **scopes** that grant access to specific resources. Scopes follow a `read_` / `write_` convention; `write_` implies `read_`.
| Scope | Endpoints |
| -------------------------------------------- | ------------------------------------------------------------------------- |
| `read_orders` / `write_orders` | `/orders/*`, `/orders/:id/items` |
| `read_products` / `write_products` | `/products/*`, `/variants/*`, `/option_types/*`, `/media/*` |
| `read_customers` / `write_customers` | `/customers/*`, `/customers/:id/addresses`, `/customers/:id/credit_cards` |
| `read_payments` / `write_payments` | `/orders/:id/payments` |
| `read_fulfillments` / `write_fulfillments` | `/orders/:id/fulfillments` |
| `read_refunds` / `write_refunds` | `/orders/:id/refunds` |
| `read_gift_cards` / `write_gift_cards` | `/orders/:id/gift_cards` |
| `read_store_credits` / `write_store_credits` | `/customers/:id/store_credits`, `/orders/:id/store_credits` |
| `read_categories` / `write_categories` | `/categories/*` |
| `read_settings` / `write_settings` | `/payment_methods`, `/markets`, `/countries`, `/tax_categories`, `/store` |
| `read_dashboard` | `/dashboard/*` (analytics) |
Two convenience aliases:
* **`read_all`** — every `read_*` scope
* **`write_all`** — every `read_*` and `write_*` scope (full admin)
If the key lacks the required scope, the API returns `403 Forbidden`:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "access_denied",
"message": "API key lacks scope: write_orders",
"details": {
"required_scope": "write_orders"
}
}
}
```
The `details.required_scope` field tells you exactly which scope to add.
Pick scopes when creating the key in **Settings → API Keys**. Choose the narrowest set that covers your integration's needs.
### JWT bearer tokens: CanCanCan abilities
JWT-authenticated admin users are authorized via [CanCanCan](https://github.com/CanCanCommunity/cancancan) abilities derived from their `Spree::Role`s. The SPA uses this fine-grained model to render UI conditionally; partial-permission staff users see only the resources their role grants.
If the caller lacks permission for a specific action, the API returns `403 Forbidden`:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "access_denied",
"message": "You are not authorized to perform this action"
}
}
```
## Authentication summary
| Method | Header | Use case | Authorization |
| -------------- | ------------------------------- | ------------------------------- | ------------------- |
| Secret API key | `X-Spree-Api-Key: sk_xxx` | Server-to-server integrations | Scopes |
| JWT token | `Authorization: Bearer ` | Interactive admin sessions; SPA | CanCanCan abilities |
If both headers are present, the JWT token wins: CanCanCan applies and scopes are ignored. This lets you use `sk_xxx` to bootstrap a session and then issue per-user JWTs for individual admin actions.
# Get current admin user and permissions
Source: https://spreecommerce.org/docs/api-reference/admin-api/authentication/get-current-admin-user-and-permissions
/api-reference/admin.yaml get /api/v3/admin/me
Returns the current admin user profile and a serialized list of permissions (CanCanCan rules). The SPA uses these to drive UI permission checks.
# Login
Source: https://spreecommerce.org/docs/api-reference/admin-api/authentication/login
/api-reference/admin.yaml post /api/v3/admin/auth/login
Authenticates an admin user and returns a short-lived JWT access token.
The rotatable refresh token is set in an HttpOnly cookie — it is not
included in the response body.
Dispatches by the `provider` field to a strategy registered in
`Spree.admin_authentication_strategies`. When `provider` is omitted it
defaults to `email`, which uses the built-in email/password strategy.
To plug in a third-party identity provider (Okta, Azure AD, Google
Workspace SSO, a custom JWT issuer, SAML, etc.), register a
`Spree::Authentication::Strategies::BaseStrategy` subclass under a
provider key, then send `{ "provider": "", ... }` with the
fields your strategy requires. The endpoint returns the same Spree-issued
JWT regardless of which strategy authenticated the request.
# Logout
Source: https://spreecommerce.org/docs/api-reference/admin-api/authentication/logout
/api-reference/admin.yaml post /api/v3/admin/auth/logout
Revokes the refresh-token cookie, effectively logging the admin out.
# Refresh token
Source: https://spreecommerce.org/docs/api-reference/admin-api/authentication/refresh-token
/api-reference/admin.yaml post /api/v3/admin/auth/refresh
Exchanges the HttpOnly refresh-token cookie for a new access JWT and a
rotated refresh token cookie. No request body or Authorization header
is required — the cookie alone authenticates the call.
# Create a channel
Source: https://spreecommerce.org/docs/api-reference/admin-api/channels/create-a-channel
/api-reference/admin.yaml post /api/v3/admin/channels
Creates a new channel on the current store. `code` is normalized to a
URL-safe slug (`Point of Sale` → `point-of-sale`); when omitted it's
derived from `name`.
**Required scope:** `write_settings` (for API-key authentication).
# Delete a channel
Source: https://spreecommerce.org/docs/api-reference/admin-api/channels/delete-a-channel
/api-reference/admin.yaml delete /api/v3/admin/channels/{id}
**Required scope:** `write_settings` (for API-key authentication).
# Get a channel
Source: https://spreecommerce.org/docs/api-reference/admin-api/channels/get-a-channel
/api-reference/admin.yaml get /api/v3/admin/channels/{id}
**Required scope:** `read_settings` (for API-key authentication).
# List channels
Source: https://spreecommerce.org/docs/api-reference/admin-api/channels/list-channels
/api-reference/admin.yaml get /api/v3/admin/channels
Returns the channels configured for the current store.
**Required scope:** `read_settings` (for API-key authentication).
# Publish products on a channel
Source: https://spreecommerce.org/docs/api-reference/admin-api/channels/publish-products-on-a-channel
/api-reference/admin.yaml post /api/v3/admin/channels/{id}/add_products
Publishes the listed products on this channel. Idempotent — re-publishing
an already-published product updates its publication window. Products from
sibling stores are silently dropped.
**Required scope:** `write_products` (for API-key authentication).
# Unpublish products from a channel
Source: https://spreecommerce.org/docs/api-reference/admin-api/channels/unpublish-products-from-a-channel
/api-reference/admin.yaml post /api/v3/admin/channels/{id}/remove_products
Unpublishes the listed products from this channel.
**Required scope:** `write_products` (for API-key authentication).
# Update a channel
Source: https://spreecommerce.org/docs/api-reference/admin-api/channels/update-a-channel
/api-reference/admin.yaml patch /api/v3/admin/channels/{id}
**Required scope:** `write_settings` (for API-key authentication).
# Create a custom field definition
Source: https://spreecommerce.org/docs/api-reference/admin-api/custom-fields/create-a-custom-field-definition
/api-reference/admin.yaml post /api/v3/admin/custom_field_definitions
**Required scope:** `write_custom_field_definitions` (for API-key authentication).
# Delete a custom field definition
Source: https://spreecommerce.org/docs/api-reference/admin-api/custom-fields/delete-a-custom-field-definition
/api-reference/admin.yaml delete /api/v3/admin/custom_field_definitions/{id}
Deletes the definition and cascades to all custom field values referencing it.
**Required scope:** `write_custom_field_definitions` (for API-key authentication).
# List custom field definitions
Source: https://spreecommerce.org/docs/api-reference/admin-api/custom-fields/list-custom-field-definitions
/api-reference/admin.yaml get /api/v3/admin/custom_field_definitions
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).
# Show a custom field definition
Source: https://spreecommerce.org/docs/api-reference/admin-api/custom-fields/show-a-custom-field-definition
/api-reference/admin.yaml get /api/v3/admin/custom_field_definitions/{id}
**Required scope:** `read_custom_field_definitions` (for API-key authentication).
# Update a custom field definition
Source: https://spreecommerce.org/docs/api-reference/admin-api/custom-fields/update-a-custom-field-definition
/api-reference/admin.yaml patch /api/v3/admin/custom_field_definitions/{id}
**Required scope:** `write_custom_field_definitions` (for API-key authentication).
# Create a customer group
Source: https://spreecommerce.org/docs/api-reference/admin-api/customer-groups/create-a-customer-group
/api-reference/admin.yaml post /api/v3/admin/customer_groups
Creates a customer group in the current store. `customer_ids` is
optional; when present, customers are attached at create time.
Pass prefixed IDs (e.g. `cus_…`) — the server decodes them
automatically.
**Required scope:** `write_customers` (for API-key authentication).
# Delete a customer group
Source: https://spreecommerce.org/docs/api-reference/admin-api/customer-groups/delete-a-customer-group
/api-reference/admin.yaml delete /api/v3/admin/customer_groups/{id}
Soft-deletes the group. Member users are not deleted; their `customer_group_users` rows are dropped.
**Required scope:** `write_customers` (for API-key authentication).
# Get a customer group
Source: https://spreecommerce.org/docs/api-reference/admin-api/customer-groups/get-a-customer-group
/api-reference/admin.yaml get /api/v3/admin/customer_groups/{id}
Returns a single customer group. Pass `?expand=customers` to embed
the full member list inline (recommended only for single-record
reads — embed cost scales with membership size).
**Required scope:** `read_customers` (for API-key authentication).
# List customer groups
Source: https://spreecommerce.org/docs/api-reference/admin-api/customer-groups/list-customer-groups
/api-reference/admin.yaml get /api/v3/admin/customer_groups
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).
# Update a customer group
Source: https://spreecommerce.org/docs/api-reference/admin-api/customer-groups/update-a-customer-group
/api-reference/admin.yaml patch /api/v3/admin/customer_groups/{id}
Updates name, description, or membership. `customer_ids` is a
full-set replacement — the server reconciles the membership to
match the array, adding new IDs and removing ones not present.
Send `customer_ids: []` to clear all members.
**Required scope:** `write_customers` (for API-key authentication).
# Bulk-add customers to groups
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/bulk-add-customers-to-groups
/api-reference/admin.yaml post /api/v3/admin/customers/bulk_add_to_groups
Attaches each customer in `ids` to every group in `customer_group_ids`.
Idempotent — customers already in a group are skipped server-side.
Groups from sibling stores are silently ignored. Returns counts of
customers and groups that were processed (post store-scoping).
**Required scope:** `write_customers` (for API-key authentication).
# Bulk-add tags to customers
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/bulk-add-tags-to-customers
/api-reference/admin.yaml post /api/v3/admin/customers/bulk_add_tags
Adds each tag name in `tags` to every customer in `ids`. Tags are
upserted by name; re-adding an existing tag is a no-op.
**Required scope:** `write_customers` (for API-key authentication).
# Bulk-remove customers from groups
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/bulk-remove-customers-from-groups
/api-reference/admin.yaml post /api/v3/admin/customers/bulk_remove_from_groups
Detaches each customer in `ids` from every group in `customer_group_ids`.
No-op for non-members. Groups from sibling stores are silently ignored.
**Required scope:** `write_customers` (for API-key authentication).
# Bulk-remove tags from customers
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/bulk-remove-tags-from-customers
/api-reference/admin.yaml post /api/v3/admin/customers/bulk_remove_tags
Removes each tag name in `tags` from every customer in `ids`. No-op
for customers that don't carry the tag.
**Required scope:** `write_customers` (for API-key authentication).
# Create a customer
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/create-a-customer
/api-reference/admin.yaml post /api/v3/admin/customers
Creates a customer. No welcome email is sent automatically.
**Required scope:** `write_customers` (for API-key authentication).
# Create a customer address
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/create-a-customer-address
/api-reference/admin.yaml post /api/v3/admin/customers/{customer_id}/addresses
Adds a new address to the customer's address book. Pass `is_default_billing: true` or `is_default_shipping: true` to set as the default — the previous default loses its flag in the same transaction.
**Required scope:** `write_customers` (for API-key authentication).
# Delete a customer
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/delete-a-customer
/api-reference/admin.yaml delete /api/v3/admin/customers/{id}
Deletes a customer. Returns 422 if the customer has any orders.
**Required scope:** `write_customers` (for API-key authentication).
# Delete a customer address
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/delete-a-customer-address
/api-reference/admin.yaml delete /api/v3/admin/customers/{customer_id}/addresses/{id}
Deletes the address. If it was a default, the customer loses that default (no auto-promotion).
**Required scope:** `write_customers` (for API-key authentication).
# Delete a customer credit card
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/delete-a-customer-credit-card
/api-reference/admin.yaml delete /api/v3/admin/customers/{customer_id}/credit_cards/{id}
Deletes a saved credit card.
**Required scope:** `write_customers` (for API-key authentication).
# Delete a store credit
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/delete-a-store-credit
/api-reference/admin.yaml delete /api/v3/admin/customers/{customer_id}/store_credits/{id}
Deletes an unused store credit (amount_used == 0). Returns 422 otherwise.
**Required scope:** `write_store_credits` (for API-key authentication).
# Issue a store credit to a customer
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/issue-a-store-credit-to-a-customer
/api-reference/admin.yaml post /api/v3/admin/customers/{customer_id}/store_credits
`created_by` is set automatically from the authenticated admin.
**Required scope:** `write_store_credits` (for API-key authentication).
# List customer addresses
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/list-customer-addresses
/api-reference/admin.yaml get /api/v3/admin/customers/{customer_id}/addresses
Returns the customer's saved addresses.
**Required scope:** `read_customers` (for API-key authentication).
# List customer credit cards
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/list-customer-credit-cards
/api-reference/admin.yaml get /api/v3/admin/customers/{customer_id}/credit_cards
Returns the customer's saved credit cards. Useful for off-session admin charges via `POST /admin/orders/:id/payments { source_id }`.
**Required scope:** `read_customers` (for API-key authentication).
# List customer store credits
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/list-customer-store-credits
/api-reference/admin.yaml get /api/v3/admin/customers/{customer_id}/store_credits
Returns store credits issued to the customer.
**Required scope:** `read_store_credits` (for API-key authentication).
# List customers
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/list-customers
/api-reference/admin.yaml get /api/v3/admin/customers
Returns a paginated list of customers. Supports Ransack search/filters.
**Required scope:** `read_customers` (for API-key authentication).
# Show a customer
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/show-a-customer
/api-reference/admin.yaml get /api/v3/admin/customers/{id}
Returns full customer details including computed order stats (orders_count, total_spent, last_order_completed_at).
**Required scope:** `read_customers` (for API-key authentication).
# Show a customer credit card
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/show-a-customer-credit-card
/api-reference/admin.yaml get /api/v3/admin/customers/{customer_id}/credit_cards/{id}
Returns a saved credit card by ID.
**Required scope:** `read_customers` (for API-key authentication).
# Update a customer
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/update-a-customer
/api-reference/admin.yaml patch /api/v3/admin/customers/{id}
Updates customer attributes. `tags` replaces the full set.
**Required scope:** `write_customers` (for API-key authentication).
# Update a customer address
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/update-a-customer-address
/api-reference/admin.yaml patch /api/v3/admin/customers/{customer_id}/addresses/{id}
Updates a customer address.
**Required scope:** `write_customers` (for API-key authentication).
# Update a store credit
Source: https://spreecommerce.org/docs/api-reference/admin-api/customers/update-a-store-credit
/api-reference/admin.yaml patch /api/v3/admin/customers/{customer_id}/store_credits/{id}
Update memo / category / amount. The amount can only be changed if `amount_used == 0`.
**Required scope:** `write_store_credits` (for API-key authentication).
# Admin API error responses, status codes, and handling
Source: https://spreecommerce.org/docs/api-reference/admin-api/errors
Reference for the Spree Admin API Stripe-style error response format, HTTP status codes, and admin-specific error codes returned by endpoints.
The Admin API uses the same Stripe-style error format as the rest of the Spree v3 API. Every error response carries a machine-readable `code` and a human-readable `message`.
## Error response format
```json theme={"theme":"night-owl"}
{
"error": {
"code": "record_not_found",
"message": "Order not found"
}
}
```
Validation errors include a `details` field with per-field error messages:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "validation_error",
"message": "Email is invalid and Phone can't be blank",
"details": {
"email": ["is invalid"],
"phone": ["can't be blank"]
}
}
}
```
Some specialized errors carry structured `details` (for example, scope errors include the `required_scope`):
```json theme={"theme":"night-owl"}
{
"error": {
"code": "access_denied",
"message": "API key lacks scope: write_orders",
"details": {
"required_scope": "write_orders"
}
}
}
```
### Schema
| Field | Type | Description |
| --------------- | -------- | ------------------------------------------------------------------------------------ |
| `error.code` | `string` | Machine-readable error code (see tables below) |
| `error.message` | `string` | Human-readable description of the error |
| `error.details` | `object` | Optional. Field-specific validation errors or structured context (varies by `code`). |
## HTTP status codes
| Status | Meaning | When |
| ------ | --------------------- | -------------------------------------------------------------------------------------------- |
| `400` | Bad Request | Missing required parameters, malformed JSON |
| `401` | Unauthorized | Missing or invalid API key, expired or invalid JWT token |
| `403` | Forbidden | Authenticated but lacks permission (CanCanCan ability) or scope |
| `404` | Not Found | Resource doesn't exist, isn't accessible to the calling key, or belongs to a different store |
| `409` | Conflict | Resource was modified by a concurrent request (optimistic locking) |
| `422` | Unprocessable Content | Validation failed, invalid state transition, business rule violation |
| `429` | Too Many Requests | Login/refresh rate limit exceeded |
## Authentication & authorization
| Code | Status | Description |
| -------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `authentication_required` | 401 | Request reached a protected endpoint with no credentials |
| `authentication_failed` | 401 | Login email/password was wrong |
| `invalid_token` | 401 | API key or JWT token is invalid or expired |
| `invalid_refresh_token` | 401 | Refresh token is invalid or expired |
| `access_denied` | 403 | Caller lacks permission. For API-key callers, `details.required_scope` indicates the missing scope (see [Authentication](/docs/api-reference/admin-api/authentication#permissions)). For JWT callers, the user's role lacks the CanCanCan ability for this action. |
| `current_password_invalid` | 422 | Current password is wrong (when changing password) |
## Resources
| Code | Status | Description |
| ------------------ | ------ | --------------------------------------------------------------------- |
| `record_not_found` | 404 | Resource doesn't exist or isn't accessible in the calling key's store |
| `resource_invalid` | 422 | Resource couldn't be saved |
## Validation
| Code | Status | Description |
| ------------------- | ------ | ----------------------------------------------------------------------- |
| `validation_error` | 422 | Model validation failed. Inspect `details` for field-specific messages. |
| `parameter_missing` | 400 | A required parameter is missing |
| `parameter_invalid` | 400 | A parameter has an invalid value |
## Orders
| Code | Status | Description |
| ------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------- |
| `cart_cannot_transition` | 422 | Order state machine refused the transition (e.g., completing an order without an address or payment) |
| `cart_already_updated` | 409 | Order was modified by a concurrent request. Refetch and retry. See [optimistic locking](#optimistic-locking) below. |
| `cart_invalid_state` | 422 | Order is in a state that doesn't allow this operation |
| `cart_empty` | 422 | Cannot complete an order with no line items |
## Customers
| Code | Status | Description |
| --------------------- | ------ | ------------------------------------------------------------------ |
| `customer_has_orders` | 422 | Cannot delete a customer with completed orders. Anonymize instead. |
## Store credits
| Code | Status | Description |
| --------------------- | ------ | --------------------------------------------------------------------------------------- |
| `store_credit_in_use` | 422 | Cannot edit `amount` on or delete a store credit that has been partially or fully used. |
## Tags
| Code | Status | Description |
| ----------------------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
| `invalid_taggable_type` | 422 | The `taggable_type` query param isn't one of the allowed values (`Spree::Product`, `Spree::Order`, `Spree::User`). |
## Payments
| Code | Status | Description |
| -------------------------- | ------ | ----------------------------------------------------------- |
| `payment_failed` | 422 | Payment was declined by the gateway |
| `payment_processing_error` | 422 | Spree couldn't process the payment due to an internal error |
| `gateway_error` | 422 | Payment gateway returned an error |
## Examples
### Insufficient scope (API key)
```bash theme={"theme":"night-owl"}
curl -X POST 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx' \
-H 'Content-Type: application/json' \
-d '{"email": "test@example.com"}'
```
```json 403 theme={"theme":"night-owl"}
{
"error": {
"code": "access_denied",
"message": "API key lacks scope: write_orders",
"details": {
"required_scope": "write_orders"
}
}
}
```
### Validation error (customer create)
```bash theme={"theme":"night-owl"}
curl -X POST 'https://store.example.com/api/v3/admin/customers' \
-H 'X-Spree-Api-Key: sk_xxx' \
-H 'Content-Type: application/json' \
-d '{}'
```
```json 422 theme={"theme":"night-owl"}
{
"error": {
"code": "validation_error",
"message": "Email can't be blank",
"details": {
"email": ["can't be blank"]
}
}
}
```
### Customer with completed orders
```bash theme={"theme":"night-owl"}
curl -X DELETE 'https://store.example.com/api/v3/admin/customers/cus_xxx' \
-H 'X-Spree-Api-Key: sk_xxx'
```
```json 422 theme={"theme":"night-owl"}
{
"error": {
"code": "customer_has_orders",
"message": "Cannot delete customer with completed orders"
}
}
```
### Concurrent order update
```bash theme={"theme":"night-owl"}
curl -X PATCH 'https://store.example.com/api/v3/admin/orders/or_xxx' \
-H 'X-Spree-Api-Key: sk_xxx' \
-H 'Content-Type: application/json' \
-d '{"email": "new@example.com"}'
```
```json 409 theme={"theme":"night-owl"}
{
"error": {
"code": "cart_already_updated",
"message": "Order was modified by another request. Refetch and retry."
}
}
```
## Handling errors with the SDK
`@spree/admin-sdk` throws a `SpreeError` for every non-2xx response:
```typescript theme={"theme":"night-owl"}
import { SpreeError } from '@spree/admin-sdk'
try {
await client.orders.update(orderId, { email: 'new@example.com' })
} catch (error) {
if (error instanceof SpreeError) {
console.log(error.code) // 'cart_already_updated'
console.log(error.message) // 'Order was modified by another request...'
console.log(error.status) // 409
console.log(error.details) // undefined or { ... }
}
}
```
### Common patterns
**Branch on error code**:
```typescript theme={"theme":"night-owl"}
try {
await client.customers.delete(customerId)
} catch (error) {
if (error instanceof SpreeError && error.code === 'customer_has_orders') {
// Anonymize instead of deleting
return anonymizeCustomer(customerId)
}
throw error
}
```
**Retry on optimistic-lock conflicts**:
```typescript theme={"theme":"night-owl"}
async function updateOrderWithRetry(id, params, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await client.orders.update(id, params)
} catch (error) {
if (error instanceof SpreeError && error.code === 'cart_already_updated' && i < attempts - 1) {
continue
}
throw error
}
}
}
```
**Show field-level validation errors**:
```typescript theme={"theme":"night-owl"}
try {
await client.customers.create(customerData)
} catch (error) {
if (error instanceof SpreeError && error.details) {
for (const [field, messages] of Object.entries(error.details)) {
setFieldError(field, (messages as string[]).join(', '))
}
}
}
```
## Optimistic locking
Orders use a `state_lock_version` column to detect concurrent modifications. Every state-changing operation increments it; if two callers update the same order simultaneously, the second write fails with `cart_already_updated` (409) — refetch and retry.
This protects against race conditions when multiple clients (or the same client, retried) try to mutate the same order. Combined with idempotency at the integration level (e.g., dedupe webhook deliveries by event ID), it makes admin order management safe under concurrency.
# Create an export
Source: https://spreecommerce.org/docs/api-reference/admin-api/exports/create-an-export
/api-reference/admin.yaml post /api/v3/admin/exports
Queues a CSV export. The `type` selects the dataset; `search_params` is an
optional Ransack query (same shape used by the `q[...]` params on list endpoints)
that filters which records are exported. Pass `record_selection: "all"` to
clear the filter server-side and export everything in scope.
Generation is asynchronous. Poll `GET /admin/exports/{id}` until `done` is `true`,
then redirect the browser to `download_url` to fetch the file.
**Required scope:** `write_exports` (for API-key authentication).
# Delete an export
Source: https://spreecommerce.org/docs/api-reference/admin-api/exports/delete-an-export
/api-reference/admin.yaml delete /api/v3/admin/exports/{id}
Removes the export and purges its attachment.
**Required scope:** `write_exports` (for API-key authentication).
# Download an export
Source: https://spreecommerce.org/docs/api-reference/admin-api/exports/download-an-export
/api-reference/admin.yaml get /api/v3/admin/exports/{id}/download
Streams the exported CSV with `Content-Disposition: attachment`. Returns 422 with `code: export_not_ready` while `done` is still `false`. The endpoint is JWT/API-key protected, so SPA clients must fetch it (with `Authorization` header) and trigger the browser download via a Blob URL — a top-level navigation cannot carry the JWT.
**Required scope:** `read_exports` (for API-key authentication).
# List exports
Source: https://spreecommerce.org/docs/api-reference/admin-api/exports/list-exports
/api-reference/admin.yaml get /api/v3/admin/exports
Returns CSV exports queued or completed for the current store. Polled by the admin SPA to detect when an export finishes (`done: true`).
**Required scope:** `read_exports` (for API-key authentication).
# Show an export
Source: https://spreecommerce.org/docs/api-reference/admin-api/exports/show-an-export
/api-reference/admin.yaml get /api/v3/admin/exports/{id}
Returns export status. While `done` is `false`, the SPA continues polling.
**Required scope:** `read_exports` (for API-key authentication).
# Cancel a fulfillment
Source: https://spreecommerce.org/docs/api-reference/admin-api/fulfillments/cancel-a-fulfillment
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/fulfillments/{id}/cancel
Cancels a fulfillment.
**Required scope:** `write_fulfillments` (for API-key authentication).
# Fulfill a fulfillment
Source: https://spreecommerce.org/docs/api-reference/admin-api/fulfillments/fulfill-a-fulfillment
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/fulfillments/{id}/fulfill
Marks a fulfillment as fulfilled.
**Required scope:** `write_fulfillments` (for API-key authentication).
# List fulfillments
Source: https://spreecommerce.org/docs/api-reference/admin-api/fulfillments/list-fulfillments
/api-reference/admin.yaml get /api/v3/admin/orders/{order_id}/fulfillments
Returns all shipments for an order.
**Required scope:** `read_fulfillments` (for API-key authentication).
# Resume a fulfillment
Source: https://spreecommerce.org/docs/api-reference/admin-api/fulfillments/resume-a-fulfillment
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/fulfillments/{id}/resume
Resumes a canceled fulfillment.
**Required scope:** `write_fulfillments` (for API-key authentication).
# Show a shipment
Source: https://spreecommerce.org/docs/api-reference/admin-api/fulfillments/show-a-shipment
/api-reference/admin.yaml get /api/v3/admin/orders/{order_id}/fulfillments/{id}
Returns details of a specific shipment.
**Required scope:** `read_fulfillments` (for API-key authentication).
# Split a fulfillment
Source: https://spreecommerce.org/docs/api-reference/admin-api/fulfillments/split-a-fulfillment
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/fulfillments/{id}/split
Transfers items from this shipment to a new shipment at a different stock location.
**Required scope:** `write_fulfillments` (for API-key authentication).
# Update a shipment
Source: https://spreecommerce.org/docs/api-reference/admin-api/fulfillments/update-a-shipment
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/fulfillments/{id}
Updates a shipment (tracking, shipping rate).
**Required scope:** `write_fulfillments` (for API-key authentication).
# Create a gift card
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/create-a-gift-card
/api-reference/admin.yaml post /api/v3/admin/gift_cards
Issues a gift card scoped to the current store. The code is
auto-generated when omitted. `currency` defaults to the store's
configured currency. Pass `user_id` (prefixed ID) to attach the
card to a specific customer.
**Required scope:** `write_gift_cards` (for API-key authentication).
# Create a gift card batch
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/create-a-gift-card-batch
/api-reference/admin.yaml post /api/v3/admin/gift_card_batches
Issues a batch of gift cards in a single call. The server generates
`codes_count` cards inline for small batches (configurable via
`Spree.config.gift_card_batch_web_limit`, default 500) or enqueues
a background job for larger ones. Each card's code is the batch
`prefix` followed by random hex.
**Required scope:** `write_gift_cards` (for API-key authentication).
# Delete a gift card
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/delete-a-gift-card
/api-reference/admin.yaml delete /api/v3/admin/gift_cards/{id}
Deletes an unused gift card. Cards that have been redeemed or
partially redeemed cannot be deleted and return 422.
**Required scope:** `write_gift_cards` (for API-key authentication).
# Get a gift card
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/get-a-gift-card
/api-reference/admin.yaml get /api/v3/admin/gift_cards/{id}
Returns a single gift card.
**Required scope:** `read_gift_cards` (for API-key authentication).
# Get a gift card batch
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/get-a-gift-card-batch
/api-reference/admin.yaml get /api/v3/admin/gift_card_batches/{id}
Returns a single batch.
**Required scope:** `read_gift_cards` (for API-key authentication).
# List gift card batches
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/list-gift-card-batches
/api-reference/admin.yaml get /api/v3/admin/gift_card_batches
Returns the gift card batches issued by the current store. Each batch
groups the cards generated together for a campaign or bulk-issuance
— the cards themselves live under `/admin/gift_cards` and reference
the batch via `gift_card_batch_id`.
**Required scope:** `read_gift_cards` (for API-key authentication).
# List gift cards
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/list-gift-cards
/api-reference/admin.yaml get /api/v3/admin/gift_cards
Returns the gift cards issued by the current store. Filter by
`q[code_cont]` for code search, `q[user_id_eq]` for cards issued
to a specific customer, or `q[state_eq]` for status filtering.
**Required scope:** `read_gift_cards` (for API-key authentication).
# Update a gift card
Source: https://spreecommerce.org/docs/api-reference/admin-api/gift-cards/update-a-gift-card
/api-reference/admin.yaml patch /api/v3/admin/gift_cards/{id}
Updates an active gift card's editable attributes. Redeemed or
partially-redeemed cards cannot be edited.
**Required scope:** `write_gift_cards` (for API-key authentication).
# Spree Admin API introduction and SDK quick start
Source: https://spreecommerce.org/docs/api-reference/admin-api/introduction
Overview of the Spree Admin REST API for managing products, orders, customers, and fulfillments, with SDK install and quick start examples.
The Admin API is a REST API for managing Spree stores programmatically — products, orders, customers, fulfillments, payments, and more. It is intended for backend integrations, custom admin tooling, and automation.
All routes are prefixed with `/api/v3/admin`. During development the API is available under `http://localhost:3000/api/v3/admin`. For production, replace `http://localhost:3000` with your Spree application URL.
## Admin API vs Store API
| | Admin API | Store API |
| -------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------- |
| **Purpose** | Manage store data | Power storefronts |
| **Audience** | Staff users, backend integrations | Customers, storefronts |
| **Authentication** | Secret API key (`sk_…`) or admin JWT | Publishable API key (`pk_…`), customer JWT, order token |
| **Permissions** | API key scopes (API key authentication) or Admin Staff permission sets | Customer can only read/modify their own data |
| **Write operations** | Full CRUD on most resources | Limited to the current customer's cart, addresses, profile |
If you're building a storefront, use the [Store API](/docs/api-reference/store-api/introduction). The Admin API exposes administrative operations that should never be invoked from a browser.
## Using the SDK
We recommend using `@spree/admin-sdk` to interact with the Admin API. It provides typed clients, automatic retries, and idempotency support.
### Installation
```bash theme={"theme":"night-owl"}
npm install @spree/admin-sdk
# or
yarn add @spree/admin-sdk
# or
pnpm add @spree/admin-sdk
```
### Quick start
```typescript theme={"theme":"night-owl"}
import { createAdminClient } from '@spree/admin-sdk'
const client = createAdminClient({
baseUrl: 'http://localhost:3000',
secretKey: 'sk_xxx',
})
const { data: orders } = await client.orders.list({
status_eq: 'complete',
limit: 25,
})
```
Before integrating, read:
* [Authentication](/docs/api-reference/admin-api/authentication) — secret API keys, scopes, and JWT tokens
* [Errors](/docs/api-reference/admin-api/errors) — error format and admin-specific codes
* [Querying](/docs/api-reference/admin-api/querying) — filtering, sorting, pagination, and `expand`
# Create a market
Source: https://spreecommerce.org/docs/api-reference/admin-api/markets/create-a-market
/api-reference/admin.yaml post /api/v3/admin/markets
Creates a new market for the current store.
- `country_isos` accepts 2-letter ISO country codes (e.g. `["DE", "FR"]`);
the market must contain at least one country. Unknown codes are
silently dropped.
- `supported_locales` accepts an array of locale codes; the
`default_locale` is always implicitly included.
- Setting `default: true` automatically demotes the previous default
market in the store.
**Required scope:** `write_settings` (for API-key authentication).
# Delete a market
Source: https://spreecommerce.org/docs/api-reference/admin-api/markets/delete-a-market
/api-reference/admin.yaml delete /api/v3/admin/markets/{id}
Soft-deletes the market (sets `deleted_at`). The default market and
the last remaining market in a store cannot be deleted — both return
422 with a `validation_error`.
**Required scope:** `write_settings` (for API-key authentication).
# Get a market
Source: https://spreecommerce.org/docs/api-reference/admin-api/markets/get-a-market
/api-reference/admin.yaml get /api/v3/admin/markets/{id}
**Required scope:** `read_settings` (for API-key authentication).
# List markets
Source: https://spreecommerce.org/docs/api-reference/admin-api/markets/list-markets
/api-reference/admin.yaml get /api/v3/admin/markets
Returns the markets configured for the current store. Markets are
store-scoped and ordered by `position` (an `acts_as_list` column —
update the order via `PATCH /markets/{id}` with `position`).
**Required scope:** `read_settings` (for API-key authentication).
# Update a market
Source: https://spreecommerce.org/docs/api-reference/admin-api/markets/update-a-market
/api-reference/admin.yaml patch /api/v3/admin/markets/{id}
Updates an existing market. Pass `country_isos` to replace the
market's country list (full-set update), `supported_locales` to
replace the supported locales, or `position` to reorder the market
within the store.
Setting `default: true` automatically demotes the previous default.
**Required scope:** `write_settings` (for API-key authentication).
# Create an option type
Source: https://spreecommerce.org/docs/api-reference/admin-api/option-types/create-an-option-type
/api-reference/admin.yaml post /api/v3/admin/option_types
Creates a new option type. Supports nested option values.
Option values can be provided inline and will be created or updated by name.
**Required scope:** `write_products` (for API-key authentication).
# Delete an option type
Source: https://spreecommerce.org/docs/api-reference/admin-api/option-types/delete-an-option-type
/api-reference/admin.yaml delete /api/v3/admin/option_types/{id}
Deletes an option type.
**Required scope:** `write_products` (for API-key authentication).
# Get an option type
Source: https://spreecommerce.org/docs/api-reference/admin-api/option-types/get-an-option-type
/api-reference/admin.yaml get /api/v3/admin/option_types/{id}
Returns a single option type by ID, including its option values.
**Required scope:** `read_products` (for API-key authentication).
# List option types
Source: https://spreecommerce.org/docs/api-reference/admin-api/option-types/list-option-types
/api-reference/admin.yaml get /api/v3/admin/option_types
Returns a paginated list of option types.
**Required scope:** `read_products` (for API-key authentication).
# Update an option type
Source: https://spreecommerce.org/docs/api-reference/admin-api/option-types/update-an-option-type
/api-reference/admin.yaml patch /api/v3/admin/option_types/{id}
Updates an option type. Supports updating nested option values.
**Required scope:** `write_products` (for API-key authentication).
# Add an item
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/add-an-item
/api-reference/admin.yaml post /api/v3/admin/orders/{order_id}/items
Adds a new line item to the order.
**Required scope:** `write_orders` (for API-key authentication).
# Apply a gift card to an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/apply-a-gift-card-to-an-order
/api-reference/admin.yaml post /api/v3/admin/orders/{order_id}/gift_cards
Applies a gift card by code to the order. Returns the gift card.
**Required scope:** `write_gift_cards` (for API-key authentication).
# Apply customer's store credit to an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/apply-customers-store-credit-to-an-order
/api-reference/admin.yaml post /api/v3/admin/orders/{order_id}/store_credits
Applies the order customer's available store credit. When `amount` is omitted, applies up to the order outstanding balance.
**Required scope:** `write_store_credits` (for API-key authentication).
# Approve an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/approve-an-order
/api-reference/admin.yaml patch /api/v3/admin/orders/{id}/approve
Approves an order (e.g., for fraud review).
**Required scope:** `write_orders` (for API-key authentication).
# Cancel an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/cancel-an-order
/api-reference/admin.yaml patch /api/v3/admin/orders/{id}/cancel
Cancels a completed order.
**Required scope:** `write_orders` (for API-key authentication).
# Complete an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/complete-an-order
/api-reference/admin.yaml patch /api/v3/admin/orders/{id}/complete
Completes an order in the `confirm` state, marking it as placed.
Set `notify_customer: true` to send the order confirmation email.
**Required scope:** `write_orders` (for API-key authentication).
# Create a draft order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/create-a-draft-order
/api-reference/admin.yaml post /api/v3/admin/orders
Creates a new draft order in one shot. Customer, items, addresses, currency,
market, channel, locale, notes, metadata, and a coupon code can all be
provided inline.
Setting `preferred_stock_location_id` pins the order's preferred fulfillment
location — Order Routing's built-in `PreferredLocation` rule consumes it
when picking which stock location ships each shipment.
Invalid coupon codes are non-fatal — the order is created and the failure
is reported on the service result (not in the API response body for now).
**Required scope:** `write_orders` (for API-key authentication).
# Delete a draft order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/delete-a-draft-order
/api-reference/admin.yaml delete /api/v3/admin/orders/{id}
Deletes a draft order. Completed orders cannot be deleted.
**Required scope:** `write_orders` (for API-key authentication).
# List order items
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/list-order-items
/api-reference/admin.yaml get /api/v3/admin/orders/{order_id}/items
Returns all line items for an order.
**Required scope:** `read_orders` (for API-key authentication).
# List orders
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/list-orders
/api-reference/admin.yaml get /api/v3/admin/orders
Returns a paginated list of orders for the current store.
**Required scope:** `read_orders` (for API-key authentication).
# Remove a gift card from an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/remove-a-gift-card-from-an-order
/api-reference/admin.yaml delete /api/v3/admin/orders/{order_id}/gift_cards/{id}
Removes the gift card from the order.
**Required scope:** `write_gift_cards` (for API-key authentication).
# Remove an item
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/remove-an-item
/api-reference/admin.yaml delete /api/v3/admin/orders/{order_id}/items/{id}
Removes an item from the order.
**Required scope:** `write_orders` (for API-key authentication).
# Remove store credit from an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/remove-store-credit-from-an-order
/api-reference/admin.yaml delete /api/v3/admin/orders/{order_id}/store_credits
Removes any applied store credit from the order.
**Required scope:** `write_store_credits` (for API-key authentication).
# Resend confirmation email
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/resend-confirmation-email
/api-reference/admin.yaml post /api/v3/admin/orders/{id}/resend_confirmation
Publishes the order.completed event to trigger confirmation email delivery.
**Required scope:** `write_orders` (for API-key authentication).
# Resume a canceled order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/resume-a-canceled-order
/api-reference/admin.yaml patch /api/v3/admin/orders/{id}/resume
Resumes a previously canceled order.
**Required scope:** `write_orders` (for API-key authentication).
# Show an item
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/show-an-item
/api-reference/admin.yaml get /api/v3/admin/orders/{order_id}/items/{id}
Returns details of a specific line item.
**Required scope:** `read_orders` (for API-key authentication).
# Show an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/show-an-order
/api-reference/admin.yaml get /api/v3/admin/orders/{id}
Returns full order details including admin-only fields.
**Required scope:** `read_orders` (for API-key authentication).
# Update an item
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/update-an-item
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/items/{id}
Updates an order item quantity or metadata.
**Required scope:** `write_orders` (for API-key authentication).
# Update an order
Source: https://spreecommerce.org/docs/api-reference/admin-api/orders/update-an-order
/api-reference/admin.yaml patch /api/v3/admin/orders/{id}
Updates an order. Supports updating email, addresses, special instructions, and line items.
**Required scope:** `write_orders` (for API-key authentication).
# List available payment provider types
Source: https://spreecommerce.org/docs/api-reference/admin-api/payment-methods/list-available-payment-provider-types
/api-reference/admin.yaml get /api/v3/admin/payment_methods/types
Returns the registered Spree::PaymentMethod subclasses that can be used to create new payment methods. Useful for populating a "Provider" dropdown in admin UIs.
**Required scope:** `read_settings` (for API-key authentication).
# List payment methods
Source: https://spreecommerce.org/docs/api-reference/admin-api/payment-methods/list-payment-methods
/api-reference/admin.yaml get /api/v3/admin/payment_methods
Returns the store's configured payment methods. Use `source_required: true` to know which methods need a saved source.
**Required scope:** `read_settings` (for API-key authentication).
# Show a payment method
Source: https://spreecommerce.org/docs/api-reference/admin-api/payment-methods/show-a-payment-method
/api-reference/admin.yaml get /api/v3/admin/payment_methods/{id}
Returns a payment method by ID.
**Required scope:** `read_settings` (for API-key authentication).
# Capture a payment
Source: https://spreecommerce.org/docs/api-reference/admin-api/payments/capture-a-payment
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/payments/{id}/capture
Captures a pending payment.
**Required scope:** `write_payments` (for API-key authentication).
# Create a payment
Source: https://spreecommerce.org/docs/api-reference/admin-api/payments/create-a-payment
/api-reference/admin.yaml post /api/v3/admin/orders/{order_id}/payments
Creates a new payment for the order.
**Required scope:** `write_payments` (for API-key authentication).
# List payments
Source: https://spreecommerce.org/docs/api-reference/admin-api/payments/list-payments
/api-reference/admin.yaml get /api/v3/admin/orders/{order_id}/payments
Returns all payments for an order.
**Required scope:** `read_payments` (for API-key authentication).
# Show a payment
Source: https://spreecommerce.org/docs/api-reference/admin-api/payments/show-a-payment
/api-reference/admin.yaml get /api/v3/admin/orders/{order_id}/payments/{id}
Returns details of a specific payment.
**Required scope:** `read_payments` (for API-key authentication).
# Void a payment
Source: https://spreecommerce.org/docs/api-reference/admin-api/payments/void-a-payment
/api-reference/admin.yaml patch /api/v3/admin/orders/{order_id}/payments/{id}/void
Voids a payment.
**Required scope:** `write_payments` (for API-key authentication).
# Activate a price list
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/activate-a-price-list
/api-reference/admin.yaml patch /api/v3/admin/price_lists/{id}/activate
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).
# Bulk-delete prices
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/bulk-delete-prices
/api-reference/admin.yaml delete /api/v3/admin/prices/bulk_destroy
Soft-deletes each price in `ids`. Returns the count actually destroyed.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-upsert prices
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/bulk-upsert-prices
/api-reference/admin.yaml post /api/v3/admin/prices/bulk_upsert
Upserts a batch of prices in a single SQL round trip.
Each row either:
* targets an existing price by `id`, OR
* matches on the unique key `(variant_id, currency, price_list_id)` —
updating the existing row if one exists, creating one otherwise.
Model callbacks (e.g. PriceHistory) are bypassed; this is a
bulk-write fast path for the admin spreadsheet. The response
carries `price_count` — the number of rows touched.
**Required scope:** `write_products` (for API-key authentication).
# Create a price
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/create-a-price
/api-reference/admin.yaml post /api/v3/admin/prices
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).
# Create a price list
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/create-a-price-list
/api-reference/admin.yaml post /api/v3/admin/price_lists
Creates a new draft price list.
**Required scope:** `write_products` (for API-key authentication).
# Deactivate a price list
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/deactivate-a-price-list
/api-reference/admin.yaml patch /api/v3/admin/price_lists/{id}/deactivate
**Required scope:** `write_products` (for API-key authentication).
# Delete a price
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/delete-a-price
/api-reference/admin.yaml delete /api/v3/admin/prices/{id}
Soft-deletes the price (acts_as_paranoid).
**Required scope:** `write_products` (for API-key authentication).
# Delete a price list
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/delete-a-price-list
/api-reference/admin.yaml delete /api/v3/admin/price_lists/{id}
Soft-deletes the price list. Associated prices are removed asynchronously.
**Required scope:** `write_products` (for API-key authentication).
# Get a price
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/get-a-price
/api-reference/admin.yaml get /api/v3/admin/prices/{id}
**Required scope:** `read_products` (for API-key authentication).
# Get a price list
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/get-a-price-list
/api-reference/admin.yaml get /api/v3/admin/price_lists/{id}
**Required scope:** `read_products` (for API-key authentication).
# List price lists
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/list-price-lists
/api-reference/admin.yaml get /api/v3/admin/price_lists
Returns the price lists configured for the current store.
**Required scope:** `read_products` (for API-key authentication).
# List prices
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/list-prices
/api-reference/admin.yaml get /api/v3/admin/prices
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).
# Update a price
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/update-a-price
/api-reference/admin.yaml patch /api/v3/admin/prices/{id}
**Required scope:** `write_products` (for API-key authentication).
# Update a price list
Source: https://spreecommerce.org/docs/api-reference/admin-api/pricing/update-a-price-list
/api-reference/admin.yaml patch /api/v3/admin/price_lists/{id}
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).
# Bulk-add products to categories
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-add-products-to-categories
/api-reference/admin.yaml post /api/v3/admin/products/bulk_add_to_categories
Attaches each product in `ids` to every category (taxon) in `category_ids`.
Categories from sibling stores are silently ignored.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-add products to channels
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-add-products-to-channels
/api-reference/admin.yaml post /api/v3/admin/products/bulk_add_to_channels
Publishes each product in `ids` on every channel in `channel_ids`. Idempotent —
re-publishing on an existing channel is a no-op. Channels from sibling stores
are silently ignored.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-add tags to products
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-add-tags-to-products
/api-reference/admin.yaml post /api/v3/admin/products/bulk_add_tags
Adds each tag name in `tags` to every product in `ids`. Tags are upserted by name.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-delete products
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-delete-products
/api-reference/admin.yaml delete /api/v3/admin/products/bulk_destroy
Soft-deletes each product in `ids`. Returns the count actually destroyed.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-remove products from categories
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-remove-products-from-categories
/api-reference/admin.yaml post /api/v3/admin/products/bulk_remove_from_categories
Detaches each product in `ids` from every category in `category_ids`.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-remove products from channels
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-remove-products-from-channels
/api-reference/admin.yaml post /api/v3/admin/products/bulk_remove_from_channels
Unpublishes each product in `ids` from every channel in `channel_ids`.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-remove tags from products
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-remove-tags-from-products
/api-reference/admin.yaml post /api/v3/admin/products/bulk_remove_tags
Removes each tag in `tags` from every product in `ids`.
**Required scope:** `write_products` (for API-key authentication).
# Bulk-update product status
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/bulk-update-product-status
/api-reference/admin.yaml post /api/v3/admin/products/bulk_status_update
Sets `status` on each product in `ids`. Reindexes the affected products
for search. Cross-store IDs are silently dropped. Returns counts.
**Required scope:** `write_products` (for API-key authentication).
# Create a product
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/create-a-product
/api-reference/admin.yaml post /api/v3/admin/products
Creates a new product. Supports nested variants with prices and option types.
Option types and values are auto-created if they don't exist.
Prices are upserted by currency. Stock items are upserted by stock location.
**Required scope:** `write_products` (for API-key authentication).
# Create a product custom field
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/create-a-product-custom-field
/api-reference/admin.yaml post /api/v3/admin/products/{product_id}/custom_fields
Sets a custom field value on the product. Requires an existing CustomFieldDefinition; pass its prefixed `cfdef_…` id.
**Required scope:** `write_products` (for API-key authentication).
# Delete a product
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/delete-a-product
/api-reference/admin.yaml delete /api/v3/admin/products/{id}
Soft-deletes a product.
**Required scope:** `write_products` (for API-key authentication).
# Delete a product custom field
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/delete-a-product-custom-field
/api-reference/admin.yaml delete /api/v3/admin/products/{product_id}/custom_fields/{id}
**Required scope:** `write_products` (for API-key authentication).
# Get a product
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/get-a-product
/api-reference/admin.yaml get /api/v3/admin/products/{id}
Returns a single product by ID.
**Required scope:** `read_products` (for API-key authentication).
# List product custom fields
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/list-product-custom-fields
/api-reference/admin.yaml get /api/v3/admin/products/{product_id}/custom_fields
Returns the product's custom field values.
**Required scope:** `read_products` (for API-key authentication).
# List products
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/list-products
/api-reference/admin.yaml get /api/v3/admin/products
Returns a paginated list of products for the current store.
**Required scope:** `read_products` (for API-key authentication).
# Show a product custom field
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/show-a-product-custom-field
/api-reference/admin.yaml get /api/v3/admin/products/{product_id}/custom_fields/{id}
**Required scope:** `read_products` (for API-key authentication).
# Update a product
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/update-a-product
/api-reference/admin.yaml patch /api/v3/admin/products/{id}
Updates a product. Only provided fields are updated.
**Required scope:** `write_products` (for API-key authentication).
# Update a product custom field
Source: https://spreecommerce.org/docs/api-reference/admin-api/products/update-a-product-custom-field
/api-reference/admin.yaml patch /api/v3/admin/products/{product_id}/custom_fields/{id}
Updates the custom field's `value`. The linked definition cannot be changed — delete and recreate to switch.
**Required scope:** `write_products` (for API-key authentication).
# Create a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/create-a-promotion
/api-reference/admin.yaml post /api/v3/admin/promotions
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).
# Create a rule on a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/create-a-rule-on-a-promotion
/api-reference/admin.yaml post /api/v3/admin/promotions/{promotion_id}/promotion_rules
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).
# Create an action on a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/create-an-action-on-a-promotion
/api-reference/admin.yaml post /api/v3/admin/promotions/{promotion_id}/promotion_actions
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).
# Delete a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/delete-a-promotion
/api-reference/admin.yaml delete /api/v3/admin/promotions/{id}
**Required scope:** `write_promotions` (for API-key authentication).
# Delete a rule from a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/delete-a-rule-from-a-promotion
/api-reference/admin.yaml delete /api/v3/admin/promotions/{promotion_id}/promotion_rules/{id}
**Required scope:** `write_promotions` (for API-key authentication).
# Delete an action from a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/delete-an-action-from-a-promotion
/api-reference/admin.yaml delete /api/v3/admin/promotions/{promotion_id}/promotion_actions/{id}
**Required scope:** `write_promotions` (for API-key authentication).
# List actions for a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/list-actions-for-a-promotion
/api-reference/admin.yaml get /api/v3/admin/promotions/{promotion_id}/promotion_actions
**Required scope:** `read_promotions` (for API-key authentication).
# List available promotion action types
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/list-available-promotion-action-types
/api-reference/admin.yaml get /api/v3/admin/promotion_actions/types
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).
# List available promotion rule types
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/list-available-promotion-rule-types
/api-reference/admin.yaml get /api/v3/admin/promotion_rules/types
Returns the registered Spree::PromotionRule subclasses with their preference schemas.
**Required scope:** `read_promotions` (for API-key authentication).
# List coupon codes for a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/list-coupon-codes-for-a-promotion
/api-reference/admin.yaml get /api/v3/admin/promotions/{promotion_id}/coupon_codes
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).
# List promotions
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/list-promotions
/api-reference/admin.yaml get /api/v3/admin/promotions
Returns the store's promotions, including manual coupon and automatic promotions.
**Required scope:** `read_promotions` (for API-key authentication).
# List rules for a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/list-rules-for-a-promotion
/api-reference/admin.yaml get /api/v3/admin/promotions/{promotion_id}/promotion_rules
**Required scope:** `read_promotions` (for API-key authentication).
# Show a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/show-a-promotion
/api-reference/admin.yaml get /api/v3/admin/promotions/{id}
**Required scope:** `read_promotions` (for API-key authentication).
# Update a promotion
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/update-a-promotion
/api-reference/admin.yaml patch /api/v3/admin/promotions/{id}
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).
# Update a rule's preferences
Source: https://spreecommerce.org/docs/api-reference/admin-api/promotions/update-a-rules-preferences
/api-reference/admin.yaml patch /api/v3/admin/promotions/{promotion_id}/promotion_rules/{id}
**Required scope:** `write_promotions` (for API-key authentication).
# Filter, sort, paginate, and expand Admin API responses
Source: https://spreecommerce.org/docs/api-reference/admin-api/querying
Query Spree Admin API list endpoints with Ransack filters, sorting, pagination parameters, and the expand option to include related resources.
The Admin API uses [Ransack](https://activerecord-hackery.github.io/ransack/) for filtering and sorting on collection endpoints. All filter conditions go through the `q` parameter; sorting and pagination are top-level params.
## Filtering
Pass filter conditions via `q`:
```typescript SDK theme={"theme":"night-owl"}
const orders = await client.orders.list({
status_eq: 'complete',
total_gteq: 100,
email_cont: '@example.com',
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx' \
--data-urlencode 'q[status_eq]=complete' \
--data-urlencode 'q[total_gteq]=100' \
--data-urlencode 'q[email_cont]=@example.com'
```
The SDK automatically wraps filter keys in `q[...]` and appends `[]` for array values — pass flat params.
### Common predicates
| Predicate | Description | SDK | cURL |
| ------------------- | ------------------------------------ | ------------------------------------- | ------------------------------------------------- |
| `eq` | Equals | `status_eq: 'complete'` | `q[status_eq]=complete` |
| `not_eq` | Not equals | `status_not_eq: 'canceled'` | `q[status_not_eq]=canceled` |
| `cont` | Contains (case-insensitive) | `email_cont: '@acme'` | `q[email_cont]=@acme` |
| `start` | Starts with | `number_start: 'R10'` | `q[number_start]=R10` |
| `end` | Ends with | `slug_end: 'sale'` | `q[slug_end]=sale` |
| `lt` / `lteq` | Less than / less than or equal | `total_lteq: 50` | `q[total_lteq]=50` |
| `gt` / `gteq` | Greater than / greater than or equal | `total_gteq: 100` | `q[total_gteq]=100` |
| `in` | In a list | `status_in: ['complete', 'canceled']` | `q[status_in][]=complete&q[status_in][]=canceled` |
| `null` / `not_null` | Is null / not null | `completed_at_not_null: true` | `q[completed_at_not_null]=true` |
| `true` / `false` | Boolean | `accepts_email_marketing_true: 1` | `q[accepts_email_marketing_true]=1` |
### Prefixed IDs in filters
Resource ID filters accept Stripe-style prefixed IDs directly. The server decodes them before querying:
```typescript SDK theme={"theme":"night-owl"}
// All orders for a specific customer
const orders = await client.orders.list({
user_id_eq: 'cus_UkLWZg9DAJ',
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx' \
--data-urlencode 'q[user_id_eq]=cus_UkLWZg9DAJ'
```
The same applies to `_id_in`, `_id_not_eq`, and other ID predicates.
### Combining filters
Multiple filters combine with AND:
```typescript SDK theme={"theme":"night-owl"}
// Completed orders over $100 from the last 7 days
const orders = await client.orders.list({
status_eq: 'complete',
total_gteq: 100,
completed_at_gteq: new Date(Date.now() - 7 * 86_400_000).toISOString(),
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx' \
--data-urlencode 'q[status_eq]=complete' \
--data-urlencode 'q[total_gteq]=100' \
--data-urlencode 'q[completed_at_gteq]=2026-04-22T00:00:00Z'
```
### Filtering by association
Use underscore notation to filter on associated model attributes:
```typescript SDK theme={"theme":"night-owl"}
// Customers tagged as "wholesale"
const customers = await client.customers.list({
tags_name_eq: 'wholesale',
})
// Products in a specific category
const products = await client.products.list({
taxons_id_eq: 'ctg_xxx',
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/customers' \
-H 'X-Spree-Api-Key: sk_xxx' \
--data-urlencode 'q[tags_name_eq]=wholesale'
```
### Custom search scopes
Some resources expose convenience search scopes:
| Resource | Scope | Example |
| --------- | ---------------------- | -------------------------------------- |
| Customers | `search` | Full-text over email + first/last name |
| Customers | `with_min_total_spent` | Filter by lifetime spend |
| Orders | `multi_search` | Number + email full-text |
```typescript SDK theme={"theme":"night-owl"}
const customers = await client.customers.list({
search: 'jane',
})
const vipCustomers = await client.customers.list({
with_min_total_spent: 1000,
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/customers' \
-H 'X-Spree-Api-Key: sk_xxx' \
--data-urlencode 'q[search]=jane'
```
## Sorting
Use the top-level `sort` parameter on any list endpoint. Prefix with `-` for descending. Follows the [JSON:API sorting convention](https://jsonapi.org/format/#fetching-sorting).
```typescript SDK theme={"theme":"night-owl"}
// Most recent orders first
const orders = await client.orders.list({
sort: '-completed_at',
})
// Multiple sort keys (priority left to right)
const customers = await client.customers.list({
sort: '-total_spent,email',
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx' \
-d 'sort=-completed_at'
```
Sortable columns are limited to those whitelisted on the model (Ransack's `whitelisted_ransackable_attributes`). Sorting on a virtual column (e.g., a serializer-computed field like `display_total_spent`) is not supported.
## Pagination
All collection endpoints return paginated results. Control with `page` and `limit`:
```typescript SDK theme={"theme":"night-owl"}
const { data: orders, meta } = await client.orders.list({
page: 2,
limit: 50,
})
// meta.count, meta.pages, meta.previous, meta.next ...
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx' \
-d 'page=2' \
-d 'limit=50'
```
| Parameter | Default | Max | Description |
| --------- | ------- | ----- | ----------------------- |
| `page` | `1` | — | Page number (1-indexed) |
| `limit` | `25` | `100` | Records per page |
### Pagination metadata
Responses include a `meta` object:
```json theme={"theme":"night-owl"}
{
"data": [...],
"meta": {
"page": 2,
"limit": 50,
"count": 327,
"pages": 7,
"from": 51,
"to": 100,
"in": 50,
"previous": 1,
"next": 3
}
}
```
| Field | Description |
| -------------------- | ------------------------------------ |
| `page` | Current page number |
| `limit` | Records per page |
| `count` | Total number of matching records |
| `pages` | Total number of pages |
| `from` / `to` / `in` | Position range / count of this page |
| `previous` / `next` | Previous/next page number, or `null` |
## Expanding associations
Most admin endpoints return slim payloads by default — associations are returned as IDs. Use the `expand` parameter to include related resources inline:
```typescript SDK theme={"theme":"night-owl"}
const order = await client.orders.get('or_xxx', {
expand: ['items', 'fulfillments', 'payments', 'customer'],
})
// Nested expand
const customer = await client.customers.get('cus_xxx', {
expand: ['addresses', 'store_credits'],
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/orders/or_xxx' \
-H 'X-Spree-Api-Key: sk_xxx' \
-d 'expand=items,fulfillments,payments,customer'
```
### Nested expand
Use dot notation up to 4 levels deep:
```typescript theme={"theme":"night-owl"}
const order = await client.orders.get('or_xxx', {
expand: ['items.variant.product', 'fulfillments.tracking'],
})
```
A nested expand implicitly includes its parent — `expand: ['items.variant']` returns both `items` and their `variant` data.
### What can I expand?
Each endpoint documents its supported expand keys in the OpenAPI reference. Common admin expansions:
| Resource | Common expands |
| --------- | ------------------------------------------------------------------------------------------------------------------ |
| Orders | `items`, `fulfillments`, `payments`, `customer`, `discounts`, `adjustments`, `billing_address`, `shipping_address` |
| Customers | `addresses`, `store_credits`, `orders` |
| Products | `variants`, `media`, `option_types`, `categories` |
## Field selection
Use the `fields` parameter to request only specific fields on a resource. Reduces payload size for bandwidth-sensitive integrations:
```typescript SDK theme={"theme":"night-owl"}
const orders = await client.orders.list({
fields: ['number', 'total', 'status', 'completed_at'],
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'https://store.example.com/api/v3/admin/orders' \
-H 'X-Spree-Api-Key: sk_xxx' \
-d 'fields=number,total,status,completed_at'
```
Rules:
* `id` is always included
* Expanded associations return their full payload regardless of `fields`
* Field selection applies to the top-level resource only
TypeScript types in `@spree/admin-sdk` remain fully typed regardless of `fields`. At runtime, only the requested fields are present — the rest are `undefined`.
# Create a refund
Source: https://spreecommerce.org/docs/api-reference/admin-api/refunds/create-a-refund
/api-reference/admin.yaml post /api/v3/admin/orders/{order_id}/refunds
Creates a refund for a payment on the order. The refund is automatically processed via the payment gateway.
**Required scope:** `write_refunds` (for API-key authentication).
# List refunds
Source: https://spreecommerce.org/docs/api-reference/admin-api/refunds/list-refunds
/api-reference/admin.yaml get /api/v3/admin/orders/{order_id}/refunds
Returns all refunds for an order.
**Required scope:** `read_refunds` (for API-key authentication).
# Get a store credit category
Source: https://spreecommerce.org/docs/api-reference/admin-api/settings/get-a-store-credit-category
/api-reference/admin.yaml get /api/v3/admin/store_credit_categories/{id}
Returns a single store credit category by prefixed ID.
**Required scope:** `read_settings` (for API-key authentication).
# Get the current store
Source: https://spreecommerce.org/docs/api-reference/admin-api/settings/get-the-current-store
/api-reference/admin.yaml get /api/v3/admin/store
Returns the current store configuration. The store is resolved from the request context (host or admin selection); there is no `id` parameter.
**Required scope:** `read_settings` (for API-key authentication).
# List store credit categories
Source: https://spreecommerce.org/docs/api-reference/admin-api/settings/list-store-credit-categories
/api-reference/admin.yaml get /api/v3/admin/store_credit_categories
Returns the configured store credit categories. Categories classify
store credits (e.g., "Goodwill", "Gift Card", "Refund") and surface
in the admin UI as a dropdown when issuing or editing a store
credit. Category names matching `Spree::Config[:non_expiring_credit_types]`
are flagged via `non_expiring: true`.
**Required scope:** `read_settings` (for API-key authentication).
# List tags
Source: https://spreecommerce.org/docs/api-reference/admin-api/settings/list-tags
/api-reference/admin.yaml get /api/v3/admin/tags
Returns tag names for a given taggable type. Used for autocomplete in tag inputs on products, orders, and customers.
# Update the current store
Source: https://spreecommerce.org/docs/api-reference/admin-api/settings/update-the-current-store
/api-reference/admin.yaml patch /api/v3/admin/store
Updates the current store configuration.
**Required scope:** `write_settings` (for API-key authentication).
# Create an invitation
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/create-an-invitation
/api-reference/admin.yaml post /api/v3/admin/invitations
Invites a teammate by email. The invitation is scoped to the current store and carries the chosen role; on accept, a `RoleUser` is created via the invitation's `after_accept` callback.
**Required scope:** `write_settings` (for API-key authentication).
# List invitations
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/list-invitations
/api-reference/admin.yaml get /api/v3/admin/invitations
Returns invitations for the current store, including pending and accepted.
**Required scope:** `read_settings` (for API-key authentication).
# List roles
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/list-roles
/api-reference/admin.yaml get /api/v3/admin/roles
Returns the roles available for staff role pickers. Roles are global, not per-store.
**Required scope:** `read_settings` (for API-key authentication).
# List staff
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/list-staff
/api-reference/admin.yaml get /api/v3/admin/admin_users
Returns admin users with at least one role assignment on the current store.
**Required scope:** `read_settings` (for API-key authentication).
# Remove a staff member from this store
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/remove-a-staff-member-from-this-store
/api-reference/admin.yaml delete /api/v3/admin/admin_users/{id}
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).
# Resend an invitation
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/resend-an-invitation
/api-reference/admin.yaml patch /api/v3/admin/invitations/{id}/resend
Issues a fresh token and dispatches the invitation email again.
**Required scope:** `write_settings` (for API-key authentication).
# Revoke an invitation
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/revoke-an-invitation
/api-reference/admin.yaml delete /api/v3/admin/invitations/{id}
**Required scope:** `write_settings` (for API-key authentication).
# Show a staff member
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/show-a-staff-member
/api-reference/admin.yaml get /api/v3/admin/admin_users/{id}
**Required scope:** `read_settings` (for API-key authentication).
# Update a staff member
Source: https://spreecommerce.org/docs/api-reference/admin-api/staff/update-a-staff-member
/api-reference/admin.yaml patch /api/v3/admin/admin_users/{id}
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).
# Create a stock location
Source: https://spreecommerce.org/docs/api-reference/admin-api/stock-locations/create-a-stock-location
/api-reference/admin.yaml post /api/v3/admin/stock_locations
Creates a new stock location.
Setting `default: true` automatically demotes the previous default
location.
**Required scope:** `write_settings` (for API-key authentication).
# Delete a stock location
Source: https://spreecommerce.org/docs/api-reference/admin-api/stock-locations/delete-a-stock-location
/api-reference/admin.yaml delete /api/v3/admin/stock_locations/{id}
Soft-deletes the stock location (sets `deleted_at`). Existing
fulfillments that referenced it keep the historical record via
`Spree::StockLocation.with_deleted`.
**Required scope:** `write_settings` (for API-key authentication).
# Get a stock location
Source: https://spreecommerce.org/docs/api-reference/admin-api/stock-locations/get-a-stock-location
/api-reference/admin.yaml get /api/v3/admin/stock_locations/{id}
Returns a single stock location by prefixed ID.
**Required scope:** `read_settings` (for API-key authentication).
# List stock locations
Source: https://spreecommerce.org/docs/api-reference/admin-api/stock-locations/list-stock-locations
/api-reference/admin.yaml get /api/v3/admin/stock_locations
Returns the configured stock locations. Stock locations are global
(shared across stores). Filter with Ransack predicates such as
`q[active_eq]`, `q[kind_eq]`, `q[pickup_enabled_eq]`, or
`q[name_cont]`.
Pickup-related attributes (`kind`, `pickup_enabled`,
`pickup_stock_policy`, `pickup_ready_in_minutes`,
`pickup_instructions`) drive merchant pickup support at checkout —
customers can collect orders from any active location with
`pickup_enabled: true`.
**Required scope:** `read_settings` (for API-key authentication).
# Update a stock location
Source: https://spreecommerce.org/docs/api-reference/admin-api/stock-locations/update-a-stock-location
/api-reference/admin.yaml patch /api/v3/admin/stock_locations/{id}
Updates an existing stock location. Same address-field conventions as
the create endpoint.
Setting `default: true` automatically demotes the previous default.
**Required scope:** `write_settings` (for API-key authentication).
# Create a variant
Source: https://spreecommerce.org/docs/api-reference/admin-api/variants/create-a-variant
/api-reference/admin.yaml post /api/v3/admin/products/{product_id}/variants
Creates a new variant for a product. Supports nested prices and stock items.
Option types and values are auto-created if they don't exist.
Prices are upserted by currency. Stock items are upserted by stock location.
**Required scope:** `write_products` (for API-key authentication).
# Delete a variant
Source: https://spreecommerce.org/docs/api-reference/admin-api/variants/delete-a-variant
/api-reference/admin.yaml delete /api/v3/admin/products/{product_id}/variants/{id}
Soft-deletes a variant.
**Required scope:** `write_products` (for API-key authentication).
# Get a variant
Source: https://spreecommerce.org/docs/api-reference/admin-api/variants/get-a-variant
/api-reference/admin.yaml get /api/v3/admin/products/{product_id}/variants/{id}
Returns a single variant by ID.
**Required scope:** `read_products` (for API-key authentication).
# List product variants
Source: https://spreecommerce.org/docs/api-reference/admin-api/variants/list-product-variants
/api-reference/admin.yaml get /api/v3/admin/products/{product_id}/variants
Returns a paginated list of variants for a product, including the master variant.
**Required scope:** `read_products` (for API-key authentication).
# Update a variant
Source: https://spreecommerce.org/docs/api-reference/admin-api/variants/update-a-variant
/api-reference/admin.yaml patch /api/v3/admin/products/{product_id}/variants/{id}
Updates a variant. Only provided fields are updated.
**Required scope:** `write_products` (for API-key authentication).
# Create a webhook endpoint
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/create-a-webhook-endpoint
/api-reference/admin.yaml post /api/v3/admin/webhook_endpoints
Creates a new outbound webhook subscription. The plaintext
`secret_key` is returned **once** in this response — persist it
immediately to verify incoming webhook signatures. Subsequent reads
return `null` for the secret. Pass an empty `subscriptions` array or
omit it to receive every event.
**Required scope:** `write_settings` (for API-key authentication).
# Delete a webhook endpoint
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/delete-a-webhook-endpoint
/api-reference/admin.yaml delete /api/v3/admin/webhook_endpoints/{id}
Soft-deletes the endpoint and stops future deliveries.
**Required scope:** `write_settings` (for API-key authentication).
# Disable a webhook endpoint
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/disable-a-webhook-endpoint
/api-reference/admin.yaml patch /api/v3/admin/webhook_endpoints/{id}/disable
Manually pauses an endpoint. Unlike auto-disable (triggered after
repeated delivery failures), no notification email is sent.
**Required scope:** `write_settings` (for API-key authentication).
# Get a webhook delivery
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/get-a-webhook-delivery
/api-reference/admin.yaml get /api/v3/admin/webhook_endpoints/{webhook_endpoint_id}/deliveries/{id}
Returns a single delivery attempt with the full request payload and
the response body the receiver returned. Use this for ad-hoc debug
of failed deliveries.
**Required scope:** `read_settings` (for API-key authentication).
# Get a webhook endpoint
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/get-a-webhook-endpoint
/api-reference/admin.yaml get /api/v3/admin/webhook_endpoints/{id}
Returns a single webhook endpoint by prefixed ID.
**Required scope:** `read_settings` (for API-key authentication).
# List webhook deliveries
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/list-webhook-deliveries
/api-reference/admin.yaml get /api/v3/admin/webhook_endpoints/{webhook_endpoint_id}/deliveries
Returns delivery attempts for the given endpoint, most recent first.
Each row carries the original request payload, the response code
(when the receiver replied), the execution time, and any transport
error — everything needed to audit failures and decide whether to
redeliver.
**Required scope:** `read_settings` (for API-key authentication).
# List webhook endpoints
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/list-webhook-endpoints
/api-reference/admin.yaml get /api/v3/admin/webhook_endpoints
Returns outbound webhook subscriptions for the current store. Each
endpoint receives a signed POST when any subscribed event fires.
`secret_key` is `null` on list reads — the plaintext is delivered
exactly once on create.
**Required scope:** `read_settings` (for API-key authentication).
# Re-enable a webhook endpoint
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/re-enable-a-webhook-endpoint
/api-reference/admin.yaml patch /api/v3/admin/webhook_endpoints/{id}/enable
Re-enables an endpoint that was manually or automatically disabled.
**Required scope:** `write_settings` (for API-key authentication).
# Redeliver a webhook delivery
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/redeliver-a-webhook-delivery
/api-reference/admin.yaml post /api/v3/admin/webhook_endpoints/{webhook_endpoint_id}/deliveries/{id}/redeliver
Creates a new delivery row with the same payload + event_name and
queues it. The original row is preserved for audit history.
**Required scope:** `write_settings` (for API-key authentication).
# Send a test delivery
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/send-a-test-delivery
/api-reference/admin.yaml post /api/v3/admin/webhook_endpoints/{id}/send_test
Creates a `webhook.test` delivery record and queues it. Use this to
verify the endpoint is reachable and your signature verification
accepts Spree's payloads.
**Required scope:** `write_settings` (for API-key authentication).
# Update a webhook endpoint
Source: https://spreecommerce.org/docs/api-reference/admin-api/webhooks/update-a-webhook-endpoint
/api-reference/admin.yaml patch /api/v3/admin/webhook_endpoints/{id}
Updates name, URL, active flag, or the event subscription list.
Toggling `active` here is equivalent to calling `disable`/`enable`
without an audit reason.
**Required scope:** `write_settings` (for API-key authentication).
# Create an Address
Source: https://spreecommerce.org/docs/api-reference/platform/addresses/create-an-address
/api-reference/platform.yaml post /api/v2/platform/addresses
Creates an Address
# Delete an Address
Source: https://spreecommerce.org/docs/api-reference/platform/addresses/delete-an-address
/api-reference/platform.yaml delete /api/v2/platform/addresses/{id}
Deletes an Address
# Return a list of Addresses
Source: https://spreecommerce.org/docs/api-reference/platform/addresses/return-a-list-of-addresses
/api-reference/platform.yaml get /api/v2/platform/addresses
Returns a list of Addresses
# Return an Address
Source: https://spreecommerce.org/docs/api-reference/platform/addresses/return-an-address
/api-reference/platform.yaml get /api/v2/platform/addresses/{id}
Returns an Address
# Update an Address
Source: https://spreecommerce.org/docs/api-reference/platform/addresses/update-an-address
/api-reference/platform.yaml patch /api/v2/platform/addresses/{id}
Updates an Address
# Create an Adjustment
Source: https://spreecommerce.org/docs/api-reference/platform/adjustments/create-an-adjustment
/api-reference/platform.yaml post /api/v2/platform/adjustments
Creates an Adjustment
# Delete an Adjustment
Source: https://spreecommerce.org/docs/api-reference/platform/adjustments/delete-an-adjustment
/api-reference/platform.yaml delete /api/v2/platform/adjustments/{id}
Deletes an Adjustment
# Return a list of Adjustments
Source: https://spreecommerce.org/docs/api-reference/platform/adjustments/return-a-list-of-adjustments
/api-reference/platform.yaml get /api/v2/platform/adjustments
Returns a list of Adjustments
# Return an Adjustment
Source: https://spreecommerce.org/docs/api-reference/platform/adjustments/return-an-adjustment
/api-reference/platform.yaml get /api/v2/platform/adjustments/{id}
Returns an Adjustment
# Update an Adjustment
Source: https://spreecommerce.org/docs/api-reference/platform/adjustments/update-an-adjustment
/api-reference/platform.yaml patch /api/v2/platform/adjustments/{id}
Updates an Adjustment
# Authentication
Source: https://spreecommerce.org/docs/api-reference/platform/authentication
Platform API is meant to be used by external applications to perform operations within Spree. Because of that, it uses a different authentication schema than the Storefront API.
### Creating an application inside Spree
To generate a valid token for the Platform API, you'll first need to create an application inside Spree.
1. Go to Spree's admin panel and open `Apps` -> `oAuth Applications` in the menu
2. Click on `New oAuth Application`
3. Give your application a name and click `Create`
4. Save your Client ID and Secret - you'll later use it to generate an OAuth token to access the platform API
### Generating OAuth token
Once the application is configured inside Spree, you can use its credentials to generate an OAuth token that will give you access to the APIs.
To obtain the token, send the following `POST` request to `/spree_oauth/token`
```json theme={"theme":"night-owl"}
{
"grant_type": "client_credentials",
"client_id": "xxx",
"client_secret": "xxx",
"scope": "admin"
}
```
In the response, you'll receive a token to pass in `Authorization: Bearer {token}` header when making requests to the Platform API.
# Create a Classification
Source: https://spreecommerce.org/docs/api-reference/platform/classifications/create-a-classification
/api-reference/platform.yaml post /api/v2/platform/classifications
Creates a Classification
# Delete a Classification
Source: https://spreecommerce.org/docs/api-reference/platform/classifications/delete-a-classification
/api-reference/platform.yaml delete /api/v2/platform/classifications/{id}
Deletes a Classification
# Return a Classification
Source: https://spreecommerce.org/docs/api-reference/platform/classifications/return-a-classification
/api-reference/platform.yaml get /api/v2/platform/classifications/{id}
Returns a Classification
# Return a list of Classifications
Source: https://spreecommerce.org/docs/api-reference/platform/classifications/return-a-list-of-classifications
/api-reference/platform.yaml get /api/v2/platform/classifications
Returns a list of Classifications
# Update a Classification
Source: https://spreecommerce.org/docs/api-reference/platform/classifications/update-a-classification
/api-reference/platform.yaml patch /api/v2/platform/classifications/{id}
Updates a Classification
# Create a CMS Page
Source: https://spreecommerce.org/docs/api-reference/platform/cms-pages/create-a-cms-page
/api-reference/platform.yaml post /api/v2/platform/cms_pages
Creates a CMS Page
# Delete a CMS Page
Source: https://spreecommerce.org/docs/api-reference/platform/cms-pages/delete-a-cms-page
/api-reference/platform.yaml delete /api/v2/platform/cms_pages/{id}
Deletes a CMS Page
# Return a CMS Page
Source: https://spreecommerce.org/docs/api-reference/platform/cms-pages/return-a-cms-page
/api-reference/platform.yaml get /api/v2/platform/cms_pages/{id}
Returns a CMS Page
# Return a list of CMS Pages
Source: https://spreecommerce.org/docs/api-reference/platform/cms-pages/return-a-list-of-cms-pages
/api-reference/platform.yaml get /api/v2/platform/cms_pages
Returns a list of CMS Pages
# Update a CMS Page
Source: https://spreecommerce.org/docs/api-reference/platform/cms-pages/update-a-cms-page
/api-reference/platform.yaml patch /api/v2/platform/cms_pages/{id}
Updates a CMS Page
# Create a CMS Section
Source: https://spreecommerce.org/docs/api-reference/platform/cms-sections/create-a-cms-section
/api-reference/platform.yaml post /api/v2/platform/cms_sections
Creates a CMS Section
# Delete a CMS Section
Source: https://spreecommerce.org/docs/api-reference/platform/cms-sections/delete-a-cms-section
/api-reference/platform.yaml delete /api/v2/platform/cms_sections/{id}
Deletes a CMS Section
# Return a CMS Section
Source: https://spreecommerce.org/docs/api-reference/platform/cms-sections/return-a-cms-section
/api-reference/platform.yaml get /api/v2/platform/cms_sections/{id}
Returns a CMS Section
# Return a list of CMS Sections
Source: https://spreecommerce.org/docs/api-reference/platform/cms-sections/return-a-list-of-cms-sections
/api-reference/platform.yaml get /api/v2/platform/cms_sections
Returns a list of CMS Sections
# Update a CMS Section
Source: https://spreecommerce.org/docs/api-reference/platform/cms-sections/update-a-cms-section
/api-reference/platform.yaml patch /api/v2/platform/cms_sections/{id}
Updates a CMS Section
# Returns a Country
Source: https://spreecommerce.org/docs/api-reference/platform/countries/returns-a-country
/api-reference/platform.yaml get /api/v2/platform/countries/{id}
Returns a Country
# Returns a list of Countries
Source: https://spreecommerce.org/docs/api-reference/platform/countries/returns-a-list-of-countries
/api-reference/platform.yaml get /api/v2/platform/countries
Returns a list of Countries
# Create a Data Feed
Source: https://spreecommerce.org/docs/api-reference/platform/data-feeds/create-a-data-feed
/api-reference/platform.yaml post /api/v2/platform/data_feeds
Creates a Data Feed
# Delete a Data Feed
Source: https://spreecommerce.org/docs/api-reference/platform/data-feeds/delete-a-data-feed
/api-reference/platform.yaml delete /api/v2/platform/data_feeds/{id}
Deletes a Data Feed
# Return a Data Feed
Source: https://spreecommerce.org/docs/api-reference/platform/data-feeds/return-a-data-feed
/api-reference/platform.yaml get /api/v2/platform/data_feeds/{id}
Returns a Data Feed
# Return a list of Data Feeds
Source: https://spreecommerce.org/docs/api-reference/platform/data-feeds/return-a-list-of-data-feeds
/api-reference/platform.yaml get /api/v2/platform/data_feeds
# Update a Data Feed
Source: https://spreecommerce.org/docs/api-reference/platform/data-feeds/update-a-data-feed
/api-reference/platform.yaml patch /api/v2/platform/data_feeds/{id}
Updates a Data Feed
# Create a Digital Asset
Source: https://spreecommerce.org/docs/api-reference/platform/digital-assets/create-a-digital-asset
/api-reference/platform.yaml post /api/v2/platform/digitals
Creates a Digital Asset
# Delete a Digital Asset
Source: https://spreecommerce.org/docs/api-reference/platform/digital-assets/delete-a-digital-asset
/api-reference/platform.yaml delete /api/v2/platform/digitals/{id}
Deletes a Digital Asset
# Return a Digital Asset
Source: https://spreecommerce.org/docs/api-reference/platform/digital-assets/return-a-digital-asset
/api-reference/platform.yaml get /api/v2/platform/digitals/{id}
Returns a Digital Asset
# Return a list of Digital Assets
Source: https://spreecommerce.org/docs/api-reference/platform/digital-assets/return-a-list-of-digital-assets
/api-reference/platform.yaml get /api/v2/platform/digitals
Returns a list of Digital Assets
# Update a Digital Asset
Source: https://spreecommerce.org/docs/api-reference/platform/digital-assets/update-a-digital-asset
/api-reference/platform.yaml patch /api/v2/platform/digitals/{id}
Updates a Digital Asset
# Create a Digital Link
Source: https://spreecommerce.org/docs/api-reference/platform/digital-links/create-a-digital-link
/api-reference/platform.yaml post /api/v2/platform/digital_links
Creates a Digital Link
# Delete a Digital Link
Source: https://spreecommerce.org/docs/api-reference/platform/digital-links/delete-a-digital-link
/api-reference/platform.yaml delete /api/v2/platform/digital_links/{id}
Deletes a Digital Link
# Reset a Digital Link
Source: https://spreecommerce.org/docs/api-reference/platform/digital-links/reset-a-digital-link
/api-reference/platform.yaml patch /api/v2/platform/digital_links/{id}/reset
Resets a digital link, allowing further downloads.
# Return a Digital Link
Source: https://spreecommerce.org/docs/api-reference/platform/digital-links/return-a-digital-link
/api-reference/platform.yaml get /api/v2/platform/digital_links/{id}
Returns a Digital Link
# Return a list of Digital Links
Source: https://spreecommerce.org/docs/api-reference/platform/digital-links/return-a-list-of-digital-links
/api-reference/platform.yaml get /api/v2/platform/digital_links
Returns a list of Digital Links
# Update a Digital Link
Source: https://spreecommerce.org/docs/api-reference/platform/digital-links/update-a-digital-link
/api-reference/platform.yaml patch /api/v2/platform/digital_links/{id}
Updates a Digital Link
# Create a Line Item
Source: https://spreecommerce.org/docs/api-reference/platform/line-items/create-a-line-item
/api-reference/platform.yaml post /api/v2/platform/line_items
Creates a Line Item
# Delete a Line Item
Source: https://spreecommerce.org/docs/api-reference/platform/line-items/delete-a-line-item
/api-reference/platform.yaml delete /api/v2/platform/line_items/{id}
Deletes a Line Item
# Return a Line Item
Source: https://spreecommerce.org/docs/api-reference/platform/line-items/return-a-line-item
/api-reference/platform.yaml get /api/v2/platform/line_items/{id}
Returns a Line Item
# Return a list of Line Items
Source: https://spreecommerce.org/docs/api-reference/platform/line-items/return-a-list-of-line-items
/api-reference/platform.yaml get /api/v2/platform/line_items
Returns a list of Line Items
# Update a Line Item
Source: https://spreecommerce.org/docs/api-reference/platform/line-items/update-a-line-item
/api-reference/platform.yaml patch /api/v2/platform/line_items/{id}
Updates a Line Item
# Create a Menu Item
Source: https://spreecommerce.org/docs/api-reference/platform/menu-items/create-a-menu-item
/api-reference/platform.yaml post /api/v2/platform/menu_items
Creates a Menu Item
# Delete a Menu Item
Source: https://spreecommerce.org/docs/api-reference/platform/menu-items/delete-a-menu-item
/api-reference/platform.yaml delete /api/v2/platform/menu_items/{id}
Deletes a Menu Item
# Reposition a Menu Item
Source: https://spreecommerce.org/docs/api-reference/platform/menu-items/reposition-a-menu-item
/api-reference/platform.yaml patch /api/v2/platform/menu_items/{id}/reposition
Reposition a Menu Item
# Return a list of Menu Items
Source: https://spreecommerce.org/docs/api-reference/platform/menu-items/return-a-list-of-menu-items
/api-reference/platform.yaml get /api/v2/platform/menu_items
Returns a list of Menu Items
# Return a Menu Item
Source: https://spreecommerce.org/docs/api-reference/platform/menu-items/return-a-menu-item
/api-reference/platform.yaml get /api/v2/platform/menu_items/{id}
Returns a Menu Item
# Update a Menu Item
Source: https://spreecommerce.org/docs/api-reference/platform/menu-items/update-a-menu-item
/api-reference/platform.yaml patch /api/v2/platform/menu_items/{id}
Updates a Menu Item
# Create a Menu
Source: https://spreecommerce.org/docs/api-reference/platform/menus/create-a-menu
/api-reference/platform.yaml post /api/v2/platform/menus
Creates a Menu
# Delete a Menu
Source: https://spreecommerce.org/docs/api-reference/platform/menus/delete-a-menu
/api-reference/platform.yaml delete /api/v2/platform/menus/{id}
Deletes a Menu
# Return a list of Menus
Source: https://spreecommerce.org/docs/api-reference/platform/menus/return-a-list-of-menus
/api-reference/platform.yaml get /api/v2/platform/menus
Returns a list of Menus
# Return a Menu
Source: https://spreecommerce.org/docs/api-reference/platform/menus/return-a-menu
/api-reference/platform.yaml get /api/v2/platform/menus/{id}
Returns a Menu
# Update a Menu
Source: https://spreecommerce.org/docs/api-reference/platform/menus/update-a-menu
/api-reference/platform.yaml patch /api/v2/platform/menus/{id}
Updates a Menu
# Create an Option Type
Source: https://spreecommerce.org/docs/api-reference/platform/option-types/create-an-option-type
/api-reference/platform.yaml post /api/v2/platform/option_types
Creates an Option Type
# Delete an Option Type
Source: https://spreecommerce.org/docs/api-reference/platform/option-types/delete-an-option-type
/api-reference/platform.yaml delete /api/v2/platform/option_types/{id}
Deletes an Option Type
# Return a list of Option Types
Source: https://spreecommerce.org/docs/api-reference/platform/option-types/return-a-list-of-option-types
/api-reference/platform.yaml get /api/v2/platform/option_types
Returns a list of Option Types
# Return an Option Type
Source: https://spreecommerce.org/docs/api-reference/platform/option-types/return-an-option-type
/api-reference/platform.yaml get /api/v2/platform/option_types/{id}
Returns an Option Type
# Update an Option Type
Source: https://spreecommerce.org/docs/api-reference/platform/option-types/update-an-option-type
/api-reference/platform.yaml patch /api/v2/platform/option_types/{id}
Updates an Option Type
# Create an Option Value
Source: https://spreecommerce.org/docs/api-reference/platform/option-values/create-an-option-value
/api-reference/platform.yaml post /api/v2/platform/option_values
Creates an Option Value
# Delete an Option Value
Source: https://spreecommerce.org/docs/api-reference/platform/option-values/delete-an-option-value
/api-reference/platform.yaml delete /api/v2/platform/option_values/{id}
Deletes an Option Value
# Return a list of Option Values
Source: https://spreecommerce.org/docs/api-reference/platform/option-values/return-a-list-of-option-values
/api-reference/platform.yaml get /api/v2/platform/option_values
Returns a list of Option Values
# Return an Option Value
Source: https://spreecommerce.org/docs/api-reference/platform/option-values/return-an-option-value
/api-reference/platform.yaml get /api/v2/platform/option_values/{id}
Returns an Option Value
# Update an Option Value
Source: https://spreecommerce.org/docs/api-reference/platform/option-values/update-an-option-value
/api-reference/platform.yaml patch /api/v2/platform/option_values/{id}
Updates an Option Value
# Advances an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/advances-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/advance
Advances an Order
# Apply Coupon Code for an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/apply-coupon-code-for-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/apply_coupon_code
Creates Store Credit payment for an Order
# Approves an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/approves-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/approve
Approves an Order, when using a token created for a user, it will save this user as the approver
# Cancels an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/cancels-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/cancel
Cancels an Order, when using a token created for a user, it will save this user as the canceler
# Completes an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/completes-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/complete
Marks an Order as completed
# Creates an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/creates-an-order
/api-reference/platform.yaml post /api/v2/platform/orders
Creates an Order
# Delete an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/delete-an-order
/api-reference/platform.yaml delete /api/v2/platform/orders/{id}
Deletes an Order
# Empties an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/empties-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/empty
Removes all line items, promotions, shipment and payments from an Order
# Next an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/next-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/next
Moves an Order to the next state
# Return a list of Orders
Source: https://spreecommerce.org/docs/api-reference/platform/orders/return-a-list-of-orders
/api-reference/platform.yaml get /api/v2/platform/orders
Returns a list of Orders
# Return an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/return-an-order
/api-reference/platform.yaml get /api/v2/platform/orders/{id}
Returns an Order
# Update an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/update-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}
Updates an Order
# Use Store Credit for an Order
Source: https://spreecommerce.org/docs/api-reference/platform/orders/use-store-credit-for-an-order
/api-reference/platform.yaml patch /api/v2/platform/orders/{id}/use_store_credit
Creates Store Credit payment for an Order
# Create a Payment Method
Source: https://spreecommerce.org/docs/api-reference/platform/payment-methods/create-a-payment-method
/api-reference/platform.yaml post /api/v2/platform/payment_methods
Creates a Payment Method
# Delete a Payment Method
Source: https://spreecommerce.org/docs/api-reference/platform/payment-methods/delete-a-payment-method
/api-reference/platform.yaml delete /api/v2/platform/payment_methods/{id}
Deletes a Payment Method
# Return a list of Payment Methods
Source: https://spreecommerce.org/docs/api-reference/platform/payment-methods/return-a-list-of-payment-methods
/api-reference/platform.yaml get /api/v2/platform/payment_methods
Returns a list of Payment Methods
# Return a Payment Method
Source: https://spreecommerce.org/docs/api-reference/platform/payment-methods/return-a-payment-method
/api-reference/platform.yaml get /api/v2/platform/payment_methods/{id}
Returns a Payment Method
# Update a Payment Method
Source: https://spreecommerce.org/docs/api-reference/platform/payment-methods/update-a-payment-method
/api-reference/platform.yaml patch /api/v2/platform/payment_methods/{id}
Updates a Payment Method
# Delete a Payment
Source: https://spreecommerce.org/docs/api-reference/platform/payments/delete-a-payment
/api-reference/platform.yaml delete /api/v2/platform/payments/{id}
Deletes a Payment
# Return a list of Payments
Source: https://spreecommerce.org/docs/api-reference/platform/payments/return-a-list-of-payments
/api-reference/platform.yaml get /api/v2/platform/payments
Returns a list of Payments
# Return a Payment
Source: https://spreecommerce.org/docs/api-reference/platform/payments/return-a-payment
/api-reference/platform.yaml get /api/v2/platform/payments/{id}
Returns a Payment
# Create a Product
Source: https://spreecommerce.org/docs/api-reference/platform/products/create-a-product
/api-reference/platform.yaml post /api/v2/platform/products
Creates a Product
# Delete a Product
Source: https://spreecommerce.org/docs/api-reference/platform/products/delete-a-product
/api-reference/platform.yaml delete /api/v2/platform/products/{id}
Deletes a Product
# Return a list of Products
Source: https://spreecommerce.org/docs/api-reference/platform/products/return-a-list-of-products
/api-reference/platform.yaml get /api/v2/platform/products
Returns a list of Products
# Return a Product
Source: https://spreecommerce.org/docs/api-reference/platform/products/return-a-product
/api-reference/platform.yaml get /api/v2/platform/products/{id}
Returns a Product
# Update a Product
Source: https://spreecommerce.org/docs/api-reference/platform/products/update-a-product
/api-reference/platform.yaml patch /api/v2/platform/products/{id}
Updates a Product
# Create a Promotion Action
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-actions/create-a-promotion-action
/api-reference/platform.yaml post /api/v2/platform/promotion_actions
Creates a Promotion Action
# Delete a Promotion Action
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-actions/delete-a-promotion-action
/api-reference/platform.yaml delete /api/v2/platform/promotion_actions/{id}
Deletes a Promotion Action
# Return a list of Promotion Actions
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-actions/return-a-list-of-promotion-actions
/api-reference/platform.yaml get /api/v2/platform/promotion_actions
Returns a list of Promotion Actions
# Return a Promotion Action
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-actions/return-a-promotion-action
/api-reference/platform.yaml get /api/v2/platform/promotion_actions/{id}
Returns a Promotion Action
# Update a Promotion Action
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-actions/update-a-promotion-action
/api-reference/platform.yaml patch /api/v2/platform/promotion_actions/{id}
Updates a Promotion Action
# Create a Promotion Category
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-categories/create-a-promotion-category
/api-reference/platform.yaml post /api/v2/platform/promotion_categories
Creates a Promotion Category
# Delete a Promotion Category
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-categories/delete-a-promotion-category
/api-reference/platform.yaml delete /api/v2/platform/promotion_categories/{id}
Deletes a Promotion Category
# Return a list of Promotion Categories
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-categories/return-a-list-of-promotion-categories
/api-reference/platform.yaml get /api/v2/platform/promotion_categories
Returns a list of Promotion Categories
# Return a Promotion Category
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-categories/return-a-promotion-category
/api-reference/platform.yaml get /api/v2/platform/promotion_categories/{id}
Returns a Promotion Category
# Update a Promotion Category
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-categories/update-a-promotion-category
/api-reference/platform.yaml patch /api/v2/platform/promotion_categories/{id}
Updates a Promotion Category
# Create a Promotion Rule
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-rules/create-a-promotion-rule
/api-reference/platform.yaml post /api/v2/platform/promotion_rules
Creates a Promotion Rule
# Delete a Promotion Rule
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-rules/delete-a-promotion-rule
/api-reference/platform.yaml delete /api/v2/platform/promotion_rules/{id}
Deletes a Promotion Rule
# Return a list of Promotion Rules
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-rules/return-a-list-of-promotion-rules
/api-reference/platform.yaml get /api/v2/platform/promotion_rules
Returns a list of Promotion Rules
# Return a Promotion Rule
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-rules/return-a-promotion-rule
/api-reference/platform.yaml get /api/v2/platform/promotion_rules/{id}
Returns a Promotion Rule
# Update a Promotion Rule
Source: https://spreecommerce.org/docs/api-reference/platform/promotion-rules/update-a-promotion-rule
/api-reference/platform.yaml patch /api/v2/platform/promotion_rules/{id}
Updates a Promotion Rule
# Create a Promotion
Source: https://spreecommerce.org/docs/api-reference/platform/promotions/create-a-promotion
/api-reference/platform.yaml post /api/v2/platform/promotions
Creates a Promotion
# Delete a Promotion
Source: https://spreecommerce.org/docs/api-reference/platform/promotions/delete-a-promotion
/api-reference/platform.yaml delete /api/v2/platform/promotions/{id}
Deletes a Promotion
# Return a list of Promotions
Source: https://spreecommerce.org/docs/api-reference/platform/promotions/return-a-list-of-promotions
/api-reference/platform.yaml get /api/v2/platform/promotions
Returns a list of Promotions
# Return a Promotion
Source: https://spreecommerce.org/docs/api-reference/platform/promotions/return-a-promotion
/api-reference/platform.yaml get /api/v2/platform/promotions/{id}
Returns a Promotion
# Update a Promotion
Source: https://spreecommerce.org/docs/api-reference/platform/promotions/update-a-promotion
/api-reference/platform.yaml patch /api/v2/platform/promotions/{id}
Updates a Promotion
# Create a Role
Source: https://spreecommerce.org/docs/api-reference/platform/roles/create-a-role
/api-reference/platform.yaml post /api/v2/platform/roles
Creates a Role
# Delete a Role
Source: https://spreecommerce.org/docs/api-reference/platform/roles/delete-a-role
/api-reference/platform.yaml delete /api/v2/platform/roles/{id}
Deletes a Role
# Return a list of Roles
Source: https://spreecommerce.org/docs/api-reference/platform/roles/return-a-list-of-roles
/api-reference/platform.yaml get /api/v2/platform/roles
Returns a list of Roles
# Return a Role
Source: https://spreecommerce.org/docs/api-reference/platform/roles/return-a-role
/api-reference/platform.yaml get /api/v2/platform/roles/{id}
Returns a Role
# Update a Role
Source: https://spreecommerce.org/docs/api-reference/platform/roles/update-a-role
/api-reference/platform.yaml patch /api/v2/platform/roles/{id}
Updates a Role
# Adds item (Variant) to an existing Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/adds-item-variant-to-an-existing-shipment
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}/add_item
If selected Variant was already added to Order it will increase the quantity of existing Line Item, if not it will create a new Line Item
# Cancels the Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/cancels-the-shipment
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}/cancel
Cancels the Shipment
# Create a Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/create-a-shipment
/api-reference/platform.yaml post /api/v2/platform/shipments
Creates a Shipment
# Delete a Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/delete-a-shipment
/api-reference/platform.yaml delete /api/v2/platform/shipments/{id}
Deletes a Shipment
# Mark Shipment as ready to be shipped
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/mark-shipment-as-ready-to-be-shipped
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}/ready
Marks Shipment as ready to be shipped
# Mark Shipment as shipped
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/mark-shipment-as-shipped
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}/ship
Marks Shipment as shipped
# Moves Shipment back to pending state
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/moves-shipment-back-to-pending-state
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}/pend
Moves Shipment back to pending state
# Removes item (Variant) from Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/removes-item-variant-from-shipment
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}/remove_item
If selected Variant is removed completely and Shipment doesn't include any other Line Items, Shipment itself will be deleted
# Resumes the Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/resumes-the-shipment
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}/resume
Resumes previously canceled Shipment
# Return a list of Shipments
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/return-a-list-of-shipments
/api-reference/platform.yaml get /api/v2/platform/shipments
Returns a list of Shipments
# Return a Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/return-a-shipment
/api-reference/platform.yaml get /api/v2/platform/shipments/{id}
Returns a Shipment
# Update a Shipment
Source: https://spreecommerce.org/docs/api-reference/platform/shipments/update-a-shipment
/api-reference/platform.yaml patch /api/v2/platform/shipments/{id}
Updates a Shipment
# Create a Shipping Category
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-categories/create-a-shipping-category
/api-reference/platform.yaml post /api/v2/platform/shipping_categories
Creates a Shipping Category
# Delete a Shipping Category
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-categories/delete-a-shipping-category
/api-reference/platform.yaml delete /api/v2/platform/shipping_categories/{id}
Deletes a Shipping Category
# Return a list of Shipping Categories
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-categories/return-a-list-of-shipping-categories
/api-reference/platform.yaml get /api/v2/platform/shipping_categories
Returns a list of Shipping Categories
# Return a Shipping Category
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-categories/return-a-shipping-category
/api-reference/platform.yaml get /api/v2/platform/shipping_categories/{id}
Returns a Shipping Category
# Update a Shipping Category
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-categories/update-a-shipping-category
/api-reference/platform.yaml patch /api/v2/platform/shipping_categories/{id}
Updates a Shipping Category
# Create a Shipping Method
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-methods/create-a-shipping-method
/api-reference/platform.yaml post /api/v2/platform/shipping_methods
Creates a Shipping Method
# Delete a Shipping Method
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-methods/delete-a-shipping-method
/api-reference/platform.yaml delete /api/v2/platform/shipping_methods/{id}
Deletes a Shipping Method
# Return a list of Shipping Methods
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-methods/return-a-list-of-shipping-methods
/api-reference/platform.yaml get /api/v2/platform/shipping_methods
Returns a list of Shipping Methods
# Return a Shipping Method
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-methods/return-a-shipping-method
/api-reference/platform.yaml get /api/v2/platform/shipping_methods/{id}
Returns a Shipping Method
# Update a Shipping Method
Source: https://spreecommerce.org/docs/api-reference/platform/shipping-methods/update-a-shipping-method
/api-reference/platform.yaml patch /api/v2/platform/shipping_methods/{id}
Updates a Shipping Method
# Returns a list of States
Source: https://spreecommerce.org/docs/api-reference/platform/states/returns-a-list-of-states
/api-reference/platform.yaml get /api/v2/platform/states
Returns a list of States
# Returns a State
Source: https://spreecommerce.org/docs/api-reference/platform/states/returns-a-state
/api-reference/platform.yaml get /api/v2/platform/states/{id}
Returns a State
# Create a Stock Item
Source: https://spreecommerce.org/docs/api-reference/platform/stock-items/create-a-stock-item
/api-reference/platform.yaml post /api/v2/platform/stock_items
Creates a Stock Item
# Delete a Stock Item
Source: https://spreecommerce.org/docs/api-reference/platform/stock-items/delete-a-stock-item
/api-reference/platform.yaml delete /api/v2/platform/stock_items/{id}
Deletes a Stock Item
# Return a list of Stock Items
Source: https://spreecommerce.org/docs/api-reference/platform/stock-items/return-a-list-of-stock-items
/api-reference/platform.yaml get /api/v2/platform/stock_items
Returns a list of Stock Items
# Return a Stock Item
Source: https://spreecommerce.org/docs/api-reference/platform/stock-items/return-a-stock-item
/api-reference/platform.yaml get /api/v2/platform/stock_items/{id}
Returns a Stock Item
# Update a Stock Item
Source: https://spreecommerce.org/docs/api-reference/platform/stock-items/update-a-stock-item
/api-reference/platform.yaml patch /api/v2/platform/stock_items/{id}
Updates a Stock Item
# Create a Stock Location
Source: https://spreecommerce.org/docs/api-reference/platform/stock-locations/create-a-stock-location
/api-reference/platform.yaml post /api/v2/platform/stock_locations
Creates a Stock Location
# Delete a Stock Location
Source: https://spreecommerce.org/docs/api-reference/platform/stock-locations/delete-a-stock-location
/api-reference/platform.yaml delete /api/v2/platform/stock_locations/{id}
Deletes a Stock Location
# Return a list of Stock Locations
Source: https://spreecommerce.org/docs/api-reference/platform/stock-locations/return-a-list-of-stock-locations
/api-reference/platform.yaml get /api/v2/platform/stock_locations
Returns a list of Stock Locations
# Return a Stock Location
Source: https://spreecommerce.org/docs/api-reference/platform/stock-locations/return-a-stock-location
/api-reference/platform.yaml get /api/v2/platform/stock_locations/{id}
Returns a Stock Location
# Update a Stock Location
Source: https://spreecommerce.org/docs/api-reference/platform/stock-locations/update-a-stock-location
/api-reference/platform.yaml patch /api/v2/platform/stock_locations/{id}
Updates a Stock Location
# Create a Store Credit Category
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-categories/create-a-store-credit-category
/api-reference/platform.yaml post /api/v2/platform/store_credit_categories
Creates a Store Credit Category
# Delete a Store Credit Category
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-categories/delete-a-store-credit-category
/api-reference/platform.yaml delete /api/v2/platform/store_credit_categories/{id}
Deletes a Store Credit Category
# Return a list of Store Credit Categories
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-categories/return-a-list-of-store-credit-categories
/api-reference/platform.yaml get /api/v2/platform/store_credit_categories
Returns a list of Store Credit Categories
# Return a Store Credit Category
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-categories/return-a-store-credit-category
/api-reference/platform.yaml get /api/v2/platform/store_credit_categories/{id}
Returns a Store Credit Category
# Update a Store Credit Category
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-categories/update-a-store-credit-category
/api-reference/platform.yaml patch /api/v2/platform/store_credit_categories/{id}
Updates a Store Credit Category
# Create a Store Credit Type
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-types/create-a-store-credit-type
/api-reference/platform.yaml post /api/v2/platform/store_credit_types
Creates a Store Credit Type
# Delete a Store Credit Type
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-types/delete-a-store-credit-type
/api-reference/platform.yaml delete /api/v2/platform/store_credit_types/{id}
Deletes a Store Credit Type
# Return a list of Store Credit Types
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-types/return-a-list-of-store-credit-types
/api-reference/platform.yaml get /api/v2/platform/store_credit_types
Returns a list of Store Credit Types
# Return a Store Credit Type
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-types/return-a-store-credit-type
/api-reference/platform.yaml get /api/v2/platform/store_credit_types/{id}
Returns a Store Credit Type
# Update a Store Credit Type
Source: https://spreecommerce.org/docs/api-reference/platform/store-credit-types/update-a-store-credit-type
/api-reference/platform.yaml patch /api/v2/platform/store_credit_types/{id}
Updates a Store Credit Type
# Create a Store Credit
Source: https://spreecommerce.org/docs/api-reference/platform/store-credits/create-a-store-credit
/api-reference/platform.yaml post /api/v2/platform/store_credits
Creates a Store Credit
# Delete a Store Credit
Source: https://spreecommerce.org/docs/api-reference/platform/store-credits/delete-a-store-credit
/api-reference/platform.yaml delete /api/v2/platform/store_credits/{id}
Deletes a Store Credit
# Return a list of Store Credits
Source: https://spreecommerce.org/docs/api-reference/platform/store-credits/return-a-list-of-store-credits
/api-reference/platform.yaml get /api/v2/platform/store_credits
Returns a list of Store Credits
# Return a Store Credit
Source: https://spreecommerce.org/docs/api-reference/platform/store-credits/return-a-store-credit
/api-reference/platform.yaml get /api/v2/platform/store_credits/{id}
Returns a Store Credit
# Update a Store Credit
Source: https://spreecommerce.org/docs/api-reference/platform/store-credits/update-a-store-credit
/api-reference/platform.yaml patch /api/v2/platform/store_credits/{id}
Updates a Store Credit
# Create a Tax Category
Source: https://spreecommerce.org/docs/api-reference/platform/tax-categories/create-a-tax-category
/api-reference/platform.yaml post /api/v2/platform/tax_categories
Creates a Tax Category
# Delete a Tax Category
Source: https://spreecommerce.org/docs/api-reference/platform/tax-categories/delete-a-tax-category
/api-reference/platform.yaml delete /api/v2/platform/tax_categories/{id}
Deletes a Tax Category
# Return a list of Tax Categories
Source: https://spreecommerce.org/docs/api-reference/platform/tax-categories/return-a-list-of-tax-categories
/api-reference/platform.yaml get /api/v2/platform/tax_categories
Returns a list of Tax Categories
# Return a Tax Category
Source: https://spreecommerce.org/docs/api-reference/platform/tax-categories/return-a-tax-category
/api-reference/platform.yaml get /api/v2/platform/tax_categories/{id}
Returns a Tax Category
# Update a Tax Category
Source: https://spreecommerce.org/docs/api-reference/platform/tax-categories/update-a-tax-category
/api-reference/platform.yaml patch /api/v2/platform/tax_categories/{id}
Updates a Tax Category
# Create a Tax Rate
Source: https://spreecommerce.org/docs/api-reference/platform/tax-rates/create-a-tax-rate
/api-reference/platform.yaml post /api/v2/platform/tax_rates
Creates a Tax Rate
# Delete a Tax Rate
Source: https://spreecommerce.org/docs/api-reference/platform/tax-rates/delete-a-tax-rate
/api-reference/platform.yaml delete /api/v2/platform/tax_rates/{id}
Deletes a Tax Rate
# Return a list of Tax Rates
Source: https://spreecommerce.org/docs/api-reference/platform/tax-rates/return-a-list-of-tax-rates
/api-reference/platform.yaml get /api/v2/platform/tax_rates
Returns a list of Tax Rates
# Return a Tax Rate
Source: https://spreecommerce.org/docs/api-reference/platform/tax-rates/return-a-tax-rate
/api-reference/platform.yaml get /api/v2/platform/tax_rates/{id}
Returns a Tax Rate
# Update a Tax Rate
Source: https://spreecommerce.org/docs/api-reference/platform/tax-rates/update-a-tax-rate
/api-reference/platform.yaml patch /api/v2/platform/tax_rates/{id}
Updates a Tax Rate
# Create a Taxonomy
Source: https://spreecommerce.org/docs/api-reference/platform/taxonomies/create-a-taxonomy
/api-reference/platform.yaml post /api/v2/platform/taxonomies
Creates a Taxonomy
# Delete a Taxonomy
Source: https://spreecommerce.org/docs/api-reference/platform/taxonomies/delete-a-taxonomy
/api-reference/platform.yaml delete /api/v2/platform/taxonomies/{id}
Deletes a Taxonomy
# Return a list of Taxonomies
Source: https://spreecommerce.org/docs/api-reference/platform/taxonomies/return-a-list-of-taxonomies
/api-reference/platform.yaml get /api/v2/platform/taxonomies
Returns a list of Taxonomies
# Return a Taxonomy
Source: https://spreecommerce.org/docs/api-reference/platform/taxonomies/return-a-taxonomy
/api-reference/platform.yaml get /api/v2/platform/taxonomies/{id}
Returns a Taxonomy
# Update a Taxonomy
Source: https://spreecommerce.org/docs/api-reference/platform/taxonomies/update-a-taxonomy
/api-reference/platform.yaml patch /api/v2/platform/taxonomies/{id}
Updates a Taxonomy
# Create a Taxon
Source: https://spreecommerce.org/docs/api-reference/platform/taxons/create-a-taxon
/api-reference/platform.yaml post /api/v2/platform/taxons
Creates a Taxon
# Delete a Taxon
Source: https://spreecommerce.org/docs/api-reference/platform/taxons/delete-a-taxon
/api-reference/platform.yaml delete /api/v2/platform/taxons/{id}
Deletes a Taxon
# Reposition a Taxon
Source: https://spreecommerce.org/docs/api-reference/platform/taxons/reposition-a-taxon
/api-reference/platform.yaml patch /api/v2/platform/taxons/{id}/reposition
Reposition a Taxon
# Return a list of Taxons
Source: https://spreecommerce.org/docs/api-reference/platform/taxons/return-a-list-of-taxons
/api-reference/platform.yaml get /api/v2/platform/taxons
Returns a list of Taxons
# Return a Taxon
Source: https://spreecommerce.org/docs/api-reference/platform/taxons/return-a-taxon
/api-reference/platform.yaml get /api/v2/platform/taxons/{id}
Returns a Taxon
# Update a Taxon
Source: https://spreecommerce.org/docs/api-reference/platform/taxons/update-a-taxon
/api-reference/platform.yaml patch /api/v2/platform/taxons/{id}
Updates a Taxon
# Create a User
Source: https://spreecommerce.org/docs/api-reference/platform/users/create-a-user
/api-reference/platform.yaml post /api/v2/platform/users
Creates a User
# Delete a User
Source: https://spreecommerce.org/docs/api-reference/platform/users/delete-a-user
/api-reference/platform.yaml delete /api/v2/platform/users/{id}
Deletes a User
# Return a list of Users
Source: https://spreecommerce.org/docs/api-reference/platform/users/return-a-list-of-users
/api-reference/platform.yaml get /api/v2/platform/users
Returns a list of Users
# Return a User
Source: https://spreecommerce.org/docs/api-reference/platform/users/return-a-user
/api-reference/platform.yaml get /api/v2/platform/users/{id}
Returns a User
# Update a User
Source: https://spreecommerce.org/docs/api-reference/platform/users/update-a-user
/api-reference/platform.yaml patch /api/v2/platform/users/{id}
Updates a User
# Delete a Variant
Source: https://spreecommerce.org/docs/api-reference/platform/variants/delete-a-variant
/api-reference/platform.yaml delete /api/v2/platform/variants/{id}
Deletes a Variant
# Return a list of Variants
Source: https://spreecommerce.org/docs/api-reference/platform/variants/return-a-list-of-variants
/api-reference/platform.yaml get /api/v2/platform/variants
Returns a list of Variants
# Return a Variant
Source: https://spreecommerce.org/docs/api-reference/platform/variants/return-a-variant
/api-reference/platform.yaml get /api/v2/platform/variants/{id}
Returns a Variant
# Approves Vendor
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/approves-vendor
/api-reference/platform.yaml patch /api/v2/platform/vendors/{id}/approve
Marks Vendor as approved, and triggers an approval email send out to the vendor's contact person. Also activated Vendor products will become available for purchase. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Completes onboarding process
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/completes-onboarding-process
/api-reference/platform.yaml patch /api/v2/platform/vendors/{id}/complete_onboarding
Marks Vendor as onboarding complete. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Create a Vendor
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/create-a-vendor
/api-reference/platform.yaml post /api/v2/platform/vendors
Creates a Vendor. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Delete a Vendor
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/delete-a-vendor
/api-reference/platform.yaml delete /api/v2/platform/vendors/{id}
Deletes a Vendor. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Invites Vendor to the platform
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/invites-vendor-to-the-platform
/api-reference/platform.yaml patch /api/v2/platform/vendors/{id}/invite
Also triggers an invitation email send out to the vendor's contact person. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Rejects Vendor
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/rejects-vendor
/api-reference/platform.yaml patch /api/v2/platform/vendors/{id}/reject
Marks Vendor as rejected, and triggers an approval email send out to the vendor's contact person. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Return a list of Vendors
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/return-a-list-of-vendors
/api-reference/platform.yaml get /api/v2/platform/vendors
Returns a list of Vendors. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Return a Vendor
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/return-a-vendor
/api-reference/platform.yaml get /api/v2/platform/vendors/{id}
Returns a Vendor. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Start onboarding process
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/start-onboarding-process
/api-reference/platform.yaml patch /api/v2/platform/vendors/{id}/start_onboarding
Marks Vendor as onboarding in progress. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Suspends Vendor
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/suspends-vendor
/api-reference/platform.yaml patch /api/v2/platform/vendors/{id}/suspend
Marks Vendor as suspended, and triggers an approval email send out to the vendor's contact person. Also the vendor's products will become unavailable for purchase and will be hidden from the storefront. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Update a Vendor
Source: https://spreecommerce.org/docs/api-reference/platform/vendors/update-a-vendor
/api-reference/platform.yaml patch /api/v2/platform/vendors/{id}
Updates a Vendor. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Return a list of Webhook Events
Source: https://spreecommerce.org/docs/api-reference/platform/webhook-events/return-a-list-of-webhook-events
/api-reference/platform.yaml get /api/v2/platform/webhooks/events
Returns a list of Webhook Events
# Create a Webhook Subscriber
Source: https://spreecommerce.org/docs/api-reference/platform/webhook-subscribers/create-a-webhook-subscriber
/api-reference/platform.yaml post /api/v2/platform/webhooks/subscribers
Creates a Webhook Subscriber
# Delete a Webhook Subscriber
Source: https://spreecommerce.org/docs/api-reference/platform/webhook-subscribers/delete-a-webhook-subscriber
/api-reference/platform.yaml delete /api/v2/platform/webhooks/subscribers/{id}
Deletes a Webhook Subscriber
# Return a list of Webhook Subscribers
Source: https://spreecommerce.org/docs/api-reference/platform/webhook-subscribers/return-a-list-of-webhook-subscribers
/api-reference/platform.yaml get /api/v2/platform/webhooks/subscribers
Returns a list of Webhook Subscribers
# Return a Webhook Subscriber
Source: https://spreecommerce.org/docs/api-reference/platform/webhook-subscribers/return-a-webhook-subscriber
/api-reference/platform.yaml get /api/v2/platform/webhooks/subscribers/{id}
Returns a Webhook Subscriber
# Update a Webhook Subscriber
Source: https://spreecommerce.org/docs/api-reference/platform/webhook-subscribers/update-a-webhook-subscriber
/api-reference/platform.yaml patch /api/v2/platform/webhooks/subscribers/{id}
Updates a Webhook Subscriber
# Create a Wished Item
Source: https://spreecommerce.org/docs/api-reference/platform/wished-items/create-a-wished-item
/api-reference/platform.yaml post /api/v2/platform/wished_items
Creates a Wished Item
# Delete a Wished Item
Source: https://spreecommerce.org/docs/api-reference/platform/wished-items/delete-a-wished-item
/api-reference/platform.yaml delete /api/v2/platform/wished_items/{id}
Deletes a Wished Item
# Return a list of Wished Items
Source: https://spreecommerce.org/docs/api-reference/platform/wished-items/return-a-list-of-wished-items
/api-reference/platform.yaml get /api/v2/platform/wished_items
Returns a list of Wished Items
# Return a Wished Item
Source: https://spreecommerce.org/docs/api-reference/platform/wished-items/return-a-wished-item
/api-reference/platform.yaml get /api/v2/platform/wished_items/{id}
Returns a Wished Item
# Update a Wished Item
Source: https://spreecommerce.org/docs/api-reference/platform/wished-items/update-a-wished-item
/api-reference/platform.yaml patch /api/v2/platform/wished_items/{id}
Updates a Wished Item
# Create a Wishlist
Source: https://spreecommerce.org/docs/api-reference/platform/wishlists/create-a-wishlist
/api-reference/platform.yaml post /api/v2/platform/wishlists
Creates a Wishlist
# Delete a Wishlist
Source: https://spreecommerce.org/docs/api-reference/platform/wishlists/delete-a-wishlist
/api-reference/platform.yaml delete /api/v2/platform/wishlists/{id}
Deletes a Wishlist
# Return a list of Wishlists
Source: https://spreecommerce.org/docs/api-reference/platform/wishlists/return-a-list-of-wishlists
/api-reference/platform.yaml get /api/v2/platform/wishlists
Returns a list of Wishlists
# Return a Wishlist
Source: https://spreecommerce.org/docs/api-reference/platform/wishlists/return-a-wishlist
/api-reference/platform.yaml get /api/v2/platform/wishlists/{id}
Returns a Wishlist
# Update a Wishlist
Source: https://spreecommerce.org/docs/api-reference/platform/wishlists/update-a-wishlist
/api-reference/platform.yaml patch /api/v2/platform/wishlists/{id}
Updates a Wishlist
# Create a Zone
Source: https://spreecommerce.org/docs/api-reference/platform/zones/create-a-zone
/api-reference/platform.yaml post /api/v2/platform/zones
Creates a Zone
# Delete a Zone
Source: https://spreecommerce.org/docs/api-reference/platform/zones/delete-a-zone
/api-reference/platform.yaml delete /api/v2/platform/zones/{id}
Deletes a Zone
# Return a list of Zones
Source: https://spreecommerce.org/docs/api-reference/platform/zones/return-a-list-of-zones
/api-reference/platform.yaml get /api/v2/platform/zones
Returns a list of Zones
# Return a Zone
Source: https://spreecommerce.org/docs/api-reference/platform/zones/return-a-zone
/api-reference/platform.yaml get /api/v2/platform/zones/{id}
Returns a Zone
# Update a Zone
Source: https://spreecommerce.org/docs/api-reference/platform/zones/update-a-zone
/api-reference/platform.yaml patch /api/v2/platform/zones/{id}
Updates a Zone
# Authentication
Source: https://spreecommerce.org/docs/api-reference/store-api/authentication
How to authenticate requests to the Store API
The Store API uses three authentication mechanisms depending on the use case: **API keys** for all requests, **JWT tokens** for authenticated customers, and **order tokens** for guest checkout.
## API Key (Required)
Every request to the Store API requires a **publishable API key**. This key identifies your storefront and is safe to use in client-side code.
Pass the key via the `X-Spree-Api-Key` header:
```typescript SDK theme={"theme":"night-owl"}
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'http://localhost:3000',
publishableKey: 'pk_xxx',
})
// The SDK automatically sends the publishable key with every request
const products = await client.products.list()
```
```bash cURL theme={"theme":"night-owl"}
curl -X GET 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx'
```
Publishable API keys are prefixed with `pk_`. You can create them in the Spree Admin under **Settings > API Keys** or via the Spree CLI:
```bash theme={"theme":"night-owl"}
spree api-key create # Create a new API key
spree api-key list # List existing API keys
```
If you omit the API key, the API returns a `401 Unauthorized` error:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "invalid_token",
"message": "Valid API key required"
}
}
```
## JWT Token (Authenticated Customer)
For actions that require a logged-in customer (viewing orders, managing addresses, saved payment methods), use a **JWT bearer token** in addition to the API key.
### Login
```typescript SDK theme={"theme":"night-owl"}
// Login to get a JWT token
const { token, user } = await client.auth.login({
email: 'customer@example.com',
password: 'password123',
})
// Use the token for authenticated requests
const orders = await client.customer.orders.list({}, { token })
```
```bash cURL theme={"theme":"night-owl"}
# Login
curl -X POST 'http://localhost:3000/api/v3/store/auth/login' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'Content-Type: application/json' \
-d '{"email": "customer@example.com", "password": "password123"}'
# Use the returned token for authenticated requests
curl -X GET 'http://localhost:3000/api/v3/store/orders' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'Authorization: Bearer '
```
### Register
```typescript SDK theme={"theme":"night-owl"}
const { token, user } = await client.customers.create({
email: 'new@example.com',
password: 'password123',
password_confirmation: 'password123',
first_name: 'John',
last_name: 'Doe',
})
```
```bash cURL theme={"theme":"night-owl"}
curl -X POST 'http://localhost:3000/api/v3/store/customers' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'Content-Type: application/json' \
-d '{
"email": "new@example.com",
"password": "password123",
"password_confirmation": "password123",
"first_name": "John",
"last_name": "Doe"
}'
```
### Token Refresh
JWT tokens expire after 1 hour by default. Use the refresh endpoint to get a new token:
```typescript SDK theme={"theme":"night-owl"}
const { token } = await client.auth.refresh({ token: currentToken })
```
```bash cURL theme={"theme":"night-owl"}
curl -X POST 'http://localhost:3000/api/v3/store/auth/refresh' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'Authorization: Bearer '
```
## Order Token (Guest Checkout)
For guest checkout flows, use the **order token** returned when creating a cart. This allows unauthenticated users to manage their cart and complete checkout.
Pass the token via the `x-spree-token` header:
```typescript SDK theme={"theme":"night-owl"}
// Create a cart (guest)
const cart = await client.carts.create()
// Use spreeToken for all guest cart operations
const options = { spreeToken: cart.token }
// Add items
await client.carts.items.create(cart.id, {
variant_id: 'variant_abc123',
quantity: 1,
}, options)
```
```bash cURL theme={"theme":"night-owl"}
# Create a cart
curl -X POST 'http://localhost:3000/api/v3/store/carts' \
-H 'X-Spree-Api-Key: pk_xxx'
# Use the returned token for cart operations
curl -X POST 'http://localhost:3000/api/v3/store/carts/cart_xxx/items' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Token: ' \
-H 'Content-Type: application/json' \
-d '{"variant_id": "variant_abc123", "quantity": 1}'
```
### Associating a Guest Cart
After a guest user logs in, you can associate their guest cart with their account:
```typescript SDK theme={"theme":"night-owl"}
await client.carts.associate(cart.id, {
token: jwtToken,
spreeToken: cart.token,
})
```
```bash cURL theme={"theme":"night-owl"}
curl -X PATCH 'http://localhost:3000/api/v3/store/carts/cart_xxx/associate' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'Authorization: Bearer ' \
-H 'X-Spree-Token: '
```
## Authentication Summary
| Method | Header | Use Case |
| ----------- | ------------------------------- | ------------------------------ |
| API Key | `X-Spree-Api-Key: pk_xxx` | All requests (required) |
| JWT Token | `Authorization: Bearer ` | Authenticated customer actions |
| Order Token | `X-Spree-Token: ` | Guest cart and checkout |
# Login
Source: https://spreecommerce.org/docs/api-reference/store-api/authentication/login
/api-reference/store.yaml post /api/v3/store/auth/login
Authenticates a customer and returns a JWT access token + refresh token.
Dispatches by the `provider` field to a strategy registered in
`Spree.store_authentication_strategies`. When `provider` is omitted it
defaults to `email`, which uses the built-in email/password strategy.
To plug in a third-party identity provider (Auth0, Okta, Firebase, a
custom JWT issuer, SAML, etc.), register a `Spree::Authentication::Strategies::BaseStrategy`
subclass under a provider key, then send `{ "provider": "", ... }`
with the fields your strategy requires. The endpoint returns the same
Spree-issued JWT + refresh token regardless of which strategy authenticated
the request.
# Logout
Source: https://spreecommerce.org/docs/api-reference/store-api/authentication/logout
/api-reference/store.yaml post /api/v3/store/auth/logout
Revokes the submitted refresh token. The refresh token itself is the credential — no Authorization header is required, so a client with an expired access JWT can still log out.
# Refresh token
Source: https://spreecommerce.org/docs/api-reference/store-api/authentication/refresh-token
/api-reference/store.yaml post /api/v3/store/auth/refresh
Exchanges a refresh token for a new access JWT and rotated refresh token. No Authorization header needed.
# Request a password reset
Source: https://spreecommerce.org/docs/api-reference/store-api/authentication/request-a-password-reset
/api-reference/store.yaml post /api/v3/store/password_resets
Sends a password reset email if an account exists for the given email address. Always returns 202 Accepted to prevent email enumeration.
# Reset password with token
Source: https://spreecommerce.org/docs/api-reference/store-api/authentication/reset-password-with-token
/api-reference/store.yaml patch /api/v3/store/password_resets/{token}
Resets the password using a token received via email. Returns a JWT token on success (auto-login).
# Add item to cart
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/add-item-to-cart
/api-reference/store.yaml post /api/v3/store/carts/{cart_id}/items
Adds a variant to the cart. Creates a new line item or increases quantity if variant already in cart.
# Apply discount code
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/apply-discount-code
/api-reference/store.yaml post /api/v3/store/carts/{cart_id}/discount_codes
Applies a promotion discount code to the cart. The code is matched case-insensitively.
For gift cards, use the dedicated `POST /carts/{cart_id}/gift_cards` endpoint instead.
# Apply gift card
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/apply-gift-card
/api-reference/store.yaml post /api/v3/store/carts/{cart_id}/gift_cards
Applies a gift card to the cart. Gift cards are treated as a payment method, not a discount —
the cart `total` remains unchanged while `amount_due` is reduced.
For promotion discount codes, use the `POST /carts/{cart_id}/discount_codes` endpoint instead.
# Apply store credit
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/apply-store-credit
/api-reference/store.yaml post /api/v3/store/carts/{cart_id}/store_credits
Applies store credit to the cart during checkout.
# Associate guest cart with authenticated user
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/associate-guest-cart-with-authenticated-user
/api-reference/store.yaml patch /api/v3/store/carts/{id}/associate
Associates a guest cart with the currently authenticated user.
Requires JWT authentication. The cart must not belong to another user.
# Complete cart
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/complete-cart
/api-reference/store.yaml post /api/v3/store/carts/{id}/complete
Completes the cart and finalizes the purchase. Returns an Order (not Cart).
# Complete payment session
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/complete-payment-session
/api-reference/store.yaml patch /api/v3/store/carts/{cart_id}/payment_sessions/{id}/complete
Completes a payment session by confirming the payment with the provider. This triggers payment capture/authorization and order completion.
# Create a new cart
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/create-a-new-cart
/api-reference/store.yaml post /api/v3/store/carts
Creates a new shopping cart. Can be created by guests or authenticated customers.
Returns a `token` that must be used for guest access to the cart.
# Create payment
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/create-payment
/api-reference/store.yaml post /api/v3/store/carts/{cart_id}/payments
Creates a payment for a non-session payment method (e.g. Check, Cash on Delivery, Bank Transfer). For payment methods that require a session (e.g. Stripe, PayPal), use the payment sessions endpoint instead.
# Create payment session
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/create-payment-session
/api-reference/store.yaml post /api/v3/store/carts/{cart_id}/payment_sessions
Creates a new payment session for the cart. Delegates to the payment gateway to initialize a provider-specific session (e.g. Stripe PaymentIntent, Adyen session, PayPal order).
# Delete a cart
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/delete-a-cart
/api-reference/store.yaml delete /api/v3/store/carts/{id}
Deletes/abandons the cart.
# Get a cart
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/get-a-cart
/api-reference/store.yaml get /api/v3/store/carts/{id}
Returns a shopping cart by prefixed ID.
Authorize via x-spree-token header (guest) or JWT Bearer token (authenticated user).
# Get payment session
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/get-payment-session
/api-reference/store.yaml get /api/v3/store/carts/{cart_id}/payment_sessions/{id}
Returns a single payment session with its current status and provider data.
# List active carts
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/list-active-carts
/api-reference/store.yaml get /api/v3/store/carts
Returns all active (incomplete) carts for the authenticated user.
# Remove discount code
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/remove-discount-code
/api-reference/store.yaml delete /api/v3/store/carts/{cart_id}/discount_codes/{id}
Removes a previously applied discount code from the cart. The ID is the discount code string itself.
# Remove gift card
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/remove-gift-card
/api-reference/store.yaml delete /api/v3/store/carts/{cart_id}/gift_cards/{id}
Removes a previously applied gift card from the cart.
# Remove line item from cart
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/remove-line-item-from-cart
/api-reference/store.yaml delete /api/v3/store/carts/{cart_id}/items/{id}
Removes a line item from the cart
# Remove store credit
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/remove-store-credit
/api-reference/store.yaml delete /api/v3/store/carts/{cart_id}/store_credits
Removes store credit from the cart.
# Select delivery rate for fulfillment
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/select-delivery-rate-for-fulfillment
/api-reference/store.yaml patch /api/v3/store/carts/{cart_id}/fulfillments/{id}
Selects a delivery rate for a specific fulfillment and auto-advances checkout.
# Update a cart
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/update-a-cart
/api-reference/store.yaml patch /api/v3/store/carts/{id}
Updates cart info (email, addresses, customer note). When addresses change, the order state is reverted to address to ensure shipments are recalculated.
# Update line item quantity
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/update-line-item-quantity
/api-reference/store.yaml patch /api/v3/store/carts/{cart_id}/items/{id}
Updates the quantity of a line item in the cart
# Update payment session
Source: https://spreecommerce.org/docs/api-reference/store-api/carts/update-payment-session
/api-reference/store.yaml patch /api/v3/store/carts/{cart_id}/payment_sessions/{id}
Updates a payment session. Delegates to the payment gateway to sync changes with the provider.
# Complete payment setup session
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/complete-payment-setup-session
/api-reference/store.yaml patch /api/v3/store/customers/me/payment_setup_sessions/{id}/complete
Completes a payment setup session by confirming the setup with the provider, resulting in a saved payment method.
# Create an address
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/create-an-address
/api-reference/store.yaml post /api/v3/store/customers/me/addresses
Adds a new address to the customer address book
# Create payment setup session
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/create-payment-setup-session
/api-reference/store.yaml post /api/v3/store/customers/me/payment_setup_sessions
Creates a new payment setup session for saving a payment method for future use. Delegates to the payment gateway to initialize a provider-specific setup flow (e.g. Stripe SetupIntent, Adyen zero-auth tokenization).
# Delete a credit card
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/delete-a-credit-card
/api-reference/store.yaml delete /api/v3/store/customers/me/credit_cards/{id}
Removes a saved credit card from the customer account
# Delete an address
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/delete-an-address
/api-reference/store.yaml delete /api/v3/store/customers/me/addresses/{id}
# Get a credit card
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/get-a-credit-card
/api-reference/store.yaml get /api/v3/store/customers/me/credit_cards/{id}
Returns a saved credit card by its ID
# Get a gift card
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/get-a-gift-card
/api-reference/store.yaml get /api/v3/store/customers/me/gift_cards/{id}
Returns a gift card by its ID
# Get a store credit
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/get-a-store-credit
/api-reference/store.yaml get /api/v3/store/customers/me/store_credits/{id}
# Get an address
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/get-an-address
/api-reference/store.yaml get /api/v3/store/customers/me/addresses/{id}
# Get an order
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/get-an-order
/api-reference/store.yaml get /api/v3/store/customers/me/orders/{id}
Returns a single completed order for the authenticated customer.
# Get current customer profile
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/get-current-customer-profile
/api-reference/store.yaml get /api/v3/store/customers/me
Returns the profile of the currently authenticated customer
# Get payment setup session
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/get-payment-setup-session
/api-reference/store.yaml get /api/v3/store/customers/me/payment_setup_sessions/{id}
Returns a payment setup session with its current status and provider data.
# List customer addresses
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/list-customer-addresses
/api-reference/store.yaml get /api/v3/store/customers/me/addresses
Returns all addresses in the customer address book
# List gift cards
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/list-gift-cards
/api-reference/store.yaml get /api/v3/store/customers/me/gift_cards
Returns all gift cards for the authenticated customer
# List orders
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/list-orders
/api-reference/store.yaml get /api/v3/store/customers/me/orders
Returns a paginated list of completed orders for the authenticated customer.
# List saved credit cards
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/list-saved-credit-cards
/api-reference/store.yaml get /api/v3/store/customers/me/credit_cards
Returns all saved credit cards for the authenticated customer
# List store credits
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/list-store-credits
/api-reference/store.yaml get /api/v3/store/customers/me/store_credits
Returns store credits for the authenticated customer, filtered by current store and currency. Supports Ransack filtering.
# Register a new customer
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/register-a-new-customer
/api-reference/store.yaml post /api/v3/store/customers
Creates a new customer account and returns a JWT token
# Update an address
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/update-an-address
/api-reference/store.yaml patch /api/v3/store/customers/me/addresses/{id}
# Update current customer profile
Source: https://spreecommerce.org/docs/api-reference/store-api/customers/update-current-customer-profile
/api-reference/store.yaml patch /api/v3/store/customers/me
Updates the profile of the currently authenticated customer
# Download a digital product
Source: https://spreecommerce.org/docs/api-reference/store-api/digitals/download-a-digital-product
/api-reference/store.yaml get /api/v3/store/digitals/{token}
Downloads a digital product file using the digital link token.
The token is provided via the `download_url` field on digital links
returned with order line items. No API key or authentication required —
the token itself grants access.
Each download increments the access counter. Downloads may be limited by
store settings (number of downloads and/or time-based expiration).
# Errors
Source: https://spreecommerce.org/docs/api-reference/store-api/errors
Reference for Spree Store API error responses — JSON format, machine-readable codes, HTTP status codes, validation details, and retry strategies.
The Store API uses a consistent, Stripe-style error format across all endpoints. Every error response includes a machine-readable `code` and a human-readable `message`.
## Error Response Format
All errors return a JSON object with a single `error` key:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "record_not_found",
"message": "Product not found"
}
}
```
Validation errors include an additional `details` field with per-field error messages:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "validation_error",
"message": "Name can't be blank and Email is invalid",
"details": {
"name": ["can't be blank"],
"email": ["is invalid"]
}
}
}
```
### Schema
| Field | Type | Description |
| --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `error.code` | `string` | Machine-readable error code (see table below) |
| `error.message` | `string` | Human-readable description of the error |
| `error.details` | `object` | Field-specific validation errors. Each key is a field name, each value is an array of error strings. Only present for validation errors. |
## HTTP Status Codes
| Status | Meaning | When |
| ------ | --------------------- | ---------------------------------------------------------------------------------- |
| `400` | Bad Request | Missing required parameters, malformed JSON, invalid arguments |
| `401` | Unauthorized | Missing or invalid API key, expired JWT token |
| `403` | Forbidden | Authenticated but not authorized for this resource |
| `404` | Not Found | Resource doesn't exist or isn't accessible |
| `409` | Conflict | Resource was modified by another request (concurrent update) |
| `422` | Unprocessable Content | Validation failed, invalid state transition, payment error |
| `429` | Too Many Requests | Rate limit exceeded (see [Rate Limiting](/docs/api-reference/store-api/rate-limitting)) |
## Error Codes
### Authentication & Authorization
| Code | Status | Description |
| ------------------------- | ------ | -------------------------------------------- |
| `authentication_required` | 401 | Request requires a valid JWT token |
| `authentication_failed` | 401 | Email or password is incorrect |
| `invalid_token` | 401 | API key or JWT token is invalid or expired |
| `invalid_provider` | 400 | OAuth provider not recognized |
| `access_denied` | 403 | User doesn't have permission for this action |
### Resource Errors
| Code | Status | Description |
| ------------------ | ------ | --------------------------------------------------------------- |
| `record_not_found` | 404 | Resource doesn't exist or isn't accessible in the current store |
| `resource_invalid` | 422 | Resource couldn't be saved |
### Validation Errors
| Code | Status | Description |
| ------------------- | ------ | --------------------------------------------------------------------- |
| `validation_error` | 422 | Model validation failed. Check `details` for field-specific messages. |
| `parameter_missing` | 400 | A required parameter is missing |
| `parameter_invalid` | 400 | A parameter has an invalid value |
### Cart Errors
| Code | Status | Description |
| ------------------------ | ------ | ----------------------------------------------------------------------------------- |
| `cart_not_found` | 404 | Cart doesn't exist or doesn't belong to the current user/guest |
| `cart_cannot_complete` | 422 | Cart cannot be completed (e.g., missing payment or address) |
| `cart_cannot_transition` | 422 | Internal state machine transition failed (e.g., completing a cart that isn't ready) |
| `cart_empty` | 422 | Cart has no line items |
| `cart_invalid_state` | 422 | Cart is in an invalid state for this operation |
| `cart_already_updated` | 409 | Cart was modified by another request (optimistic locking conflict) |
### Order Errors
| Code | Status | Description |
| ----------------- | ------ | ------------------------------------------------------------------------- |
| `order_not_found` | 404 | Completed order doesn't exist or doesn't belong to the current user/guest |
### Line Item & Stock Errors
| Code | Status | Description |
| --------------------- | ------ | -------------------------------------------------- |
| `line_item_not_found` | 404 | Line item doesn't exist in this order |
| `variant_not_found` | 404 | Variant doesn't exist or isn't available |
| `insufficient_stock` | 422 | Not enough stock to fulfill the requested quantity |
| `invalid_quantity` | 422 | Quantity must be a positive integer |
### Payment Errors
| Code | Status | Description |
| -------------------------- | ------ | --------------------------------------------- |
| `payment_failed` | 422 | Payment was declined or couldn't be processed |
| `payment_processing_error` | 422 | Error communicating with the payment gateway |
| `gateway_error` | 422 | Payment gateway returned an error |
### Digital Download Errors
| Code | Status | Description |
| ------------------------- | ------ | -------------------------------------------------- |
| `attachment_missing` | 403 | File attachment not found for this digital product |
| `download_unauthorized` | 403 | User is not authorized to download this file |
| `digital_link_expired` | 403 | Download link has expired |
| `download_limit_exceeded` | 403 | Maximum number of downloads reached |
### Concurrency & Idempotency Errors
| Code | Status | Description |
| ------------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `order_already_updated` | 409 | Order was modified by another concurrent request. Retry with fresh data. |
| `idempotency_key_reused` | 422 | Idempotency key was already used with different request parameters. See [Idempotency](/docs/api-reference/store-api/idempotency). |
### Other Errors
| Code | Status | Description |
| --------------------- | ------ | -------------------------------------------------------------- |
| `rate_limit_exceeded` | 429 | Too many requests. Retry after the `Retry-After` header value. |
| `request_too_large` | 413 | Request body exceeds the size limit |
| `processing_error` | 422 | Generic server-side processing error |
| `invalid_request` | 400 | Request is malformed (e.g., invalid JSON body) |
## Examples
### Not Found
```bash theme={"theme":"night-owl"}
curl https://api.mystore.com/api/v3/store/products/prod_nonexistent \
-H "X-Spree-API-Key: pk_xxx"
```
```json 404 theme={"theme":"night-owl"}
{
"error": {
"code": "record_not_found",
"message": "Product not found"
}
}
```
### Validation Error
```bash theme={"theme":"night-owl"}
curl -X POST https://api.mystore.com/api/v3/store/account/addresses \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{}'
```
```json 422 theme={"theme":"night-owl"}
{
"error": {
"code": "validation_error",
"message": "First name can't be blank, Address can't be blank, City can't be blank, and Country can't be blank",
"details": {
"firstname": ["can't be blank"],
"address1": ["can't be blank"],
"city": ["can't be blank"],
"country": ["can't be blank"]
}
}
}
```
### Insufficient Stock
```bash theme={"theme":"night-owl"}
curl -X POST https://api.mystore.com/api/v3/store/carts/cart_xxx/items \
-H "X-Spree-API-Key: pk_xxx" \
-H "X-Spree-Token: abc123" \
-H "Content-Type: application/json" \
-d '{"variant_id": "var_xxx", "quantity": 999}'
```
```json 422 theme={"theme":"night-owl"}
{
"error": {
"code": "insufficient_stock",
"message": "Quantity selected exceeds available stock"
}
}
```
### Invalid State Transition
```bash theme={"theme":"night-owl"}
curl -X POST https://api.mystore.com/api/v3/store/carts/cart_xxx/complete \
-H "X-Spree-API-Key: pk_xxx"
```
```json 422 theme={"theme":"night-owl"}
{
"error": {
"code": "cart_cannot_transition",
"message": "Cannot transition cart to complete — ensure address, shipping, and payment are set"
}
}
```
## Handling Errors in the SDK
The `@spree/sdk` package throws a `SpreeError` for all non-2xx responses:
```typescript theme={"theme":"night-owl"}
import { SpreeError } from '@spree/sdk';
try {
const product = await client.products.get('nonexistent');
} catch (error) {
if (error instanceof SpreeError) {
console.log(error.code); // 'record_not_found'
console.log(error.message); // 'Product not found'
console.log(error.status); // 404
console.log(error.details); // undefined (or field errors for validation)
}
}
```
### Common Patterns
Handle specific error codes:
```typescript theme={"theme":"night-owl"}
try {
await client.carts.items.create(cartId, {
variant_id: variantId,
quantity: 1,
});
} catch (error) {
if (error instanceof SpreeError) {
switch (error.code) {
case 'insufficient_stock':
showNotification('This item is out of stock');
break;
case 'variant_not_found':
showNotification('This product is no longer available');
break;
default:
showNotification(error.message);
}
}
}
```
Display validation errors per field:
```typescript theme={"theme":"night-owl"}
try {
await client.customer.addresses.create(addressData);
} catch (error) {
if (error instanceof SpreeError && error.details) {
// error.details = { city: ["can't be blank"], zipcode: ["is invalid"] }
for (const [field, messages] of Object.entries(error.details)) {
setFieldError(field, messages.join(', '));
}
}
}
```
# Idempotency
Source: https://spreecommerce.org/docs/api-reference/store-api/idempotency
Use Idempotency-Key headers on Spree Store API mutations to safely retry carts, checkouts, and payments without creating duplicate side effects.
The Store API supports idempotency keys on mutating endpoints. This lets you safely retry requests without risking duplicate side effects — for example, adding an item to cart twice or creating duplicate payments due to network timeouts.
## How It Works
Include an `Idempotency-Key` header with a unique value (e.g., a UUID) on any supported request. The API will:
1. **First request** — process normally and cache the response for 24 hours
2. **Duplicate request** (same key, same parameters) — return the cached response without re-executing the operation
3. **Key reuse with different parameters** — return a `422` error to prevent misuse
```bash theme={"theme":"night-owl"}
curl -X POST https://api.mystore.com/api/v3/store/carts/cart_xxx/items \
-H "X-Spree-API-Key: pk_xxx" \
-H "X-Spree-Token: abc123" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{"variant_id": "variant_xxx", "quantity": 1}'
```
If the client retries this exact request with the same idempotency key, the API returns the original response with an `Idempotent-Replayed: true` header — without adding the item again.
## Supported Endpoints
| Endpoint | Actions |
| ------------------------------------------------ | ------------------------ |
| `POST /carts` | Cart creation |
| `PATCH /carts/:id` | Cart updates |
| `POST /carts/:id/complete` | Order completion |
| `POST /carts/:id/items` | Adding items to cart |
| `POST /carts/:id/payment_sessions` | Payment session creation |
| `PATCH /carts/:id/payment_sessions/:id/complete` | Payment completion |
| `POST /carts/:id/coupon_codes` | Applying coupon codes |
| `POST /carts/:id/store_credits` | Applying store credits |
Idempotency keys are ignored on `GET`, `DELETE`, and other non-supported actions.
## Key Requirements
* Must be a string of **255 characters or less**
* Should be unique per distinct operation (UUIDs are recommended)
* Keys are scoped per API key — different API keys can use the same idempotency key without conflict
* Cached responses expire after **24 hours**
## Response Headers
When a cached response is replayed, the API sets:
```
Idempotent-Replayed: true
```
You can use this header to detect replayed responses in your application or logging.
## Error Handling
### Key Reuse with Different Parameters
If you send a request with an idempotency key that was previously used with different request parameters (different body, different path), the API returns a `422` error:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "idempotency_key_reused",
"message": "This Idempotency-Key has already been used with different request parameters."
}
}
```
### Key Too Long
Keys longer than 255 characters return a `400` error:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "invalid_request",
"message": "Idempotency-Key must be 255 characters or less."
}
}
```
### Server Errors
`5xx` responses are **not cached**. If the server fails to process your request, you can safely retry with the same idempotency key and the request will be re-executed.
## SDK Usage
The Spree SDK supports idempotency keys via the `idempotencyKey` option:
```typescript theme={"theme":"night-owl"}
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'http://localhost:3000',
publishableKey: 'pk_xxx',
})
// Add item to cart with idempotency key
await client.carts.items.create(cartId, {
variant_id: 'variant_xxx',
quantity: 1,
}, {
idempotencyKey: '550e8400-e29b-41d4-a716-446655440000',
})
```
## Best Practices
* **Generate a new key for each distinct operation.** Use a UUID (v4) or another random identifier. Never reuse keys across different operations.
* **Store the key before sending the request.** If the request fails due to a network error, retry with the same key to ensure the operation is only performed once.
* **Don't use idempotency keys for GET requests.** GET requests are naturally idempotent and the API ignores the header on read-only endpoints.
* **Let keys expire naturally.** Cached responses expire after 24 hours. Don't rely on idempotency keys for longer-term deduplication.
## Relationship with Optimistic Locking
The Store API also uses [optimistic locking](/docs/api-reference/store-api/introduction) via the `state_lock_version` field on orders. These mechanisms complement each other:
| Mechanism | Prevents | Scope |
| --------------------------------------------- | --------------------------------- | ---------------------------------- |
| **Idempotency keys** | Duplicate operations from retries | Per-request deduplication |
| **Optimistic locking** (`state_lock_version`) | Concurrent modifications | Conflict detection between clients |
Use both together for robust checkout flows: idempotency keys protect against network retries, while `state_lock_version` detects when another client has modified the order.
# Store API
Source: https://spreecommerce.org/docs/api-reference/store-api/introduction
This API reference includes Spree Store APIs, which are REST APIs exposed by the Spree application. They are used to create a storefront for your commerce store, such as a website, point of sale or a commerce mobile app.
All API Routes are prefixed with `/api/v3/store`. So, during development, the API Routes will be available under the path `http://localhost:3000/api/v3/store`. For production, replace `http://localhost:3000` with your Spree application URL.
## Using SDK
We recommend using the Spree SDK to interact with the Store API. The SDK provides a convenient way to make API requests and handle responses.
### Installation
```bash theme={"theme":"night-owl"}
npm install @spree/sdk
# or
yarn add @spree/sdk
# or
pnpm add @spree/sdk
```
### Quick Start
```typescript theme={"theme":"night-owl"}
import { createClient } from '@spree/sdk';
// Initialize the client
const client = createClient({
baseUrl: 'http://localhost:3000',
publishableKey: 'pk_xxx'
});
```
# Localization
Source: https://spreecommerce.org/docs/api-reference/store-api/localization
How to set locale, currency, and country for API requests
The Store API supports multi-language, multi-currency, and market-aware responses. Use request headers to control the locale, currency, and country for each request.
## Headers
| Header | Example | Description |
| ------------------ | ------- | ------------------------------------------------------------------- |
| `X-Spree-Locale` | `fr` | Language for translated content (product names, descriptions, etc.) |
| `X-Spree-Currency` | `EUR` | Currency for prices and totals |
| `X-Spree-Country` | `FR` | Country ISO code for market resolution |
## Client-Level Defaults
Set locale, currency, and country once at initialization — all subsequent requests use these defaults:
```typescript SDK theme={"theme":"night-owl"}
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://api.mystore.com',
publishableKey: 'pk_xxx',
locale: 'fr',
currency: 'EUR',
country: 'FR',
})
// All requests use fr/EUR/FR automatically
const products = await client.products.list()
```
Update defaults at any time:
```typescript theme={"theme":"night-owl"}
client.setLocale('de')
client.setCurrency('EUR')
client.setCountry('DE')
```
## Per-Request Overrides
Override client defaults for individual requests:
```typescript SDK theme={"theme":"night-owl"}
const products = await client.products.list({}, {
locale: 'fr',
currency: 'EUR',
country: 'FR',
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Locale: fr' \
-H 'X-Spree-Currency: EUR'
```
## Country and Markets
The `X-Spree-Country` header resolves the customer's [market](/docs/developer/core-concepts/markets), which influences default locale and currency. Markets allow you to configure different pricing, languages, and product availability per region.
```typescript SDK theme={"theme":"night-owl"}
// Setting country automatically resolves the market
const products = await client.products.list({}, {
country: 'DE', // Resolves German market → EUR, de locale
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Country: DE'
```
When a market is resolved from the country:
1. The market's default locale is used (unless overridden by `X-Spree-Locale`)
2. The market's default currency is used (unless overridden by `X-Spree-Currency`)
You can also resolve the market explicitly using the [Markets API](/docs/developer/sdk/store/markets):
```typescript SDK theme={"theme":"night-owl"}
// Resolve which market applies for a country
const market = await client.markets.resolve('DE')
// => { id: "mkt_xxx", name: "Europe", currency: "EUR", default_locale: "de", ... }
// Then set the client defaults
client.setLocale(market.default_locale)
client.setCurrency(market.currency)
client.setCountry('DE')
```
```bash cURL theme={"theme":"night-owl"}
# Resolve market by country
curl 'http://localhost:3000/api/v3/store/markets/resolve?country=DE' \
-H 'X-Spree-Api-Key: pk_xxx'
```
## Resolution Priority
Each value is resolved in the following order:
### Locale
1. `X-Spree-Locale` header
2. `locale` query parameter
3. Market default locale (if country is set)
4. Store default locale
### Currency
1. `X-Spree-Currency` header
2. `currency` query parameter
3. Market default currency (if country is set)
4. Store default currency
### Market
1. `X-Spree-Country` header
2. `country` query parameter
The locale and currency must be supported by the current store. If an unsupported value is provided, the API falls back to the store's default.
## Translated Content
When a locale is set, all translatable fields are returned in the requested language. This includes product names, descriptions, category names, and other content managed through [translations](/docs/developer/core-concepts/translations).
```typescript SDK theme={"theme":"night-owl"}
// English (default)
const enProduct = await client.products.get('spree-tote')
console.log(enProduct.name) // "Spree Tote"
// French
const frProduct = await client.products.get('spree-tote', {}, {
locale: 'fr',
})
console.log(frProduct.name) // "Sac Spree"
```
```bash cURL theme={"theme":"night-owl"}
# English
curl 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Locale: en'
# French
curl 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Locale: fr'
```
If a translation doesn't exist for the requested locale, the API falls back to the store's default locale automatically.
## Currency-Aware Prices
All price fields in the response reflect the requested currency:
```typescript SDK theme={"theme":"night-owl"}
// USD prices
const usdProduct = await client.products.get('spree-tote', {}, {
currency: 'USD',
})
console.log(usdProduct.price) // { amount: "15.99", currency: "USD" }
// EUR prices
const eurProduct = await client.products.get('spree-tote', {}, {
currency: 'EUR',
})
console.log(eurProduct.price) // { amount: "14.49", currency: "EUR" }
```
```bash cURL theme={"theme":"night-owl"}
# USD prices
curl 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Currency: USD'
# EUR prices
curl 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Currency: EUR'
```
## Discovering Available Options
Use the dedicated endpoints to discover which markets, countries, locales, and currencies are available. These are derived from your store's [markets](/docs/developer/core-concepts/markets) configuration.
### Markets
List all markets to get the full picture of regions, currencies, and supported locales:
```typescript SDK theme={"theme":"night-owl"}
const { data: markets } = await client.markets.list()
// [
// { id: "mkt_xxx", name: "North America", currency: "USD", default_locale: "en",
// supported_locales: ["en", "es"], countries: [{ iso: "US", ... }, { iso: "CA", ... }] },
// { id: "mkt_yyy", name: "Europe", currency: "EUR", default_locale: "de",
// supported_locales: ["de", "en", "fr"], countries: [{ iso: "DE", ... }, { iso: "FR", ... }] },
// ]
```
```bash cURL theme={"theme":"night-owl"}
curl 'http://localhost:3000/api/v3/store/markets' \
-H 'X-Spree-Api-Key: pk_xxx'
```
### Countries
List all countries or countries within a specific market. Each country includes its market's currency and supported locales:
```typescript SDK theme={"theme":"night-owl"}
// All countries across all markets
const { data: countries } = await client.countries.list()
// Countries in a specific market (useful for checkout address forms)
const { data: marketCountries } = await client.markets.countries.list('mkt_xxx')
// Get a single country with states
const usa = await client.countries.get('US', {
expand: ['states'],
})
console.log(usa.states) // [{ abbr: "CA", name: "California" }, ...]
```
```bash cURL theme={"theme":"night-owl"}
# All countries
curl 'http://localhost:3000/api/v3/store/countries' \
-H 'X-Spree-Api-Key: pk_xxx'
# Countries in a specific market
curl 'http://localhost:3000/api/v3/store/markets/mkt_xxx/countries' \
-H 'X-Spree-Api-Key: pk_xxx'
# Get a country with states
curl 'http://localhost:3000/api/v3/store/countries/US?expand=states' \
-H 'X-Spree-Api-Key: pk_xxx'
```
### Locales
```typescript SDK theme={"theme":"night-owl"}
const { data: locales } = await client.locales.list()
// [{ code: "en", name: "English" }, { code: "fr", name: "French" }, ...]
```
```bash cURL theme={"theme":"night-owl"}
curl 'http://localhost:3000/api/v3/store/locales' \
-H 'X-Spree-Api-Key: pk_xxx'
```
### Currencies
```typescript SDK theme={"theme":"night-owl"}
const { data: currencies } = await client.currencies.list()
// [{ iso_code: "USD", name: "US Dollar", symbol: "$" }, { iso_code: "EUR", name: "Euro", symbol: "€" }, ...]
```
```bash cURL theme={"theme":"night-owl"}
curl 'http://localhost:3000/api/v3/store/currencies' \
-H 'X-Spree-Api-Key: pk_xxx'
```
# Get a country
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/get-a-country
/api-reference/store.yaml get /api/v3/store/countries/{iso}
Returns a single country by ISO code. Supports ?expand=states for address forms and ?expand=market for market details.
# Get a country in a market
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/get-a-country-in-a-market
/api-reference/store.yaml get /api/v3/store/markets/{market_id}/countries/{id}
Returns a single country by ISO code within a market. Supports ?expand=states for address forms.
# Get a market
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/get-a-market
/api-reference/store.yaml get /api/v3/store/markets/{id}
Returns a single market by prefixed ID with its countries, currency, locales, and tax configuration.
# List countries
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/list-countries
/api-reference/store.yaml get /api/v3/store/countries
Returns countries available in the store. Use ?expand=market to include market details (currency, locale, tax_inclusive).
# List countries in a market
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/list-countries-in-a-market
/api-reference/store.yaml get /api/v3/store/markets/{market_id}/countries
Returns countries belonging to a specific market. Use this for address form country dropdowns during checkout.
# List markets
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/list-markets
/api-reference/store.yaml get /api/v3/store/markets
Returns all markets for the current store with their countries, currency, locales, and tax configuration.
# List supported currencies
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/list-supported-currencies
/api-reference/store.yaml get /api/v3/store/currencies
Returns currencies supported by the store (derived from markets)
# List supported locales
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/list-supported-locales
/api-reference/store.yaml get /api/v3/store/locales
Returns locales supported by the store (derived from markets)
# Resolve market by country
Source: https://spreecommerce.org/docs/api-reference/store-api/markets/resolve-market-by-country
/api-reference/store.yaml get /api/v3/store/markets/resolve
Determine which market applies for a given country ISO code. Useful for auto-selecting the correct currency and locale when a customer's location is known.
# Metadata
Source: https://spreecommerce.org/docs/api-reference/store-api/metadata
How to store and retrieve custom metadata on carts, orders, and line items
The Store API supports storing arbitrary key-value **metadata** on carts (orders) and line items. Metadata is useful for tracking custom information like gift messages, attribution data, or integration-specific fields.
Metadata is different from [metafields](/docs/developer/core-concepts/metafields). Metadata is simple JSON storage (untyped, no schema), while metafields are structured, typed, and schema-defined. Use metadata for integration data and internal tracking. Use metafields for customer-facing custom attributes.
## Cart Metadata
You can attach metadata when creating a cart:
```typescript SDK theme={"theme":"night-owl"}
const cart = await client.carts.create({
metadata: {
utm_source: 'google',
utm_campaign: 'summer_sale',
referral_code: 'FRIEND20',
},
})
```
```bash cURL theme={"theme":"night-owl"}
curl -X POST 'http://localhost:3000/api/v3/store/carts' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'Content-Type: application/json' \
-d '{
"metadata": {
"utm_source": "google",
"utm_campaign": "summer_sale",
"referral_code": "FRIEND20"
}
}'
```
## Cart Metadata (Update)
Update metadata on an existing cart:
```typescript SDK theme={"theme":"night-owl"}
await client.carts.update(cart.id, {
metadata: {
gift_message: 'Happy Birthday!',
preferred_delivery: 'morning',
},
}, { spreeToken: cart.token })
```
```bash cURL theme={"theme":"night-owl"}
curl -X PATCH 'http://localhost:3000/api/v3/store/carts/cart_xxx' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Token: ' \
-H 'Content-Type: application/json' \
-d '{
"metadata": {
"gift_message": "Happy Birthday!",
"preferred_delivery": "morning"
}
}'
```
## Item Metadata
Attach metadata to individual items when adding or updating them:
### When Adding an Item
```typescript SDK theme={"theme":"night-owl"}
await client.carts.items.create(cart.id, {
variant_id: 'variant_abc123',
quantity: 1,
metadata: {
personalization: 'John',
gift_wrap: true,
},
}, { spreeToken: cart.token })
```
```bash cURL theme={"theme":"night-owl"}
curl -X POST 'http://localhost:3000/api/v3/store/carts/cart_xxx/items' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Token: ' \
-H 'Content-Type: application/json' \
-d '{
"variant_id": "variant_abc123",
"quantity": 1,
"metadata": {
"personalization": "John",
"gift_wrap": true
}
}'
```
### When Updating an Item
Updating metadata **merges** with existing values rather than replacing them:
```typescript SDK theme={"theme":"night-owl"}
await client.carts.items.update(cart.id, 'li_xyz789', {
metadata: {
personalization: 'Jane', // Updates existing key
engraving: 'With Love', // Adds new key
},
}, { spreeToken: cart.token })
```
```bash cURL theme={"theme":"night-owl"}
curl -X PATCH 'http://localhost:3000/api/v3/store/carts/cart_xxx/items/li_xyz789' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'X-Spree-Token: ' \
-H 'Content-Type: application/json' \
-d '{
"metadata": {
"personalization": "Jane",
"engraving": "With Love"
}
}'
```
Metadata values can be any JSON-serializable type: strings, numbers, booleans, arrays, or nested objects.
## Metadata Structure
Metadata is stored as a flat JSON object. You can use any keys and values:
```json theme={"theme":"night-owl"}
{
"metadata": {
"string_value": "hello",
"number_value": 42,
"boolean_value": true,
"nested_object": {
"key": "value"
}
}
}
```
## Metadata vs Metafields
Spree has two permanent, complementary systems for custom data — **metadata for machines, metafields for humans**.
| | Metadata | Metafields |
| -------------- | --------------------------------------------------------- | ------------------------------------------------------ |
| **Purpose** | Developer escape hatch — integration IDs, sync state | Merchant-defined structured attributes |
| **Schema** | Schemaless JSON — no definition required | Defined via MetafieldDefinitions (typed, validated) |
| **Validation** | None | Type-specific validation |
| **Visibility** | Write-only in Store API, readable in Admin API | Configurable (admin-only or public) |
| **Admin UI** | JSON preview | Dedicated form fields |
| **Best for** | Integration data, tracking, attribution, write-and-forget | Product specs, custom attributes, customer-facing data |
| **API access** | Write via Store API, read via Admin API | Read/write via both APIs |
Both systems are here to stay. For more details on metafields, see the [Metafields guide](/docs/developer/core-concepts/metafields).
# Migrating from Storefront API v2
Source: https://spreecommerce.org/docs/api-reference/store-api/migrating-from-storefront-api-v2
Map every Storefront API v2 endpoint, concept, and SDK call to its Store API v3 equivalent.
The Store API is the successor to the [legacy Storefront API](/docs/api-reference/v2/introduction). It exposes the same surface — products, carts, checkout, customers, wishlists — but with a new transport (flat JSON instead of JSON:API), a new [fully-typed TypeScript SDK](/docs/developer/sdk/quickstart), and resource-oriented routes that line up with the new [Admin API](/docs/api-reference/admin-api). It's faster, safer and easier to work with.
This guide walks you through the differences and gives you a one-to-one mapping you can grep against during a migration.
API v2 is available via [spree\_legacy\_api\_v2](https://github.com/spree/spree_legacy_api_v2) gem and will work with Spree 5. However new features such as [Markets](/docs/developer/core-concepts/markets) or [new Pricing engine](/docs/developer/core-concepts/pricing) are only available in API v3.
## TL;DR
| | **Storefront API v2** | **Store API v3** |
| ---------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| Path prefix | `/api/v2/storefront/*` | `/api/v3/store/*` |
| Response format | [JSON:API](https://jsonapi.org/) (`data` / `attributes` / `relationships` / `included`) | Flat JSON (attributes inlined on the resource) |
| ID format | Numeric (`123`) or slug | Prefixed string (`prod_86Rf07xd4z`, `cart_k5nR8xLq`) |
| Routing style | Action-based (`/cart/add_item`, `/checkout/next`) | RESTful resources (`POST /carts/:id/items`, no checkout state machine) |
| Filtering | `filter[...]` params, fixed per endpoint | [Ransack](/docs/api-reference/store-api/querying) via `q[...]`, plus per-endpoint scopes |
| Including associations | `?include=variants,images` | `?expand=variants,media` (single param, dot-nested up to 4 levels) |
| API key | *(none — fully public)* | `X-Spree-Api-Key: pk_xxx` *(publishable key, required on every request)* |
| Cart token header | `X-Spree-Order-Token` | `X-Spree-Token` |
| Customer auth | `Authorization: Bearer ` (OAuth via `/spree_oauth/token`) | `Authorization: Bearer ` (JWT via `/auth/login`) |
| Checkout model | Step state machine (`address → delivery → payment → confirm → complete`) | Stateless cart + nested resources (addresses, payments, payment sessions) |
| SDK package | [`@spree/storefront-api-v2-sdk`](https://www.npmjs.com/package/@spree/storefront-api-v2-sdk) *(deprecated)* | [`@spree/sdk`](https://www.npmjs.com/package/@spree/sdk) |
| SDK factory | `makeClient({ host })` | `createClient({ baseUrl, publishableKey })` |
| SDK response | `Result` with `.success()` / `.fail()` | Returns the resource directly; throws `SpreeError` on failure |
| Type safety | Hand-written interfaces | Auto-generated TypeScript types + Zod runtime validators |
## Mental model: what changed and why
### v2 — JSON:API with action endpoints
Storefront v2 was modelled on JSON:API. Every response had `data`/`attributes`/`relationships`/`included`, and most non-`GET` calls invoked a named action on a singleton resource (`/cart/add_item`, `/checkout/next`, `/checkout/select_shipping_method`). The current cart was implicit — the server resolved it from the `X-Spree-Order-Token` header. Checkout was a five-step state machine; the SPA's job was to drive `PATCH /checkout/next` until the order reached `complete`.
This made cart and checkout calls easy to write but hard to reason about. The same payload could land you in different checkout states depending on which step the order happened to be on, and refactoring the front-end meant knowing which actions transitioned which states.
### v3 — REST with explicit resources
Store API v3 collapses checkout into the cart. There is no checkout state machine, no `/checkout/next`, no `/checkout/advance`. Instead:
* The cart is a real resource with a stable prefixed ID (`cart_…`). You `PATCH /carts/:id` to attach an email or addresses, and you `POST /carts/:id/items` to add line items.
* Delivery rates and payment methods are not separate endpoints — fulfillments are nested under the cart (`PATCH /carts/:id/fulfillments/:fid` to pick a delivery rate), and payments are nested under the cart (`POST /carts/:id/payments` for non-session methods, `POST /carts/:id/payment_sessions` for Stripe/PayPal/Adyen).
* Completing checkout is a single explicit call: `POST /carts/:id/complete`. It returns the resulting `Order`.
The cart can be created, edited, abandoned, completed, and associated with a user from a single URL. No step transitions, no implicit current cart. This makes it possible to ship Shopify-style one-page checkout without fighting the API.
### Why JSON:API is gone
JSON:API's strengths — sparse fieldsets, relationship graphs, normalized payloads — are real, but most storefront clients flattened the response anyway. The cost was a noisy, hard-to-cache wire format and a two-step deserialization on every call. v3 returns the resource directly with associations inlined when `expand` is requested:
```json v2 (JSON:API) theme={"theme":"night-owl"}
{
"data": {
"id": "96",
"type": "product",
"attributes": {
"name": "Bomber Jacket",
"slug": "bomber-jacket",
"available_on": "2021-10-02T11:02:29.288Z",
"purchasable": true,
"in_stock": true,
"currency": "USD",
"price": "38.99",
"display_price": "$38.99",
"compare_at_price": null,
"display_compare_at_price": null
},
"relationships": {
"variants": { "data": [{ "id": "212", "type": "variant" }] },
"default_variant": { "data": { "id": "212", "type": "variant" } }
}
},
"included": [
{
"id": "212",
"type": "variant",
"attributes": { "sku": "JacketsandCoats_bomberjacket_38.99", "price": "38.99" }
}
]
}
```
```json v3 (Flat JSON, with ?expand=variants) theme={"theme":"night-owl"}
{
"id": "prod_UkLWZg9DAJ",
"name": "Bomber Jacket",
"slug": "bomber-jacket",
"available_on": "2025-05-13T22:27:22.136Z",
"purchasable": true,
"in_stock": true,
"description": "Dolorem nulla odit nostrum placeat...",
"description_html": "
Dolorem nulla odit nostrum placeat...
",
"default_variant_id": "variant_gbHJdmfrXB",
"thumbnail_url": null,
"tags": [],
"price": {
"id": "price_gbHJdmfrXB",
"amount": "38.99",
"amount_in_cents": 3899,
"currency": "USD",
"display_amount": "$38.99",
"compare_at_amount": null,
"compare_at_amount_in_cents": null,
"display_compare_at_amount": null
},
"original_price": null,
"variants": [
{
"id": "variant_gbHJdmfrXB",
"product_id": "prod_UkLWZg9DAJ",
"sku": "JacketsandCoats_bomberjacket_38.99",
"options_text": "Size: M",
"purchasable": true,
"in_stock": true,
"price": {
"amount": "38.99",
"amount_in_cents": 3899,
"currency": "USD",
"display_amount": "$38.99"
}
}
]
}
```
You can still ask for sparse fields (`?fields=name,price`), and you still control association depth (`?expand=variants.media`), but you no longer have to walk `included` to assemble the response. See [Querying](/docs/api-reference/store-api/querying) and [Relations](/docs/api-reference/store-api/relations).
### Prefixed IDs everywhere
Every v3 resource has a Stripe-style prefixed ID — `prod_…`, `variant_…`, `cart_…`, `ord_…`, `addr_…`. The prefix is part of the public surface: pass it back exactly as received, never strip the prefix or cast it to an integer. (Internally, IDs are still numeric, but the API only ever exposes the prefixed form.) See the [Introduction](/docs/api-reference/store-api/introduction).
## SDK: `@spree/storefront-api-v2-sdk` → `@spree/sdk`
The two SDKs cover the same ground but differ in shape. The legacy `@spree/storefront-api-v2-sdk` uses a `makeClient` factory, exposes resource namespaces (`account`, `cart`, `checkout`, `products`, `taxons`, `wishlists`), wraps every response in a `Result` envelope, and passes tokens via an `IToken` (`{ orderToken, bearerToken }`) argument on every method.
`@spree/sdk` uses a `createClient` factory, lines its resource namespaces up with the REST tree (`products`, `categories`, `carts`, `carts.items`, `customer.orders`, …), returns the resource directly (no `Result` wrapper), and threads auth through a per-call `RequestOptions` (`{ token, spreeToken }`) — the publishable key is set once at client construction.
### Installing
```bash @spree/sdk (v3) theme={"theme":"night-owl"}
npm install @spree/sdk
# or pnpm add @spree/sdk
```
```bash @spree/storefront-api-v2-sdk (v2 — deprecated) theme={"theme":"night-owl"}
npm install @spree/storefront-api-v2-sdk
```
### Creating a client
```typescript v3 — @spree/sdk theme={"theme":"night-owl"}
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'https://your-store.com',
publishableKey: 'pk_xxx',
})
```
```typescript v2 — @spree/storefront-api-v2-sdk theme={"theme":"night-owl"}
import { makeClient } from '@spree/storefront-api-v2-sdk'
const client = makeClient({
host: 'https://your-store.com',
})
// No API key — the Storefront API v2 was fully public.
```
The Storefront API v2 had no API key concept — anyone with the host could call it. Store API v3 introduces a **publishable key** (`pk_xxx`) that's required on every request and identifies which store the call targets. The key is safe to expose in client-side code; it's how v3 supports multi-store on a single domain and gives you per-key rate limits, scopes, and audit trails.
### Calling an endpoint
```typescript v3 — @spree/sdk theme={"theme":"night-owl"}
// Returns the Product directly — throws on failure
const product = await client.products.get('spree-tote', {
expand: ['variants', 'media'],
})
console.log(product.name, product.price)
```
```typescript v2 — @spree/storefront-api-v2-sdk theme={"theme":"night-owl"}
// Returns a Result wrapper
const response = await client.products.show({
id: 'spree-tote',
include: 'variants,images',
})
if (response.isSuccess()) {
const { data, included } = response.success()
console.log(data.attributes.name, data.attributes.price)
// Walk `included` to resolve relationships…
} else {
console.error(response.fail())
}
```
### Auth tokens
```typescript v3 — @spree/sdk theme={"theme":"night-owl"}
// Guest cart (uses cart's order token as `spreeToken`)
const cart = await client.carts.create()
await client.carts.items.create(
cart.id,
{ variant_id: 'variant_abc', quantity: 1 },
{ spreeToken: cart.token },
)
// Authenticated customer (JWT)
const { token } = await client.auth.login({
email: 'me@example.com',
password: 'spree123',
})
const orders = await client.customer.orders.list({}, { token })
```
```typescript v2 — @spree/storefront-api-v2-sdk theme={"theme":"night-owl"}
// Guest cart (orderToken)
const cartResponse = await client.cart.create()
const orderToken = cartResponse.success().data.attributes.token
await client.cart.addItem({
order_token: orderToken,
}, { variant_id: 10, quantity: 1 })
// Authenticated customer (OAuth via /spree_oauth/token)
const tokenResponse = await client.authentication.getToken({
username: 'me@example.com',
password: 'spree123',
})
const bearer = tokenResponse.success().access_token
const ordersResponse = await client.account.ordersList({
bearer_token: bearer,
})
```
In v3, `token` and `spreeToken` are passed via the `RequestOptions` object on each call — no more per-method `bearer_token` / `order_token` arguments mixed into the body. JWT refresh uses `client.auth.refresh({ refresh_token })`; the old OAuth `refresh_token` grant against `/spree_oauth/token` is gone.
### Error handling
In v3 the SDK throws a `SpreeError` instance with `code`, `status`, and `details` properties. Wrap calls in `try/catch` or let them bubble. The `Result` wrapper from v2 is gone — code that branched on `response.isSuccess()` becomes a single happy path plus a `catch`.
### TypeScript types
v3 ships generated TypeScript types and runtime [Zod](https://zod.dev) schemas that stay in lockstep with the API — every response field is typed, and you can validate payloads at runtime where you need belt-and-braces safety (form submissions, untrusted webhooks). v2's types were hand-maintained interfaces inside the SDK, which drifted from the actual responses over time.
## Endpoint mapping
The tables below cover every public path in `/api/v2/storefront/*` and where to find its v3 equivalent. Anything not listed is unchanged in scope but follows the new conventions (flat JSON, prefixed IDs, Ransack filters).
### Catalog: products, taxons, categories
| Storefront API v2 | Store API v3 | Notes |
| ------------------------------ | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `GET /products` | `GET /products` | Filters move from `filter[...]` to [Ransack `q[...]`](/docs/api-reference/store-api/querying); `include` → `expand`. |
| `GET /products/:slug` | `GET /products/:id_or_slug` | Accepts prefixed ID or slug. |
| `GET /products/:slug/variants` | `GET /products/:id?expand=variants` | Variants are returned via `expand`, not as a separate route. |
| `GET /taxons` | `GET /categories` | **Renamed.** v3 calls them Categories everywhere — same tree model, same `permalink`, parametrised by slug or prefixed ID. |
| `GET /taxons/:id` | `GET /categories/:id_or_permalink` | Permalinks containing slashes (`clothing/shirts`) work as-is. |
| *(new)* | `GET /products/filters` | Returns price range, in-stock toggle, option values, and category facets with counts — designed for filter sidebars. |
This is an area where API v3 has the biggest performance advantage over v2. `GET /products` by default will expose `default_variant_id`, `thumbnail_url` and `price` which are essential for building product lists. You don't need to expand `variants` or `media` (images) like with API v2.
### Cart and checkout
This is the biggest conceptual change. The v2 cart was a singleton accessed via the order token header; v3 carts have prefixed IDs and live alongside line items, payments, fulfillments, and discount codes as nested resources. **There is no checkout state machine in v3.** Backend will handle that automatically, without any developer action needed. This aligns with [Spree 6 upcoming changes](https://github.com/spree/spree/issues/13930).
By default all Cart endpoints will return all associations auto-expanded.
| Storefront API v2 | Store API v3 | Notes |
| ------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `POST /cart` | `POST /carts` | Returns a `Cart` with a prefixed `id` and a `token` (use as `X-Spree-Token` for guests). |
| `GET /cart` | `GET /carts/:id` | Pass the prefixed `id`. Authenticated users can `GET /carts` to list active carts. |
| `DELETE /cart` | `DELETE /carts/:id` | Same semantics. |
| `POST /cart/add_item` | `POST /carts/:id/items` | Nested resource, not an action. |
| `PATCH /cart/set_quantity` | `PATCH /carts/:id/items/:line_item_id` | Updates an explicit line item by ID. |
| `DELETE /cart/set_quantity` | `DELETE /carts/:id/items/:line_item_id` | Same. |
| `PATCH /cart/empty` | Iterate `DELETE /carts/:id/items/:line_item_id` | No bulk-empty action; remove line items individually, or `DELETE /carts/:id` to abandon. |
| `PATCH /cart/apply_coupon_code` | `POST /carts/:id/discount_codes` | Body: `{ code }`. |
| `DELETE /cart/apply_coupon_code` | `DELETE /carts/:id/discount_codes/:code` | Path-level code. |
| `DELETE /cart/remove_coupon_code` | Iterate `DELETE /carts/:id/discount_codes/:code` | No remove-all shortcut; remove each code. |
| `GET /cart/estimate_shipping_rates` | Inspect `cart.fulfillments[].delivery_rates` | Rates are returned inline with the cart. Add an address (`PATCH /carts/:id`) and the cart is recomputed. |
| `PATCH /cart/associate` | `PATCH /carts/:id/associate` | Pass the JWT for the now-authenticated user. |
| `PATCH /cart/change_currency` | `PATCH /carts/:id` | Set `currency` directly on the cart. |
| `PATCH /checkout` | `PATCH /carts/:id` | Email, addresses, special instructions, etc. — all on the cart. |
| `PATCH /checkout/next` | *(removed)* | No state machine; nothing to advance. |
| `PATCH /checkout/advance` | *(removed)* | Same. |
| `PATCH /checkout/complete` | `POST /carts/:id/complete` | Returns the resulting `Order`. |
| `PATCH /checkout/select_shipping_method` | `PATCH /carts/:id/fulfillments/:fulfillment_id` | Body: `{ selected_delivery_rate_id }`. ShippingMethod is the legacy term — v3 calls them Delivery Methods / Delivery Rates. |
| `POST /checkout/validate_order_for_payment` | *(removed)* | Validation happens server-side when you call `complete`. |
| `POST /checkout/create_payment` | `POST /carts/:id/payments` | For offline / non-session methods (cash, check, bank transfer). |
| `POST /checkout/add_store_credit` | `POST /carts/:id/store_credits` | Body: `{ amount? }`. |
| `POST /checkout/remove_store_credit` | `DELETE /carts/:id/store_credits` | Same. |
| `GET /checkout/payment_methods` | `cart.available_payment_methods` | Inlined on the cart. |
| `GET /checkout/shipping_rates` | `cart.fulfillments[].delivery_rates` | Same — inlined. |
The new RESTful design allows you to implement different usage scenarios like multiple saved carts per customer or organization (company).
#### Session-based payments (Stripe, Adyen, PayPal)
API v2 had per-gateway endpoints (`/stripe/payment_intents`, `/adyen/payment_sessions`). API v3 unifies these behind a generic [Payment Sessions API](/docs/developer/core-concepts/payments#session-based-flow-stripe-adyen-paypal-etc) — the gateway-specific payload moves into the request body, and Spree dispatches to the right provider based on the `payment_method_id`. This shortens the integration time and allows teams to deliver payment integrations faster. Also your frontend code doesn't need to change per gateway.
| Storefront API v2 | Store API v3 |
| --------------------------------------------- | ---------------------------------------------------------------------- |
| `POST /stripe/payment_intents` | `POST /carts/:id/payment_sessions` |
| `GET /stripe/payment_intents/:id` | `GET /carts/:id/payment_sessions/:id` |
| `PATCH /stripe/payment_intents/:id` | `PATCH /carts/:id/payment_sessions/:id` |
| `PATCH /stripe/payment_intents/:id` (confirm) | `PATCH /carts/:id/payment_sessions/:id/complete` |
| `POST /stripe/setup_intents` | `POST /customers/me/payment_setup_sessions` (save card for future use) |
| `POST /adyen/payment_sessions` | `POST /carts/:id/payment_sessions` |
| `POST /adyen/payment_sessions/:id/complete` | `PATCH /carts/:id/payment_sessions/:id/complete` |
### Customer account
API v2 exposed a singleton `/account` endpoint with OAuth tokens minted at `/spree_oauth/token`. API v3 splits the surface into a public registration endpoint (`POST /customers`) and a `/customers/me` namespace for the authenticated customer. Auth moves from OAuth to JWT (`POST /auth/login`).
| Storefront API v2 | Store API v3 | Notes |
| ------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------- |
| `POST /account` | `POST /customers` | Returns JWT tokens on success. |
| `GET /account` | `GET /customers/me` | |
| `PATCH /account` | `PATCH /customers/me` | `current_password` required to change email or password. |
| `GET /account/addresses` | `GET /customers/me/addresses` | |
| `POST /account/addresses` | `POST /customers/me/addresses` | |
| `PATCH /account/addresses/:id` | `PATCH /customers/me/addresses/:id` | |
| `DELETE /account/addresses/:id` | `DELETE /customers/me/addresses/:id` | |
| `GET /account/credit_cards` | `GET /customers/me/credit_cards` | |
| `GET /account/credit_cards/default` | `GET /customers/me/credit_cards?q[default_eq]=true` | Use a Ransack filter; there's no `/default` shortcut. |
| `DELETE /account/credit_cards/:id` | `DELETE /customers/me/credit_cards/:id` | |
| `GET /account/orders` | `GET /customers/me/orders` | |
| `GET /account/orders/:number` | `GET /customers/me/orders/:id` | Use prefixed ID or order number. |
| `GET /order_status/:number` | `GET /orders/:id` | Guest-accessible with the order token; no separate status endpoint. |
| *(POST /spree\_oauth/token grant=password)* | `POST /auth/login` | Returns a JWT, not an OAuth token. |
| *(POST /spree\_oauth/token grant=refresh\_token)* | `POST /auth/refresh` | |
| *(none)* | `POST /auth/logout` | Server-side revocation of the refresh token. |
| *(none)* | `POST /password_resets` / `PATCH /password_resets/:token` | First-class password reset flow. |
### Geography and store metadata
| Storefront API v2 | Store API v3 | Notes |
| --------------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `GET /countries` | `GET /countries` | |
| `GET /countries/:iso` | `GET /countries/:iso` | Use `?expand=states` for the address form. |
| `GET /countries/default` | `client.markets.resolve(country)` | The "default country" concept moved into Markets — resolve which market applies to a country, then read `market.default_country`. |
| `GET /store` | *(removed from the storefront surface)* | Store identity is conveyed via the publishable key; you don't need to fetch the store record. |
| *(none in v2)* | `GET /markets`, `GET /markets/:id`, `GET /markets/:id/countries`, `GET /markets/resolve` | New in v3 — Markets group countries, currency, and locale. See [Localization](/docs/api-reference/store-api/localization). |
| *(none in v2)* | `GET /currencies`, `GET /locales` | Enumerate currencies and locales supported by the store. |
| `GET /policies` / `GET /policies/:slug` | `GET /policies` / `GET /policies/:id_or_slug` | Same — return policy, privacy, terms, etc. |
### Wishlists
| Storefront API v2 | Store API v3 |
| ----------------------------------------------- | -------------------------------------------------- |
| `GET /wishlists` | `GET /wishlists` |
| `POST /wishlists` | `POST /wishlists` |
| `GET /wishlists/:token` | `GET /wishlists/:id` |
| `PATCH /wishlists/:token` | `PATCH /wishlists/:id` |
| `DELETE /wishlists/:token` | `DELETE /wishlists/:id` |
| `GET /wishlists/default` | `GET /wishlists?q[is_default_eq]=true` |
| `POST /wishlists/:token/add_item` | `POST /wishlists/:wishlist_id/items` |
| `PATCH /wishlists/:token/set_item_quantity/:id` | `PATCH /wishlists/:wishlist_id/items/:id` |
| `DELETE /wishlists/:token/remove_item/:id` | `DELETE /wishlists/:wishlist_id/items/:id` |
| `POST /wishlists/:token/add_items` | Iterate `POST /wishlists/:wishlist_id/items` |
| `DELETE /wishlists/:token/remove_items` | Iterate `DELETE /wishlists/:wishlist_id/items/:id` |
### Digital downloads
| Storefront API v2 | Store API v3 |
| ---------------------- | ---------------------- |
| `GET /digitals/:token` | `GET /digitals/:token` |
### Removed without a v3 equivalent
A handful of v2 surfaces don't exist in v3:
* **Posts** / **Menus** / **CMS Pages** — the blog/CMS surface is not part of v3 or Spree Core anymore. Recommended: use a dedicated CMS like Payload or Strapi
## Migration checklist
The mechanical bits, in order:
1. **Install `@spree/sdk` alongside `@spree/storefront-api-v2-sdk`.** They have different package names, so both can coexist while you cut over endpoints incrementally.
2. **Create a publishable API key** in Spree Admin → Settings → API Keys (or via `spree api-key create`). v3 requires it on every request — v2 had no API key concept at all.
3. **Replace `makeClient({ host })` with `createClient({ baseUrl, publishableKey })`** in one entry point at a time. Keep the v2 client wired up for not-yet-migrated calls.
4. **Switch from `Result<…>` to direct returns + try/catch.** Any code that did `if (response.isSuccess()) { response.success() }` becomes a single statement, with errors thrown as `SpreeError`.
5. **Update token handling.** Replace `{ bearer_token, order_token }` per-method arguments with the `{ token, spreeToken }` second-argument `RequestOptions`. JWT tokens come from `client.auth.login` / `client.customers.create`; cart tokens come from `cart.token` on the cart resource.
6. **Convert filters from `filter[...]` to `q[...]`.** Most filters have a direct Ransack equivalent (see the [Querying](/docs/api-reference/store-api/querying) reference). For products specifically, `taxon_ids` → `in_categories`, `name` → `name_cont` or `search`, `price` range → `price_gte` / `price_lte`.
7. **Rewrite cart/checkout calls as resource operations.** This is the deepest change. The cleanest path is to delete your checkout step controller wholesale and rebuild it as a single page that PATCHes the cart and POSTs to nested resources, then calls `complete` at the end.
8. **Stop walking `included`.** Replace JSON:API normalization helpers with direct attribute access. Use `expand` to pull in associations, and accept that they arrive inlined.
9. **Replace numeric IDs and slugs with prefixed IDs.** Update any code that parsed integers out of IDs, stored IDs as numbers in state, or constructed admin links from raw IDs.
10. **Switch the OAuth token endpoints for JWT.** The `/spree_oauth/token` endpoints are no longer the customer auth surface; use `/api/v3/store/auth/login` / `/auth/refresh` / `/auth/logout`. Refresh tokens are rotated on each refresh call, and `logout` revokes the token server-side.
For the conceptual changes — flat JSON, RESTful checkout, Markets — give yourself a sprint of breathing room rather than treating the migration as a string-replace. The win on the other side is a smaller, more obvious client surface and a Store API that lines up with the Admin API for full-stack work.
## See also
* [Store API — Introduction](/docs/api-reference/store-api/introduction)
* [Authentication](/docs/api-reference/store-api/authentication)
* [Querying (Ransack, sorting, pagination, expand, fields)](/docs/api-reference/store-api/querying)
* [Relations — `expand` rules and nested associations](/docs/api-reference/store-api/relations)
* [Localization — Markets, currencies, locales](/docs/api-reference/store-api/localization)
* [Errors](/docs/api-reference/store-api/errors)
# Monetary Amounts
Source: https://spreecommerce.org/docs/api-reference/store-api/monetary-amounts
How monetary values are represented in API responses
All monetary values in the Store API are returned as **strings** (e.g., `"29.99"`, `"0.0"`), not numbers. This preserves decimal precision and avoids floating-point rounding issues common with JSON numbers.
## Response Format
Every monetary field has a corresponding `display_` field that includes currency formatting:
```json theme={"theme":"night-owl"}
{
"total": "129.99",
"display_total": "$129.99",
"item_total": "99.99",
"display_item_total": "$99.99",
"ship_total": "10.00",
"display_ship_total": "$10.00",
"tax_total": "20.00",
"display_tax_total": "$20.00"
}
```
## Affected Types
This convention applies to all monetary fields across all resources:
| Resource | Monetary Fields |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **Order** | `total`, `item_total`, `ship_total`, `tax_total`, `adjustment_total`, `promo_total`, `included_tax_total`, `additional_tax_total` |
| **Line Item** | `price`, `total`, `adjustment_total`, `promo_total`, `pre_tax_amount`, `discounted_amount`, `compare_at_amount` |
| **Shipment** | `cost` |
| **Payment** | `amount` |
| **Gift Card** | `amount`, `amount_used`, `amount_authorized`, `amount_remaining` |
| **Store Credit** | `amount`, `amount_used`, `amount_remaining` |
| **Price** | `amount`, `compare_at_amount` |
## Working with Amounts
```typescript SDK theme={"theme":"night-owl"}
const order = await client.orders.get('or_abc123', {}, { token });
// Raw string values
order.total; // "129.99"
order.display_total; // "$129.99"
// Convert to number for calculations
const total = parseFloat(order.total);
```
```javascript JavaScript theme={"theme":"night-owl"}
const data = await response.json();
// Use display fields for rendering
element.textContent = data.display_total; // "$129.99"
// Use raw fields for calculations
const total = parseFloat(data.total);
```
Use `display_*` fields for rendering prices in the UI — they are pre-formatted with the correct currency symbol and decimal places based on the order's currency. Use the raw string fields when you need to perform calculations.
# Subscribe to the newsletter
Source: https://spreecommerce.org/docs/api-reference/store-api/newsletter-subscribers/subscribe-to-the-newsletter
/api-reference/store.yaml post /api/v3/store/newsletter_subscribers
Subscribes an email address to the newsletter for the current store.
Behavior:
- If the email is already verified for this store, the existing subscription is returned unchanged.
- If the request is unauthenticated (guest), the subscription is created in an unverified state
and two events are published: `newsletter_subscriber.subscription_requested` (carrying the
`verification_token` and the validated `redirect_url`, intended for headless storefronts that
want to send the confirmation email themselves via a webhook handler) and the legacy
`newsletter_subscriber.subscribed` lifecycle event (which the bundled `spree_emails` package
listens to and uses to send a default confirmation email). The confirmation link should point
at `redirect_url?token=` and call `POST /newsletter_subscribers/verify`
when the user clicks it.
- If the request is authenticated via JWT and the customer's email matches the subscribed email,
the subscription is auto-verified and no events are fired — the JWT already proves email
ownership, so no confirmation email is needed.
The optional `redirect_url` is where the verification token should land on the storefront. The
server does not return a validation error when the URL is outside the store's
[Allowed Origins](/developer/core-concepts/allowed-origins); instead, the URL is silently
omitted from the webhook payload (secure-by-default). When no allow-list is configured on the
store, the URL is also omitted. Callers therefore receive the same 201 regardless, and the
webhook handler should fall back to the store's storefront URL when `redirect_url` is missing
from the payload.
Newsletter consent is preserved across registration: if a guest subscribes and later registers
with the same email, the existing subscriber record is reused.
# Verify a newsletter subscription
Source: https://spreecommerce.org/docs/api-reference/store-api/newsletter-subscribers/verify-a-newsletter-subscription
/api-reference/store.yaml post /api/v3/store/newsletter_subscribers/verify
Confirms a pending newsletter subscription using the verification token sent by email.
After successful verification:
- The subscriber record is marked verified.
- If the subscription is associated with a customer, that customer's `accepts_email_marketing`
flag is set to `true`.
# Get an order
Source: https://spreecommerce.org/docs/api-reference/store-api/orders/get-an-order
/api-reference/store.yaml get /api/v3/store/orders/{id}
Returns a single completed order by prefixed ID. Accessible via JWT (authenticated users) or order token header (guests).
# Get a policy
Source: https://spreecommerce.org/docs/api-reference/store-api/policies/get-a-policy
/api-reference/store.yaml get /api/v3/store/policies/{id}
Returns a single policy by slug or prefixed ID. Includes the full rich text body.
# List store policies
Source: https://spreecommerce.org/docs/api-reference/store-api/policies/list-store-policies
/api-reference/store.yaml get /api/v3/store/policies
Returns all policies for the current store (e.g., return policy, privacy policy, terms of service).
Policies are managed in Spree Admin and contain rich text content.
# Get a category
Source: https://spreecommerce.org/docs/api-reference/store-api/product-catalog/get-a-category
/api-reference/store.yaml get /api/v3/store/categories/{id}
Returns a single category by permalink or prefix ID
# Get a product
Source: https://spreecommerce.org/docs/api-reference/store-api/product-catalog/get-a-product
/api-reference/store.yaml get /api/v3/store/products/{id}
Returns a single product by slug or prefix ID
# Get product filters
Source: https://spreecommerce.org/docs/api-reference/store-api/product-catalog/get-product-filters
/api-reference/store.yaml get /api/v3/store/products/filters
Returns available filters for products with their options and counts.
Use this endpoint to build filter UIs for product listing pages.
The filters are context-aware - when a category_id is provided, only filters
relevant to products in that category are returned.
# List categories
Source: https://spreecommerce.org/docs/api-reference/store-api/product-catalog/list-categories
/api-reference/store.yaml get /api/v3/store/categories
Returns a paginated list of categories for the current store
# List products
Source: https://spreecommerce.org/docs/api-reference/store-api/product-catalog/list-products
/api-reference/store.yaml get /api/v3/store/products
Returns a paginated list of active products for the current store
# Querying
Source: https://spreecommerce.org/docs/api-reference/store-api/querying
How to filter, sort, and paginate Store API results using Ransack
The Store API uses [Ransack](https://activerecord-hackery.github.io/ransack/) for filtering and sorting collection endpoints. All query parameters are passed via the `q` parameter.
## Filtering
Pass filter conditions using the `q` parameter with Ransack predicates:
```typescript SDK theme={"theme":"night-owl"}
const products = await client.products.list({
name_cont: 'shirt',
price_gte: 20,
price_lte: 100,
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
--data-urlencode 'q[name_cont]=shirt' \
--data-urlencode 'q[price_gte]=20' \
--data-urlencode 'q[price_lte]=100'
```
### Common Predicates
| Predicate | Description | SDK | cURL |
| ---------- | --------------------------- | -------------------------------- | -------------------------------------------- |
| `eq` | Equals | `status_eq: 'active'` | `q[status_eq]=active` |
| `not_eq` | Not equals | `status_not_eq: 'draft'` | `q[status_not_eq]=draft` |
| `cont` | Contains (case-insensitive) | `name_cont: 'shirt'` | `q[name_cont]=shirt` |
| `start` | Starts with | `name_start: 'Spree'` | `q[name_start]=Spree` |
| `end` | Ends with | `slug_end: 'tote'` | `q[slug_end]=tote` |
| `lt` | Less than | `price_lt: 50` | `q[price_lt]=50` |
| `lteq` | Less than or equal | `price_lteq: 50` | `q[price_lteq]=50` |
| `gt` | Greater than | `price_gt: 10` | `q[price_gt]=10` |
| `gteq` | Greater than or equal | `price_gteq: 10` | `q[price_gteq]=10` |
| `in` | In a list | `status_in: ['active', 'draft']` | `q[status_in][]=active&q[status_in][]=draft` |
| `null` | Is null | `deleted_at_null: true` | `q[deleted_at_null]=true` |
| `not_null` | Is not null | `completed_at_not_null: true` | `q[completed_at_not_null]=true` |
| `present` | Is present (not empty) | `description_present: true` | `q[description_present]=true` |
| `blank` | Is blank (null or empty) | `description_blank: true` | `q[description_blank]=true` |
| `true` | Is true (boolean) | `purchasable_true: 1` | `q[purchasable_true]=1` |
| `false` | Is false (boolean) | `purchasable_false: 1` | `q[purchasable_false]=1` |
The SDK automatically wraps filter keys in `q[...]` and appends `[]` for array values — just pass flat params.
### Combining Filters
Multiple filters are combined with AND logic:
```typescript SDK theme={"theme":"night-owl"}
// Products that contain "shirt" AND cost between $20-$100
const products = await client.products.list({
name_cont: 'shirt',
price_gteq: 20,
price_lteq: 100,
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
--data-urlencode 'q[name_cont]=shirt' \
--data-urlencode 'q[price_gteq]=20' \
--data-urlencode 'q[price_lteq]=100'
```
### Filtering by Association
You can filter by associated model attributes using underscore notation:
```typescript SDK theme={"theme":"night-owl"}
// Products in a specific category (includes descendants)
const products = await client.products.list({
in_category: 'ctg_abc123',
})
// Multiple categories (OR logic, checkbox filters)
const products = await client.products.list({
in_categories: ['ctg_abc123', 'ctg_def456'],
})
// Categories at a specific depth
const categories = await client.categories.list({
depth_eq: 1,
})
```
```bash cURL theme={"theme":"night-owl"}
# Products in a specific category (includes descendants)
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
--data-urlencode 'q[in_category]=ctg_abc123'
# Top-level categories only
curl -G 'http://localhost:3000/api/v3/store/categories' \
-H 'X-Spree-Api-Key: pk_xxx' \
--data-urlencode 'q[depth_eq]=1'
```
## Product Scopes
Products support additional filter scopes beyond standard Ransack predicates:
```typescript SDK theme={"theme":"night-owl"}
const products = await client.products.list({
price_gte: 20, // Minimum price
price_lte: 100, // Maximum price
with_option_value_ids: ['optval_abc', 'optval_def'], // Filter by option values
in_stock: true, // Only in-stock products
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
--data-urlencode 'q[price_gte]=20' \
--data-urlencode 'q[price_lte]=100' \
--data-urlencode 'q[with_option_value_ids][]=optval_abc' \
--data-urlencode 'q[with_option_value_ids][]=optval_def' \
--data-urlencode 'q[in_stock]=true'
```
| Scope | Description | SDK | cURL |
| ----------------------- | -------------------------- | --------------------------------------- | --------------------------------------- |
| `price_gte` | Minimum price | `price_gte: 20` | `q[price_gte]=20` |
| `price_lte` | Maximum price | `price_lte: 100` | `q[price_lte]=100` |
| `with_option_value_ids` | Filter by option value IDs | `with_option_value_ids: ['optval_abc']` | `q[with_option_value_ids][]=optval_abc` |
| `in_stock` | Only in-stock products | `in_stock: true` | `q[in_stock]=true` |
| `out_of_stock` | Only out-of-stock products | `out_of_stock: true` | `q[out_of_stock]=true` |
| `search` | Full-text search | `search: 'shirt'` | `q[search]=shirt` |
## Sorting
Use the `sort` parameter on any list endpoint. Prefix a field with `-` for descending order (ascending is the default). This follows the [JSON:API sorting convention](https://jsonapi.org/format/#fetching-sorting).
```typescript SDK theme={"theme":"night-owl"}
// Sort by price (low to high)
const products = await client.products.list({
sort: 'price',
})
// Sort by price (high to low)
const products = await client.products.list({
sort: '-price',
})
// Sort by best selling
const products = await client.products.list({
sort: 'best_selling',
})
```
```bash cURL theme={"theme":"night-owl"}
# Sort by price low to high
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'sort=price'
# Sort by price high to low
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'sort=-price'
```
### Product Sort Options
| Value | Description |
| --------------- | ------------------------------------------------ |
| `manual` | Manual sort order (default, uses taxon position) |
| `best_selling` | Best selling products first |
| `price` | Price low to high |
| `-price` | Price high to low |
| `name` | Name A-Z |
| `-name` | Name Z-A |
| `-available_on` | Newest first |
| `available_on` | Oldest first |
### Sorting Other Resources
The `sort` parameter works on all list endpoints. Use any sortable column name:
```typescript SDK theme={"theme":"night-owl"}
// Categories sorted by name
const categories = await client.categories.list({
sort: 'name',
})
// Customer orders sorted by most recent
const orders = await client.customer.orders.list({
sort: '-completed_at',
})
```
```bash cURL theme={"theme":"night-owl"}
# Categories sorted by name
curl -G 'http://localhost:3000/api/v3/store/categories' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'sort=name'
# Customer orders by most recent
curl -G 'http://localhost:3000/api/v3/store/customer/orders' \
-H 'X-Spree-Api-Key: pk_xxx' \
-H 'Authorization: Bearer ' \
-d 'sort=-completed_at'
```
## Expanding Associations
Use the `expand` parameter to include associated resources in the response. Pass a comma-separated list of association names:
```typescript SDK theme={"theme":"night-owl"}
const product = await client.products.get('spree-tote', {
expand: ['variants', 'media'],
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=variants,media'
```
### Nested Expand
Use dot notation to expand nested associations (up to 4 levels deep):
```typescript SDK theme={"theme":"night-owl"}
// Expand variants and their media in one request
const product = await client.products.get('spree-tote', {
expand: ['variants.media'],
})
// Multiple nested expands
const product = await client.products.get('spree-tote', {
expand: ['variants.media', 'variants.custom_fields', 'option_types'],
})
// Category with nested children
const category = await client.categories.get('clothing/shirts', {
expand: ['children.children'], // Two levels of subcategories
})
```
```bash cURL theme={"theme":"night-owl"}
# Expand variants with their media
curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=variants.media'
# Multiple nested expands
curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=variants.media,variants.custom_fields,option_types'
```
### Rules
* Maximum depth is **4 levels** (e.g., `a.b.c.d`)
* A nested expand automatically includes its parent — `expand=variants.media` expands both `variants` and their `media`
* Nested expand only applies to conditional associations (those controlled by `expand`)
## Field Selection
Use the `fields` parameter to request only specific fields in the response. This reduces payload size for bandwidth-sensitive clients like mobile apps or server-side rendering.
```typescript SDK theme={"theme":"night-owl"}
// Only return name, slug, and price
const products = await client.products.list({
fields: ['name', 'slug', 'price', 'display_price'],
})
// Works on single resources too
const product = await client.products.get('spree-tote', {
fields: ['name', 'slug', 'price'],
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'fields=name,slug,price,display_price'
```
```json theme={"theme":"night-owl"}
{
"data": [
{
"id": "prod_86Rf07xd4z",
"name": "Spree Tote",
"slug": "spree-tote",
"price": "15.99",
"display_price": "$15.99"
}
],
"meta": { ... }
}
```
### Rules
* The `id` field is **always included**, even if not listed in `fields`
* Omitting `fields` returns all fields (default behavior)
* Field selection applies to the top-level resource only — expanded associations always return their full set of fields
* Expanded associations are **always included** in the response regardless of `fields` — `?fields=name&expand=variants` returns `id`, `name`, and `variants`
The SDK TypeScript types remain fully typed regardless of field selection. When using `fields`, be aware that only the requested fields will be present at runtime.
## Pagination
All collection endpoints return paginated results. Control pagination with `page` and `limit` parameters:
```typescript SDK theme={"theme":"night-owl"}
const { data: products, meta } = await client.products.list({
page: 2,
limit: 10,
})
// meta contains pagination info
console.log(meta)
// {
// page: 2,
// limit: 10,
// count: 85,
// pages: 9,
// from: 11,
// to: 20,
// in: 10,
// previous: 1,
// next: 3
// }
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'page=2' \
-d 'limit=10'
```
### Pagination Parameters
| Parameter | Default | Max | Description |
| --------- | ------- | ----- | -------------------------- |
| `page` | `1` | - | Page number |
| `limit` | `25` | `100` | Number of records per page |
### Pagination Metadata
Collection responses include a `meta` object with pagination info:
```json theme={"theme":"night-owl"}
{
"data": [...],
"meta": {
"page": 1,
"limit": 25,
"count": 85,
"pages": 4,
"from": 1,
"to": 25,
"in": 25,
"previous": null,
"next": 2
}
}
```
| Field | Description |
| ---------- | ----------------------------------------- |
| `page` | Current page number |
| `limit` | Records per page |
| `count` | Total number of records |
| `pages` | Total number of pages |
| `from` | Starting record number on this page |
| `to` | Ending record number on this page |
| `in` | Number of records returned on this page |
| `previous` | Previous page number (null if first page) |
| `next` | Next page number (null if last page) |
# Rate Limiting
Source: https://spreecommerce.org/docs/api-reference/store-api/rate-limitting
Rate limits and throttling for the Store API
The Store API enforces rate limits to protect against abuse and ensure fair usage. Rate limits are applied per API key or per IP address depending on the endpoint.
## Default Limits
| Endpoint | Limit | Scope | Window |
| -------------------- | ------------ | ----------- | -------- |
| All endpoints | 300 requests | Per API key | 1 minute |
| `POST /auth/login` | 5 requests | Per IP | 1 minute |
| `POST /customers` | 3 requests | Per IP | 1 minute |
| `POST /auth/refresh` | 10 requests | Per IP | 1 minute |
The global rate limit is tracked by your publishable API key (`X-Spree-Api-Key`). If the key is not provided, the limit falls back to the client's IP address.
Authentication endpoints have stricter per-IP limits to prevent brute-force attacks.
## Rate Limit Headers
Every Store API response includes headers that show your current rate limit usage:
| Header | Description |
| ----------------------- | -------------------------------------------------------------------- |
| `X-RateLimit-Limit` | Maximum number of requests allowed per window |
| `X-RateLimit-Remaining` | Number of requests remaining in the current window |
| `Retry-After` | Seconds to wait before retrying (only present when limit is reached) |
Example response headers:
```
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295
```
## Rate Limit Response
When you exceed the rate limit, the API returns a `429 Too Many Requests` response:
```json theme={"theme":"night-owl"}
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please retry later."
}
}
```
The response includes rate limit headers and a `Retry-After` header indicating how many seconds to wait before retrying:
```
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
Retry-After: 60
```
## SDK Retry Handling
The Spree SDK automatically handles rate-limited responses with built-in retry logic and exponential backoff:
```typescript theme={"theme":"night-owl"}
import { createClient } from '@spree/sdk'
const client = createClient({
baseUrl: 'http://localhost:3000',
publishableKey: 'pk_xxx',
retry: {
maxRetries: 2, // Number of retry attempts (default: 2)
baseDelay: 300, // Initial delay in ms (default: 300)
maxDelay: 10000, // Maximum delay in ms (default: 10000)
},
})
```
The SDK respects the `Retry-After` header and only retries on `429` status codes for non-GET requests. For GET/HEAD requests, it also retries on `500`, `502`, `503`, and `504` errors.
## Configuring Rate Limits
If you're self-hosting Spree, you can adjust rate limits in your initializer:
```ruby theme={"theme":"night-owl"}
# config/initializers/spree.rb
Spree::Api::Config[:rate_limit_per_key] = 300 # Global limit per API key
Spree::Api::Config[:rate_limit_window] = 60 # Window in seconds
Spree::Api::Config[:rate_limit_login] = 5 # Login attempts per IP
Spree::Api::Config[:rate_limit_register] = 3 # Registration attempts per IP
Spree::Api::Config[:rate_limit_refresh] = 10 # Token refresh per IP
Spree::Api::Config[:rate_limit_oauth] = 5 # OAuth callbacks per IP
```
Rate limiting uses `Rails.cache` as the backing store. For production environments with multiple application servers, ensure you're using a shared cache store like Redis:
```ruby theme={"theme":"night-owl"}
# config/environments/production.rb
config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] }
```
# Relations
Source: https://spreecommerce.org/docs/api-reference/store-api/relations
How to include related resources in API responses
By default, the Store API returns only the primary resource attributes to keep responses fast and lightweight. Use the `expand` parameter to expand related resources inline.
## Including Relations
Pass a comma-separated list of relation names via the `expand` query parameter:
```typescript SDK theme={"theme":"night-owl"}
// Product with variants and media
const product = await client.products.get('spree-tote', {
expand: ['variants', 'media'],
})
// Access included relations directly
console.log(product.variants) // Array of variant objects
console.log(product.media) // Array of media objects
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=variants,media'
```
## Response Format
Without `expand`, relation fields are omitted from the response:
```json theme={"theme":"night-owl"}
{
"id": "prod_86Rf07xd4z",
"name": "Spree Tote",
"slug": "spree-tote",
"price": { "amount": "15.99", "currency": "USD" },
"created_at": "2025-01-15T10:30:00Z"
}
```
With `?expand=variants,media`, the related resources are embedded:
```json theme={"theme":"night-owl"}
{
"id": "prod_86Rf07xd4z",
"name": "Spree Tote",
"slug": "spree-tote",
"price": { "amount": "15.99", "currency": "USD" },
"created_at": "2025-01-15T10:30:00Z",
"variants": [
{
"id": "variant_k5nR8xLq",
"sku": "SPR-TOTE-RED",
"price": { "amount": "15.99", "currency": "USD" },
"in_stock": true,
"option_values": [{ "name": "Red", "option_type_name": "Color" }]
}
],
"media": [
{
"id": "asset_9xPq2wLm",
"position": 1,
"alt": "Spree Tote",
"media_type": "image",
"product_id": "prod_86Rf07xd4z",
"variant_ids": ["variant_k5nR8xLq"],
"original_url": "https://cdn.example.com/spree-tote.jpg",
"small_url": "https://cdn.example.com/spree-tote-small.jpg",
"medium_url": "https://cdn.example.com/spree-tote-medium.jpg",
"large_url": "https://cdn.example.com/spree-tote-large.jpg"
}
]
}
```
## Available Relations by Resource
### Products
| Relation | Description |
| ----------------- | --------------------------------------------------------- |
| `variants` | All purchasable variants |
| `default_variant` | The default variant |
| `media` | All product media (images and videos across all variants) |
| `primary_media` | The main product image |
| `option_types` | Option types (e.g., Size, Color) |
| `categories` | Categories this product belongs to |
| `custom_fields` | Public custom fields (structured metadata) |
| `prior_price` | Previous price history (for showing strikethrough) |
```typescript SDK theme={"theme":"night-owl"}
const product = await client.products.get('spree-tote', {
expand: ['variants', 'media', 'option_types', 'custom_fields'],
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=variants,media,option_types,custom_fields'
```
### Categories
| Relation | Description |
| --------------- | ------------------------------------------ |
| `parent` | Parent category |
| `ancestors` | All ancestor categories (for breadcrumbs) |
| `children` | Direct child categories |
| `custom_fields` | Public custom fields (structured metadata) |
```typescript SDK theme={"theme":"night-owl"}
const category = await client.categories.get('clothing/shirts', {
expand: ['ancestors', 'children'],
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/categories/clothing/shirts' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=ancestors,children'
```
### Countries
| Relation | Description |
| -------- | ----------------------------------- |
| `states` | States/provinces within the country |
```typescript SDK theme={"theme":"night-owl"}
const usa = await client.countries.get('US', {
expand: ['states'],
})
console.log(usa.states) // Array of state objects
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/countries/US' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=states'
```
## Collections with Includes
The `expand` parameter also works on collection endpoints:
```typescript SDK theme={"theme":"night-owl"}
// List products with their media and default variant
const { data: products } = await client.products.list({
expand: ['media', 'default_variant'],
limit: 12,
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=media,default_variant' \
-d 'limit=12'
```
## Nested Includes
Use dot notation to include nested relations:
```typescript SDK theme={"theme":"night-owl"}
// Include variants and their nested option values
const product = await client.products.get('spree-tote', {
expand: ['variants.option_values'],
})
```
```bash cURL theme={"theme":"night-owl"}
curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
-H 'X-Spree-Api-Key: pk_xxx' \
-d 'expand=variants.option_values'
```
Only include relations you actually need. Each included relation requires additional database queries, so requesting unnecessary relations will slow down the response.
# Add item to wishlist
Source: https://spreecommerce.org/docs/api-reference/store-api/wishlists/add-item-to-wishlist
/api-reference/store.yaml post /api/v3/store/wishlists/{wishlist_id}/items
Adds a variant to the wishlist
# Create a wishlist
Source: https://spreecommerce.org/docs/api-reference/store-api/wishlists/create-a-wishlist
/api-reference/store.yaml post /api/v3/store/wishlists
Creates a new wishlist for the customer
# Delete a wishlist
Source: https://spreecommerce.org/docs/api-reference/store-api/wishlists/delete-a-wishlist
/api-reference/store.yaml delete /api/v3/store/wishlists/{id}
# Get a wishlist
Source: https://spreecommerce.org/docs/api-reference/store-api/wishlists/get-a-wishlist
/api-reference/store.yaml get /api/v3/store/wishlists/{id}
# List wishlists
Source: https://spreecommerce.org/docs/api-reference/store-api/wishlists/list-wishlists
/api-reference/store.yaml get /api/v3/store/wishlists
Returns all wishlists for the authenticated customer
# Remove item from wishlist
Source: https://spreecommerce.org/docs/api-reference/store-api/wishlists/remove-item-from-wishlist
/api-reference/store.yaml delete /api/v3/store/wishlists/{wishlist_id}/items/{id}
# Update a wishlist
Source: https://spreecommerce.org/docs/api-reference/store-api/wishlists/update-a-wishlist
/api-reference/store.yaml patch /api/v3/store/wishlists/{id}
# Create an Address
Source: https://spreecommerce.org/docs/api-reference/storefront/account-address/create-an-address
/api-reference/storefront.yaml post /api/v2/storefront/account/addresses
Creates a new address for the current user.
# List all Addresses
Source: https://spreecommerce.org/docs/api-reference/storefront/account-address/list-all-addresses
/api-reference/storefront.yaml get /api/v2/storefront/account/addresses
Returns a list of addresses for the current user.
# Remove an Address
Source: https://spreecommerce.org/docs/api-reference/storefront/account-address/remove-an-address
/api-reference/storefront.yaml delete /api/v2/storefront/account/addresses/{id}
This endpoint removes the specified address for the current user. It uses a soft delete to retain address information for pre-existing orders.
# Update an Address
Source: https://spreecommerce.org/docs/api-reference/storefront/account-address/update-an-address
/api-reference/storefront.yaml patch /api/v2/storefront/account/addresses/{id}
Updates the specified address for the current user.
# List all Credit Cards
Source: https://spreecommerce.org/docs/api-reference/storefront/account-credit-cards/list-all-credit-cards
/api-reference/storefront.yaml get /api/v2/storefront/account/credit_cards
Returns a list of credit cards for the current user.
# Remove a Credit Card
Source: https://spreecommerce.org/docs/api-reference/storefront/account-credit-cards/remove-a-credit-card
/api-reference/storefront.yaml delete /api/v2/storefront/account/credit_cards/{id}
Removes a specified credit card for the current user with a soft delete to retain payment information for any pre-existing orders.
# Retrieve the default Credit Card
Source: https://spreecommerce.org/docs/api-reference/storefront/account-credit-cards/retrieve-the-default-credit-card
/api-reference/storefront.yaml get /api/v2/storefront/account/credit_cards/default
Returns the current user's default credit card.
# List all Orders
Source: https://spreecommerce.org/docs/api-reference/storefront/account-orders/list-all-orders
/api-reference/storefront.yaml get /api/v2/storefront/account/orders
Returns all completed orders placed by the current user in the current store.
# Retrieve an Order
Source: https://spreecommerce.org/docs/api-reference/storefront/account-orders/retrieve-an-order
/api-reference/storefront.yaml get /api/v2/storefront/account/orders/{order_number}
Returns a completed order for the current user within the scope of the current store.
# Create an Account
Source: https://spreecommerce.org/docs/api-reference/storefront/account/create-an-account
/api-reference/storefront.yaml post /api/v2/storefront/account
Creates a new account
# Retrieve an Account
Source: https://spreecommerce.org/docs/api-reference/storefront/account/retrieve-an-account
/api-reference/storefront.yaml get /api/v2/storefront/account
Returns the current user details.
# Update an Account
Source: https://spreecommerce.org/docs/api-reference/storefront/account/update-an-account
/api-reference/storefront.yaml patch /api/v2/storefront/account
Updates the users account details
# Complete an Adyen payment session and order
Source: https://spreecommerce.org/docs/api-reference/storefront/adyen/complete-an-adyen-payment-session-and-order
/api-reference/storefront.yaml post /api/v2/storefront/adyen/payment_sessions/{id}/complete
Complete an Adyen payment session and order. Adyen support is currently in private beta. [Please contact us](https://spreecommerce.org/contact) to get access.
# Create an Adyen Payment Session
Source: https://spreecommerce.org/docs/api-reference/storefront/adyen/create-an-adyen-payment-session
/api-reference/storefront.yaml post /api/v2/storefront/adyen/payment_sessions
Create a new Adyen payment session with the specified amount. Adyen support is currently in private beta. [Please contact us](https://spreecommerce.org/contact) to get access.
# Get Adyen Payment Session
Source: https://spreecommerce.org/docs/api-reference/storefront/adyen/get-adyen-payment-session
/api-reference/storefront.yaml get /api/v2/storefront/adyen/payment_sessions/{id}
Retrieve An Adyen payment session information. Adyen support is currently in private beta. [Please contact us](https://spreecommerce.org/contact) to get access.
# Authentication
Source: https://spreecommerce.org/docs/api-reference/storefront/authentication
Learn how to authenticate requests to the Storefront API.
Storefront API requires authorization only for certain actions associated with user account (e.g. updating saved addresses) or manipulating cart and checkout.
## For guest users
### Using X-Spree-Order-Token header
[Cart](/docs/api-reference/storefront/cart) and [Checkout](/docs/api-reference/storefront/checkout) endpoints paths also allow interactions without the bearer token to allow creating and managing guest checkouts.
When you first create a cart via:
```bash theme={"theme":"night-owl"}
curl --request POST \
--url 'https://demo.spreecommerce.org/api/v2/storefront/cart?fields%5Bcart%5D=number%2Ctoken' \
--header 'Content-Type: application/vnd.api+json'
```
You'll receive a response containing an empty cart. This response also contains a `data.token` attribute.
```json theme={"theme":"night-owl"}
{
"data": {
"id": "114",
"type": "cart",
"attributes": {
"number": "R522550303",
"token": "NswjLVjZOw4OpEm1yWqlJg1713367317414"
},
"relationships": {}
}
}
```
You can store this token in the frontend session (eg. Session Storage or a cookie) and pass it in a `X-Spree-Order-Token: {token}` header.
## For signed in users
For users who have an account in your store, you will need to generate oAuth tokens to authenticate requests to endpoints such as [Account](/docs/api-reference/storefront/account), [Cart](/docs/api-reference/storefront/cart) and [Checkout](/docs/api-reference/storefront/checkout).
### Generating OAuth token
To obtain a token, execute the following curl command:
```bash theme={"theme":"night-owl"}
curl -X POST http://localhost:3000/spree_oauth/token \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "grant_type=password&username=spree@example.com&password=spree123"
```
You should receive a JSON response with a `access_token` and a `refresh_token`, eg.
```json theme={"theme":"night-owl"}
{
"access_token": "CmVXoDp6f5Y51s2xFAAdSbdT5wcGZIuGKKr27zAkBvQ",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "g5xPzY51_QYyok-ZcH9f4_btBkT_RZ6pB7ugGRaMjQQ",
"created_at": 1713367848
}
```
### Refreshing OAuth token
OAuth tokens obtained via the previous step are valid only for a specific time (defined in `expires_in` attribute).
After that period, you can refresh the token by executing the following curl command:
```bash theme={"theme":"night-owl"}
curl -X POST http://localhost:3000/spree_oauth/token \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "grant_type=refresh_token&refresh_token=g5xPzY51_QYyok-ZcH9f4_btBkT_RZ6pB7ugGRaMjQQ"
```
On a success, you'll receive a new bearer token to use when accessing the API, eg.
```json theme={"theme":"night-owl"}
{
"access_token": "JVMcaoCkxV4o2xofhAwf7ReeFEWUM94ZnVSKRITd3TQ",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "nMlyfxfA9U6xfSDnFhoZQzL4IOkDc-EkW1y66ZTf5Oc",
"created_at": 1713367950
}
```
# Apply a Coupon Code / Gift Card
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-coupons/apply-a-coupon-code-gift-card
/api-reference/storefront.yaml patch /api/v2/storefront/cart/apply_coupon_code
Applies a coupon code or gift card code to the current cart.
# Remove a Coupon / Gift Card
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-coupons/remove-a-coupon-gift-card
/api-reference/storefront.yaml delete /api/v2/storefront/cart/remove_coupon_code/{coupon_code}
Removes a specified coupon code or gift card code from the current cart.
# Remove all Coupons
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-coupons/remove-all-coupons
/api-reference/storefront.yaml delete /api/v2/storefront/cart/remove_coupon_code
Removes all coupons that have been applied to the current cart.
# Add an Item to Cart
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-line-items/add-an-item-to-cart
/api-reference/storefront.yaml post /api/v2/storefront/cart/add_item
Adds a variant to the current cart by creating a line item. Each line item represents a specified variant and the desired quantity.
# Remove a Line Item
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-line-items/remove-a-line-item
/api-reference/storefront.yaml delete /api/v2/storefront/cart/remove_line_item/{id}
Removes a line item from the cart by deleting the line item.
After deleting the line item, the system will re-calculate taxes, promotions, shipments etc.
# Set Line Item Quantity
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-line-items/set-line-item-quantity
/api-reference/storefront.yaml patch /api/v2/storefront/cart/set_quantity
Sets the quantity of a specified line item.
# Associate a Cart with a User
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-other/associate-a-cart-with-a-user
/api-reference/storefront.yaml patch /api/v2/storefront/cart/associate
Associates a guest cart with the currently signed in user.
# Change Cart Currency
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-other/change-cart-currency
/api-reference/storefront.yaml patch /api/v2/storefront/cart/change_currency
Changes the cart currency and recalculates the cart values.
# Empty the Cart
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-other/empty-the-cart
/api-reference/storefront.yaml patch /api/v2/storefront/cart/empty
This endpoint removed all line items from the cart. Inventory that was previously taken by this order will be re-stocked.
# List Estimated Shipping Rates
Source: https://spreecommerce.org/docs/api-reference/storefront/cart-other/list-estimated-shipping-rates
/api-reference/storefront.yaml get /api/v2/storefront/cart/estimate_shipping_rates
Returns a list of shipping rates for the current cart. The rates given are only estimates and can vary from the final shipping rates.
# Create a Cart
Source: https://spreecommerce.org/docs/api-reference/storefront/cart/create-a-cart
/api-reference/storefront.yaml post /api/v2/storefront/cart
Creates a new cart.
**Please be aware**; The `token` value found in the response body is used to authorize all future operations on this cart through the Auth API Key `X-Spree-Order-Token`.
# Delete a Cart
Source: https://spreecommerce.org/docs/api-reference/storefront/cart/delete-a-cart
/api-reference/storefront.yaml delete /api/v2/storefront/cart
Deletes a specified cart.
When this endpoint is successfully executed, all shipments are cancelled, payments are voided, then line items, shipments & payments are all deleted.
# Retrieve a Cart
Source: https://spreecommerce.org/docs/api-reference/storefront/cart/retrieve-a-cart
/api-reference/storefront.yaml get /api/v2/storefront/cart
Returns the cart for the current user.
# Create new Payment
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-payments/create-new-payment
/api-reference/storefront.yaml post /api/v2/storefront/checkout/create_payment
Creates new Payment for the current checkout.
You can either create new payment source (eg. a Credit Card) or use an existing (for signed in users only).
Newly created payment source will be associated to the current signed in user.
System will automatically invalidate previous (non-finalized) payments (excluding store credit / gift card payments).
[More details on payment system](/developer/core-concepts/payments)
# List Payment Methods
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-payments/list-payment-methods
/api-reference/storefront.yaml get /api/v2/storefront/checkout/payment_methods
Returns a list of available payment methods for this checkout.
# List Shipping Rates
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-shipments/list-shipping-rates
/api-reference/storefront.yaml get /api/v2/storefront/checkout/shipping_rates
Returns a list of available shipping rates for the checkout.
Shipping rates are grouped against shipments. Each checkout can have multiple shipments. Some products are in stock and will be shipped immediately, while others might be back-ordered and sent later.
# Selects shipping method for shipment(s)
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-shipments/selects-shipping-method-for-shipments
/api-reference/storefront.yaml patch /api/v2/storefront/checkout/select_shipping_method
Selects shipping method for Shipment(s).
To generate shipments you first need to fetch shipping rates via
[Get Shipping Rates](/api-reference/storefront/checkout-shipments/list-shipping-rates) endpoint
# Advance Checkout
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-state/advance-checkout
/api-reference/storefront.yaml patch /api/v2/storefront/checkout/advance
Advances the checkout to the furthest checkout step validation allows, up until the **completed** step.
# Complete Checkout
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-state/complete-checkout
/api-reference/storefront.yaml patch /api/v2/storefront/checkout/complete
Completes the checkout by marking the order as complete.
**Please be aware**; Once a checkout is marked as `complete` it is considered a completed order, the Cart and Checkout endpoints will no longer access a completed order, and a new cart will need to be created.
If you want to access a completed order you will need to use the **Account / Orders** or **Order Status** endpoints.
# Next Checkout Step
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-state/next-checkout-step
/api-reference/storefront.yaml patch /api/v2/storefront/checkout/next
Goes to the next checkout step.
# Add Store Credit
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-store-credit/add-store-credit
/api-reference/storefront.yaml post /api/v2/storefront/checkout/add_store_credit
The Add Store Credit endpoint takes the users existing store credit from their account and adds a set amount of this store credit to the current cart.
In essence, by adding the user's store credit to a cart, the user's store credit is being spent.
# Remove Store Credit
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout-store-credit/remove-store-credit
/api-reference/storefront.yaml post /api/v2/storefront/checkout/remove_store_credit
Removes store credit from the cart if any had previously been applied.
# Update Checkout
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout/update-checkout
/api-reference/storefront.yaml patch /api/v2/storefront/checkout
The Update Checkout endpoint allows you to manage the typical stages of an e-commerce checkout system.
# Validate order payment
Source: https://spreecommerce.org/docs/api-reference/storefront/checkout/validate-order-payment
/api-reference/storefront.yaml post /api/v2/storefront/checkout/validate_order_for_payment
Validate an order before placing it. It will respond with an error when:
- cart was changed
- any order item is out of stock
- any order item is discontinued
# Get Default Country
Source: https://spreecommerce.org/docs/api-reference/storefront/countries/get-default-country
/api-reference/storefront.yaml get /api/v2/storefront/countries/default
Returns the default country for the current store. By default this will be the US.
# List all Countries
Source: https://spreecommerce.org/docs/api-reference/storefront/countries/list-all-countries
/api-reference/storefront.yaml get /api/v2/storefront/countries
Returns a list of all countries.
# Retrieve a Country
Source: https://spreecommerce.org/docs/api-reference/storefront/countries/retrieve-a-country
/api-reference/storefront.yaml get /api/v2/storefront/countries/{iso}
Returns the details of a specific country.
# Download a Digital Asset
Source: https://spreecommerce.org/docs/api-reference/storefront/digital-downloads/download-a-digital-asset
/api-reference/storefront.yaml get /api/v2/storefront/digitals/{token}
This endpoint allows you to download a digital item using the unique digital_link token.
The digital_link token value can be found by including `line_items.digital_links` in a completed order lookup.
Use the **Retrieve an Order Status** endpoint found under the Order Status tab, or the **Retrieve an Order** endpoint found under the Account / Orders tab to perform a completed order lookup.
Depending on the store that the item was purchased in, downloads may be restricted to a set number of days since the purchase was made. Additionally, the number of times a download link can be used may be restricted.
If you are not authorized to perform the download due to the download limit restrictions mentioned above, a 403 response will be returned.
# Retrieve an Order Status
Source: https://spreecommerce.org/docs/api-reference/storefront/order-status/retrieve-an-order-status
/api-reference/storefront.yaml get /api/v2/storefront/order_status/{order_number}
Returns completed order information.
This endpoint is useful when fetching orders placed by a guest user, allowing customers without an account to check the status of their order: (shipment/payment/processing) etc.
Pass the cart `token` value as the `X-Spree-Order-Token` for authorization, and the corresponding cart `number` in the URI **{order_number}** to successfully retrieve an order.
# List all Store Policies
Source: https://spreecommerce.org/docs/api-reference/storefront/policies/list-all-store-policies
/api-reference/storefront.yaml get /api/v2/storefront/policies
Returns a list of Store Policies. This endpoint is only available in Spree 5.2 or later.
# Retrieve a Policy
Source: https://spreecommerce.org/docs/api-reference/storefront/policies/retrieve-a-policy
/api-reference/storefront.yaml get /api/v2/storefront/policies/{policy_slug}
Returns the details of a specified Policy. This endpoint is only available in Spree 5.2 or later.
# List all Post Categories
Source: https://spreecommerce.org/docs/api-reference/storefront/post-categories/list-all-post-categories
/api-reference/storefront.yaml get /api/v2/storefront/post_categories
Returns a list of Post Categories. This endpoint is only available in Spree 5.2 or later.
# Retrieve a Post Category
Source: https://spreecommerce.org/docs/api-reference/storefront/post-categories/retrieve-a-post-category
/api-reference/storefront.yaml get /api/v2/storefront/post_categories/{id}
Returns the details of a specified Post Category, including related posts. You can use either the category slug or ID. This endpoint is only available in Spree 5.2 or later.
# List all Posts
Source: https://spreecommerce.org/docs/api-reference/storefront/posts/list-all-posts
/api-reference/storefront.yaml get /api/v2/storefront/posts
Returns a list of published Posts. This endpoint is only available in Spree 5.2 or later.
# Retrieve a Post
Source: https://spreecommerce.org/docs/api-reference/storefront/posts/retrieve-a-post
/api-reference/storefront.yaml get /api/v2/storefront/posts/{id}
Returns the details of a specified Post. You can use either the post slug or ID. This endpoint is only available in Spree 5.2 or later.
# List all Products
Source: https://spreecommerce.org/docs/api-reference/storefront/products/list-all-products
/api-reference/storefront.yaml get /api/v2/storefront/products
Returns a list of products for the current Store.
# Retrieve a Product
Source: https://spreecommerce.org/docs/api-reference/storefront/products/retrieve-a-product
/api-reference/storefront.yaml get /api/v2/storefront/products/{product_slug}
Returns Product details. You can use product permalink:
```
GET /api/v2/storefront/products/knitted-high-neck-sweater
```
Or Product ID:
```
GET /api/v2/storefront/products/21
```
**Note** API will attempt a permalink lookup before an ID lookup.
# Return the current Store
Source: https://spreecommerce.org/docs/api-reference/storefront/stores/return-the-current-store
/api-reference/storefront.yaml get /api/v2/storefront/store
Returns the current Store. [Read more about Stores](/developer/core-concepts/stores)
# Create a Stripe Payment Intent
Source: https://spreecommerce.org/docs/api-reference/storefront/stripe/create-a-stripe-payment-intent
/api-reference/storefront.yaml post /api/v2/storefront/stripe/payment_intents
Create a Stripe Payment Intent using provided payment method. It creates a Stripe customer if not exists.
# Create a Stripe Setup Intent
Source: https://spreecommerce.org/docs/api-reference/storefront/stripe/create-a-stripe-setup-intent
/api-reference/storefront.yaml post /api/v2/storefront/stripe/setup_intents
First, this endpoint creates a customer in Stripe (if it doesn't already exist), then it creates an Ephemeral Key for the customer, and finally, it creates a Setup Intent for the customer.
# Mark the payment intent as confirmed, and move the order to the complete state
Source: https://spreecommerce.org/docs/api-reference/storefront/stripe/mark-the-payment-intent-as-confirmed-and-move-the-order-to-the-complete-state
/api-reference/storefront.yaml patch /api/v2/storefront/stripe/payment_intents/{id}/confirm
This endpoint is used to complete the order with succeeded payment intent. First it will check if the payment intent has `status` `succeeded`, if yes, then it will move the order to the complete state.
# Return a Stripe Payment Intent
Source: https://spreecommerce.org/docs/api-reference/storefront/stripe/return-a-stripe-payment-intent
/api-reference/storefront.yaml get /api/v2/storefront/stripe/payment_intents/{id}
Returns the Payment Intent information
# Updates Stripe Payment Intent
Source: https://spreecommerce.org/docs/api-reference/storefront/stripe/updates-stripe-payment-intent
/api-reference/storefront.yaml patch /api/v2/storefront/stripe/payment_intents/{id}
Updates the payment intent with new `amount` and `stripe_payment_method_id`
# List all Taxons
Source: https://spreecommerce.org/docs/api-reference/storefront/taxons/list-all-taxons
/api-reference/storefront.yaml get /api/v2/storefront/taxons
Returns a list of Taxons. [Read more about Taxons](/developer/core-concepts/products#taxons-and-taxonomies)
# Retrieve a Taxon
Source: https://spreecommerce.org/docs/api-reference/storefront/taxons/retrieve-a-taxon
/api-reference/storefront.yaml get /api/v2/storefront/taxons/{taxon_permalink}
Returns the details of a specified taxon.
# List all Product Variants
Source: https://spreecommerce.org/docs/api-reference/storefront/variants/list-all-product-variants
/api-reference/storefront.yaml get /api/v2/storefront/products/{product_slug}/variants
Returns a list of product variants. You can use product permalink:
```
GET /api/v2/storefront/products/knitted-high-neck-sweater/variants
```
Or Product ID:
```
GET /api/v2/storefront/products/21/variants
```
**Note** API will attempt a permalink lookup before an ID lookup.
# List all Vendors
Source: https://spreecommerce.org/docs/api-reference/storefront/vendors/list-all-vendors
/api-reference/storefront.yaml get /api/v2/storefront/vendors
Returns a list of Vendors. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Retrieve a Vendor
Source: https://spreecommerce.org/docs/api-reference/storefront/vendors/retrieve-a-vendor
/api-reference/storefront.yaml get /api/v2/storefront/vendors/{vendor_slug}
Returns the details of a specified Vendor. Only available in [Enterprise Edition](https://spreecommerce.org/pricing)
# Add Item to Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists-wished-items/add-item-to-wishlist
/api-reference/storefront.yaml post /api/v2/storefront/wishlists/{token}/add_item
The Add Item to Wishlist endpoint adds a variant to an existing wishlist by creating a new `wished_item`. A wished item in a wishlist is comparable to a line item in a cart.
Each wished item references a single variant, holds the desired quantity and returns price information determined by the variant price in current currency, and desired quantity.
# Add Items to Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists-wished-items/add-items-to-wishlist
/api-reference/storefront.yaml post /api/v2/storefront/wishlists/{token}/add_items
The Add Items to Wishlist endpoint adds variants to an existing wishlist by creating a new `wished_item` objects. A wished item in a wishlist is comparable to a line item in a cart.
Each wished item references a single variant, holds the desired quantity and returns price information determined by the variant price in current currency, and desired quantity.
# Delete Item from Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists-wished-items/delete-item-from-wishlist
/api-reference/storefront.yaml delete /api/v2/storefront/wishlists/{token}/remove_item/{item_id}
Removes a wished item from a wishlist.
# Delete Items from Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists-wished-items/delete-items-from-wishlist
/api-reference/storefront.yaml delete /api/v2/storefront/wishlists/{token}/remove_items
Removes wished items from a wishlist.
# Set Wished Item Quantity
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists-wished-items/set-wished-item-quantity
/api-reference/storefront.yaml patch /api/v2/storefront/wishlists/{token}/set_item_quantity/{item_id}
This endpoint sets the wished item quantity.
# Create a Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists/create-a-wishlist
/api-reference/storefront.yaml post /api/v2/storefront/wishlists
Creates a new wishlist for the current user in the current store.
# Delete a Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists/delete-a-wishlist
/api-reference/storefront.yaml delete /api/v2/storefront/wishlists/{token}
This operation deletes the wishlist identified in the URI `token`.
# List all Wishlists
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists/list-all-wishlists
/api-reference/storefront.yaml get /api/v2/storefront/wishlists
Returns all wishlists available to the current user, in the current store.
# Retrieve a Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists/retrieve-a-wishlist
/api-reference/storefront.yaml get /api/v2/storefront/wishlists/{token}
Retrieves a wishlist using the wishlist token.
If the wishlist is publicly viewable, the endpoint will return the requested wishlist regardless of the user. If the wishlist is private, only the wishlist owner can access the wishlist.
# Retrieve the default Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists/retrieve-the-default-wishlist
/api-reference/storefront.yaml get /api/v2/storefront/wishlists/default
Returns the default wishlist for the current user, in the current store. If the user does not have a default wishlist in the current store one will be created.
# Update a Wishlist
Source: https://spreecommerce.org/docs/api-reference/storefront/wishlists/update-a-wishlist
/api-reference/storefront.yaml patch /api/v2/storefront/wishlists/{token}
Updates the specific Wishlist by setting the values passed in the request body. Any parameters not provided will be left unchanged.
# Adyen Integration Guide for Android
Source: https://spreecommerce.org/docs/api-reference/tutorials/adyen-integration-guide-for-android
This guide provides step-by-step instructions for integrating Adyen Android Drop-in with spree_adyen using session flow and Drop-In component.
This guide is aimed at advanced users who want to create adyen integration for their custom android application.
You also need to install Spree Adyen extension before.
## Note
The list of available library versions can be found on [Official Adyen Documentation for Android integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=Android\&integration=Drop-in\&version=5.13.1)
Current newest version available at the moment of writing the tutorial is 5.13.1.
This doc will be referring to the library version as YOUR\_VERSION.
## Resources
* [Official Adyen Documentation for Android integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=Android\&integration=Drop-in\&version=5.13.1)
* Spree Adyen API docs - [create payment\_session](/docs/api-reference/storefront/adyen/create-an-adyen-payment-session) and [get payment\_session](/docs/api-reference/storefront/adyen/get-adyen-payment-session)
* [Official Adyen example for Android integration](https://github.com/adyen-examples/adyen-android-online-payments)
## Overview
The integration consists of two main components:
* **Spree Adyen**: Provides API for your client and receive payment result from Adyen
* **Your Android client app**: Shows the Drop-in UI and handles payment flow
## Step 1: Import the library
Import the compatibility module:
### Import the module with Jet Compose
```bash theme={"theme":"night-owl"}
implementation "com.adyen.checkout:drop-in-compose:YOUR_VERSION"
```
### Import without Jet Compose
```bash theme={"theme":"night-owl"}
implementation "com.adyen.checkout:drop-in:YOUR_VERSION"
```
## Step 2: Create a checkout session
Create session using [this endpoint](/docs/api-reference/storefront/adyen/create-an-adyen-payment-session).
```kotlin theme={"theme":"night-owl"}
val sessionModel = SessionModel.SERIALIZER.deserialize(sessionsResponseJSON)
```
sessionsResponseJSON should contain:
* `sessionData` - available as `adyen_data` in payment\_session API response
* `id` - available as `adyen_id` in payment\_session API response
```kotlin theme={"theme":"night-owl"}
val sessionModel = SessionModel.SERIALIZER.deserialize(sessionsResponseJSON)
```
## Step 3
call `CheckoutSessionProvider.createSession` passing serialized session data (`sessionModel`) and `dropInConfiguration`
dropInConfiguration example:
```kotlin theme={"theme":"night-owl"}
val checkoutConfiguration = CheckoutConfiguration(
environment = environment,
clientKey = clientKey,
shopperLocale = shopperLocale, // Optional
) {
// Optional: add Drop-in configuration.
dropIn {
setEnableRemovingStoredPaymentMethods(true)
}
// Optional: add or change default configuration for the card payment method.
card {
setHolderNameRequired(true)
setShopperReference("...")
}
// Optional: change configuration for 3D Secure 2.
adyen3DS2 {
setThreeDSRequestorAppURL("...")
}
}
```
see also: [https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=Web\&integration=Drop-in\&version=6.18.1#create-instance](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=Web\&integration=Drop-in\&version=6.18.1#create-instance)
`environment` - enum: `live` or `test`
`clientKey` - `client_key` from payment\_sessions endpoint
`shopperLocale` - shopper locale in ISO format
```kotlin theme={"theme":"night-owl"}
// Create an object for the checkout session.
val result = CheckoutSessionProvider.createSession(sessionModel, dropInConfiguration)
// If the payment session is successful, handle the result.
// If the payment session encounters an error, handle the error.
when (result) {
is CheckoutSessionResult.Success -> handleCheckoutSession(result.checkoutSession)
is CheckoutSessionResult.Error -> handleError(result.exception)
}
```
## Step 4: Launch and show Drop-in
```kotlin theme={"theme":"night-owl"}
override fun onDropInResult(sessionDropInResult: SessionDropInResult?) {
when (sessionDropInResult) {
// The payment finishes with a result.
is SessionDropInResult.Finished -> handleResult(sessionDropInResult.result)
// The shopper dismisses Drop-in.
is SessionDropInResult.CancelledByUser ->
// Drop-in encounters an error.
is SessionDropInResult.Error -> handleError(sessionDropInResult.reason)
// Drop-in encounters an unexpected state.
null ->
}
}
```
## Step 5: Create the Drop-in launcher
DropIn.startPayment, passing:
* `dropInLauncher` - The Drop-in launcher object
* `checkoutSession` - result of `CheckoutSessionProvider.createSession`
* `dropInConfiguration` - Your Drop-in configuration
Example:
```kotlin theme={"theme":"night-owl"}
import com.adyen.checkout.dropin.compose.startPayment
import com.adyen.checkout.dropin.compose.rememberLauncherForDropInResult
@Composable
private fun ComposableDropIn() {
val dropInLauncher = rememberLauncherForDropInResult(sessionDropInCallback)
DropIn.startPayment(dropInLauncher, checkoutSession, dropInConfiguration)
}
```
## Get payment outcome
1. Wait for backend to process the payment
2. Continue shopping experience
### 1. Wait for backend to process the payment
backend will change the state of `payment_session` to one of the following state
* `pending` - chosen payment method can take a while to complete
* `completed` - payment resulted in success, order completed
* `canceled` - payment canceled, payment is `void`
* `refused` - payment failed
### 2. Continue shopping experience
if succeed - order is processed and completed
if failed - payment can be retried using new payment session
# Adyen Integration Guide for iOS
Source: https://spreecommerce.org/docs/api-reference/tutorials/adyen-integration-guide-for-ios
This guide provides step-by-step instructions for integrating Adyen iOS Drop-in with spree_adyen using session flow and Drop-In component.
This guide is aimed at advanced users who want to create adyen integration for their custom iOS application.
You also need to install Spree Adyen extension before.
## Requirements
* Adyen test account
* Set up `spree_adyen` spree extension
### return\_url
spree\_adyen needs to be configured with `return_url`.
Return url tells where shopper should be redirect after the payment from outside your application (for example klarna or most of others buy now pay later systems).
Use the custom URL for your app, like `my-app://adyen`. Url can contain custom query params however do not include any personally identifiable information (PII) of your customer. Maximum length of the url is 1024 characters.
## Note
The list of available library versions can be found on [Official Adyen Documentation for iOS integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=iOS\&integration=Drop-in\&version=5.13.1)
Current newest version available at the moment of writing the tutorial is 5.19.2.
## Resources
* [Official Adyen Documentation for iOS integration](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=iOS\&integration=Drop-in\&version=5.19.2)
* Spree Adyen API docs - [create payment\_session](/docs/api-reference/storefront/adyen/create-an-adyen-payment-session) and [get payment\_session](/docs/api-reference/storefront/adyen/get-adyen-payment-session)
* [Official Adyen example for iOS integration](https://github.com/Adyen/adyen-ios/tree/develop/Demo)
* Apple Developer documentation on [defining custom url scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app)
## Overview
The integration consists of two main components:
* **Spree Adyen**: Provides API for your client and receive payment result from Adyen
* **Your iOS client app**: Shows the Drop-in UI and handles payment flow
## Step 1: Install adyen with Swift Package Manager
repository URL:
```
https://github.com/Adyen/adyen-ios
```
use at least version 5.0.0
CocoaPods and Carthage instructions are available [here](https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/?platform=iOS\&integration=Drop-in\&version=5.19.2\&tab=cocoapods_1_2#1-get-adyen-ios).
## Step 2: Create the context
Create the instance of APIContext that includes client key and environment setting.
```swift theme={"theme":"night-owl"}
// Set the client key and environment in an instance of APIContext.
let apiContext = APIContext(clientKey: clientKey, environment: Environment.test) // Set the environment to a live one when going live.
// Create the amount with the value in minor units and the currency code.
let amount = Amount(value: 1000, currencyCode: "EUR")
// Create the payment object with the amount and country code.
let payment = Payment(amount: amount, countryCode: "NL")
// Create an instance of AdyenContext, passing the instance of APIContext, and payment object.
let adyenContext = AdyenContext(apiContext: apiContext, payment:payment)
```
`environment` - Environment.test or Environment.live
`clientKey` - `client_key` from payment\_sessions endpoint
## Step 3: Create and set up session
Create a session using [payment\_session endpoint](/docs/api-reference/storefront/adyen/create-an-adyen-payment-session).
Then set a configuration using data from the response:
```swift theme={"theme":"night-owl"}
let configuration = AdyenSession.Configuration(sessionIdentifier: sessionId,
initialSessionData: data)
```
* `data` - available as `adyen_data` in payment\_session API response
* `sessionId` - available as `adyen_id` in payment\_session API response
With the configuration you initialize AdyenSession:
```swift theme={"theme":"night-owl"}
AdyenSession.initialize(with: configuration, delegate: self, presentationDelegate: self) { [weak self] result in
switch result {
case let .success(session):
//Store the session object.
self?.session = session
case let .failure(error):
//Handle the error.
}
}
```
## Step 4. Configure Drop-in
```swift theme={"theme":"night-owl"}
let dropInConfiguration = DropInComponent.Configuration()
// Some payment methods have additional required or optional configuration.
// For example, an optional configuration to show the cardholder name field for cards.
dropInConfiguration.card.showsHolderNameField = true
```
## Step 5: Initialize the DropInComponent class
```swift theme={"theme":"night-owl"}
let dropInComponent = DropInComponent(paymentMethods: session.sessionContext.paymentMethods,
context: adyenContext,
configuration: dropInConfiguration)
// Keep the instance of Drop-in to so that it doesn't get destroyed after the function is executed.
self.dropInComponent = dropInComponent
// Set the session as the delegate.
dropInComponent.delegate = session
// If you support gift cards, set the session as the partial payment delegate.
dropInComponent.partialPaymentDelegate = session
```
## Step 6: Show Drop-in in your app
```swift theme={"theme":"night-owl"}
myCheckoutViewController.present(dropInComponent.viewController, animated: true)
```
If the `action` field is `redirect` you need to handle the redirect result.
## Step 7. Handling the redirect result
If the `action` field returns `redirect` the shopper is completing the payment outside of your application. You need to inform the Drop-in when the shopper returns to your app.
Here an example for a Custom Url scheme:
* implement the following in your `UIApplicationDelegate`:
```swift theme={"theme":"night-owl"}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
return RedirectComponent.applicationDidOpen(from: url)
}
```
for Universal URL use this instead:
```swift theme={"theme":"night-owl"}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let incomingURL = userActivity.webpageURL else { return false }
return RedirectComponent.applicationDidOpen(from: incomingURL)
}
```
## Step 8: Show the shopper result of the payment
When the payment flow is finished, your instance of AdyenSession calls the didComplete method.
Implement the following in your Drop-in configuration object.
```swift theme={"theme":"night-owl"}
func didComplete(with result: AdyenSessionResult, // The session result.
component: Component, // The Drop-in component.
session: AdyenSession) // Your instance of AdyenSession.
```
Use the resultCode to inform your shopper about the current payment status.
Possible resultCode values:
* `authorised` - payment authorised
* `refused` - payment refused
* `pending` - payment pending (for payments with asynchronous flow like iDEAL). When the shopper completes the payment webhook will process the payment.
* `cancelled` - payment canceled
* `received` - some payments needs more time to be processed. When the status is available webhook will process the payment
* `error` - an error occurred when processing the payment. The response contains more details with the error code
Your instance of AdyenSession calls the didFail method containing the error.
```swift theme={"theme":"night-owl"}
func didFail(with error: Error, // The error object.
from component: Component, // The Drop-in component.
session: AdyenSession) // Your instance of AdyenSession.
```
## Step 8: Continue shopping experience
1. Wait for backend to process the payment
2. Continue shopping experience
### 1. Wait for backend to process the payment
backend after receiving webhook will change the state of `payment_session` to one of the following state:
* `pending` - chosen payment method can take a while to complete
* `completed` - payment resulted in success, order completed
* `canceled` - payment canceled, payment is `void`
* `refused` - payment failed
### 2. Continue shopping experience
if succeed - order is processed and completed
if failed - payment can be retried using new payment session
# Quick Checkout with Stripe and Storefront API
Source: https://spreecommerce.org/docs/api-reference/tutorials/quick-checkout-with-stripe
This tutorial will show you how to add quick checkout to your headless/composable storefront using Stripe and Spree APIs.
This guide is aimed at advanced users who have some experience with Spree API and Stripe.
You also need to install [Spree Stripe](https://github.com/spree/spree_stripe) extension before.
If you're using the standard Spree Storefront, then you can skip this tutorial as quick checkout is already built in.
## Prerequisites
Assume that you have a cart made with line items in it already.
Quick checkout works by handling 3 different events:
* Address change
* Shipping Method/Rate change
* Confirmation
How you should handle them depends on your platform/language:
* For Web and JS, please review:
* [Express Checkout Element](https://docs.stripe.com/elements/express-checkout-element)
* We also recommend reviewing the [spree\_stripe implementation in Stimulus.js](https://github.com/spree/spree_stripe/blob/main/app/javascript/spree_stripe/controllers/stripe_button_controller.js)
* For iOS, please review:
* [StripeApplePay](https://docs.stripe.com/apple-pay)
* [STPApplePayContext](https://stripe.dev/stripe-ios/stripeapplepay/documentation/stripeapplepay/stpapplepaycontext#instance-methods)
## Checkout Flow
### Address change
Here we need to send some basic information about the customer's shipping address, and we should move the order to the delivery step (don't forget to replace the placeholders with the customer's data):
```bash Update order [expandable] theme={"theme":"night-owl"}
curl -X PATCH /api/v2/storefront/checkout \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"order": {
"ship_address_attributes": {
"quick_checkout": true,
"firstname": ,
"lastname": ,
"city": ,
"zipcode": ,
"country_iso": ,
"state_name":
},
"bill_address_id": "CLEAR"
}
}'
```
`true` indicating that the order is from quick checkout. It is required as the address details you will receive from Apple Pay or Google Pay are not complete and wouldn't be valid for the standard checkout.
Customer's first name, e.g. John
Customer's last name, e.g. Doe
Customer's city, e.g. Mountain View
Customer's zip code, e.g. 94043
Customer's country ISO, e.g. US
Customer's address state, e.g. CA (empty string is also accepted)
Set it to `CLEAR` to clear the existing billing address (this prevents the order from accidentally advancing to the `payment` step).
[Full documentation](/docs/api-reference/storefront/checkout/update-checkout)
[Endpoint documentation](/docs/api-reference/storefront/checkout-state/advance-checkout)
```bash Advance order to the delivery step theme={"theme":"night-owl"}
curl -X PATCH '/api/v2/storefront/checkout/advance?state=delivery&include=shipments.shipping_rates' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"quick_checkout": true,
"shipping_method_id":
}'
```
`true` indicating that the order is from quick checkout
You don't have to send `shipping_method_id` if you don't have it yet, but if you received `Shipping Method/Rate changed` event, and you already have the selected shipping method, then you can send it.
This will return you an order response, and you can update the payment element with a new total (you should use `total_minus_store_credits` for total) and shipping rates.
### Shipping Method/Rate change
Here we need to send the selected shipping method to the backend and update the total in the payment element
[Endpoint documentation](/docs/api-reference/storefront/checkout-shipments/selects-shipping-method-for-shipments)
```bash Select shipping method theme={"theme":"night-owl"}
curl -X PATCH '/api/v2/storefront/checkout/select_shipping_method' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"shipping_method_id":
}'
```
Shipping method ID of the selected shipping rate
Subsequently, update the payment element with a new total taken from the response's `total_minus_store_credits`
### Confirming the payment
Now you should make several more calls to the backend
```bash Validate order for payment theme={"theme":"night-owl"}
curl -X POST '/api/v2/storefront/checkout/validate_order_for_payment?skip_state=true' \
-H 'Authorization: Bearer '
```
`200` response code means that the order is ready for the payment.
[Endpoint documentation](/docs/api-reference/storefront/checkout/validate-order-payment)
You should have a lot more information about the customer (in previous events, Stripe probably will not provide you information such as customer address), so send them to the backend:
[Endpoint documentation](/docs/api-reference/storefront/checkout/update-checkout)
```bash Update the order [expandable] theme={"theme":"night-owl"}
curl -X PATCH /api/v2/storefront/checkout \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"order": {
"email": ,
"ship_address_attributes": {
"quick_checkout": true,
"firstname": ,
"lastname": ,
"address1": ,
"address2": ,
"city": ,
"zipcode": ,
"country_iso": ,
"state_name": ,
"phone":
}
},
"do_not_change_state": true
}'
```
Customer's email, e.g. [email@example.com](mailto:email@example.com)
`true` indicating that the order is from quick checkout
Customer's first name, e.g. John
Customer's last name, e.g. Doe
Customer's address, e.g. 123 Main St
Customer's address 2, e.g., Apt. 1
Customer's zip code, e.g. 94043
Customer's country ISO, e.g. US
Customer's address state, e.g. CA (empty string is also accepted)
Customer's phone number, e.g. +1234567890
Set it to `true` so the order does not advance to the next state
[Endpoint documentation](/docs/api-reference/storefront/checkout-state/advance-checkout)
```bash Move the order to the payment step theme={"theme":"night-owl"}
curl -X PATCH '/api/v2/storefront/checkout/advance?state=payment' \
-H 'Authorization: Bearer ' \
-d '{
"shipping_method_id":
}'
```
Shipping method ID of the selected shipping rate
Thereafter, you should confirm the payment intent using the Stripe library; this depends on your platform/language.
`` should be Spree's internal payment intent ID, which you will receive when you create the payment intent. Do not confuse it with Stripe's payment intent ID.
If you like to redirect the user to Spree's order summary page, then set the `return_url` when confirming the payment intent to `/stripe/payment_intents/`. This will check if the payment intent is confirmed, move the order to the complete state, and redirect the user to the order summary.
If you like to make the order summary page by yourself, then after confirming the payment intent in Stripe, make this request:
```bash Confirm payment intent theme={"theme":"night-owl"}
curl -X POST /api/v2/storefront/stripe/payment_intents//confirm \
-H 'Authorization: Bearer '
```
[Endpoint documentation](/docs/api-reference/storefront/stripe/mark-the-payment-intent-as-confirmed-and-move-the-order-to-the-complete-state)
This will also check if the payment intent is confirmed, and it will move the order to the complete state
### User cancels the payment
If at any point, the user cancels the payment (closes the quick checkout sheet/modal), you will need to handle this event and clear the shipping and billing address from the order as these addresses will not be valid and if someones decides to use standard checkout it could lead to errors.
```bash Reset order addresses theme={"theme":"night-owl"}
curl -X PATCH /api/v2/storefront/checkout \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"order": {
"ship_address_id": "CLEAR",
"bill_address_id": "CLEAR"
}
}'
```
[Endpoint documentation](/docs/api-reference/storefront/checkout/update-checkout)
# Fetching multiple resources
Source: https://spreecommerce.org/docs/api-reference/v2/fetching-multiple-resources
Spree APIs allow you to fetch multiple associated resources in one API call, both for singular resources and collections, eg. we can fetch a Product with all of its variants and images:
```curl theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products/classic-varsity-top?include=variants%252Cimages' \
--header 'Accept: application/vnd.api+json'
```
This will return a JSON response with `data[relationships]` node (links to what resources connects to which) and `included` node (images and variants JSON responses).
This way you can easily control what resources you want to include in the response and
avoid making multiple API calls.
## Nested resources
You can also nest resources, eg. fetching Product Variants with their Option Values:
```curl theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products/classic-varsity-top?include=variants.option_values' \
--header 'Accept: application/vnd.api+json'
```
## Open source libraries to transform JSONApi to a flat JSON response
As you probably noticed the JSON response can sometimes be quite big and hard to follow. To ease working with included resources we recommend checking out [one of the open-source libraries](https://jsonapi.org/implementations/) that can help deserialize responses.
# Filtering and sorting
Source: https://spreecommerce.org/docs/api-reference/v2/filtering-and-sorting
## Filtering
You can filter out collection results by applying filter parameters to your API calls, eg.
```curl theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products' \
--header 'Accept: application/vnd.api+json' \
--data-urlencode 'filter[skus]=classic-varsity-top-large'
```
You can combine multiple filters to find only records that match both criteria:
```http theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products' \
--header 'Accept: application/vnd.api+json' \
--data-urlencode 'filter[price]=10,100' \
--data-urlencode 'filter[name]=Classic Varsity'
```
[Products list endpoint ](https://developers.spreecommerce.org/reference/products-list) covers how to filter by these attributes in more detail.
## Sorting
Sorting is being performed by supplying `sort` parameter in your API calls.
Ascending sort, eg.
```curl theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products?sort=price' \
--header 'Accept: application/vnd.api+json'
```
Descending sort is performed by adding `-` before the column name, eg:
```curl theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products?sort=-price' \
--header 'Accept: application/vnd.api+json'
```
You can also combine multiple attributes:
```curl theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products' \
--data-urlencode 'sort=-price,updated_at' \
--header 'Accept: application/vnd.api+json'
```
Each endpoint includes a list of attributes you can sort by. The default ones are always `id`, `created_at`, `updated_at` and `name`.
# Ecommerce API
Source: https://spreecommerce.org/docs/api-reference/v2/introduction
Spree open-source comes with a fully-featured Ecommerce API for headless eCommerce apps.
Spree Commerce open-source comes with a fully-featured Ecommerce API enabling a fully headless mode. This means that you can use Spree as a backend to build your custom [Next.js storefront](https://spreecommerce.org/category/next-js-ecommerce/), eCommerce mobile app functionality, or any other customer-facing application that needs to interact with an e-commerce platform.
## API v2
Currently Spree includes 2 modern REST APIs:
Designed to allow customers to interact with the store via external applications (e.g. Next.js storefront or a dedicated mobile app)
Provides management capabilities, allowing third party apps to perform actions otherwise available via the admin panel.
## Thank you!
Give Spree a [GitHub Star](https://github.com/spree/spree), why don't ya? Thank you for supporting Spree open-source!
Need support or want to give some feedback? Join our [Discord](https://discord.spreecommerce.org/)
# Pagination
Source: https://spreecommerce.org/docs/api-reference/v2/pagination
All lists implement the same method for pagination with `page` and `per_page` parameters, eg.
```curl theme={"theme":"night-owl"}
curl --request GET \
--url 'https://demo.spreecommerce.org/api/v2/storefront/products?page=1&per_page=25' \
--header 'Accept: application/vnd.api+json'
```
Both of these parameters are optional. There is a limit of 500 records that can be fetched by a single request. If this doesn't work for your use case, please contact us so we can work on resolving this issue.
Response for that call will include a `meta` node with:
```json theme={"theme":"night-owl"}
"meta": {
"count": 25,
"total_count": 26,
"total_pages": 2
}
```
`count` is the number of records returned on the current page\
`total_count` is the total number of records in the collection\
`total_pages` is the total number of pages
The response will also include the`links` node:
```json theme={"theme":"night-owl"}
"links": {
"self": "https://demo.spreecommerce.org/api/v2/storefront/products?per_page=25",
"next": "https://demo.spreecommerce.org/api/v2/storefront/products?page=2&per_page=25",
"prev": "https://demo.spreecommerce.org/api/v2/storefront/products?page=1&per_page=25",
"last": "https://demo.spreecommerce.org/api/v2/storefront/products?page=2&per_page=25",
"first": "https://demo.spreecommerce.org/api/v2/storefront/products?page=1&per_page=25"
}
```
With fully generates API URLs for pagination.
# Webhook Events & Payloads
Source: https://spreecommerce.org/docs/api-reference/webhooks-events
Complete reference of all webhook event types and their payload schemas
Every webhook delivery sends a JSON envelope with the event metadata and a `data` object containing the serialized resource:
```json theme={"theme":"night-owl"}
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "order.completed",
"created_at": "2025-01-15T10:30:00Z",
"data": { ... },
"metadata": {
"spree_version": "5.4.0"
}
}
```
| Field | Type | Description |
| ------------ | ------ | ------------------------------------------ |
| `id` | string | Unique UUID for this event |
| `name` | string | Event name (e.g., `order.completed`) |
| `created_at` | string | ISO 8601 timestamp |
| `data` | object | Serialized resource (see payloads below) |
| `metadata` | object | Additional context including Spree version |
Event payloads use the same [Store API V3 serializers](/docs/api-reference/introduction) as the REST API. All `id` fields use [prefixed IDs](/docs/api-reference/introduction) (e.g., `or_m3Rp9wXz`, `prod_86Rf07xd4z`). All monetary values are strings. All timestamps are ISO 8601.
For details on creating webhook endpoints and verifying signatures, see [Webhooks](/docs/developer/core-concepts/webhooks). For the event system internals and subscriber pattern, see [Events](/docs/developer/core-concepts/events).
Event payloads include the same top-level attributes and unconditional associations as API responses. Conditional associations (like product variants, media, or custom fields) are not included in event payloads.
***
## Order Events
Events: `order.created`, `order.updated`, `order.completed`, `order.canceled`, `order.resumed`, `order.paid`, `order.shipped`
Order payloads include nested `items`, `fulfillments` (the Store API name for shipments), `payments`, `billing_address`, `shipping_address`, `payment_methods`, and `discounts`.
```json theme={"theme":"night-owl"}
{
"id": "or_m3Rp9wXz",
"number": "R123456789",
"state": "complete",
"token": "abc123def456",
"email": "customer@example.com",
"special_instructions": null,
"currency": "USD",
"item_count": 3,
"fulfillment_status": "shipped",
"payment_state": "paid",
"item_total": "89.99",
"display_item_total": "$89.99",
"delivery_total": "10.00",
"display_delivery_total": "$10.00",
"adjustment_total": "0.00",
"display_adjustment_total": "$0.00",
"promo_total": "0.00",
"display_promo_total": "$0.00",
"tax_total": "0.00",
"display_tax_total": "$0.00",
"included_tax_total": "0.00",
"display_included_tax_total": "$0.00",
"additional_tax_total": "0.00",
"display_additional_tax_total": "$0.00",
"total": "99.99",
"display_total": "$99.99",
"completed_at": "2025-01-15T10:30:00Z",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:30:00Z",
"promotions": [],
"items": [
{
"id": "li_7xRt4wPq",
"variant_id": "var_k5nR8xLq",
"quantity": 2,
"currency": "USD",
"name": "Spree Tote Bag",
"slug": "spree-tote-bag",
"options_text": "Size: M, Color: Black",
"price": "29.99",
"display_price": "$29.99",
"total": "59.98",
"display_total": "$59.98",
"thumbnail_url": "https://cdn.example.com/images/tote-bag.jpg",
"option_values": [],
"digital_links": [],
"..."
}
],
"fulfillments": [
{
"id": "ful_9xPq4wMn",
"number": "H123456789",
"status": "shipped",
"fulfillment_type": "shipping",
"tracking": "1Z999AA10123456784",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=1Z999AA10123456784",
"cost": "10.00",
"display_cost": "$10.00",
"fulfilled_at": "2025-01-16T14:00:00Z",
"delivery_method": { "id": "dm_2wMn7xRt", "..." },
"stock_location": { "id": "sl_2wMn7xRt", "..." },
"delivery_rates": [],
"..."
}
],
"payments": [
{
"id": "pay_3wXz7mRp",
"state": "completed",
"number": "P123456",
"amount": "99.99",
"display_amount": "$99.99",
"response_code": "ch_abc123",
"payment_method_id": "pm_4xLq8nRt",
"source_type": "credit_card",
"source_id": "cc_5wPq9mXz",
"source": { "..." },
"payment_method": { "id": "pm_4xLq8nRt", "..." },
"..."
}
],
"bill_address": {
"id": "addr_1xPq2wMn",
"..."
},
"ship_address": {
"id": "addr_2wMn3xPq",
"..."
},
"payment_methods": [
{ "id": "pm_4xLq8nRt", "..." }
]
}
```
## Line Item Events
Events: `line_item.created`, `line_item.updated`, `line_item.deleted`
Line item payloads include nested `option_values` and `digital_links`.
```json theme={"theme":"night-owl"}
{
"id": "li_7xRt4wPq",
"variant_id": "var_k5nR8xLq",
"quantity": 2,
"currency": "USD",
"name": "Spree Tote Bag",
"slug": "spree-tote-bag",
"options_text": "Size: M, Color: Black",
"price": "29.99",
"display_price": "$29.99",
"total": "59.98",
"display_total": "$59.98",
"adjustment_total": "0.00",
"display_adjustment_total": "$0.00",
"additional_tax_total": "2.40",
"display_additional_tax_total": "$2.40",
"included_tax_total": "0.00",
"display_included_tax_total": "$0.00",
"promo_total": "-5.00",
"display_promo_total": "-$5.00",
"pre_tax_amount": "54.98",
"display_pre_tax_amount": "$54.98",
"discounted_amount": "54.98",
"display_discounted_amount": "$54.98",
"compare_at_amount": null,
"display_compare_at_amount": null,
"thumbnail_url": "https://cdn.example.com/images/tote-bag.jpg",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"option_values": [
{ "id": "ov_2wMn9xPq", "name": "M", "presentation": "Medium" }
],
"digital_links": []
}
```
## Payment Events
Events: `payment.created`, `payment.updated`, `payment.paid`
Payment payloads include a nested `payment_method` and polymorphic `source` (credit card, store credit, or payment source).
```json theme={"theme":"night-owl"}
{
"id": "pay_3wXz7mRp",
"state": "completed",
"number": "P123456",
"amount": "99.99",
"display_amount": "$99.99",
"response_code": "ch_abc123",
"payment_method_id": "pm_4xLq8nRt",
"source_type": "credit_card",
"source_id": "cc_5wPq9mXz",
"source": {
"id": "cc_5wPq9mXz",
"..."
},
"payment_method": {
"id": "pm_4xLq8nRt",
"..."
},
"created_at": "2025-01-15T10:25:00Z",
"updated_at": "2025-01-15T10:25:00Z"
}
```
The `source_type` field is normalized to one of: `"credit_card"`, `"store_credit"`, `"payment_source"`, or `null`.
## Payment Session Events
Events: `payment_session.created`, `payment_session.updated`, `payment_session.deleted`
Payment session payloads include a nested `payment_method` and optionally a nested `payment`.
```json theme={"theme":"night-owl"}
{
"id": "ps_6nRt2xLq",
"status": "pending",
"amount": "99.99",
"currency": "USD",
"external_id": "pi_3abc123",
"external_data": {},
"customer_external_id": null,
"order_id": "or_m3Rp9wXz",
"payment_method_id": "pm_4xLq8nRt",
"payment_method": {
"id": "pm_4xLq8nRt",
"..."
},
"expires_at": "2025-01-15T11:00:00Z",
"created_at": "2025-01-15T10:25:00Z",
"updated_at": "2025-01-15T10:25:00Z"
}
```
## Payment Setup Session Events
Events: `payment_setup_session.created`, `payment_setup_session.updated`, `payment_setup_session.deleted`
Payment setup session payloads include a nested `payment_method`.
```json theme={"theme":"night-owl"}
{
"id": "pss_8mXz3wPq",
"status": "pending",
"external_id": "seti_abc123",
"external_client_secret": "seti_abc123_secret_xyz",
"external_data": {},
"payment_method_id": "pm_4xLq8nRt",
"payment_source_id": "cc_5wPq9mXz",
"payment_source_type": "Spree::CreditCard",
"customer_id": "usr_k5nR8xLq",
"payment_method": {
"id": "pm_4xLq8nRt",
"..."
},
"created_at": "2025-01-15T10:25:00Z",
"updated_at": "2025-01-15T10:25:00Z"
}
```
## Shipment Events
Events: `shipment.created`, `shipment.updated`, `shipment.shipped`, `shipment.canceled`, `shipment.resumed`
The Store API/SDK exposes shipments as `fulfillments`, and webhook payloads use the same V3 serializer. Payloads include nested `delivery_method`, `stock_location`, and `delivery_rates`.
```json theme={"theme":"night-owl"}
{
"id": "ful_9xPq4wMn",
"number": "H123456789",
"status": "shipped",
"fulfillment_type": "shipping",
"tracking": "1Z999AA10123456784",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=1Z999AA10123456784",
"cost": "10.00",
"display_cost": "$10.00",
"fulfilled_at": "2025-01-16T14:00:00Z",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-16T14:00:00Z",
"delivery_method": {
"id": "dm_2wMn7xRt",
"..."
},
"stock_location": {
"id": "sl_2wMn7xRt",
"..."
},
"delivery_rates": []
}
```
## Product Events
Events: `product.created`, `product.updated`, `product.deleted`, `product.activate`, `product.archive`, `product.out_of_stock`, `product.back_in_stock`
Product event payloads include pricing, stock status, and availability flags. Conditional associations (variants, media, option types, categories, custom fields) are not included in event payloads.
```json theme={"theme":"night-owl"}
{
"id": "prod_86Rf07xd4z",
"name": "Spree Tote Bag",
"slug": "spree-tote-bag",
"description": "A beautiful tote bag",
"meta_description": null,
"meta_keywords": null,
"variant_count": 3,
"default_variant_id": "var_k5nR8xLq",
"thumbnail_url": "https://cdn.example.com/images/tote-bag.jpg",
"purchasable": true,
"in_stock": true,
"backorderable": false,
"available": true,
"tags": ["summer", "accessories"],
"price": {
"id": "pri_4wPq9mXz",
"amount": "29.99",
"amount_in_cents": 2999,
"display_amount": "$29.99",
"compare_at_amount": null,
"compare_at_amount_in_cents": null,
"display_compare_at_amount": null,
"currency": "USD",
"price_list_id": null
},
"original_price": null,
"available_on": "2025-01-01T00:00:00Z",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
```
## Variant Events
Events: `variant.created`, `variant.updated`, `variant.deleted`
Variant event payloads include pricing, stock status, and always-included `option_values`. Conditional associations (media, custom fields) are not included in event payloads.
```json theme={"theme":"night-owl"}
{
"id": "var_k5nR8xLq",
"product_id": "prod_86Rf07xd4z",
"sku": "SPR-TOTE-BLK",
"is_master": false,
"options_text": "Size: M, Color: Black",
"track_inventory": true,
"media_count": 2,
"thumbnail": "https://cdn.example.com/images/tote-bag-black.jpg",
"purchasable": true,
"in_stock": true,
"backorderable": false,
"weight": 0.5,
"height": 40.0,
"width": 35.0,
"depth": 10.0,
"price": {
"id": "pri_4wPq9mXz",
"amount": "29.99",
"amount_in_cents": 2999,
"display_amount": "$29.99",
"compare_at_amount": null,
"compare_at_amount_in_cents": null,
"display_compare_at_amount": null,
"currency": "USD",
"price_list_id": null
},
"original_price": null,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"option_values": [
{ "id": "ov_2wMn9xPq", "name": "M", "presentation": "Medium" },
{ "id": "ov_3xLq8nRt", "name": "Black", "presentation": "Black" }
]
}
```
## Price Events
Events: `price.created`, `price.updated`, `price.deleted`
```json theme={"theme":"night-owl"}
{
"id": "pri_4wPq9mXz",
"amount": "29.99",
"amount_in_cents": 2999,
"display_amount": "$29.99",
"compare_at_amount": "39.99",
"compare_at_amount_in_cents": 3999,
"display_compare_at_amount": "$39.99",
"currency": "USD",
"price_list_id": null
}
```
## Image Events
Events: `image.created`, `image.updated`, `image.deleted`
Image payloads include URLs for all configured image variants (mini, small, medium, large, xlarge).
```json theme={"theme":"night-owl"}
{
"id": "img_5mXz3wPq",
"type": "Spree::Image",
"viewable_type": "Spree::Variant",
"viewable_id": "var_k5nR8xLq",
"position": 1,
"alt": "Black tote bag front view",
"original_url": "https://cdn.example.com/images/original.jpg",
"mini_url": "https://cdn.example.com/images/mini.jpg",
"small_url": "https://cdn.example.com/images/small.jpg",
"medium_url": "https://cdn.example.com/images/medium.jpg",
"large_url": "https://cdn.example.com/images/large.jpg",
"xlarge_url": "https://cdn.example.com/images/xlarge.jpg",
"og_image_url": "https://cdn.example.com/images/og.jpg",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
```
## Stock Item Events
Events: `stock_item.created`, `stock_item.updated`, `stock_item.deleted`
```json theme={"theme":"night-owl"}
{
"id": "si_6nRt2xLq",
"count_on_hand": 25,
"backorderable": false,
"stock_location_id": "sl_2wMn7xRt",
"variant_id": "var_k5nR8xLq",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
```
## Stock Movement Events
Events: `stock_movement.created`, `stock_movement.updated`, `stock_movement.deleted`
```json theme={"theme":"night-owl"}
{
"id": "sm_7xRt4wPq",
"quantity": -1,
"action": "sold",
"originator_type": "Spree::Shipment",
"originator_id": "ful_9xPq4wMn",
"stock_item_id": "si_6nRt2xLq",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
```
## Stock Transfer Events
Events: `stock_transfer.created`, `stock_transfer.updated`, `stock_transfer.deleted`
```json theme={"theme":"night-owl"}
{
"id": "st_8mXz3wPq",
"number": "T123456789",
"type": "Spree::StockTransfer",
"reference": "Warehouse rebalance",
"source_location_id": "sl_2wMn7xRt",
"destination_location_id": "sl_9xPq4wMn",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
```
## Customer Events
Events: `customer.created`, `customer.updated`, `customer.deleted`
Customer payloads include nested `addresses`, `default_billing_address`, and `default_shipping_address`.
```json theme={"theme":"night-owl"}
{
"id": "usr_k5nR8xLq",
"email": "customer@example.com",
"first_name": "John",
"last_name": "Doe",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"addresses": [],
"default_billing_address": null,
"default_shipping_address": null
}
```
## Promotion Events
Events: `promotion.created`, `promotion.updated`, `promotion.deleted`
```json theme={"theme":"night-owl"}
{
"id": "promo_2wMn9xPq",
"name": "Summer Sale 20% Off",
"description": "20% off all summer items",
"code": "SUMMER20",
"type": "Spree::Promotion",
"kind": "coupon",
"path": null,
"match_policy": "all",
"usage_limit": 1000,
"advertise": true,
"multi_codes": false,
"code_prefix": null,
"number_of_codes": null,
"starts_at": "2025-06-01T00:00:00Z",
"expires_at": "2025-08-31T23:59:59Z",
"promotion_category_id": "pcat_3xLq8nRt",
"created_at": "2025-05-15T10:00:00Z",
"updated_at": "2025-05-15T10:00:00Z"
}
```
## Gift Card Events
Events: `gift_card.created`, `gift_card.updated`, `gift_card.deleted`
```json theme={"theme":"night-owl"}
{
"id": "gc_4xLq8nRt",
"code": "****-1234",
"state": "active",
"amount": 50.0,
"amount_used": 15.0,
"amount_authorized": 0.0,
"amount_remaining": 35.0,
"display_amount": "$50.00",
"display_amount_used": "$15.00",
"display_amount_remaining": "$35.00",
"currency": "USD",
"expired": false,
"active": true,
"expires_at": "2026-01-01T00:00:00Z",
"redeemed_at": "2025-02-01T10:00:00Z",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-02-01T10:00:00Z"
}
```
The gift card `code` is displayed as a masked value (e.g., `****-1234`) for security.
## Gift Card Batch Events
Events: `gift_card_batch.created`, `gift_card_batch.updated`, `gift_card_batch.deleted`
```json theme={"theme":"night-owl"}
{
"id": "gcb_5wPq9mXz",
"codes_count": 100,
"amount": "25.00",
"currency": "USD",
"prefix": "HOLIDAY",
"expires_at": "2026-12-31T00:00:00Z",
"created_by_id": "adm_8mXz3wPq",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
```
## Store Credit Events
Events: `store_credit.created`, `store_credit.updated`, `store_credit.deleted`
```json theme={"theme":"night-owl"}
{
"id": "sc_6nRt2xLq",
"amount": "100.00",
"amount_used": "25.00",
"amount_remaining": "75.00",
"display_amount": "$100.00",
"display_amount_used": "$25.00",
"display_amount_remaining": "$75.00",
"currency": "USD"
}
```
## Refund Events
Events: `refund.created`, `refund.updated`, `refund.deleted`
```json theme={"theme":"night-owl"}
{
"id": "ref_7xRt4wPq",
"amount": "29.99",
"transaction_id": "txn_abc123",
"payment_id": "pay_3wXz7mRp",
"refund_reason_id": "rr_2wMn9xPq",
"reimbursement_id": "rei_3xLq8nRt",
"created_at": "2025-01-20T10:00:00Z",
"updated_at": "2025-01-20T10:00:00Z"
}
```
## Reimbursement Events
Events: `reimbursement.created`, `reimbursement.updated`, `reimbursement.deleted`
```json theme={"theme":"night-owl"}
{
"id": "rei_3xLq8nRt",
"number": "RI123456789",
"reimbursement_status": "reimbursed",
"total": "29.99",
"order_id": "or_m3Rp9wXz",
"customer_return_id": "cr_4xLq8nRt",
"created_at": "2025-01-20T10:00:00Z",
"updated_at": "2025-01-20T10:00:00Z"
}
```
## Return Authorization Events
Events: `return_authorization.created`, `return_authorization.updated`, `return_authorization.deleted`
```json theme={"theme":"night-owl"}
{
"id": "ra_8mXz3wPq",
"number": "RA123456789",
"state": "authorized",
"order_id": "or_m3Rp9wXz",
"stock_location_id": "sl_2wMn7xRt",
"return_authorization_reason_id": "rar_9xPq4wMn",
"created_at": "2025-01-18T10:00:00Z",
"updated_at": "2025-01-18T10:00:00Z"
}
```
## Return Item Events
Events: `return_item.created`, `return_item.updated`, `return_item.deleted`
```json theme={"theme":"night-owl"}
{
"id": "ri_9xPq4wMn",
"reception_status": "received",
"acceptance_status": "accepted",
"pre_tax_amount": "29.99",
"included_tax_total": "0.00",
"additional_tax_total": "2.40",
"inventory_unit_id": "iu_2wMn7xRt",
"return_authorization_id": "ra_8mXz3wPq",
"customer_return_id": "cr_4xLq8nRt",
"reimbursement_id": "rei_3xLq8nRt",
"exchange_variant_id": null,
"created_at": "2025-01-19T10:00:00Z",
"updated_at": "2025-01-19T10:00:00Z"
}
```
## Customer Return Events
Events: `customer_return.created`, `customer_return.updated`, `customer_return.deleted`
```json theme={"theme":"night-owl"}
{
"id": "cr_4xLq8nRt",
"number": "CR123456789",
"stock_location_id": "sl_2wMn7xRt",
"created_at": "2025-01-19T10:00:00Z",
"updated_at": "2025-01-19T10:00:00Z"
}
```
## Wishlist Events
Events: `wishlist.created`, `wishlist.updated`, `wishlist.deleted`
Wishlist items are a conditional association and are not included in event payloads.
```json theme={"theme":"night-owl"}
{
"id": "wl_5wPq9mXz",
"name": "My Wishlist",
"token": "abc123def456",
"is_default": true,
"is_private": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
```
## Wished Item Events
Events: `wished_item.created`, `wished_item.updated`, `wished_item.deleted`
Wished item payloads include a nested `variant`.
```json theme={"theme":"night-owl"}
{
"id": "wi_6nRt2xLq",
"variant_id": "var_k5nR8xLq",
"wishlist_id": "wl_5wPq9mXz",
"quantity": 1,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"variant": {
"id": "var_k5nR8xLq",
"..."
}
}
```
## Post Events
Events: `post.created`, `post.updated`, `post.deleted`
```json theme={"theme":"night-owl"}
{
"id": "post_7xRt4wPq",
"title": "Summer Collection 2025",
"slug": "summer-collection-2025",
"meta_title": "Summer Collection | My Store",
"meta_description": "Discover our new summer collection",
"published_at": "2025-06-01T00:00:00Z",
"author_id": "adm_8mXz3wPq",
"post_category_id": "pcat_9xPq4wMn",
"created_at": "2025-05-15T10:00:00Z",
"updated_at": "2025-05-15T10:00:00Z"
}
```
## Post Category Events
Events: `post_category.created`, `post_category.updated`, `post_category.deleted`
```json theme={"theme":"night-owl"}
{
"id": "pcat_9xPq4wMn",
"title": "News",
"slug": "news",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
```
## Newsletter Subscriber Events
Events: `newsletter_subscriber.created`, `newsletter_subscriber.updated`, `newsletter_subscriber.deleted`
```json theme={"theme":"night-owl"}
{
"id": "ns_2wMn9xPq",
"email": "subscriber@example.com",
"verified": true,
"verified_at": "2025-01-02T10:00:00Z",
"user_id": "usr_k5nR8xLq",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-02T10:00:00Z"
}
```
## Digital Product Events
Events: `digital.created`, `digital.updated`, `digital.deleted`
```json theme={"theme":"night-owl"}
{
"id": "dig_3xLq8nRt",
"variant_id": "var_k5nR8xLq",
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
```
## Digital Link Events
Events: `digital_link.created`, `digital_link.updated`, `digital_link.deleted`
```json theme={"theme":"night-owl"}
{
"id": "dl_4xLq8nRt",
"access_counter": 3,
"filename": "ebook.pdf",
"content_type": "application/pdf",
"download_url": "/api/v3/store/digital_downloads/abc123",
"authorizable": true,
"expired": false,
"access_limit_exceeded": false,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T12:00:00Z"
}
```
## Import Events
Events: `import.created`, `import.updated`, `import.deleted`
```json theme={"theme":"night-owl"}
{
"id": "imp_5wPq9mXz",
"number": "I123456789",
"type": "Spree::Imports::Products",
"status": "completed",
"owner_type": "Spree::Store",
"owner_id": "str_9xPq2wMn",
"user_id": "adm_8mXz3wPq",
"rows_count": 150,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:05:00Z"
}
```
## Import Row Events
Events: `import_row.created`, `import_row.updated`, `import_row.deleted`
```json theme={"theme":"night-owl"}
{
"id": "ir_6nRt2xLq",
"import_id": "imp_5wPq9mXz",
"row_number": 42,
"status": "success",
"validation_errors": [],
"item_type": "Spree::Product",
"item_id": "prod_86Rf07xd4z",
"created_at": "2025-01-15T10:01:00Z",
"updated_at": "2025-01-15T10:01:00Z"
}
```
## Export Events
Events: `export.created`, `export.updated`, `export.deleted`
```json theme={"theme":"night-owl"}
{
"id": "exp_7xRt4wPq",
"number": "E123456789",
"type": "Spree::Exports::Products",
"format": "csv",
"user_id": "adm_8mXz3wPq",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:02:00Z"
}
```
## Report Events
Events: `report.created`, `report.updated`, `report.deleted`
```json theme={"theme":"night-owl"}
{
"id": "rep_8mXz3wPq",
"type": "Spree::Reports::SalesByProduct",
"user_id": "adm_8mXz3wPq",
"currency": "USD",
"date_from": "2025-01-01T00:00:00Z",
"date_to": "2025-01-31T23:59:59Z",
"created_at": "2025-02-01T10:00:00Z",
"updated_at": "2025-02-01T10:00:00Z"
}
```
## Invitation Events
Events: `invitation.created`, `invitation.updated`, `invitation.deleted`
```json theme={"theme":"night-owl"}
{
"id": "inv_9xPq4wMn",
"email": "newadmin@example.com",
"status": "pending",
"resource_type": "Spree::Store",
"resource_id": "str_9xPq2wMn",
"inviter_type": "Spree::AdminUser",
"inviter_id": "adm_8mXz3wPq",
"invitee_type": null,
"invitee_id": null,
"role_id": "role_2wMn9xPq",
"expires_at": "2025-02-15T10:00:00Z",
"accepted_at": null,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
```
# Admin Dashboard
Source: https://spreecommerce.org/docs/developer/admin/admin
Customize and extend the Spree Admin Dashboard to manage products, orders, customers, promotions, and store settings for your ecommerce platform.
The Spree Admin Dashboard is a full-featured administration interface for managing your e-commerce store.
## What You Can Do
The Admin Dashboard allows store administrators to manage:
* **Products** - Create and manage products, variants, images, and inventory
* **Orders** - Process orders, refunds, and shipments
* **Customers** - View customer accounts and order history
* **Promotions** - Create discounts, coupon codes, and special offers
* **Settings** - Configure store settings, shipping, taxes, and payments
## Customization Options
As a developer, you can fully customize the Admin Dashboard:
Create entirely new admin pages for custom features like Brands, Vendors, or any custom model
Inject custom fields, buttons, and sections into existing admin pages
Add menu items to the sidebar or create custom navigation structures
Add your own CSS to match your brand or modify the look and feel
## Architecture Overview
Spree Admin follows standard Rails conventions with some Spree-specific patterns:
```
app/
├── controllers/
│ └── spree/
│ └── admin/
│ └── products_controller.rb # Your custom controllers
├── views/
│ └── spree/
│ └── admin/
│ └── products/
│ ├── index.html.erb # List view
│ ├── _form.html.erb # Shared form partial
│ └── _table_row.html.erb # Table row partial
├── helpers/
│ └── spree/
│ └── admin/
│ └── products_helper.rb # View helpers
└── assets/
└── tailwind/
└── spree_admin.css # Custom Tailwind styles
```
## Key Concepts
### Controllers
Admin controllers inherit from `Spree::Admin::ResourceController` which provides:
* Full CRUD operations (index, new, create, edit, update, destroy)
* Automatic authorization checks
* Flash messages and redirects
* Search and filtering with Ransack
```ruby theme={"theme":"night-owl"}
# app/controllers/spree/admin/brands_controller.rb
module Spree
module Admin
class BrandsController < ResourceController
# That's it! CRUD is handled automatically.
# Override methods only when needed.
end
end
end
```
Learn more about creating admin sections in the [Admin Dashboard Tutorial](/docs/developer/tutorial/admin).
### Views & Templates
Views use standard Rails ERB templates with Spree's [Form Builder](/docs/developer/admin/form-builder) and [Components](/docs/developer/admin/components):
```erb theme={"theme":"night-owl"}
<%# app/views/spree/admin/brands/_form.html.erb %>
```
### JavaScript & Interactivity
Spree Admin uses [Hotwire](https://hotwire.dev/) (Turbo + Stimulus) for interactivity:
* **Turbo Drive** - Fast page navigation without full reloads
* **Turbo Frames** - Update parts of the page independently
* **Turbo Streams** - Real-time updates over WebSocket
* **Stimulus** - Lightweight JavaScript controllers
```erb theme={"theme":"night-owl"}
<%# Using Stimulus controllers %>
...
```
Add custom JavaScript using [Stimulus controllers](/docs/developer/admin/custom-javascript).
### Styling
The Admin Dashboard uses [Tailwind CSS v4](https://tailwindcss.com/) for styling. You can:
* Use Tailwind utility classes directly in your views
* Override theme variables (colors, spacing, typography)
* Add custom components using `@layer components`
```erb theme={"theme":"night-owl"}
<%# Using Tailwind utility classes in views %>
My Custom Card
Card content here
```
Learn how to customize styles in [Custom CSS](/docs/developer/admin/custom-css).
## Quick Reference
### Available Tools
| Tool | Purpose | Documentation |
| -------------- | --------------------------------------- | ------------------------------------------------- |
| Form Builder | Create consistent forms with validation | [Form Builder](/docs/developer/admin/form-builder) |
| Components | Dropdowns, dialogs, icons, badges, etc. | [Components](/docs/developer/admin/components) |
| Helper Methods | Navigation, links, utilities | [Helper Methods](/docs/developer/admin/helper-methods) |
| UI Extensions | Inject content into existing pages | [Extending UI](/docs/developer/admin/extending-ui) |
### Common Tasks
| Task | How To |
| ---------------------- | --------------------------------------------------------------------------- |
| Add a new admin page | Use the scaffold generator: `bin/rails g spree:admin:scaffold Spree::Brand` |
| Add sidebar navigation | Use `Spree.admin.navigation.sidebar.add` in an initializer |
| Add form fields | Use `f.spree_text_field`, `f.spree_select`, etc. |
| Show flash messages | They're automatic with `ResourceController` |
| Check permissions | Use `can?(:update, @product)` in views |
### Generator Commands
```bash Spree CLI (Docker) theme={"theme":"night-owl"}
# Generate a complete admin section (controller, views, routes)
spree generate spree:admin:scaffold Spree::Brand
# Generate just a controller
spree generate controller Spree::Admin::Brands --skip-routes
```
```bash Without Spree CLI theme={"theme":"night-owl"}
# Generate a complete admin section (controller, views, routes)
bin/rails g spree:admin:scaffold Spree::Brand
# Generate just a controller
bin/rails g controller Spree::Admin::Brands --skip-routes
```
## Authentication & Authorization
### Authentication
Admin users must be authenticated to access the dashboard. Spree supports:
* Built-in Devise authentication
* Custom authentication adapters
* SSO integration
See [Authentication](/docs/developer/admin/authentication) for setup details.
### Authorization
Spree uses [CanCanCan](https://github.com/CanCanCommunity/cancancan) for authorization:
```ruby theme={"theme":"night-owl"}
# Check permissions in controllers
authorize! :update, @product
# Check permissions in views
<% if can?(:destroy, @product) %>
<%= link_to_delete(@product) %>
<% end %>
```
See [Permissions](/docs/developer/customization/permissions) for defining custom abilities.
## Next Steps
Step-by-step guide to creating a complete admin section
Learn all available form field helpers
Explore UI components like dropdowns, dialogs, and icons
Add custom content to existing admin pages
# Admin Panel Authentication
Source: https://spreecommerce.org/docs/developer/admin/authentication
How to customize the Spree admin panel authentication
Spree allows you to use a different model for the admin panel than the storefront (that's the default since Spree 5.2).
Here you can find how to customize the admin panel authentication to use a different model.
Let's assume you have an existing `AdminUser` model in your application and you're using Devise for authentication.
In `config/initializers/spree.rb` file, add the following line:
```ruby theme={"theme":"night-owl"}
Spree.admin_user_class = 'AdminUser'
```
This will tell Spree to use your `AdminUser` model for the admin panel. You will also need to add the following line in that model file:
```ruby theme={"theme":"night-owl"}
include Spree::UserMethods
```
In your `config/initializers/routes.rb` file, you will need to define devise routes for the 2nd model:
```ruby theme={"theme":"night-owl"}
Spree::Core::Engine.routes.prepend_routes do
# Admin authentication
devise_for(
Spree.admin_user_class.model_name.singular_route_key,
class_name: Spree.admin_user_class.to_s,
controllers: {
sessions: 'spree/admin/user_sessions',
passwords: 'spree/admin/user_passwords'
},
skip: :registrations,
path: :admin_user,
router_name: :spree
)
end
```
And now in your `lib/spree/authentication_helpers.rb` file, please replace the following lines:
```diff theme={"theme":"night-owl"}
def spree_admin_login_path(opts = {})
- spree_login_path(opts)
+ new_admin_user_session_path(opts)
end
def spree_admin_logout_path(opts = {})
- spree_logout_path(opts)
+ destroy_admin_user_session_path(opts)
end
```
Now when attempting to access the admin panel, you will be redirected to the dedicated admin panel login page.
# Admin Components
Source: https://spreecommerce.org/docs/developer/admin/components
Spree Admin provides a set of reusable UI components that you can use in your custom admin views. These components are implemented as view helpers and integrate with Stimulus controllers for interactivity.
## Dropdown
The dropdown component creates accessible dropdown menus with automatic positioning using Floating UI.
### Basic Usage
```erb theme={"theme":"night-owl"}
<%= dropdown do %>
<%= dropdown_toggle class: 'btn-light btn-sm' do %>
<%= icon('dots-vertical', class: 'mr-0') %>
<% end %>
<%= dropdown_menu do %>
<%= link_to_with_icon 'pencil', Spree.t(:edit), edit_path, class: 'dropdown-item' %>
<%= link_to_with_icon 'trash', Spree.t(:delete), delete_path,
class: 'dropdown-item text-danger',
data: { turbo_method: :delete, turbo_confirm: Spree.t(:are_you_sure) } %>
<% end %>
<% end %>
```
### Features
* **Automatic positioning** - Uses Floating UI to position the menu optimally
* **Auto-flip** - Menu flips to stay within viewport
* **Click outside to close** - Menu closes when clicking outside
* **Escape to close** - Menu closes when pressing Escape key
* **Keyboard navigation** - Full keyboard accessibility
### `dropdown`
Creates the dropdown container with Stimulus controller.
```erb theme={"theme":"night-owl"}
<%= dropdown do %>
<% end %>
<%= dropdown placement: 'top-end' do %>
<% end %>
```
| Option | Type | Default | Description |
| ----------- | ------- | -------------- | --------------------------------------------------------------------------------- |
| `class` | String | - | Additional CSS classes |
| `placement` | String | `bottom-start` | Menu placement: `bottom-start`, `bottom-end`, `top-start`, `top-end` |
| `direction` | String | - | Legacy option: `left` → `bottom-end`, `top` → `top-start`, `top-left` → `top-end` |
| `portal` | Boolean | - | Whether to portal the dropdown to body |
| `data` | Hash | - | Additional data attributes |
### `dropdown_toggle`
Creates the button that toggles the dropdown menu.
```erb theme={"theme":"night-owl"}
<%= dropdown_toggle class: 'btn-primary' do %>
Actions <%= icon('chevron-down', class: 'ml-2') %>
<% end %>
```
| Option | Type | Default | Description |
| ------- | ------ | ------- | -------------------------------------------------- |
| `class` | String | - | Additional CSS classes (added to `btn` base class) |
| `data` | Hash | - | Additional data attributes |
### `dropdown_menu`
Creates the menu container for dropdown items.
```erb theme={"theme":"night-owl"}
<%= dropdown_menu do %>
<%= link_to 'Option 1', '#', class: 'dropdown-item' %>
<%= link_to 'Option 2', '#', class: 'dropdown-item text-danger' %>
<% end %>
```
| Option | Type | Default | Description |
| ------- | ------ | ------- | -------------------------- |
| `class` | String | - | Additional CSS classes |
| `data` | Hash | - | Additional data attributes |
### Complete Example
```erb theme={"theme":"night-owl"}
<%= content_for :page_actions do %>
<%= dropdown do %>
<%= dropdown_toggle class: 'btn-primary' do %>
<%= icon('settings', class: 'mr-2') %>
Actions
<%= icon('chevron-down', class: 'ml-2') %>
<% end %>
<%= dropdown_menu do %>
<%= link_to_with_icon 'download', 'Export CSV', export_path(format: :csv), class: 'dropdown-item' %>
<%= link_to_with_icon 'file-export', 'Export Excel', export_path(format: :xlsx), class: 'dropdown-item' %>
<%= link_to_with_icon 'upload', 'Import', import_path, class: 'dropdown-item' %>
<%= link_to_with_icon 'trash', 'Delete All', bulk_delete_path,
class: 'dropdown-item text-danger',
data: { turbo_method: :delete, turbo_confirm: Spree.t(:are_you_sure) } %>
<% end %>
<% end %>
<% end %>
```
## Dialog
Dialogs (modals) are used for focused interactions that require user attention. They overlay the page content and must be dismissed before continuing.
### Basic Usage
```erb theme={"theme":"night-owl"}
<%= dialog_header('Edit Product') %>
```
### `dialog_header`
Creates a dialog header with title and close button.
```erb theme={"theme":"night-owl"}
<%= dialog_header('Confirm Action') %>
<%= dialog_header('Custom Dialog', 'my-dialog') %>
```
| Parameter | Type | Default | Description |
| ----------------- | ------ | -------- | --------------------------------------------- |
| `title` | String | required | The dialog title |
| `controller_name` | String | `dialog` | Stimulus controller name for the close action |
**Renders:**
```html theme={"theme":"night-owl"}
Confirm Action
```
### `dialog_close_button`
Creates a standalone close button for dialogs.
```erb theme={"theme":"night-owl"}
<%= dialog_close_button %>
<%= dialog_close_button('custom-controller') %>
```
| Parameter | Type | Default | Description |
| ----------------- | ------ | -------- | ------------------------ |
| `controller_name` | String | `dialog` | Stimulus controller name |
### `dialog_discard_button`
Creates a "Discard" button that closes the dialog.
```erb theme={"theme":"night-owl"}
<%= dialog_discard_button %>
```
| Parameter | Type | Default | Description |
| ----------------- | ------ | -------- | ------------------------ |
| `controller_name` | String | `dialog` | Stimulus controller name |
**Renders:**
```html theme={"theme":"night-owl"}
```
### Complete Dialog Example
```erb theme={"theme":"night-owl"}
<%= turbo_frame_tag 'main-dialog' do %>
<%= dialog_header('Add New Item') %>
<%= form_with model: @item, url: items_path, data: { turbo_frame: '_top' } do |f| %>
<% end %>
```
## Drawer
Drawers are slide-out panels typically used for filters, secondary forms, or detailed views without leaving the current page.
### Basic Usage
```erb theme={"theme":"night-owl"}
<%= drawer_header('Filter Options') %>
```
### `drawer_header`
Creates a drawer header with title and close button.
```erb theme={"theme":"night-owl"}
<%= drawer_header('Filters') %>
<%= drawer_header('Details', 'custom-drawer') %>
```
| Parameter | Type | Default | Description |
| ----------------- | ------ | -------- | --------------------------------------------- |
| `title` | String | required | The drawer title |
| `controller_name` | String | `drawer` | Stimulus controller name for the close action |
**Renders:**
```html theme={"theme":"night-owl"}
```
## Progress Bar
Displays a progress bar with customizable range.
### Basic Usage
```erb theme={"theme":"night-owl"}
<%= progress_bar_component(75) %>
<%= progress_bar_component(150, max: 200) %>
<%= progress_bar_component(50, min: 0, max: 100) %>
```
### Options
| Option | Type | Default | Description |
| ------- | ------- | -------- | ---------------------- |
| `value` | Integer | required | Current progress value |
| `min` | Integer | 0 | Minimum value |
| `max` | Integer | 100 | Maximum value |
### Output
```html theme={"theme":"night-owl"}
```
### Examples
```erb theme={"theme":"night-owl"}
<%= progress_bar_component(stock_item.count_on_hand, max: stock_item.backorderable_threshold || 100) %>
<%= progress_bar_component(order.shipments.shipped.count, max: order.shipments.count) %>
<%= progress_bar_component(uploaded_count, max: total_count) %>
```
## Date & Time
Helpers for displaying dates and times in the user's local timezone.
### `spree_date`
Renders a date in the user's local format.
```erb theme={"theme":"night-owl"}
<%= spree_date(order.created_at) %>
<%= spree_date(product.available_on) %>
```
### `spree_time`
Renders a date and time in the user's local format.
```erb theme={"theme":"night-owl"}
<%= spree_time(order.completed_at) %>
<%= spree_time(shipment.shipped_at) %>
```
### `spree_time_ago`
Renders a relative time (e.g., "2 hours ago") with a tooltip showing the full timestamp.
```erb theme={"theme":"night-owl"}
<%= spree_time_ago(order.completed_at) %>
<%= spree_time_ago(comment.created_at) %>
```
**Output:**
```html theme={"theme":"night-owl"}
January 15, 2024 10:30 AM
```
### `local_time`
The underlying helper from [local\_time gem](https://github.com/basecamp/local_time) - displays time in user's browser timezone.
```erb theme={"theme":"night-owl"}
<%= local_time(order.completed_at) %>
<%= local_time(event.starts_at, format: '%B %e, %Y at %l:%M %p') %>
```
### Comparison
| Helper | Output | Use Case |
| ---------------- | --------------------------- | -------------------------- |
| `spree_date` | "Jan 15, 2024" | Date-only display |
| `spree_time` | "Jan 15, 2024 10:30 AM" | Full timestamp |
| `spree_time_ago` | "2 hours ago" | Relative time with tooltip |
| `local_time` | "January 15, 2024 10:30 AM" | Customizable format |
## Best Practices
**Use semantic components** - Choose the right component for the interaction (Dialog for focused tasks, Drawer for contextual panels)
**Provide feedback** - Use tooltips and badges to give users context about their actions
**Keep dropdowns focused** - Limit dropdown menus to related actions, use dividers to group items
**Use appropriate icons** - Choose icons that clearly represent the action
**Handle loading states** - Use `turbo_save_button_tag` for forms to show loading feedback
**Consider accessibility** - Components include ARIA attributes and keyboard navigation
# Admin Dashboard Custom CSS
Source: https://spreecommerce.org/docs/developer/admin/custom-css
Customize the Spree Admin Dashboard with your own CSS by overriding Tailwind variables, adding custom styles, and extending admin views and helpers.
Spree Admin Dashboard uses [Tailwind CSS v4](https://tailwindcss.com/) for styling. The stylesheet system is designed to be easily customizable while maintaining consistency with the Spree design system.
## How It Works
When you install Spree Admin, the installer creates a file at `app/assets/tailwind/spree_admin.css` in your application. This file:
1. Imports the base Spree Admin styles from the gem
2. Scans your custom admin views, helpers, and JavaScript for Tailwind classes
3. Allows you to add custom styles and override theme variables
## Using Tailwind Utility Classes
You can use any Tailwind CSS utility class in your custom admin views, helpers, or JavaScript files. The build process automatically scans these locations:
* `app/views/spree/admin/**/*.erb`
* `app/helpers/spree/admin/**/*.rb`
* `app/javascript/spree/admin/**/*.js`
Example usage in a view:
```erb theme={"theme":"night-owl"}
Custom Section
Your content here
```
## Customizing the Theme
### Overriding Theme Colors
To override Tailwind theme values, add a `@theme` block in your `app/assets/tailwind/spree_admin.css` file after the import:
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
/* Import Spree Admin base styles from the gem */
@import "$SPREE_ADMIN_PATH/app/assets/tailwind/spree/admin/index.css";
/* Override theme colors */
@theme {
--color-primary: #4F46E5; /* Change primary color to indigo */
--color-success: #059669; /* Custom success color */
--color-danger: #DC2626; /* Custom danger color */
}
```
### Available Theme Variables
The Spree Admin theme defines these customizable variables:
| Variable | Default | Description |
| ----------------- | ------------------------- | ------------------------ |
| `--color-primary` | `var(--color-zinc-950)` | Primary brand color |
| `--color-success` | `var(--color-green-900)` | Success state color |
| `--color-danger` | `var(--color-red-600)` | Error/danger state color |
| `--color-warning` | `var(--color-yellow-900)` | Warning state color |
| `--color-info` | `var(--color-blue-900)` | Info state color |
### Overriding Layout Variables
You can also customize layout-related CSS variables:
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
:root {
--spacing-sidebar-width: 280px; /* Default: 220px */
--spacing-sidebar-collapsed: 70px; /* Default: 59px */
--spacing-header-height: 64px; /* Default: 58px */
}
```
## Adding Custom Components
Use Tailwind's `@layer` directive to add custom component styles that work seamlessly with the existing design:
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
@layer components {
/* Custom card style */
.my-custom-card {
@apply bg-white rounded-lg shadow-sm border border-zinc-200 p-4;
}
/* Custom button variant */
.btn-custom {
@apply inline-flex items-center px-4 py-2 rounded-md;
@apply bg-indigo-600 text-white font-medium;
@apply hover:bg-indigo-700 transition-colors;
}
/* Custom status badge */
.status-badge {
@apply inline-flex items-center px-2 py-1 rounded-full text-xs font-medium;
}
.status-badge-active {
@apply status-badge bg-green-100 text-green-800;
}
.status-badge-inactive {
@apply status-badge bg-zinc-100 text-zinc-600;
}
}
```
## Adding Custom Utilities
For reusable utility classes, use the utilities layer:
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
@layer utilities {
.text-gradient {
@apply bg-clip-text text-transparent bg-gradient-to-r from-indigo-500 to-purple-500;
}
.scrollbar-hidden {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hidden::-webkit-scrollbar {
display: none;
}
}
```
## Scanning Additional Paths
If you have admin-related code in non-standard locations, add additional `@source` directives:
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
/* Scan host app's custom admin code for Tailwind classes */
@source "../../views/spree/admin/**/*.erb";
@source "../../helpers/spree/admin/**/*.rb";
@source "../../javascript/spree/admin/**/*.js";
/* Add your custom paths */
@source "../../components/admin/**/*.erb";
@source "../../views/admin/**/*.erb";
```
## Development Workflow
### Starting the CSS Watcher
During development, run the Tailwind CSS watcher to automatically rebuild styles when you make changes:
```bash Spree CLI (Docker) theme={"theme":"night-owl"}
spree rake spree:admin:tailwindcss:watch
```
```bash Without Spree CLI theme={"theme":"night-owl"}
bundle exec rake spree:admin:tailwindcss:watch
```
Or run the full development process, which includes the watcher when it's defined in `Procfile.dev`:
```bash Spree CLI (Docker) theme={"theme":"night-owl"}
spree dev
```
```bash Without Spree CLI theme={"theme":"night-owl"}
bin/dev
```
The watcher monitors:
* Your host app's CSS files in `app/assets/tailwind/`
* The Spree Admin engine's CSS files
* All files matching your `@source` patterns
### Building for Production
CSS is automatically compiled during asset precompilation:
```bash theme={"theme":"night-owl"}
bin/rails assets:precompile
```
## Common Customization Examples
### Custom Primary Color Scheme
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
@theme {
/* Use blue as the primary color */
--color-primary: #2563EB;
}
@layer components {
/* Ensure buttons use the new primary color */
.btn-primary {
@apply bg-blue-600 hover:bg-blue-700;
}
}
```
### Dark Mode Adjustments
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
@layer base {
/* Custom dark mode overrides */
.dark {
--color-primary: #60A5FA;
}
}
```
### Custom Form Styling
```css app/assets/tailwind/spree_admin.css theme={"theme":"night-owl"}
@layer components {
/* Custom input style */
.input-custom {
@apply block w-full rounded-md border-zinc-300 shadow-sm;
@apply focus:border-indigo-500 focus:ring-indigo-500;
}
/* Custom select style */
.select-custom {
@apply block w-full rounded-md border-zinc-300 py-2 pl-3 pr-10;
@apply focus:border-indigo-500 focus:outline-none focus:ring-indigo-500;
}
}
```
## Troubleshooting
### Changes Not Appearing
1. Ensure the watcher is running: `bin/rails spree:admin:tailwindcss:watch`
2. Check that your files are in paths covered by `@source` directives
3. Hard refresh the browser (Cmd+Shift+R or Ctrl+Shift+R)
### Missing Utility Classes
If a Tailwind class isn't working, ensure:
1. The class is used in a file that's scanned by `@source`
2. The class name is complete (not dynamically constructed)
3. Run a fresh build: `bin/rails spree:admin:tailwindcss:build`
### Listen Gem Required
The watch task requires the `listen` gem. Add it to your Gemfile:
```ruby Gemfile theme={"theme":"night-owl"}
group :development do
gem 'listen', '>= 3.0'
end
```
# Custom JavaScript for Admin Dashboard
Source: https://spreecommerce.org/docs/developer/admin/custom-javascript
Learn how to add custom JavaScript to your Spree Admin Dashboard
## Extending Admin Dashboard with JavaScript
Spree Admin Dashboard can be easily extended with custom JavaScript. Most of the JavaScript in the Admin Dashboard is powered by a framework called [Stimulus.js](https://stimulus.hotwired.dev/). It's a very simple and minimalistic framework only enhancing our server-side rendered HTML with a bit of interactivity.
### 3rd party JavaScript libraries
Spree Admin Dashboard comes with a few 3rd party JavaScript libraries already included.
Main libraries we're using:
* [Stimulus.js](https://stimulus.hotwired.dev/)
* [Turbo](https://turbo.hotwired.dev/)
* [EasyPick](https://easepick.com/) (date picker)
* [TomSelect](https://tom-select.js.org/) (autocomplete/dropdowns)
* [Sortable.js](https://github.com/SortableJS/Sortable) - sortable drag and drop lists
* [Uppy](https://uppy.io/) - file uploader
You can find them in the [app/assets/javascripts/vendor](https://github.com/spree/spree/blob/main/admin/vendor/javascript) directory.
### Managing JavaScript dependencies
You're probably wondering why these libraries are in the `vendor` directory, and not in `node_modules`.
That's because we're not using Node.js at all. So no Yarn or npm. We're using a different approach to manage dependencies.
We're using a tool called [Importmaps](https://github.com/rails/importmap-rails) to manage dependencies.
If you want to use a different JavaScript package manager you can do so by using [jsbundling-rails](https://github.com/rails/jsbundling-rails) gem.
#### Install dependencies
To install dependencies you need to run the following command:
```bash theme={"theme":"night-owl"}
bin/importmap pin react
```
This will install the dependencies, download the files to your `vendor/javascript` directory and add them to your `config/importmap.rb` file, eg.
```ruby theme={"theme":"night-owl"}
pin "react" # @19.1.0
```
Now you can just import the library in your application entry point, eg. `application.js`:
```js theme={"theme":"night-owl"}
import "react";
```
### Application entry point
Mentioned above, the application entry point is the `application.js` file. It's located in the `app/javascript` directory.
If you want to add custom JavaScript to your Spree Admin Dashboard, you can do so by adding a new file to the `app/javascript` directory.
### Stimulus Controllers
Stimulus controllers are a way to add interactivity to your Spree Admin Dashboard. Admin Dashboard controllers can be found in the Spree repository in the [Admin Dashboard/app/javascript/spree/admin/controllers](https://github.com/spree/spree/tree/main/admin/app/javascript/spree/admin/controllers) directory.
You can find more information about Stimulus controllers in the [Stimulus.js documentation](https://stimulus.hotwired.dev/handbook/controllers).
To add a new controller you need to create a new file in the `app/javascript/controllers` directory. It will be automatically picked up by the application.
```js theme={"theme":"night-owl"}
// app/javascript/controllers/hello_controller.js
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
connect() {
console.log("Hello Spree Commerce Stimulus!", this.element);
}
}
```
To use the controller in your HTML you need to add the `data-controller` attribute to your element, eg.
```html theme={"theme":"night-owl"}
Hello Spree Commerce Stimulus!
```
## JavaScript snippets
If you need to add a small piece of JavaScript code (eg. tracking, marketing, analytics, customer service etc.) you can do this by:
1. Declaring a new head partial in the `config/initializers/spree.rb` file, eg.
```ruby config/initializers/spree.rb theme={"theme":"night-owl"}
Rails.application.config.after_initialize do
Spree.admin.partials.head << 'spree/admin/shared/my_tracking_code'
end
```
```ruby config/initializers/spree.rb theme={"theme":"night-owl"}
Rails.application.config.spree_admin.head_partials << 'spree/admin/shared/my_tracking_code'
```
2. Creating a new file in the `app/views/spree/admin/shared/my_tracking_code.html.erb`, where you can add your tracking code, eg.
```erb theme={"theme":"night-owl"}
```
# Extending Admin Dashboard UI
Source: https://spreecommerce.org/docs/developer/admin/extending-ui
Inject custom partials into Spree Admin Dashboard pages using injection points to add fields, buttons, and sections without modifying core code.
Spree Admin Dashboard allows you to easily extend existing pages and screens with your own code, without any need to modify the core codebase. This allows you to easily inject your custom UI elements without compromising the integrity of the core codebase. Which in effect allows you to safely update your Spree installation to the latest version.
## How it works
The entire system works on the basis of injection points which are declared throughout the admin dashboard and allows you to push your own code there. Each injection point is identified by a key, eg. `body_end`.
Let's say you want to add a new footer to the admin dashboard. You'll need to generate a template in your application:
1. Ensure you have the proper directory to store your templates:
```bash theme={"theme":"night-owl"}
mkdir -p app/views/spree/admin/shared
```
2. Create a new partial template file (partial templates file names start with underscore)
```bash theme={"theme":"night-owl"}
touch app/views/spree/admin/shared/_additional_footer.html.erb
```
3. Add your own code to the partial
```erb theme={"theme":"night-owl"}
```
4. Register your partial in `config/initializers/spree.rb`
```ruby config/initializers/spree.rb theme={"theme":"night-owl"}
Rails.application.config.after_initialize do
Spree.admin.partials.body_end << 'spree/admin/shared/additional_footer'
end
```
```ruby config/initializers/spree.rb theme={"theme":"night-owl"}
Rails.application.config.spree_admin.body_end << 'spree/admin/shared/additional_footer_partials'
```
For older versions of Spree you need to add `_partials` suffix for all injection points,
eg. `body_end_partials` instead of `body_end`.
The key is the name of the injection point, eg. `body_end`.
Remember to use the correct path to your template file and skip the `_` prefix.
5. Restart your web server and you should see your new footer.
Making further changes to the partial template will not require you to restart the web server. They will be picked up automatically.
To summarize, we're injecting our code into the `body_end` array. This is a list of partials that will be rendered at the end of the body tag (before the closing `