Skip to content
Back to skills

Spree Legacy Api V2

ASecurity

Work with Spree's legacy v2 APIs — JSON:API-style Storefront API at `/api/v2/storefront/*` and Platform API at `/api/v2/platform/*`, Doorkeeper OAuth2 (password grant for storefront, client_credentials + admin scope for platform), the `spree_legacy_api_v2` gem (required in v5+ for backward compatibility), and migration patterns to API v3. Use when maintaining a v2 client during a migration window, integrating an older partner system, or deciding when to cut over to v3.

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

Works with

  • cli
  • api

Security analysis

A100/100

Scanned May 29, 2026

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

Installs into .claude/skills of the current project.

Are you the author of Spree Legacy Api V2?

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

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

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-legacy-api-v2
description: >
  Work with Spree's legacy v2 APIs — JSON:API-style Storefront API at
  `/api/v2/storefront/*` and Platform API at `/api/v2/platform/*`, Doorkeeper
  OAuth2 (password grant for storefront, client_credentials + admin scope for
  platform), the `spree_legacy_api_v2` gem (required in v5+ for backward
  compatibility), and migration patterns to API v3. Use when maintaining a v2
  client during a migration window, integrating an older partner system, or
  deciding when to cut over to v3.
---

# Spree Legacy API v2

## Before writing code

**Fetch live docs**:
1. Fetch https://github.com/spree/spree_legacy_api_v2 (README) for the current install and supported Spree versions.
2. The historical v2 docs may live at https://api.spreecommerce.org/ — verify what's still hosted.
3. Compare with the v3 reference at https://spreecommerce.org/docs/api-reference to plan migration.
4. Check the Spree release notes — v2 endpoints can be removed without notice in major upgrades.
5. Inspect the gem's controllers under `app/controllers/spree/api/v2/`.

## Conceptual Architecture

### What Was v2

API v2 was the canonical Spree API across v4.x and v5.0–5.3. Two surfaces:

| API | Path | Auth | Audience |
|-----|------|------|----------|
| **Storefront API** | `/api/v2/storefront/*` | Doorkeeper password grant + publishable `X-Spree-Order-Token` | Customer-facing |
| **Platform API** | `/api/v2/platform/*` | Doorkeeper `client_credentials` grant + `admin` scope | Admin/operations |

Style: **JSON:API 1.0** — `{ data: { id, type, attributes, relationships } }` envelope.

### v2 Status in v5+

- Bundled in `spree` umbrella through v5.3.
- **Extracted to the `spree_legacy_api_v2` gem from v5.4+** — not in the umbrella by default.
- Deprecated; will eventually be removed. Treat any new development as v3-first.

### Why It Existed (and Still Matters)

Apps built between 2020 and 2025 use v2. The gem keeps those clients working while you migrate to v3.

### Adding the Gem in v5.4+

```ruby
# Gemfile
gem 'spree_legacy_api_v2'

# Then
bundle install
bin/rails g spree_legacy_api_v2:install   # if a generator is shipped — verify
```

Mounts `/api/v2/storefront/*` and `/api/v2/platform/*`.

### Auth — Storefront API v2

**Password grant** (verify current OAuth2 grant types accepted):

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

grant_type=password&username=user@example.com&password=...
```

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

For guest carts, use `X-Spree-Order-Token` header. Some v2 endpoints accept anonymous access with just an order token.

### Auth — Platform API v2

**Client credentials grant** with `admin` scope:

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

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

Doorkeeper applications are managed in admin → Settings → OAuth Applications.

### JSON:API Envelope

```json
{
  "data": {
    "id": "1",
    "type": "product",
    "attributes": {
      "name": "Classic Tee",
      "description": "100% cotton",
      "created-at": "2025-04-15T10:00:00Z",
      "price": "19.99"
    },
    "relationships": {
      "variants": { "data": [{ "id": "2", "type": "variant" }] },
      "default-variant": { "data": { "id": "2", "type": "variant" } }
    }
  },
  "included": [
    { "id": "2", "type": "variant", "attributes": { ... } }
  ]
}
```

Compare with v3's flat JSON — different fundamental shape.

### Sparse Fieldsets & Includes

```
GET /api/v2/storefront/products?include=default_variant,images&fields[product]=name,price
```

`include` pulls related resources into `included`; `fields[type]` filters attributes per type.

### Pagination

JSON:API style:
```
GET /api/v2/storefront/products?page=2&per_page=25
```

Returns `links.first`, `links.next`, `links.prev`, `links.last` + `meta.total_count`, `meta.total_pages`.

### Filtering

```
GET /api/v2/platform/orders?filter[state]=complete&filter[created_at_gteq]=2025-01-01
```

Filters use Ransack syntax (`_eq`, `_gteq`, `_lteq`, `_in`, `_not_eq`, etc.). Powerful but verbose.

### Errors

```json
{
  "errors": [
    {
      "status": "422",
      "code": "invalid_email",
      "title": "Invalid email",
      "detail": "Email is not valid",
      "source": { "pointer": "/data/attributes/email" }
    }
  ]
}
```

## Implementation Guidance

### Decision: v2 or v3 for New Work?

**Always v3** unless:
- You're integrating with an existing v2 partner that can't migrate yet
- You're shipping a patch for an existing v2-only client
- The v3 endpoint coverage is missing for your use case (rare in v5.4+)

### Running v2 and v3 Side-By-Side

In v5.4+, gem-installing `spree_legacy_api_v2` mounts v2 endpoints without conflict — v3 lives at `/api/v3/`, v2 at `/api/v2/`. Same Doorkeeper applications can serve both.

### Authenticating a Storefront v2 Client

```ruby
require 'net/http'
require 'json'

# Get a token
res = Net::HTTP.post(
  URI('https://your-spree.com/spree_oauth/token'),
  { grant_type: 'password', username: email, password: pwd }.to_query,
  'Content-Type' => 'application/x-www-form-urlencoded'
)
token = JSON.parse(res.body)['access_token']

# Use it
req = Net::HTTP::Get.new('/api/v2/storefront/account')
req['Authorization'] = "Bearer #{token}"
```

### Authenticating a Platform v2 Client

```ruby
res = Net::HTTP.post(
  URI('https://your-spree.com/spree_oauth/token'),
  { grant_type: 'client_credentials',
    client_id: ENV['CLIENT_ID'],
    client_secret: ENV['CLIENT_SECRET'],
    scope: 'admin' }.to_query,
  'Content-Type' => 'application/x-www-form-urlencoded'
)
admin_token = JSON.parse(res.body)['access_token']
```

### Migrating From v2 to v3

Field-level changes:

| v2 (JSON:API) | v3 (flat JSON) |
|---------------|----------------|
| `data.id` ("1") | `id` ("prod_…") |
| `data.attributes.name` | `name` |
| `data.attributes.created-at` (kebab) | `created_at` (snake) |
| `data.relationships.variants.data[]` | `variants` (array of IDs) |
| `included[]` | inline via `?expand=` |
| OAuth2 password grant | Publishable key + JWT |
| OAuth2 client_credentials + admin | Per-user API key OR OAuth2 |

Migration strategy:
1. Stand up v3 endpoints in parallel
2. Update one client surface at a time (start with read-only paths)
3. Sunset v2 after observability shows no calls for N weeks
4. Eventually remove the gem

### Common Pitfalls

- **Forgetting to install `spree_legacy_api_v2`** in v5.4+ — your v2 clients silently 404.
- **Mixing v2 and v3 client code** in the same component — different envelope shapes, hard to maintain.
- **Sparse fieldsets without `include`** — relationships still show as `null` references; you need to also include them.
- **Ransack filters expose more than you want** — by default, all model columns are filterable. Configure `ransackable_attributes` per model in production.
- **Password grant exposing user credentials** — only the storefront uses it; never use password grant in third-party integrations.
- **Token refresh not handled** — v2 tokens expire; implement refresh on 401.

Always cross-check the legacy gem's README for the Spree version it currently supports — the gem can lag the umbrella by 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…