@spree/docs 0.1.88 → 0.1.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/developer/contributing/developing-spree.md +3 -1
- package/dist/developer/sdk/admin/authentication.md +108 -0
- package/dist/developer/sdk/admin/querying-and-errors.md +129 -0
- package/dist/developer/sdk/admin/quickstart.md +60 -13
- package/dist/developer/sdk/admin/resources.md +126 -0
- package/dist/developer/sdk/quickstart.md +2 -2
- package/dist/developer/tutorial/api.md +1 -1
- package/package.json +1 -1
|
@@ -337,7 +337,9 @@ cd packages/sdk # or packages/admin-sdk, packages/cli, packages/create-spree-
|
|
|
337
337
|
pnpm changeset
|
|
338
338
|
```
|
|
339
339
|
|
|
340
|
-
This creates a changeset file describing your changes. Commit it with your PR.
|
|
340
|
+
This creates a changeset file describing your changes. Commit it with your PR.
|
|
341
|
+
|
|
342
|
+
Releasing is a two-step flow: a maintainer consumes the pending changesets (`changeset version` — writes the CHANGELOG and bumps `package.json`) and merges that bump to `main`; the release jobs in `.github/workflows/packages.yml` then detect the unpublished version and publish with npm provenance via Trusted Publishing. `@spree/admin-sdk` publishes under the `next` dist-tag while on the 0.x Developer Preview line; the others ship as `latest` (prereleases go to `beta`).
|
|
341
343
|
|
|
342
344
|
Private packages (`@spree/dashboard`, `@spree/dashboard-core`, `@spree/dashboard-ui`, `@spree/sdk-core`) don't need changesets.
|
|
343
345
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Authentication"
|
|
3
|
+
description: "Authenticate the Admin SDK with a secret API key (server-to-server, scope-based) or JWT cookie auth (browser admin apps, role-based)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The Admin API supports two authentication methods. Both reach the same endpoints — they differ in **where the credential lives** and **how authorization is decided**:
|
|
7
|
+
|
|
8
|
+
| | Secret API key | JWT + cookie |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| **For** | Backend integrations, automations, cron jobs | Browser-based admin apps where a human signs in |
|
|
11
|
+
| **Credential** | `sk_…` key, created in the admin | Short-lived access token + httpOnly refresh cookie |
|
|
12
|
+
| **Authorization** | [Scopes](../../../api-reference/admin-api/authentication.md) attached to the key (`read_products`, `write_orders`, …) | The admin user's roles and permissions |
|
|
13
|
+
| **Where it runs** | Server-side only — never in a browser | Browser (the refresh token never touches your JS) |
|
|
14
|
+
|
|
15
|
+
## Secret API key (server-to-server)
|
|
16
|
+
|
|
17
|
+
Create a secret key in the admin under **Settings → API Keys**, grant it the scopes your integration needs, and pass it to the client:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
21
|
+
|
|
22
|
+
const client = createAdminClient({
|
|
23
|
+
baseUrl: 'https://your-store.com',
|
|
24
|
+
secretKey: process.env.SPREE_SECRET_KEY, // sk_xxx
|
|
25
|
+
})
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Each key carries the list of scopes granted at creation time. A request to an endpoint the key isn't scoped for fails with `code: 'access_denied'` — the error's `details.required_scope` names the missing scope (see [Querying & Errors](querying-and-errors.md#scope-errors)).
|
|
29
|
+
|
|
30
|
+
> **WARNING:** Secret keys grant back-office access to your store. Never embed them in client-side code, mobile apps, or public repositories — keep them in server-side environment variables or a secrets manager.
|
|
31
|
+
|
|
32
|
+
## JWT + cookie authentication (browser apps)
|
|
33
|
+
|
|
34
|
+
For browser-based admin tooling, authenticate as an admin user. The flow is designed so that **no long-lived credential is ever exposed to JavaScript**:
|
|
35
|
+
|
|
36
|
+
- `auth.login()` returns `{ token, user }` — a short-lived access token you hold in memory.
|
|
37
|
+
- The **refresh token never appears in JSON.** The server sets it as an `HttpOnly` cookie scoped to `/api/v3/admin/auth`, and the SDK sends requests with `credentials: 'include'` by default, so the cookie flows automatically.
|
|
38
|
+
- `auth.refresh()` takes **no arguments** — it's driven entirely by the cookie, and rotates it on every call.
|
|
39
|
+
- `auth.logout()` revokes the refresh token server-side and clears the cookie.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
43
|
+
|
|
44
|
+
// A cookie-auth app can start with no credentials at all
|
|
45
|
+
const client = createAdminClient({ baseUrl: 'https://your-store.com' })
|
|
46
|
+
|
|
47
|
+
// Sign in — the refresh token lands in the httpOnly cookie
|
|
48
|
+
const { token, user } = await client.auth.login({
|
|
49
|
+
email: 'admin@example.com',
|
|
50
|
+
password: 'password123',
|
|
51
|
+
})
|
|
52
|
+
client.setToken(token)
|
|
53
|
+
|
|
54
|
+
// Auto-recover from expired access tokens
|
|
55
|
+
client.onUnauthorized(async () => {
|
|
56
|
+
const { token: fresh } = await client.auth.refresh()
|
|
57
|
+
client.setToken(fresh)
|
|
58
|
+
return true // retry the failed request
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Sign out — revokes the refresh token server-side
|
|
62
|
+
await client.auth.logout()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Bootstrapping a returning session
|
|
66
|
+
|
|
67
|
+
Because the refresh cookie outlives the in-memory access token, a returning user can be signed back in without re-entering credentials — call `refresh()` on app load and treat failure as "not signed in":
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
try {
|
|
71
|
+
const { token } = await client.auth.refresh()
|
|
72
|
+
client.setToken(token)
|
|
73
|
+
} catch {
|
|
74
|
+
// No valid session — show the login form
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Identity providers
|
|
79
|
+
|
|
80
|
+
`auth.login()` also accepts third-party identity-provider payloads when the server has a matching strategy registered in `Spree.store_authentication_strategies`:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const { token } = await client.auth.login({ provider: 'auth0', token: idpJwt })
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Current user and permissions
|
|
87
|
+
|
|
88
|
+
After signing in, `client.me.get()` returns the admin user's profile together with their serialized permissions — use it to drive what your UI shows:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const { user, permissions } = await client.me.get()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Staff invitations
|
|
95
|
+
|
|
96
|
+
The `auth` resource also exposes the unauthenticated invitation-acceptance flow used when onboarding new staff: `auth.lookupInvitation(id, token)` returns the safe-to-render invitation context (store, role, inviter), and `auth.acceptInvitation(id, token, params)` accepts it — issuing a JWT and refresh cookie identical to `login`. Sending invitations is an authenticated operation on [`client.invitations`](resources.md).
|
|
97
|
+
|
|
98
|
+
## Custom fetch
|
|
99
|
+
|
|
100
|
+
Pass a custom `fetch` implementation when you need request interception, proxying, or a non-standard runtime:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const client = createAdminClient({
|
|
104
|
+
baseUrl: 'https://your-store.com',
|
|
105
|
+
secretKey: process.env.SPREE_SECRET_KEY,
|
|
106
|
+
fetch: customFetchImplementation,
|
|
107
|
+
})
|
|
108
|
+
```
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Querying & Errors"
|
|
3
|
+
description: "Filter, sort, paginate, and expand Admin API collections with flat Ransack parameters — and handle structured SpreeError responses."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Filtering
|
|
7
|
+
|
|
8
|
+
Collection endpoints support [Ransack](https://activerecord-hackery.github.io/ransack/) filters passed as **flat parameters** — append a predicate suffix to any filterable attribute. The SDK wraps filter keys in `q[…]` automatically:
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
const { data: orders } = await client.orders.list({
|
|
12
|
+
status_eq: 'complete', // exact match
|
|
13
|
+
total_gteq: 100, // greater than or equal
|
|
14
|
+
email_cont: '@example.com', // substring match
|
|
15
|
+
user_id_eq: 'cus_xxx', // prefixed IDs work directly
|
|
16
|
+
sort: '-completed_at',
|
|
17
|
+
page: 2,
|
|
18
|
+
limit: 50,
|
|
19
|
+
})
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Common predicates: `_eq`, `_not_eq`, `_cont` (contains), `_start`, `_end`, `_gteq` / `_lteq`, `_gt` / `_lt`, `_in` (array), `_null`. The filterable attributes per resource are listed in the [Admin API reference](../../../api-reference/admin-api/introduction.md); each model declares an explicit allowlist, so unknown filter keys are ignored rather than executed.
|
|
23
|
+
|
|
24
|
+
> **NOTE:** Foreign-key predicates accept **prefixed IDs** (`user_id_eq: 'cus_xxx'`, `variant_id_in: ['variant_a', 'variant_b']`) — the API translates them; you never handle raw database IDs.
|
|
25
|
+
|
|
26
|
+
## Sorting
|
|
27
|
+
|
|
28
|
+
Pass `sort` with an attribute name; prefix with `-` for descending. Comma-separate multiple fields:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
await client.products.list({ sort: '-updated_at,name' })
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Pagination
|
|
35
|
+
|
|
36
|
+
List responses return `{ data, meta }`. Drive pagination with `page` and `limit`:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const { data, meta } = await client.products.list({ page: 1, limit: 50 })
|
|
40
|
+
|
|
41
|
+
meta.count // total records
|
|
42
|
+
meta.pages // total pages
|
|
43
|
+
meta.next // next page number, or null on the last page
|
|
44
|
+
meta.previous // previous page number, or null on the first
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
A simple fetch-all loop:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
let page: number | null = 1
|
|
51
|
+
while (page) {
|
|
52
|
+
const { data, meta } = await client.products.list({ page, limit: 100 })
|
|
53
|
+
process(data)
|
|
54
|
+
page = meta.next
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Expanding associations
|
|
59
|
+
|
|
60
|
+
Pass `expand` to embed related records in the response, instead of making follow-up requests. Dot notation reaches nested associations (up to 4 levels):
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const order = await client.orders.get('order_xxx', {
|
|
64
|
+
expand: ['items', 'customer', 'fulfillments.items'],
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const products = await client.products.list({
|
|
68
|
+
expand: ['variants', 'variants.media'],
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`fields` does the opposite — trims the response to just the attributes you name (`id` is always included):
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
await client.products.list({ fields: ['name', 'slug', 'status'] })
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Error handling
|
|
79
|
+
|
|
80
|
+
Every non-2xx response throws a `SpreeError` with a stable machine-readable `code`, the HTTP `status`, and optional structured `details`:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { SpreeError } from '@spree/admin-sdk'
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
await client.orders.update(orderId, { email })
|
|
87
|
+
} catch (err) {
|
|
88
|
+
if (err instanceof SpreeError) {
|
|
89
|
+
err.code // e.g. 'validation_error', 'record_not_found', 'access_denied'
|
|
90
|
+
err.status // e.g. 422
|
|
91
|
+
err.message // human-readable summary
|
|
92
|
+
err.details // optional structured context
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Validation errors
|
|
98
|
+
|
|
99
|
+
On `422` responses, `details` maps attribute names to arrays of messages — ready to project onto form fields:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
try {
|
|
103
|
+
await client.products.create({ name: '' })
|
|
104
|
+
} catch (err) {
|
|
105
|
+
if (err instanceof SpreeError && err.status === 422) {
|
|
106
|
+
err.details // { name: ["can't be blank"] }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Scope errors
|
|
112
|
+
|
|
113
|
+
When a request fails because the secret API key lacks the required [scope](authentication.md), the error has `code: 'access_denied'` and `details.required_scope` names the missing scope:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
catch (err) {
|
|
117
|
+
if (err instanceof SpreeError && err.code === 'access_denied') {
|
|
118
|
+
console.error(`API key is missing scope: ${err.details?.required_scope}`)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Expired JWT sessions
|
|
124
|
+
|
|
125
|
+
For cookie-authenticated apps, register an `onUnauthorized` handler to transparently refresh and retry on `401` — see [Authentication](authentication.md#jwt--cookie-authentication-browser-apps).
|
|
126
|
+
|
|
127
|
+
## Retries
|
|
128
|
+
|
|
129
|
+
The SDK retries failed idempotent requests (GET/HEAD, plus requests carrying an idempotency key) with exponential backoff and jitter — transient network errors and retryable statuses recover without any code on your side.
|
|
@@ -1,22 +1,69 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Admin
|
|
3
|
-
|
|
2
|
+
title: "Admin SDK"
|
|
3
|
+
sidebarTitle: Quickstart
|
|
4
|
+
description: "Manage your store programmatically with @spree/admin-sdk — the official TypeScript client for the Spree Admin API v3."
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
[`@spree/admin-sdk`](https://www.npmjs.com/package/@spree/admin-sdk) is the official TypeScript SDK for the [Admin API v3](../../../api-reference/admin-api/introduction.md) — the back-office counterpart to [`@spree/sdk`](../quickstart.md). Use it to build integrations, automations, internal tools, and custom admin UIs: manage products, orders, customers, stock, promotions, webhooks, and more.
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
> **WARNING:** The Admin SDK is in **Developer Preview** on the `0.x` line and published under the `next` dist-tag. The API surface may change between minor versions — check the [changelog](https://github.com/spree/spree/blob/main/packages/admin-sdk/CHANGELOG.md) when updating. It requires Spree 5.5 or newer.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @spree/admin-sdk@next
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Create a client with a [secret API key](authentication.md) (server-to-server) and start calling resources:
|
|
9
20
|
|
|
10
21
|
```typescript
|
|
11
|
-
import {
|
|
22
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
12
23
|
|
|
13
|
-
const client =
|
|
14
|
-
baseUrl: 'https://
|
|
15
|
-
secretKey:
|
|
16
|
-
})
|
|
24
|
+
const client = createAdminClient({
|
|
25
|
+
baseUrl: 'https://your-store.com',
|
|
26
|
+
secretKey: process.env.SPREE_SECRET_KEY, // sk_xxx — server-side only
|
|
27
|
+
})
|
|
17
28
|
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
// List recent completed orders
|
|
30
|
+
const { data: orders, meta } = await client.orders.list({
|
|
31
|
+
status_eq: 'complete',
|
|
32
|
+
sort: '-completed_at',
|
|
33
|
+
limit: 25,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// Create a purchasable product — pricing lives on variants
|
|
37
|
+
const product = await client.products.create({
|
|
38
|
+
name: 'Aero Hoodie',
|
|
39
|
+
status: 'active',
|
|
40
|
+
tags: ['new-arrivals'],
|
|
41
|
+
variants: [
|
|
42
|
+
{
|
|
43
|
+
sku: 'AERO-HOODIE',
|
|
44
|
+
prices: [{ currency: 'USD', amount: '59.00' }],
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
})
|
|
22
48
|
```
|
|
49
|
+
|
|
50
|
+
Every method is fully typed — responses use `Admin`-prefixed types generated from the API serializers:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import type { AdminOrder, PaginatedResponse } from '@spree/admin-sdk'
|
|
54
|
+
|
|
55
|
+
const page: PaginatedResponse<AdminOrder> = await client.orders.list()
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> **NOTE:** Secret keys grant back-office access — never ship them in browser code. For browser-based admin apps, use [JWT cookie authentication](authentication.md#jwt--cookie-authentication-browser-apps) instead.
|
|
59
|
+
|
|
60
|
+
## Learn more
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
- [Authentication](authentication.md) — Secret keys with scopes for servers, JWT + httpOnly refresh cookie for browser apps.
|
|
64
|
+
- [Resources](resources.md) — The full resource map — products, orders, customers, stock, promotions, webhooks, and more.
|
|
65
|
+
- [Querying & Errors](querying-and-errors.md) — Filtering, sorting, pagination, prefixed IDs, and structured error handling.
|
|
66
|
+
- [Admin API Reference](../../../api-reference/admin-api/introduction.md) — The underlying REST API the SDK wraps — every endpoint, parameter, and response shape.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
> **TIP:** Adding your own resources? The [`spree generate api_resource`](../../tutorial/api.md) generator scaffolds Admin API endpoints (model, serializers, controllers, specs) in one command, and the [extending guide](../extending.md) shows how to call custom endpoints from the SDK.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Resources"
|
|
3
|
+
description: "The full @spree/admin-sdk resource map — products, orders, customers, inventory, pricing, promotions, store configuration, and platform resources."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Every Admin API resource is exposed as a property on the client (`client.orders`, `client.products`, …). Collection resources follow a consistent CRUD shape — `list`, `get`, `create`, `update`, `delete` — plus resource-specific actions. Nested resources take the **parent ID as the first argument**:
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
// Top-level
|
|
10
|
+
const order = await client.orders.get('order_xxx')
|
|
11
|
+
|
|
12
|
+
// Nested — parent ID first
|
|
13
|
+
const payments = await client.orders.payments.list('order_xxx')
|
|
14
|
+
await client.orders.payments.capture('order_xxx', 'payment_xxx')
|
|
15
|
+
|
|
16
|
+
// Nested create
|
|
17
|
+
await client.customers.addresses.create('cus_xxx', {
|
|
18
|
+
first_name: 'Jane',
|
|
19
|
+
last_name: 'Doe',
|
|
20
|
+
address1: '350 Fifth Avenue',
|
|
21
|
+
city: 'New York',
|
|
22
|
+
postal_code: '10118',
|
|
23
|
+
country_iso: 'US',
|
|
24
|
+
state_abbr: 'NY',
|
|
25
|
+
is_default_shipping: true,
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Catalog
|
|
30
|
+
|
|
31
|
+
| Client | Endpoints |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `client.products` | CRUD, `clone`, and bulk operations (`bulkStatusUpdate`, `bulkAddToCategories` / `bulkRemoveFromCategories`, `bulkAddToChannels` / `bulkRemoveFromChannels`, `bulkAddTags` / `bulkRemoveTags`, `bulkDestroy`). Nested: `media`, `variants` (with their own `media`). |
|
|
34
|
+
| `client.variants` | Top-level variant search across products (`list`, `get`). |
|
|
35
|
+
| `client.optionTypes` | CRUD on option types and their values. |
|
|
36
|
+
| `client.categories` | List categories. |
|
|
37
|
+
| `client.tags` | Autocomplete tag names per taggable type. |
|
|
38
|
+
| `client.taxCategories` | CRUD on tax categories. |
|
|
39
|
+
|
|
40
|
+
## Orders & fulfillment
|
|
41
|
+
|
|
42
|
+
| Client | Endpoints |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `client.orders` | List, get, create, update, delete, `complete`, `cancel`, `approve`, `resume`, `resendConfirmation`. Nested: `items`, `payments` (incl. `capture` / `void`), `fulfillments` (incl. `fulfill` / `cancel` / `resume` / `split`), `refunds`, `giftCards`, `storeCredits`, `adjustments`. |
|
|
45
|
+
|
|
46
|
+
## Customers
|
|
47
|
+
|
|
48
|
+
| Client | Endpoints |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `client.customers` | CRUD plus bulk group operations (`bulkAddToGroups` / `bulkRemoveFromGroups`) and bulk tags. Nested: `addresses`, `creditCards`, `storeCredits`. |
|
|
51
|
+
| `client.customerGroups` | CRUD on customer groups. |
|
|
52
|
+
|
|
53
|
+
## Pricing & promotions
|
|
54
|
+
|
|
55
|
+
| Client | Endpoints |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `client.prices` | CRUD plus `bulkUpsert` / `bulkDestroy` for variant prices. |
|
|
58
|
+
| `client.priceLists` | CRUD, `activate` / `deactivate`, and price-list rule types. |
|
|
59
|
+
| `client.promotions` | CRUD. Nested: `actions`, `rules`, `couponCodes`. |
|
|
60
|
+
| `client.promotionActions` | Lookup of available action `types` and `calculators`. |
|
|
61
|
+
| `client.promotionRules` | Lookup of available rule `types`. |
|
|
62
|
+
| `client.giftCards` | CRUD on gift cards. |
|
|
63
|
+
| `client.giftCardBatches` | List, get, and create gift card batches. |
|
|
64
|
+
| `client.storeCreditCategories` | List and read store credit categories. |
|
|
65
|
+
|
|
66
|
+
## Inventory
|
|
67
|
+
|
|
68
|
+
| Client | Endpoints |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `client.stockLocations` | CRUD on stock locations. |
|
|
71
|
+
| `client.stockItems` | List, get, update, delete stock items. |
|
|
72
|
+
| `client.stockTransfers` | List, get, create, delete stock transfers. |
|
|
73
|
+
|
|
74
|
+
## Sales channels
|
|
75
|
+
|
|
76
|
+
| Client | Endpoints |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `client.channels` | CRUD plus `addProducts` / `removeProducts`. |
|
|
79
|
+
| `client.markets` | CRUD on markets. |
|
|
80
|
+
|
|
81
|
+
## Store configuration
|
|
82
|
+
|
|
83
|
+
| Client | Endpoints |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `client.store` | Store profile (`get`, `update`). |
|
|
86
|
+
| `client.paymentMethods` | CRUD plus `types` (available gateway types). |
|
|
87
|
+
| `client.countries` | List and read countries (for address dropdowns). |
|
|
88
|
+
| `client.customFieldDefinitions` | CRUD on [custom field](../../core-concepts/metafields.md) definitions. |
|
|
89
|
+
| `client.exports` | Create and track CSV exports (products, orders, customers, …). |
|
|
90
|
+
| `client.directUploads` | Pre-signed Active Storage uploads (used by media flows). |
|
|
91
|
+
|
|
92
|
+
## Platform & access
|
|
93
|
+
|
|
94
|
+
| Client | Endpoints |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `client.auth` | Login (email/password or identity provider), cookie-driven refresh, logout, invitation lookup/acceptance — see [Authentication](authentication.md). |
|
|
97
|
+
| `client.me` | Current admin user + permissions. |
|
|
98
|
+
| `client.adminUsers` | List, get, update, delete admin users. |
|
|
99
|
+
| `client.invitations` | Staff invitations — list, get, create, delete, `resend`. |
|
|
100
|
+
| `client.roles` | List and read roles. |
|
|
101
|
+
| `client.apiKeys` | CRUD plus `revoke` for API keys. |
|
|
102
|
+
| `client.allowedOrigins` | CRUD on CORS allowed origins. |
|
|
103
|
+
| `client.webhookEndpoints` | CRUD, `sendTest`, `enable` / `disable`. Nested: `deliveries` (list, get, `redeliver`). |
|
|
104
|
+
| `client.dashboard` | Sales analytics. |
|
|
105
|
+
|
|
106
|
+
## Custom fields
|
|
107
|
+
|
|
108
|
+
Resources that support [custom fields](../../core-concepts/metafields.md) (products, variants, orders, customers, categories, option types) expose a `customFields` accessor taking the parent ID first:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
await client.products.customFields.list('prod_xxx')
|
|
112
|
+
await client.products.customFields.create('prod_xxx', {
|
|
113
|
+
custom_field_definition_id: 'cfd_xxx',
|
|
114
|
+
value: 'limited-edition',
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The generic escape hatch covers any owner type:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
await client.customFields('Spree::Product', 'prod_xxx').list()
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Adding your own resources
|
|
125
|
+
|
|
126
|
+
The resource map grows with your store. The [`spree generate api_resource`](../../tutorial/api.md) generator scaffolds new Admin API endpoints (model, serializers, controllers, routes, specs) in one command — then call them from the SDK with a [custom fetch or raw request](../extending.md), or generate a typed client for them.
|
|
@@ -3,6 +3,8 @@ title: Quickstart
|
|
|
3
3
|
description: Install the Spree TypeScript SDK, configure your Store API client, and make your first calls to products, carts, checkout, and customer endpoints.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
`@spree/sdk` is the customer-facing SDK — products, carts, checkout, and account flows against the Store API. For back-office integrations (managing products, orders, customers, stock), use the [Admin SDK](admin/quickstart.md).
|
|
7
|
+
|
|
6
8
|
## Installation
|
|
7
9
|
|
|
8
10
|
```bash
|
|
@@ -70,7 +72,6 @@ The SDK uses a resource builder pattern for nested resources:
|
|
|
70
72
|
| `customer` | `orders` | `list` |
|
|
71
73
|
| `customer` | `paymentSetupSessions` | `create`, `get`, `complete` |
|
|
72
74
|
| `policies` | — | `list`, `get` |
|
|
73
|
-
| `categories` | `products` | `list` |
|
|
74
75
|
| `wishlists` | `items` | `create`, `update`, `delete` |
|
|
75
76
|
|
|
76
77
|
```typescript
|
|
@@ -79,7 +80,6 @@ await client.carts.items.create(cartId, params, options);
|
|
|
79
80
|
await client.carts.payments.list(cartId, options);
|
|
80
81
|
await client.carts.fulfillments.update(cartId, fulfillmentId, params, options);
|
|
81
82
|
await client.customer.addresses.list({}, options);
|
|
82
|
-
await client.categories.products.list(categoryId, params, options);
|
|
83
83
|
await client.wishlists.items.create(wishlistId, params, options);
|
|
84
84
|
```
|
|
85
85
|
|
|
@@ -362,7 +362,7 @@ curl -X POST -H "X-Spree-API-Key: sk_YOUR_KEY" \
|
|
|
362
362
|
http://localhost:3000/api/v3/admin/brands
|
|
363
363
|
```
|
|
364
364
|
|
|
365
|
-
> **INFO:** Secret keys carry scopes (`read_brands`, `write_brands` style) and JWT admin users go through CanCanCan abilities — see [API authentication](../customization/api.md) for the full model.
|
|
365
|
+
> **INFO:** Secret keys carry scopes (`read_brands`, `write_brands` style) and JWT admin users go through CanCanCan abilities — see [API authentication](../customization/api.md) for the full model. From TypeScript, the [Admin SDK](../sdk/admin/quickstart.md) wraps the Admin API with typed clients for all built-in resources.
|
|
366
366
|
|
|
367
367
|
## Step 6: Add Brand to Product Responses
|
|
368
368
|
|