Skip to main content
The Admin SDK client exposes a request method — the same function that powers client.products.list(), client.orders.get(), and every other built-in resource. Use it to call any Admin API endpoint, including ones added by an extension gem that doesn’t ship its own client.
client.request uses the same auth headers (secret API key or JWT, whichever was configured at client creation), retry logic, and base URL as every other resource on the client. The 401 → refresh → retry handshake that’s wired up for the dashboard’s user session applies to your custom endpoint too.

Mutations

POST/PATCH/DELETE work the same way — pass { body } for the request payload:

Ransack filters and pagination

client.request sends params as the query string as they are, so write filters the way the Admin API reads them, as q[<attribute>_<predicate>]:
The built-in list methods take filters as plain keys and wrap them for you — client.products.list({ name_cont: 'nike' }) sends q[name_cont]=nike. To get the same in a wrapper of your own, define it as an extension (below): its listParams is that transform.

Shipping a client for an extension

An extension that adds Admin API endpoints ships a typed client for them as an npm package. The package is generated from the extension: spree sdk generate writes one SDK extension per resource, with a method per documented endpoint, and the types they take and return. An app adds them to its client with extend:
  • The extension’s calls use the client’s own request function: paths are relative to /api/v3/admin, with the same auth, headers, retries and defaults as the built-in resources.
  • extend returns a new client and leaves the original as it was. Both share their settings, so a token or locale set on either one applies to the other. extendAdminClient adds every namespace the package has; client.extend(quotes) adds one.
  • An extension adds a new namespace only. extend throws a TypeError for a name the client already has (products, or the same extension twice) and for an extension of another API.
  • The package lists @spree/admin-sdk as a peer dependency, so the app’s own client is the one extended.

Generating the client

The extension documents its endpoints with rswag specs (see documenting your extension’s endpoints); its serializers describe what they return. In the package, name the extension in package.json:
package.json
and run, from the package:
It runs the extension’s rake spree:openapi:generate and rake spree:sdk:serializer_types (build its test app first, with bundle exec rake test_app), then writes src/generated/<api>/: spree.ts re-exports the SDK’s types beside the package’s own, so a Quote that nests an order uses the SDK’s Order rather than a copy. Give the extension’s serializers names the SDK does not use: an OrderSerializer would clash with the SDK’s Order, and two serializers of one API ending in the same name are refused. A response with no schema in the document is typed by its resource’s name (quotes → Quote); one whose schema is declared inline, such as { data: [...] }, is typed from it as <Namespace><Method>Response (QuotesStatusesResponse). A method goes in the namespace of its path’s first segment, so a path nested under one of the SDK’s own resources, such as /carts/{cart_id}/quote_attachments, would make a carts namespace that extend refuses: put it in one of yours with sdk_method :presign_attachment, namespace: :quotes in the operation’s rswag spec. sdk_method also renames a method; unlike an operationId, it leaves the operation’s agent tool name alone. Two operations that would make one method are refused. Pass --no-backend to generate from the committed documents and types without running the rake tasks. Re-export what the package offers from its own entry point, and wrap or rename methods there if you want a different shape:
src/index.ts

Defining one by hand

For a single endpoint, or one the document does not describe, define the extension yourself. build gets the client’s request, plus listParams and readParams to build list and read queries the way the built-in methods do:

See also

  • The Store SDK extending guide covers the same pattern for storefront endpoints — the API is identical, only the base path (/api/v3/store) and auth header differ.
  • The API and SDK tutorials walk through creating new Spree endpoints end-to-end (Rails controller, serializer, TypeScript types). Everything they show for the Store API applies equivalently for the Admin API.
  • For building dashboard UI on top of your custom endpoint, see the Dashboard section — start with Customization Quickstart for in-app changes or Plugin Overview for redistributable packages.