Skip to content
Back to skills

Spree Api V3

ASecurity

Build with Spree's v3 APIs (v5.4+) — Store API at `/api/v3/store/*` (publishable key + per-user JWT, customer-facing) and Admin API at `/api/v3/admin/*` (per-user API keys + OAuth2 Doorkeeper, admin/operations). Covers the flat-JSON Stripe-like envelope, `?expand=` / `?include=` parameters, prefixed IDs (`prod_…`, `ord_…`), OpenAPI 3.0 spec, rate limiting, idempotency, and migration from v2 JSON:API. Use when building API clients, SDKs, or extending API endpoints in a Spree v5.4+ deployment.

  • 39 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 29, 2026
ai-agentstypescriptbashapidatabase

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned May 29, 2026

npx -y skills add OrcaQubits/agentic-commerce-skills-plugins --skill spree-api-v3 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Spree Api V3?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Spree Api V3
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/orcaqubits-spree-api-v3/badge)](https://www.skillsdirectory.com/skills/orcaqubits-spree-api-v3)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: spree-api-v3
description: >
  Build with Spree's v3 APIs (v5.4+) — Store API at `/api/v3/store/*`
  (publishable key + per-user JWT, customer-facing) and Admin API at
  `/api/v3/admin/*` (per-user API keys + OAuth2 Doorkeeper, admin/operations).
  Covers the flat-JSON Stripe-like envelope, `?expand=` / `?include=`
  parameters, prefixed IDs (`prod_…`, `ord_…`), OpenAPI 3.0 spec, rate limiting,
  idempotency, and migration from v2 JSON:API. Use when building API clients,
  SDKs, or extending API endpoints in a Spree v5.4+ deployment.
---

# Spree API v3

## Before writing code

**Fetch live docs**:
1. Fetch https://spreecommerce.org/docs/api-reference for the v3 API index.
2. Fetch the OpenAPI spec for the Spree version you target — it ships per release. Find the link on the API reference page.
3. Fetch the v5.4 announcement (https://spreecommerce.org/announcing-spree-commerce-5-4/) for the design rationale.
4. Inspect the live Spree source under `app/controllers/spree/api/v3/` for the canonical request/response shape per endpoint.
5. Check the rate-limit configuration in `config/initializers/spree.rb` for the deployment you're targeting.

## Conceptual Architecture

### Two APIs, One Generation

| API | Path | Auth | Audience |
|-----|------|------|----------|
| **Store API** | `/api/v3/store/*` | Publishable key (`pk_…`) + per-user JWT bearer | Customers, storefronts |
| **Admin API** | `/api/v3/admin/*` | Per-user API keys + OAuth2 (Doorkeeper) | Admin, operations, server-to-server |

Both follow the same envelope conventions.

### Envelope Conventions

**Flat JSON** (Stripe-like), not JSON:API:

```json
{
  "id": "prod_01HXVZ...",
  "object": "product",
  "name": "Classic Tee",
  "description": "100% cotton",
  "created_at": "2026-04-15T10:00:00Z",
  "variants": ["var_01HXVZ...", "var_01HXVZ..."],
  "default_variant": {
    "id": "var_01HXVZ...",
    "object": "variant",
    "sku": "TEE-S",
    "price": "19.99",
    "currency": "USD"
  }
}
```

vs. v2's JSON:API:
```json
{ "data": { "id": "1", "type": "product", "attributes": { ... }, "relationships": { ... } } }
```

### Prefixed IDs

IDs are strings with type prefixes:

| Prefix | Type |
|--------|------|
| `prod_` | Product |
| `var_` | Variant |
| `ord_` | Order |
| `usr_` | User |
| `pay_` | Payment |
| `ship_` | Shipment |
| `cust_` | Customer |
| `pm_` | PaymentMethod |
| `sm_` | ShippingMethod |
| `txn_` | Transaction |
| `prom_` | Promotion |

Prefixed IDs are **stable** — never reused, safe to expose, decoupled from internal database IDs. Verify the full prefix table in the live docs.

### Listing and Pagination

```
GET /api/v3/store/products?limit=25&starting_after=prod_…&ending_before=prod_…
```

Returns:

```json
{
  "object": "list",
  "url": "/api/v3/store/products",
  "has_more": true,
  "data": [ { "id": "prod_…", ... }, ... ]
}
```

Cursor pagination via `starting_after` / `ending_before` (verify against live spec — may be page-based on some endpoints).

### Expanding Relationships

```
GET /api/v3/store/orders/ord_…?expand=line_items,line_items.variant,shipping_address
```

`expand` inlines nested objects; `include` (also supported) returns them in a separate `included` array. Verify which convention the version you're on uses.

### Filtering

Per-endpoint filter params:
```
GET /api/v3/admin/orders?status=complete&payment_state=paid&created_after=2026-01-01
```

Verify the filter set per endpoint in the OpenAPI spec.

### Auth — Store API

Two layers:

1. **Publishable key** (`pk_…`) — identifies the store + currency. Required on every request via `Authorization: Bearer pk_…` or `X-Spree-Token` header (verify current).
2. **User JWT** — issued by `/api/v3/store/account/sign_in`, sent in `Authorization: Bearer <jwt>`. Identifies the logged-in user.

For guest carts, the cart's `order_token` is sent in `X-Spree-Order-Token`.

### Auth — Admin API

Two paths:

1. **Per-user API key** — generated in admin UI per user. Sent in `Authorization: Bearer <api_key>`. Inherits the user's roles.
2. **OAuth2 (Doorkeeper)** — for app integrations. `client_credentials` grant against `POST /spree_oauth/token` returns an access token with `admin` scope.

### Rate Limiting

Per-endpoint, per-token. Defaults set in `config/initializers/spree.rb`. Headers returned:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1715000000
```

Verify the exact header names against the live source.

### Idempotency

For mutating endpoints (POST/PUT), send `Idempotency-Key: <uuid>` to ensure retries don't double-create. Spree caches the response for 24+ hours (verify current TTL).

### Errors

```json
{
  "object": "error",
  "type": "validation_error",
  "code": "invalid_email",
  "message": "Email is not valid",
  "param": "email",
  "request_id": "req_…"
}
```

HTTP status codes follow standard REST: 400 / 401 / 403 / 404 / 422 / 429 / 500.

### Webhooks

Webhooks 2.0 fire alongside API operations — see `spree-events-webhooks` skill.

## Implementation Guidance

### Setting Up the Store API

In Spree admin → Settings → API Keys:
- Create a publishable key (`pk_live_…` or `pk_test_…`) per store
- Set the storefront's `NEXT_PUBLIC_SPREE_PUBLISHABLE_KEY` env var

### Customer Sign-In Flow

```http
POST /api/v3/store/account/sign_in
Authorization: Bearer pk_live_…
Content-Type: application/json

{ "email": "user@example.com", "password": "..." }
```

Response:
```json
{
  "object": "auth_token",
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "..."
}
```

Store in **httpOnly cookie** (server-side); never expose to the browser.

### Cart Creation (Guest)

```http
POST /api/v3/store/cart
Authorization: Bearer pk_live_…
```

Response includes `order_token` — store in httpOnly cookie. Subsequent cart calls use `X-Spree-Order-Token`.

### Listing Products

```http
GET /api/v3/store/products?expand=default_variant,images&limit=20
Authorization: Bearer pk_live_…
```

### Admin Order Update

```http
PATCH /api/v3/admin/orders/ord_…
Authorization: Bearer <admin_api_key>
Idempotency-Key: <uuid>
Content-Type: application/json

{ "internal_note": "Customer requested expedited shipping" }
```

### Admin OAuth2 Token

```http
POST /spree_oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=...&client_secret=...&scope=admin
```

Response:
```json
{ "access_token": "...", "token_type": "Bearer", "expires_in": 7200, "scope": "admin" }
```

### Migrating From v2 (JSON:API) to v3

Field shape changes:
- `data.attributes.name` → `name`
- `data.attributes.created-at` → `created_at`
- `data.relationships.variants.data` → `variants` (array of prefixed IDs by default; `expand=variants` to inline)
- `data.id` (numeric string) → prefixed ID

You can run v2 and v3 side-by-side during migration via the `spree_legacy_api_v2` gem.

### Generating a TypeScript Client From OpenAPI

```bash
npx @openapitools/openapi-generator-cli generate \
  -i https://your-spree.com/api/v3/openapi.json \
  -g typescript-axios \
  -o ./generated-client
```

But prefer `@spree/sdk` if you don't need every endpoint — see the `spree-typescript-sdk` skill.

### Common Pitfalls

- **Mixing v2 and v3 in the same client** — different envelopes, easy to confuse.
- **Storing API keys in browser code** — only publishable keys belong on the client; secret keys on the server.
- **Ignoring rate-limit headers** — bursty clients get 429s.
- **Skipping Idempotency-Key on retries** — double-charges, duplicate orders.
- **Hardcoding prefixed IDs in tests** — they're ULIDs/UUIDs; use the response's value.
- **Assuming v2 endpoint paths still work** — `/api/v2/storefront/cart` is the legacy path; v3 is `/api/v3/store/cart`.

Always re-fetch the OpenAPI spec for the version you're on — field shapes can shift between minor releases.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…