@spree/docs 0.1.88 → 0.1.90

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.
@@ -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. When merged to `main`, a GitHub Action creates a "Version Packages" PR that bumps the version and publishes to npm.
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,109 @@
1
+ ---
2
+ title: "Admin SDK authentication with API keys and JWT cookies"
3
+ sidebarTitle: "Authentication"
4
+ description: "Authenticate @spree/admin-sdk with a secret API key for server-to-server, scope-based access or JWT cookie auth for role-based browser admin apps."
5
+ ---
6
+
7
+ The Admin API supports two authentication methods. Both reach the same endpoints — they differ in **where the credential lives** and **how authorization is decided**:
8
+
9
+ | | Secret API key | JWT + cookie |
10
+ |---|---|---|
11
+ | **For** | Backend integrations, automations, cron jobs | Browser-based admin apps where a human signs in |
12
+ | **Credential** | `sk_…` key, created in the admin | Short-lived access token + httpOnly refresh cookie |
13
+ | **Authorization** | [Scopes](../../../api-reference/admin-api/authentication.md) attached to the key (`read_products`, `write_orders`, …) | The admin user's roles and permissions |
14
+ | **Where it runs** | Server-side only — never in a browser | Browser (the refresh token never touches your JS) |
15
+
16
+ ## Secret API key (server-to-server)
17
+
18
+ Create a secret key in the admin under **Settings → API Keys**, grant it the scopes your integration needs, and pass it to the client:
19
+
20
+ ```typescript
21
+ import { createAdminClient } from '@spree/admin-sdk'
22
+
23
+ const client = createAdminClient({
24
+ baseUrl: 'https://your-store.com',
25
+ secretKey: process.env.SPREE_SECRET_KEY, // sk_xxx
26
+ })
27
+ ```
28
+
29
+ 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)).
30
+
31
+ > **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.
32
+
33
+ ## JWT + cookie authentication (browser apps)
34
+
35
+ 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**:
36
+
37
+ - `auth.login()` returns `{ token, user }` — a short-lived access token you hold in memory.
38
+ - 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.
39
+ - `auth.refresh()` takes **no arguments** — it's driven entirely by the cookie, and rotates it on every call.
40
+ - `auth.logout()` revokes the refresh token server-side and clears the cookie.
41
+
42
+ ```typescript
43
+ import { createAdminClient } from '@spree/admin-sdk'
44
+
45
+ // A cookie-auth app can start with no credentials at all
46
+ const client = createAdminClient({ baseUrl: 'https://your-store.com' })
47
+
48
+ // Sign in — the refresh token lands in the httpOnly cookie
49
+ const { token, user } = await client.auth.login({
50
+ email: 'admin@example.com',
51
+ password: 'password123',
52
+ })
53
+ client.setToken(token)
54
+
55
+ // Auto-recover from expired access tokens
56
+ client.onUnauthorized(async () => {
57
+ const { token: fresh } = await client.auth.refresh()
58
+ client.setToken(fresh)
59
+ return true // retry the failed request
60
+ })
61
+
62
+ // Sign out — revokes the refresh token server-side
63
+ await client.auth.logout()
64
+ ```
65
+
66
+ ### Bootstrapping a returning session
67
+
68
+ 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":
69
+
70
+ ```typescript
71
+ try {
72
+ const { token } = await client.auth.refresh()
73
+ client.setToken(token)
74
+ } catch {
75
+ // No valid session — show the login form
76
+ }
77
+ ```
78
+
79
+ ### Identity providers
80
+
81
+ `auth.login()` also accepts third-party identity-provider payloads when the server has a matching strategy registered in `Spree.store_authentication_strategies`:
82
+
83
+ ```typescript
84
+ const { token } = await client.auth.login({ provider: 'auth0', token: idpJwt })
85
+ ```
86
+
87
+ ### Current user and permissions
88
+
89
+ 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:
90
+
91
+ ```typescript
92
+ const { user, permissions } = await client.me.get()
93
+ ```
94
+
95
+ ## Staff invitations
96
+
97
+ 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).
98
+
99
+ ## Custom fetch
100
+
101
+ Pass a custom `fetch` implementation when you need request interception, proxying, or a non-standard runtime:
102
+
103
+ ```typescript
104
+ const client = createAdminClient({
105
+ baseUrl: 'https://your-store.com',
106
+ secretKey: process.env.SPREE_SECRET_KEY,
107
+ fetch: customFetchImplementation,
108
+ })
109
+ ```
@@ -0,0 +1,130 @@
1
+ ---
2
+ title: "Filtering, pagination, and error handling in the Admin SDK"
3
+ sidebarTitle: "Querying & Errors"
4
+ description: "Filter, sort, paginate, and expand Admin API collections with flat Ransack parameters and handle structured SpreeError responses from @spree/admin-sdk."
5
+ ---
6
+
7
+ ## Filtering
8
+
9
+ 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:
10
+
11
+ ```typescript
12
+ const { data: orders } = await client.orders.list({
13
+ status_eq: 'complete', // exact match
14
+ total_gteq: 100, // greater than or equal
15
+ email_cont: '@example.com', // substring match
16
+ user_id_eq: 'cus_xxx', // prefixed IDs work directly
17
+ sort: '-completed_at',
18
+ page: 2,
19
+ limit: 50,
20
+ })
21
+ ```
22
+
23
+ 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.
24
+
25
+ > **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.
26
+
27
+ ## Sorting
28
+
29
+ Pass `sort` with an attribute name; prefix with `-` for descending. Comma-separate multiple fields:
30
+
31
+ ```typescript
32
+ await client.products.list({ sort: '-updated_at,name' })
33
+ ```
34
+
35
+ ## Pagination
36
+
37
+ List responses return `{ data, meta }`. Drive pagination with `page` and `limit`:
38
+
39
+ ```typescript
40
+ const { data, meta } = await client.products.list({ page: 1, limit: 50 })
41
+
42
+ meta.count // total records
43
+ meta.pages // total pages
44
+ meta.next // next page number, or null on the last page
45
+ meta.previous // previous page number, or null on the first
46
+ ```
47
+
48
+ A simple fetch-all loop:
49
+
50
+ ```typescript
51
+ let page: number | null = 1
52
+ while (page) {
53
+ const { data, meta } = await client.products.list({ page, limit: 100 })
54
+ process(data)
55
+ page = meta.next
56
+ }
57
+ ```
58
+
59
+ ## Expanding associations
60
+
61
+ Pass `expand` to embed related records in the response, instead of making follow-up requests. Dot notation reaches nested associations (up to 4 levels):
62
+
63
+ ```typescript
64
+ const order = await client.orders.get('order_xxx', {
65
+ expand: ['items', 'customer', 'fulfillments.items'],
66
+ })
67
+
68
+ const products = await client.products.list({
69
+ expand: ['variants', 'variants.media'],
70
+ })
71
+ ```
72
+
73
+ `fields` does the opposite — trims the response to just the attributes you name (`id` is always included):
74
+
75
+ ```typescript
76
+ await client.products.list({ fields: ['name', 'slug', 'status'] })
77
+ ```
78
+
79
+ ## Error handling
80
+
81
+ Every non-2xx response throws a `SpreeError` with a stable machine-readable `code`, the HTTP `status`, and optional structured `details`:
82
+
83
+ ```typescript
84
+ import { SpreeError } from '@spree/admin-sdk'
85
+
86
+ try {
87
+ await client.orders.update(orderId, { email })
88
+ } catch (err) {
89
+ if (err instanceof SpreeError) {
90
+ err.code // e.g. 'validation_error', 'record_not_found', 'access_denied'
91
+ err.status // e.g. 422
92
+ err.message // human-readable summary
93
+ err.details // optional structured context
94
+ }
95
+ }
96
+ ```
97
+
98
+ ### Validation errors
99
+
100
+ On `422` responses, `details` maps attribute names to arrays of messages — ready to project onto form fields:
101
+
102
+ ```typescript
103
+ try {
104
+ await client.products.create({ name: '' })
105
+ } catch (err) {
106
+ if (err instanceof SpreeError && err.status === 422) {
107
+ err.details // { name: ["can't be blank"] }
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### Scope errors
113
+
114
+ 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:
115
+
116
+ ```typescript
117
+ catch (err) {
118
+ if (err instanceof SpreeError && err.code === 'access_denied') {
119
+ console.error(`API key is missing scope: ${err.details?.required_scope}`)
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### Expired JWT sessions
125
+
126
+ For cookie-authenticated apps, register an `onUnauthorized` handler to transparently refresh and retry on `401` — see [Authentication](authentication.md#jwt--cookie-authentication-browser-apps).
127
+
128
+ ## Retries
129
+
130
+ 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 API
3
- description: Manage your store programmatically with the Spree Admin SDK
2
+ title: "Admin SDK quickstart for @spree/admin-sdk"
3
+ sidebarTitle: Quickstart
4
+ description: "Install and configure @spree/admin-sdk, the official TypeScript client for the Spree Admin API v3, to manage products, orders, customers, and stock."
4
5
  ---
5
6
 
6
- > **INFO:** The Admin API SDK is coming soon. The `client.admin` namespace is ready and will provide full access to administrative endpoints for managing products, orders, customers, and store settings.
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
- ## Preview
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 { createClient } from '@spree/sdk';
22
+ import { createAdminClient } from '@spree/admin-sdk'
12
23
 
13
- const client = createClient({
14
- baseUrl: 'https://api.mystore.com',
15
- secretKey: 'sk_xxx', // Admin API requires a secret key
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
- // Admin endpoints will be available under client.admin.*
19
- // client.admin.products.list()
20
- // client.admin.orders.list()
21
- // client.admin.customers.list()
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,127 @@
1
+ ---
2
+ title: "Admin SDK resources and CRUD client methods"
3
+ sidebarTitle: "Resources"
4
+ description: "Reference for every @spree/admin-sdk resource — products, orders, customers, inventory, pricing, promotions, store configuration, and platform clients."
5
+ ---
6
+
7
+ 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**:
8
+
9
+ ```typescript
10
+ // Top-level
11
+ const order = await client.orders.get('order_xxx')
12
+
13
+ // Nested — parent ID first
14
+ const payments = await client.orders.payments.list('order_xxx')
15
+ await client.orders.payments.capture('order_xxx', 'payment_xxx')
16
+
17
+ // Nested create
18
+ await client.customers.addresses.create('cus_xxx', {
19
+ first_name: 'Jane',
20
+ last_name: 'Doe',
21
+ address1: '350 Fifth Avenue',
22
+ city: 'New York',
23
+ postal_code: '10118',
24
+ country_iso: 'US',
25
+ state_abbr: 'NY',
26
+ is_default_shipping: true,
27
+ })
28
+ ```
29
+
30
+ ## Catalog
31
+
32
+ | Client | Endpoints |
33
+ |---|---|
34
+ | `client.products` | CRUD, `clone`, and bulk operations (`bulkStatusUpdate`, `bulkAddToCategories` / `bulkRemoveFromCategories`, `bulkAddToChannels` / `bulkRemoveFromChannels`, `bulkAddTags` / `bulkRemoveTags`, `bulkDestroy`). Nested: `media`, `variants` (with their own `media`). |
35
+ | `client.variants` | Top-level variant search across products (`list`, `get`). |
36
+ | `client.optionTypes` | CRUD on option types and their values. |
37
+ | `client.categories` | List categories. |
38
+ | `client.tags` | Autocomplete tag names per taggable type. |
39
+ | `client.taxCategories` | CRUD on tax categories. |
40
+
41
+ ## Orders & fulfillment
42
+
43
+ | Client | Endpoints |
44
+ |---|---|
45
+ | `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`. |
46
+
47
+ ## Customers
48
+
49
+ | Client | Endpoints |
50
+ |---|---|
51
+ | `client.customers` | CRUD plus bulk group operations (`bulkAddToGroups` / `bulkRemoveFromGroups`) and bulk tags. Nested: `addresses`, `creditCards`, `storeCredits`. |
52
+ | `client.customerGroups` | CRUD on customer groups. |
53
+
54
+ ## Pricing & promotions
55
+
56
+ | Client | Endpoints |
57
+ |---|---|
58
+ | `client.prices` | CRUD plus `bulkUpsert` / `bulkDestroy` for variant prices. |
59
+ | `client.priceLists` | CRUD, `activate` / `deactivate`, and price-list rule types. |
60
+ | `client.promotions` | CRUD. Nested: `actions`, `rules`, `couponCodes`. |
61
+ | `client.promotionActions` | Lookup of available action `types` and `calculators`. |
62
+ | `client.promotionRules` | Lookup of available rule `types`. |
63
+ | `client.giftCards` | CRUD on gift cards. |
64
+ | `client.giftCardBatches` | List, get, and create gift card batches. |
65
+ | `client.storeCreditCategories` | List and read store credit categories. |
66
+
67
+ ## Inventory
68
+
69
+ | Client | Endpoints |
70
+ |---|---|
71
+ | `client.stockLocations` | CRUD on stock locations. |
72
+ | `client.stockItems` | List, get, update, delete stock items. |
73
+ | `client.stockTransfers` | List, get, create, delete stock transfers. |
74
+
75
+ ## Sales channels
76
+
77
+ | Client | Endpoints |
78
+ |---|---|
79
+ | `client.channels` | CRUD plus `addProducts` / `removeProducts`. |
80
+ | `client.markets` | CRUD on markets. |
81
+
82
+ ## Store configuration
83
+
84
+ | Client | Endpoints |
85
+ |---|---|
86
+ | `client.store` | Store profile (`get`, `update`). |
87
+ | `client.paymentMethods` | CRUD plus `types` (available gateway types). |
88
+ | `client.countries` | List and read countries (for address dropdowns). |
89
+ | `client.customFieldDefinitions` | CRUD on [custom field](../../core-concepts/metafields.md) definitions. |
90
+ | `client.exports` | Create and track CSV exports (products, orders, customers, …). |
91
+ | `client.directUploads` | Pre-signed Active Storage uploads (used by media flows). |
92
+
93
+ ## Platform & access
94
+
95
+ | Client | Endpoints |
96
+ |---|---|
97
+ | `client.auth` | Login (email/password or identity provider), cookie-driven refresh, logout, invitation lookup/acceptance — see [Authentication](authentication.md). |
98
+ | `client.me` | Current admin user + permissions. |
99
+ | `client.adminUsers` | List, get, update, delete admin users. |
100
+ | `client.invitations` | Staff invitations — list, get, create, delete, `resend`. |
101
+ | `client.roles` | List and read roles. |
102
+ | `client.apiKeys` | CRUD plus `revoke` for API keys. |
103
+ | `client.allowedOrigins` | CRUD on CORS allowed origins. |
104
+ | `client.webhookEndpoints` | CRUD, `sendTest`, `enable` / `disable`. Nested: `deliveries` (list, get, `redeliver`). |
105
+ | `client.dashboard` | Sales analytics. |
106
+
107
+ ## Custom fields
108
+
109
+ 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:
110
+
111
+ ```typescript
112
+ await client.products.customFields.list('prod_xxx')
113
+ await client.products.customFields.create('prod_xxx', {
114
+ custom_field_definition_id: 'cfd_xxx',
115
+ value: 'limited-edition',
116
+ })
117
+ ```
118
+
119
+ The generic escape hatch covers any owner type:
120
+
121
+ ```typescript
122
+ await client.customFields('Spree::Product', 'prod_xxx').list()
123
+ ```
124
+
125
+ ## Adding your own resources
126
+
127
+ 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.
@@ -1,8 +1,11 @@
1
1
  ---
2
- title: Quickstart
3
- description: Install the Spree TypeScript SDK, configure your Store API client, and make your first calls to products, carts, checkout, and customer endpoints.
2
+ title: Spree TypeScript SDK quickstart for the Store API
3
+ sidebarTitle: Quickstart
4
+ description: Install @spree/sdk, configure the Store API client, and make your first calls to products, carts, checkout, and customer account endpoints from TypeScript.
4
5
  ---
5
6
 
7
+ `@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).
8
+
6
9
  ## Installation
7
10
 
8
11
  ```bash
@@ -70,7 +73,6 @@ The SDK uses a resource builder pattern for nested resources:
70
73
  | `customer` | `orders` | `list` |
71
74
  | `customer` | `paymentSetupSessions` | `create`, `get`, `complete` |
72
75
  | `policies` | — | `list`, `get` |
73
- | `categories` | `products` | `list` |
74
76
  | `wishlists` | `items` | `create`, `update`, `delete` |
75
77
 
76
78
  ```typescript
@@ -79,7 +81,6 @@ await client.carts.items.create(cartId, params, options);
79
81
  await client.carts.payments.list(cartId, options);
80
82
  await client.carts.fulfillments.update(cartId, fulfillmentId, params, options);
81
83
  await client.customer.addresses.list({}, options);
82
- await client.categories.products.list(categoryId, params, options);
83
84
  await client.wishlists.items.create(wishlistId, params, options);
84
85
  ```
85
86
 
@@ -1,5 +1,6 @@
1
1
  ---
2
- title: API
2
+ title: Expose a custom model through the Store and Admin APIs
3
+ sidebarTitle: API
3
4
  description: Expose your custom Brand model through the Spree Store and Admin REST APIs with serializers, controllers, routes, and the spree:api_resource generator.
4
5
  ---
5
6
 
@@ -362,7 +363,7 @@ curl -X POST -H "X-Spree-API-Key: sk_YOUR_KEY" \
362
363
  http://localhost:3000/api/v3/admin/brands
363
364
  ```
364
365
 
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.
366
+ > **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
367
 
367
368
  ## Step 6: Add Brand to Product Responses
368
369
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spree/docs",
3
- "version": "0.1.88",
3
+ "version": "0.1.90",
4
4
  "description": "Spree Commerce developer documentation for AI agents and local reference",
5
5
  "type": "module",
6
6
  "license": "CC-BY-4.0",