---
openapi: 3.0.3
info:
  title: Admin API
  contact:
    name: Spree Commerce
    url: https://spreecommerce.org
    email: hello@spreecommerce.org
  description: |
    Spree Admin API v3 - Administrative API for managing products, orders, and store settings.

    ## Authentication

    The Admin API requires a secret API key passed in the `x-spree-api-key` header.
    Secret API keys can be generated in the Spree admin dashboard.

    ## Response Format

    All responses are JSON. List endpoints return paginated responses with `data` and `meta` keys.
    Single resource endpoints return a flat JSON object.

    ## Resource IDs

    Every resource is identified by an opaque string ID (e.g. `prod_86Rf07xd4z`,
    `variant_k5nR8xLq`, `or_UkLWZg9DAJ`). Use these IDs everywhere — URL paths,
    request bodies, and Ransack filters all accept them directly.

    ## Error Handling

    Errors return a consistent format:
    ```json
    {
      "error": {
        "code": "validation_error",
        "message": "Validation failed",
        "details": { "name": ["can't be blank"] }
      }
    }
    ```
  version: v3
paths:
  "/api/v3/admin/auth/login":
    post:
      summary: Login
      tags:
      - Authentication
      security:
      - api_key: []
      description: |
        Authenticates an admin user and returns a short-lived JWT access token.
        The rotatable refresh token is set in an HttpOnly cookie — it is not
        included in the response body.

        The `provider` field selects the authentication method. When omitted it
        defaults to `email`, the built-in email/password login.

        To authenticate against a third-party identity provider (Okta, Azure AD,
        Google Workspace SSO, a custom JWT issuer, SAML, etc.), send
        `{ "provider": "<your_key>", ... }` with the fields that provider
        requires. The endpoint returns the same JWT regardless of which provider
        authenticated the request. See
        [Custom API Authentication](https://spreecommerce.org/docs/developer/how-to/custom-api-authentication)
        for the list of configured providers and their required fields.
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // The refresh token is set as an HttpOnly cookie; only `token` and `user` come back in the body.
          const auth = await client.auth.login({
            email: 'admin@example.com',
            password: 'password123',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /auth/login -d '{"email":"admin@example.com","password":"password123"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: login successful
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJhZG1pbiIsImp0aSI6ImU3YjgzNTVhLTExYWUtNGNmYy1iNzYyLTM4NGQ5OGY1ZGQwZCIsImlzcyI6InNwcmVlIiwiYXVkIjoiYWRtaW5fYXBpIiwiZXhwIjoxNzg1MTgyNzA1fQ.i0SlPXHKVN5YG7XjmSIknXGFOaKgeBwHiNkyQzHEqzw
                user:
                  id: admin_UkLWZg9DAJ
                  email: admin@example.com
                  first_name: Tien
                  last_name: Medhurst
                  full_name: Tien Medhurst
                  selected_locale:
                  created_at: '2026-07-27T20:00:04.732Z'
                  updated_at: '2026-07-27T20:00:04.732Z'
                  avatar_url:
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
                  stores:
                  - id: store_UkLWZg9DAJ
                    name: Spree Test Store
                    code: spree_1
              schema:
                "$ref": "#/components/schemas/AuthResponse"
        '401':
          description: invalid credentials
          content:
            application/json:
              example:
                error:
                  code: authentication_failed
                  message: Invalid email or password
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
              - title: EmailPasswordLogin
                description: Built-in email/password authentication (default when
                  `provider` is omitted).
                type: object
                properties:
                  provider:
                    type: string
                    enum:
                    - email
                    default: email
                  email:
                    type: string
                    format: email
                    example: admin@example.com
                  password:
                    type: string
                    example: password123
                required:
                - email
                - password
              - title: ProviderLogin
                description: |
                  Provider-dispatched login. The `provider` key selects a configured
                  authentication provider; the remaining fields are forwarded to it.
                  Required fields depend on the provider — see
                  [Custom API Authentication](https://spreecommerce.org/docs/developer/how-to/custom-api-authentication).
                type: object
                properties:
                  provider:
                    type: string
                    example: okta
                    description: Registered provider key (anything other than `email`).
                    not:
                      enum:
                      - email
                required:
                - provider
                additionalProperties: true
  "/api/v3/admin/auth/refresh":
    post:
      summary: Refresh token
      tags:
      - Authentication
      security:
      - api_key: []
      description: |
        Exchanges the HttpOnly refresh-token cookie for a new access JWT and a
        rotated refresh token cookie. No request body or Authorization header
        is required — the cookie alone authenticates the call.
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Driven entirely by the HttpOnly refresh-token cookie + CSRF header (set by the SDK).
          const auth = await client.auth.refresh()
      - lang: bash
        label: Spree CLI
        source: spree api post /auth/refresh
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: refresh successful
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJhZG1pbiIsImp0aSI6IjIwMzFkOWE3LTljMGMtNGNkZi05ZWU2LTE0MDI0MjIwZGFlYSIsImlzcyI6InNwcmVlIiwiYXVkIjoiYWRtaW5fYXBpIiwiZXhwIjoxNzg1MTgyNzA1fQ.qe0T7bUxlw38ohjW5xR0Xv2qflnGYPBNrib-RaTblI8
                user:
                  id: admin_UkLWZg9DAJ
                  email: admin@example.com
                  first_name: Santo
                  last_name: Pagac
                  full_name: Santo Pagac
                  selected_locale:
                  created_at: '2026-07-27T20:00:05.821Z'
                  updated_at: '2026-07-27T20:00:05.821Z'
                  avatar_url:
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
                  stores:
                  - id: store_UkLWZg9DAJ
                    name: Spree Test Store
                    code: spree_1
              schema:
                "$ref": "#/components/schemas/AuthResponse"
        '401':
          description: missing or invalid refresh-token cookie
          content:
            application/json:
              example:
                error:
                  code: invalid_refresh_token
                  message: Refresh token cookie missing
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/admin/auth/logout":
    post:
      summary: Logout
      tags:
      - Authentication
      security:
      - api_key: []
      description: Revokes the refresh-token cookie, effectively logging the admin
        out.
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.auth.logout()
      - lang: bash
        label: Spree CLI
        source: spree api post /auth/logout
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: logout successful
  "/api/v3/admin/me":
    get:
      summary: Get current admin user and permissions
      tags:
      - Authentication
      security:
      - api_key: []
        bearer_auth: []
      description: Returns the current admin user profile and a serialized list of
        permissions (CanCanCan rules). The SPA uses these to drive UI permission checks.
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const me = await client.me.get()
          if (me.permissions.some((r) => r.allow && r.actions.includes('manage') && r.subjects.includes('Spree::Product'))) {
            // show "Create product" button
          }
      - lang: bash
        label: Spree CLI
        source: spree api get /me
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: current admin user and permissions
          content:
            application/json:
              example:
                user:
                  id: admin_UkLWZg9DAJ
                  email: evalyn_legros@schadenhermiston.info
                  first_name: Charleen
                  last_name: Kihn
                  full_name: Charleen Kihn
                  selected_locale:
                  created_at: '2026-07-27T20:00:44.530Z'
                  updated_at: '2026-07-27T20:00:44.530Z'
                  avatar_url:
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
                  stores:
                  - id: store_UkLWZg9DAJ
                    name: Spree Test Store
                    code: spree_1
                permissions:
                - allow: true
                  actions:
                  - manage
                  subjects:
                  - all
                  has_conditions: false
                - allow: false
                  actions:
                  - cancel
                  subjects:
                  - Spree::Order
                  has_conditions: false
                - allow: true
                  actions:
                  - cancel
                  subjects:
                  - Spree::Order
                  has_conditions: true
                - allow: false
                  actions:
                  - destroy
                  subjects:
                  - Spree::Order
                  has_conditions: false
                - allow: true
                  actions:
                  - destroy
                  subjects:
                  - Spree::Order
                  has_conditions: true
                - allow: false
                  actions:
                  - edit
                  - update
                  subjects:
                  - Spree::RefundReason
                  has_conditions: true
                - allow: false
                  actions:
                  - edit
                  - update
                  subjects:
                  - Spree::ReimbursementType
                  has_conditions: true
                - allow: false
                  actions:
                  - update
                  - destroy
                  subjects:
                  - Spree::Role
                  has_conditions: true
              schema:
                "$ref": "#/components/schemas/MeResponse"
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update the current admin profile
      tags:
      - Authentication
      security:
      - api_key: []
        bearer_auth: []
      description: Self-service update of the signed-in admin's own profile, such
        as their admin UI display language (`selected_locale`).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Set the signed-in admin's own UI display language.
          const me = await client.me.update({
            selected_locale: 'de',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /me -d '{"selected_locale":"de"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: profile updated
          content:
            application/json:
              example:
                user:
                  id: admin_UkLWZg9DAJ
                  email: telma_zemlak@gutmannborer.com
                  first_name: Beulah
                  last_name: Schimmel
                  full_name: Beulah Schimmel
                  selected_locale: de
                  created_at: '2026-07-27T20:00:44.839Z'
                  updated_at: '2026-07-27T20:00:44.854Z'
                  avatar_url:
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
                  stores:
                  - id: store_UkLWZg9DAJ
                    name: Spree Test Store
                    code: spree_1
                permissions:
                - allow: true
                  actions:
                  - manage
                  subjects:
                  - all
                  has_conditions: false
                - allow: false
                  actions:
                  - cancel
                  subjects:
                  - Spree::Order
                  has_conditions: false
                - allow: true
                  actions:
                  - cancel
                  subjects:
                  - Spree::Order
                  has_conditions: true
                - allow: false
                  actions:
                  - destroy
                  subjects:
                  - Spree::Order
                  has_conditions: false
                - allow: true
                  actions:
                  - destroy
                  subjects:
                  - Spree::Order
                  has_conditions: true
                - allow: false
                  actions:
                  - edit
                  - update
                  subjects:
                  - Spree::RefundReason
                  has_conditions: true
                - allow: false
                  actions:
                  - edit
                  - update
                  subjects:
                  - Spree::ReimbursementType
                  has_conditions: true
                - allow: false
                  actions:
                  - update
                  - destroy
                  subjects:
                  - Spree::Role
                  has_conditions: true
              schema:
                "$ref": "#/components/schemas/MeResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                selected_locale:
                  type: string
                  example: de
                first_name:
                  type: string
                  example: Ada
                last_name:
                  type: string
                  example: Lovelace
  "/api/v3/admin/auth/password_resets":
    post:
      summary: Request password reset
      tags:
      - Authentication
      security:
      - api_key: []
      description: |
        Requests a password reset email for an admin user. Always returns `202`
        whether or not the email matches an account, to prevent enumeration.

        `redirect_url` is where the emailed link should point (the reset token
        is appended as a `token` query param). It must match one of the store's
        allowed origins — otherwise it is silently ignored and the server-side
        default is used. The email is delivered by Spree itself via the
        `admin_user.password_reset_requested` event; this event is never
        forwarded to webhook endpoints.
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Always resolves (202) whether or not the email exists — no account enumeration.
          // The emailed link points at redirect_url with the reset token appended as ?token=.
          await client.auth.requestPasswordReset({
            email: 'admin@example.com',
            redirect_url: 'https://admin.your-store.com/reset-password',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /auth/password_resets -d '{"email":"admin@example.com","redirect_url":"https://admin.your-store.com/reset-password"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '202':
          description: reset requested
          content:
            application/json:
              example:
                message: If an account exists for that email, password reset instructions
                  have been sent.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  example: admin@example.com
                redirect_url:
                  type: string
                  example: https://admin.your-store.com/reset-password
                  description: Must match an allowed origin of the store; ignored
                    otherwise.
              required:
              - email
  "/api/v3/admin/auth/password_resets/{id}":
    patch:
      summary: Reset password
      tags:
      - Authentication
      security:
      - api_key: []
      description: |
        Consumes a password reset token (the `token` query param from the
        emailed link), sets the new password, and signs the admin in: the
        response carries a JWT access token and the rotatable refresh token is
        set in an HttpOnly cookie. The token is single-use — it invalidates as
        soon as the password changes.
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // The token comes from the emailed link's ?token= param. On success the admin
          // is signed in: a JWT comes back and the refresh token is set as an HttpOnly cookie.
          const auth = await client.auth.resetPassword('reset-token-from-email', {
            password: 'new-password-123',
            password_confirmation: 'new-password-123',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /auth/password_resets/{id} -d '{"password":"new-password-123","password_confirmation":"new-password-123"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        description: The reset token from the emailed link
        required: true
        schema:
          type: string
      responses:
        '200':
          description: password reset
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJhZG1pbiIsImp0aSI6ImI5ZTA5YzBhLTYxMzctNGQ4YS1iM2RjLTFkMDUwZmNmOTM5YiIsImlzcyI6InNwcmVlIiwiYXVkIjoiYWRtaW5fYXBpIiwiZXhwIjoxNzg1MTg2MDc2fQ.U397bHv2j422wBayJZbq3D2Cj2_wmZ7t73zs9k7FXwE
                user:
                  id: admin_UkLWZg9DAJ
                  email: admin@example.com
                  first_name: Sana
                  last_name: Marvin
                  full_name: Sana Marvin
                  selected_locale:
                  created_at: '2026-07-27T20:01:16.038Z'
                  updated_at: '2026-07-27T20:01:16.312Z'
                  avatar_url:
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
                  stores:
                  - id: store_UkLWZg9DAJ
                    name: Spree Test Store
                    code: spree_1
              schema:
                "$ref": "#/components/schemas/AuthResponse"
        '422':
          description: invalid or expired token
          content:
            application/json:
              example:
                error:
                  code: password_reset_token_invalid
                  message: Password reset token is invalid or has expired.
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
                  example: new-password-123
                password_confirmation:
                  type: string
                  example: new-password-123
              required:
              - password
              - password_confirmation
  "/api/v3/admin/allowed_origins":
    get:
      summary: List allowed origins
      tags:
      - Allowed Origins
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the CORS allowlist for the current store. Each entry is a
        bare `scheme://host[:port]` permitted to call the admin API from a
        browser. Backs the `Rack::Cors` allowlist and the CSRF boundary of
        the admin cookie session (see
        `docs/plans/5.5-admin-auth-cookie-refresh.md`).


        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: origins } = await client.allowedOrigins.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /allowed_origins
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[origin_cont]
        in: query
        required: false
        description: Filter by origin (contains)
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending (e.g., `-created_at`).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: allowed origins found
          content:
            application/json:
              example:
                data:
                - id: ao_UkLWZg9DAJ
                  origin: https://shop.example.com
                  created_at: '2026-07-27T20:00:00.158Z'
                  updated_at: '2026-07-27T20:00:00.158Z'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/AllowedOrigin"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create an allowed origin
      tags:
      - Allowed Origins
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds an origin to the admin CORS allowlist. The value must be a bare
        `scheme://host[:port]` (no path, query, or fragment) and use `http` or
        `https`.


        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const origin = await client.allowedOrigins.create({
            origin: 'https://admin.example.com',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /allowed_origins -d '{"origin":"https://admin.example.com"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: allowed origin created
          content:
            application/json:
              example:
                id: ao_gbHJdmfrXB
                origin: https://admin.example.com
                created_at: '2026-07-27T20:00:00.744Z'
                updated_at: '2026-07-27T20:00:00.744Z'
              schema:
                "$ref": "#/components/schemas/AllowedOrigin"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Origin is invalid
                  details:
                    origin:
                    - is invalid
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                origin:
                  type: string
                  example: https://admin.example.com
              required:
              - origin
  "/api/v3/admin/allowed_origins/{id}":
    parameters:
    - name: id
      in: path
      required: true
      description: Allowed origin ID
      schema:
        type: string
    get:
      summary: Get an allowed origin
      tags:
      - Allowed Origins
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single allowed origin by prefixed ID.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const origin = await client.allowedOrigins.get('ao_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /allowed_origins/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: allowed origin found
          content:
            application/json:
              example:
                id: ao_UkLWZg9DAJ
                origin: https://shop.example.com
                created_at: '2026-07-27T20:00:01.037Z'
                updated_at: '2026-07-27T20:00:01.037Z'
              schema:
                "$ref": "#/components/schemas/AllowedOrigin"
        '404':
          description: allowed origin not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Allowed origin not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update an allowed origin
      tags:
      - Allowed Origins
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates an existing allowed origin.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const origin = await client.allowedOrigins.update('ao_xxx', {
            origin: 'https://www.example.com',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /allowed_origins/{id} -d '{"origin":"https://www.example.com"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: allowed origin updated
          content:
            application/json:
              example:
                id: ao_UkLWZg9DAJ
                origin: https://www.example.com
                created_at: '2026-07-27T20:00:01.603Z'
                updated_at: '2026-07-27T20:00:01.879Z'
              schema:
                "$ref": "#/components/schemas/AllowedOrigin"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Origin must be an origin (scheme and host) without path,
                    query, or fragment
                  details:
                    origin:
                    - must be an origin (scheme and host) without path, query, or
                      fragment
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                origin:
                  type: string
    delete:
      summary: Delete an allowed origin
      tags:
      - Allowed Origins
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes an origin from the admin CORS allowlist. After deletion the
        admin SPA running at that origin will no longer be able to call the
        admin API from a browser.


        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.allowedOrigins.delete('ao_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /allowed_origins/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '204':
          description: allowed origin deleted
  "/api/v3/admin/api_keys":
    get:
      summary: List API keys
      tags:
      - API Keys
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns publishable and secret API keys for the current store. Secret keys are listed by `token_prefix` only — the plaintext token is delivered exactly once on create.

        **Required scope:** `read_api_keys` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: keys } = await client.apiKeys.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /api_keys
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: API keys found
          content:
            application/json:
              example:
                data:
                - id: key_UkLWZg9DAJ
                  name: Storefront key
                  key_type: publishable
                  token_prefix:
                  scopes: []
                  created_at: '2026-07-27T20:00:02.459Z'
                  updated_at: '2026-07-27T20:00:02.459Z'
                  revoked_at:
                  last_used_at:
                  channel_id:
                  plaintext_token: pk_BUr9aRDjsVXrXqA54fhUUKJr
                  created_by_email:
                - id: key_gbHJdmfrXB
                  name: Backend integration
                  key_type: secret
                  token_prefix: sk_X1KbsdrkJ
                  scopes:
                  - write_all
                  created_at: '2026-07-27T20:00:02.460Z'
                  updated_at: '2026-07-27T20:00:02.460Z'
                  revoked_at:
                  last_used_at:
                  channel_id:
                  plaintext_token:
                  created_by_email:
                - id: key_EfhxLZ9ck8
                  name: perspiciatis
                  key_type: secret
                  token_prefix: sk_KwNinNmrS
                  scopes:
                  - write_all
                  created_at: '2026-07-27T20:00:02.461Z'
                  updated_at: '2026-07-27T20:00:02.461Z'
                  revoked_at:
                  last_used_at:
                  channel_id:
                  plaintext_token:
                  created_by_email:
                meta:
                  page: 1
                  limit: 25
                  count: 3
                  pages: 1
                  from: 1
                  to: 3
                  in: 3
                  previous:
                  next:
    post:
      summary: Create an API key
      tags:
      - API Keys
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a publishable or secret API key. The plaintext token is included in the response **once** for secret keys; publishable keys expose their token on every read since they are intended for client-side use.

        **Required scope:** `write_api_keys` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const key = await client.apiKeys.create({
            name: 'Backend integration',
            key_type: 'secret',
            scopes: ['read_orders', 'write_orders']
          })
          // `key.plaintext_token` is available only on this response.
      - lang: bash
        label: Spree CLI
        source: spree api post /api_keys -d '{"name":"Backend integration","key_type":"secret","scopes":["read_orders","write_orders"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: secret key created — plaintext token returned once
          content:
            application/json:
              example:
                id: key_VqXmZF31wY
                name: CI key
                key_type: secret
                token_prefix: sk_RTADPjJfn
                scopes:
                - read_orders
                created_at: '2026-07-27T20:00:03.022Z'
                updated_at: '2026-07-27T20:00:03.022Z'
                revoked_at:
                last_used_at:
                channel_id:
                plaintext_token: sk_RTADPjJfnvUVe2ckb1F9Kmkr
                created_by_email: treasa@lemke.ca
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank and Scopes can't be blank
                  details:
                    name:
                    - can't be blank
                    scopes:
                    - can't be blank
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              - key_type
              properties:
                name:
                  type: string
                  example: Backend integration
                key_type:
                  type: string
                  enum:
                  - publishable
                  - secret
                scopes:
                  type: array
                  items:
                    type: string
                  example:
                  - read_orders
                  - write_orders
  "/api/v3/admin/api_keys/{id}":
    get:
      summary: Show an API key
      tags:
      - API Keys
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_api_keys` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const key = await client.apiKeys.get('key_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /api_keys/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: API key found
          content:
            application/json:
              example:
                id: key_UkLWZg9DAJ
                name: Storefront key
                key_type: publishable
                token_prefix:
                scopes: []
                created_at: '2026-07-27T20:00:03.310Z'
                updated_at: '2026-07-27T20:00:03.310Z'
                revoked_at:
                last_used_at:
                channel_id:
                plaintext_token: pk_eTVTrmwQTUc16hVEk4nqknYg
                created_by_email:
    patch:
      summary: Update an API key
      tags:
      - API Keys
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Renames a key. `key_type` and `scopes` are fixed at creation — to change a key's authority, create a new key and revoke the old one.

        **Required scope:** `write_api_keys` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Only `name` is editable — scopes and key_type are fixed at creation.
          const key = await client.apiKeys.update('key_xxx', { name: 'CI key (renamed)' })
      - lang: bash
        label: Spree CLI
        source: spree api patch /api_keys/{id} -d '{"name":"CI key (renamed)"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: API key renamed
          content:
            application/json:
              example:
                id: key_gbHJdmfrXB
                name: Backend integration (renamed)
                key_type: secret
                token_prefix: sk_mW4Ca8p5F
                scopes:
                - write_all
                created_at: '2026-07-27T20:00:03.592Z'
                updated_at: '2026-07-27T20:00:03.885Z'
                revoked_at:
                last_used_at:
                channel_id:
                plaintext_token:
                created_by_email:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Backend integration (renamed)
    delete:
      summary: Delete an API key
      tags:
      - API Keys
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_api_keys` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.apiKeys.delete('key_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /api_keys/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: API key deleted
  "/api/v3/admin/api_keys/current":
    get:
      summary: Describe the current API key
      tags:
      - API Keys
      security:
      - api_key: []
      description: |-
        Returns the secret key that authenticated this request, including its live scopes. Useful to confirm a key's real, current authority. Only secret-key principals have a single key to describe.

        **Required scope:** none — any key can describe itself (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Describes the key you authenticated with, including its live scopes.
          const key = await client.apiKeys.current()
      - lang: bash
        label: Spree CLI
        source: spree api get /api_keys/current
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: current API key
          content:
            application/json:
              example:
                id: key_EfhxLZ9ck8
                name: ipsam
                key_type: secret
                token_prefix: sk_ekeeHsr4J
                scopes:
                - write_all
                created_at: '2026-07-27T20:00:04.179Z'
                updated_at: '2026-07-27T20:00:04.179Z'
                revoked_at:
                last_used_at:
                channel_id:
                plaintext_token:
                created_by_email:
  "/api/v3/admin/api_keys/{id}/revoke":
    patch:
      summary: Revoke an API key
      tags:
      - API Keys
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Marks the key revoked. Future requests using its token will fail; the row is preserved for audit.

        **Required scope:** `write_api_keys` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const key = await client.apiKeys.revoke('key_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api patch /api_keys/{id}/revoke -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: API key revoked
          content:
            application/json:
              example:
                id: key_gbHJdmfrXB
                name: Backend integration
                key_type: secret
                token_prefix: sk_TiYvmwsZg
                scopes:
                - write_all
                created_at: '2026-07-27T20:00:04.193Z'
                updated_at: '2026-07-27T20:00:04.470Z'
                revoked_at: '2026-07-27T20:00:04.470Z'
                last_used_at:
                channel_id:
                plaintext_token:
                created_by_email:
  "/api/v3/admin/categories":
    get:
      summary: List categories
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a paginated list of the store's categories (manual hierarchical taxons; rule-based collections are excluded).

        **Required scope:** `read_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., children, parent,
          ancestors).
        schema:
          type: string
      responses:
        '200':
          description: categories found
          content:
            application/json:
              example:
                data:
                - id: ctg_UkLWZg9DAJ
                  name: Clothing
                  permalink: clothing
                  position: 0
                  depth: 0
                  meta_title:
                  meta_description:
                  meta_keywords:
                  children_count: 0
                  parent_id:
                  description: ''
                  description_html: ''
                  image_url:
                  square_image_url:
                  is_root: true
                  is_child: false
                  is_leaf: true
                  metadata: {}
                  pretty_name: Clothing
                  lft: 1
                  rgt: 2
                  products_count: 0
                  created_at: '2026-07-27T20:00:06.415Z'
                  updated_at: '2026-07-27T20:00:06.415Z'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Category"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
    post:
      summary: Create a category
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a category. Nests under the parent when parent_id is given, otherwise creates a top-level category.

        **Required scope:** `write_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: category created
          content:
            application/json:
              example:
                id: ctg_gbHJdmfrXB
                name: Shirts
                permalink: clothing/shirts
                position: 0
                depth: 1
                meta_title:
                meta_description:
                meta_keywords:
                children_count: 0
                parent_id: ctg_UkLWZg9DAJ
                description: ''
                description_html: ''
                image_url:
                square_image_url:
                is_root: false
                is_child: true
                is_leaf: true
                metadata: {}
                pretty_name: Clothing -> Shirts
                lft: 2
                rgt: 3
                products_count: 0
                created_at: '2026-07-27T20:00:06.985Z'
                updated_at: '2026-07-27T20:00:06.991Z'
              schema:
                "$ref": "#/components/schemas/Category"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Shirts
                parent_id:
                  type: string
                  example: ctg_abc123
                  description: Prefixed ID of the parent category
                description:
                  type: string
                permalink:
                  type: string
                meta_title:
                  type: string
                meta_description:
                  type: string
                meta_keywords:
                  type: string
                hide_from_nav:
                  type: boolean
                  example: false
              required:
              - name
  "/api/v3/admin/categories/{id}":
    get:
      summary: Get a category
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single category by ID.

        **Required scope:** `read_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Category ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., children, parent,
          ancestors).
        schema:
          type: string
      responses:
        '200':
          description: category found
          content:
            application/json:
              example:
                id: ctg_UkLWZg9DAJ
                name: Clothing
                permalink: clothing
                position: 0
                depth: 0
                meta_title:
                meta_description:
                meta_keywords:
                children_count: 0
                parent_id:
                description: ''
                description_html: ''
                image_url:
                square_image_url:
                is_root: true
                is_child: false
                is_leaf: true
                metadata: {}
                pretty_name: Clothing
                lft: 1
                rgt: 2
                products_count: 0
                created_at: '2026-07-27T20:00:07.305Z'
                updated_at: '2026-07-27T20:00:07.305Z'
              schema:
                "$ref": "#/components/schemas/Category"
        '404':
          description: category not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Category not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a category
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a category.

        **Required scope:** `write_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Category ID
        schema:
          type: string
      responses:
        '200':
          description: category updated
          content:
            application/json:
              example:
                id: ctg_UkLWZg9DAJ
                name: Apparel
                permalink: clothing
                position: 0
                depth: 0
                meta_title:
                meta_description:
                meta_keywords:
                children_count: 0
                parent_id:
                description: ''
                description_html: ''
                image_url:
                square_image_url:
                is_root: true
                is_child: false
                is_leaf: true
                metadata: {}
                pretty_name: Apparel
                lft: 1
                rgt: 2
                products_count: 0
                created_at: '2026-07-27T20:00:07.899Z'
                updated_at: '2026-07-27T20:00:08.186Z'
              schema:
                "$ref": "#/components/schemas/Category"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Apparel
                parent_id:
                  type: string
                  description: Prefixed ID of the parent category
                description:
                  type: string
                permalink:
                  type: string
                meta_title:
                  type: string
                meta_description:
                  type: string
                meta_keywords:
                  type: string
                hide_from_nav:
                  type: boolean
    delete:
      summary: Delete a category
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes a category and its descendants.

        **Required scope:** `write_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Category ID
        schema:
          type: string
      responses:
        '204':
          description: category deleted
  "/api/v3/admin/categories/{id}/reposition":
    patch:
      summary: Reposition a category
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Moves a category to a new parent and/or index within the tree.

        **Required scope:** `write_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Category ID
        schema:
          type: string
      responses:
        '200':
          description: category repositioned
          content:
            application/json:
              example:
                id: ctg_gbHJdmfrXB
                name: Footwear
                permalink: clothing/footwear
                position: 0
                depth: 1
                meta_title:
                meta_description:
                meta_keywords:
                children_count: 0
                parent_id: ctg_UkLWZg9DAJ
                description: ''
                description_html: ''
                image_url:
                square_image_url:
                is_root: false
                is_child: true
                is_leaf: true
                metadata: {}
                pretty_name: Clothing -> Footwear
                lft: 2
                rgt: 3
                products_count: 0
                created_at: '2026-07-27T20:00:08.500Z'
                updated_at: '2026-07-27T20:00:08.791Z'
              schema:
                "$ref": "#/components/schemas/Category"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                new_parent_id:
                  type: string
                  description: Prefixed ID of the new parent (omit for top level)
                new_position:
                  type: integer
                  description: 0-based index among the new parent's children
              required:
              - new_position
  "/api/v3/admin/categories/{category_id}/products":
    get:
      summary: List category products
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Products classified under the category, ordered by their classification position.

        **Required scope:** `read_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: category_id
        in: path
        required: true
        description: Category ID
        schema:
          type: string
      responses:
        '200':
          description: products found
          content:
            application/json:
              example:
                data: []
                meta:
                  page: 1
                  limit: 25
                  count: 0
                  pages: 1
                  from: 0
                  to: 0
                  in: 0
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Product"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
    post:
      summary: Add a product to a category
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Classifies a product under the category (appended to the end).

        **Required scope:** `write_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: category_id
        in: path
        required: true
        description: Category ID
        schema:
          type: string
      responses:
        '201':
          description: product added
          content:
            application/json:
              example:
                id: prod_UkLWZg9DAJ
                name: Product 19585
                slug: product-19585
                meta_title:
                meta_description:
                meta_keywords:
                variant_count: 0
                available_on:
                preorder_ships_at:
                purchasable: true
                preorder: false
                in_stock: false
                backorderable: true
                available: true
                description: Inventore dicta voluptates rem amet ipsa. Dolores inventore
                  dicta commodi sequi non aliquam officia. Saepe maiores itaque in
                  earum repudiandae magnam fugit commodi. Reiciendis dolorem distinctio
                  earum a. Soluta ipsa eum sit suscipit eaque autem voluptate. Fugiat
                  asperiores non adipisci dicta consequuntur excepturi quia velit.
                  Quidem quas optio vitae voluptates nihil iste eaque. Laboriosam
                  vel quibusdam doloremque unde quis. Tempore sit eaque dolor possimus
                  pariatur molestiae perspiciatis. Impedit repudiandae perspiciatis
                  unde id accusantium nisi eos placeat. Nostrum voluptatibus assumenda
                  voluptas nesciunt molestias voluptates dicta quasi. Aliquam vitae
                  velit adipisci soluta sunt doloremque asperiores. Modi architecto
                  nisi asperiores reiciendis aspernatur voluptatum odit. Asperiores
                  facilis omnis quas officiis iusto ex sapiente. Quae sed architecto
                  fugit dolores. Non officia omnis asperiores tempore nemo hic deleniti
                  beatae. Ullam minima excepturi aspernatur qui voluptas sequi corrupti.
                  Quo aliquam excepturi laborum ullam ipsa recusandae. Aspernatur
                  vitae pariatur distinctio dolorum veritatis aliquam repellat. Corrupti
                  quo molestiae dicta assumenda quidem vitae temporibus.
                description_html: |-
                  Inventore dicta voluptates rem amet ipsa. Dolores inventore dicta commodi sequi non aliquam officia. Saepe maiores itaque in earum repudiandae magnam fugit commodi.
                  Reiciendis dolorem distinctio earum a. Soluta ipsa eum sit suscipit eaque autem voluptate. Fugiat asperiores non adipisci dicta consequuntur excepturi quia velit. Quidem quas optio vitae voluptates nihil iste eaque.
                  Laboriosam vel quibusdam doloremque unde quis. Tempore sit eaque dolor possimus pariatur molestiae perspiciatis. Impedit repudiandae perspiciatis unde id accusantium nisi eos placeat. Nostrum voluptatibus assumenda voluptas nesciunt molestias voluptates dicta quasi.
                  Aliquam vitae velit adipisci soluta sunt doloremque asperiores. Modi architecto nisi asperiores reiciendis aspernatur voluptatum odit. Asperiores facilis omnis quas officiis iusto ex sapiente. Quae sed architecto fugit dolores. Non officia omnis asperiores tempore nemo hic deleniti beatae.
                  Ullam minima excepturi aspernatur qui voluptas sequi corrupti. Quo aliquam excepturi laborum ullam ipsa recusandae. Aspernatur vitae pariatur distinctio dolorum veritatis aliquam repellat. Corrupti quo molestiae dicta assumenda quidem vitae temporibus.
                default_variant_id: variant_UkLWZg9DAJ
                thumbnail_url:
                tags: []
                price:
                  id: price_UkLWZg9DAJ
                  amount: '19.99'
                  amount_in_cents: 1999
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$19.99"
                  display_compare_at_amount:
                  price_list_id:
                  variant_id: variant_UkLWZg9DAJ
                  created_at: '2026-07-27T20:00:09.164Z'
                  updated_at: '2026-07-27T20:00:09.164Z'
                original_price:
                status: active
                metadata: {}
                deleted_at:
                created_at: '2026-07-27T20:00:09.145Z'
                updated_at: '2026-07-27T20:00:09.175Z'
                tax_category_id: taxcat_UkLWZg9DAJ
              schema:
                "$ref": "#/components/schemas/Product"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                product_id:
                  type: string
                  example: prod_abc123
              required:
              - product_id
  "/api/v3/admin/categories/{category_id}/products/{id}/reposition":
    patch:
      summary: Reposition a category product
      tags:
      - Categories
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Moves a product to a new index among the category's products.

        **Required scope:** `write_categories` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: category_id
        in: path
        required: true
        description: Category ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      responses:
        '204':
          description: product repositioned
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                new_position:
                  type: integer
                  description: 0-based index among the category's products
              required:
              - new_position
  "/api/v3/admin/channels":
    get:
      summary: List channels
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the channels configured for the current store.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: channels } = await client.channels.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /channels
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        schema:
          type: integer
      responses:
        '200':
          description: channels found
          content:
            application/json:
              example:
                data:
                - id: ch_UkLWZg9DAJ
                  name: Online Store
                  code: online
                  active: true
                  default: true
                  storefront_access: public
                  guest_checkout: true
                  preferred_order_routing_strategy:
                  preferred_storefront_access:
                  preferred_guest_checkout:
                  created_at: '2026-07-27T19:59:58.883Z'
                  updated_at: '2026-07-27T19:59:58.883Z'
                - id: ch_gbHJdmfrXB
                  name: Wholesale
                  code: wholesale
                  active: true
                  default: false
                  storefront_access: public
                  guest_checkout: true
                  preferred_order_routing_strategy:
                  preferred_storefront_access:
                  preferred_guest_checkout:
                  created_at: '2026-07-27T20:00:09.837Z'
                  updated_at: '2026-07-27T20:00:09.837Z'
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Channel"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
    post:
      summary: Create a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new channel on the current store. `code` is normalized to a
        URL-safe slug (`Point of Sale` → `point-of-sale`); when omitted it's
        derived from `name`.


        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // `code` is optional — when omitted it's derived from `name`
          // ("Point of Sale" → "point-of-sale").
          const channel = await client.channels.create({
            name: 'Point of Sale',
            code: 'pos',
            active: true,
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /channels -d '{"name":"Point of Sale","code":"pos","active":true}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: channel created
          content:
            application/json:
              example:
                id: ch_EfhxLZ9ck8
                name: Marketplace
                code: marketplace
                active: true
                default: false
                storefront_access: public
                guest_checkout: true
                preferred_order_routing_strategy:
                preferred_storefront_access:
                preferred_guest_checkout:
                created_at: '2026-07-27T20:00:10.427Z'
                updated_at: '2026-07-27T20:00:10.427Z'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                  example: Point of Sale
                code:
                  type: string
                  example: pos
                  description: Slug — auto-derived from `name` when blank.
                active:
                  type: boolean
                  default: true
                default:
                  type: boolean
                  default: false
                preferred_order_routing_strategy:
                  type: string
                  nullable: true
                  description: Routing strategy class name. `null` inherits the store
                    setting.
                preferred_storefront_access:
                  type: string
                  nullable: true
                  enum:
                  - public
                  - prices_hidden
                  - login_required
                  description: Anonymous-visitor access posture. `null` inherits the
                    store setting.
                preferred_guest_checkout:
                  type: boolean
                  nullable: true
                  description: Whether guests can check out without an account. `null`
                    inherits the store setting.
  "/api/v3/admin/channels/{id}":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: Get a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const channel = await client.channels.get('channel_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /channels/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: channel found
          content:
            application/json:
              example:
                id: ch_gbHJdmfrXB
                name: Wholesale
                code: wholesale
                active: true
                default: false
                storefront_access: public
                guest_checkout: true
                preferred_order_routing_strategy:
                preferred_storefront_access:
                preferred_guest_checkout:
                created_at: '2026-07-27T20:00:10.439Z'
                updated_at: '2026-07-27T20:00:10.439Z'
    patch:
      summary: Update a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const channel = await client.channels.update('channel_xxx', {
            name: 'Wholesale (Updated)',
            active: false,
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /channels/{id} -d '{"name":"Wholesale (Updated)","active":false}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: channel updated
          content:
            application/json:
              example:
                id: ch_gbHJdmfrXB
                name: Wholesale (Updated)
                code: wholesale
                active: true
                default: false
                storefront_access: login_required
                guest_checkout: false
                preferred_order_routing_strategy:
                preferred_storefront_access: login_required
                preferred_guest_checkout: false
                created_at: '2026-07-27T20:00:10.727Z'
                updated_at: '2026-07-27T20:00:11.011Z'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                code:
                  type: string
                active:
                  type: boolean
                default:
                  type: boolean
                preferred_order_routing_strategy:
                  type: string
                  nullable: true
                  description: Routing strategy class name. `null` inherits the store
                    setting.
                preferred_storefront_access:
                  type: string
                  nullable: true
                  enum:
                  - public
                  - prices_hidden
                  - login_required
                  description: Anonymous-visitor access posture. `null` inherits the
                    store setting.
                preferred_guest_checkout:
                  type: boolean
                  nullable: true
                  description: Whether guests can check out without an account. `null`
                    inherits the store setting.
    delete:
      summary: Delete a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.channels.delete('channel_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /channels/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: channel deleted
  "/api/v3/admin/channels/{id}/add_products":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    post:
      summary: Publish products on a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Publishes the listed products on this channel. Idempotent — re-publishing
        an already-published product updates its publication window. Products from
        sibling stores are silently dropped.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Idempotent — re-publishing an already-published product updates its
          // publication window. `published_at`/`unpublished_at` are optional:
          // `null` (or omitted) means live immediately and never come down.
          const { product_count } = await client.channels.addProducts('channel_xxx', {
            product_ids: ['prod_xxx', 'prod_yyy'],
            published_at: '2026-07-01T00:00:00Z',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /channels/{id}/add_products -d '{"product_ids":["prod_xxx","prod_yyy"],"published_at":"2026-07-01T00:00:00Z"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: products published
          content:
            application/json:
              example:
                product_count: 1
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - product_ids
              properties:
                product_ids:
                  type: array
                  items:
                    type: string
                published_at:
                  type: string
                  format: date-time
                  nullable: true
                  description: When the publications go live. `null` means immediately.
                unpublished_at:
                  type: string
                  format: date-time
                  nullable: true
                  description: When the publications come down. `null` means never.
  "/api/v3/admin/channels/{id}/remove_products":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    post:
      summary: Unpublish products from a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Unpublishes the listed products from this channel.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { product_count } = await client.channels.removeProducts('channel_xxx', {
            product_ids: ['prod_xxx', 'prod_yyy'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /channels/{id}/remove_products -d '{"product_ids":["prod_xxx","prod_yyy"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: products unpublished
          content:
            application/json:
              example:
                product_count: 1
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - product_ids
              properties:
                product_ids:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/channels/{channel_id}/order_routing_rules":
    parameters:
    - name: channel_id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: List order routing rules for a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the channel's routing rules in priority order. The rules engine walks them top-down; see the Order Routing guide.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: rules } = await client.channels.orderRoutingRules.list('ch_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /channels/{channel_id}/order_routing_rules
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: rules found
          content:
            application/json:
              example:
                data:
                - id: orule_UkLWZg9DAJ
                  position: 1
                  active: true
                  created_at: '2026-07-27T19:59:58.888Z'
                  updated_at: '2026-07-27T19:59:58.888Z'
                  type: preferred_location
                  channel_id: ch_UkLWZg9DAJ
                  preferences: {}
                  preference_schema: []
                  label: Preferred location
                  description: Fulfill from the location pinned on the order, when
                    one is set
                - id: orule_gbHJdmfrXB
                  position: 2
                  active: true
                  created_at: '2026-07-27T19:59:58.891Z'
                  updated_at: '2026-07-27T19:59:58.891Z'
                  type: minimize_splits
                  channel_id: ch_UkLWZg9DAJ
                  preferences: {}
                  preference_schema: []
                  label: Minimize splits
                  description: Prefer the location that can fulfill the most items
                    on its own, avoiding split shipments
                - id: orule_EfhxLZ9ck8
                  position: 3
                  active: true
                  created_at: '2026-07-27T19:59:58.895Z'
                  updated_at: '2026-07-27T19:59:58.895Z'
                  type: default_location
                  channel_id: ch_UkLWZg9DAJ
                  preferences: {}
                  preference_schema: []
                  label: Default location
                  description: Prefer the stock location marked as default
                meta:
                  page: 1
                  limit: 25
                  count: 3
                  pages: 1
                  from: 1
                  to: 3
                  in: 3
                  previous:
                  next:
    post:
      summary: Create an order routing rule on a channel
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds a rule to the channel's routing list. The `type` is the wire shorthand from `GET /order_routing_rules/types` (e.g. `preferred_location`). Omitting `position` appends the rule at the end of the list. Each rule kind can appear at most once per channel — a duplicate `type` is rejected with a validation error.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const rule = await client.channels.orderRoutingRules.create('ch_UkLWZg9DAJ', {
            type: 'preferred_location',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /channels/{channel_id}/order_routing_rules -d '{"type":"preferred_location"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: rule created
          content:
            application/json:
              example:
                id: orule_VqXmZF31wY
                position: 3
                active: true
                created_at: '2026-07-27T20:00:47.726Z'
                updated_at: '2026-07-27T20:00:47.726Z'
                type: default_location
                channel_id: ch_UkLWZg9DAJ
                preferences: {}
                preference_schema: []
                label: Default location
                description: Prefer the stock location marked as default
        '422':
          description: unknown rule type
          content:
            application/json:
              example:
                error:
                  code: unknown_order_routing_rule_type
                  message: Unknown type
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  example: preferred_location
                active:
                  type: boolean
                position:
                  type: integer
                preferences:
                  type: object
                  additionalProperties: true
              required:
              - type
  "/api/v3/admin/channels/{channel_id}/order_routing_rules/{id}":
    parameters:
    - name: channel_id
      in: path
      required: true
      schema:
        type: string
    - name: id
      in: path
      required: true
      schema:
        type: string
    patch:
      summary: Update an order routing rule
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a rule's `active` flag, `position` (the list reorders around it), or `preferences`. The rule kind cannot be changed — delete and re-create instead.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const rule = await client.channels.orderRoutingRules.update('ch_UkLWZg9DAJ', 'orule_k5nR8xLq', {
            active: false,
            position: 2,
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /channels/{channel_id}/order_routing_rules/{id} -d
          '{"active":false,"position":2}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: rule updated
          content:
            application/json:
              example:
                id: orule_UkLWZg9DAJ
                position: 2
                active: false
                created_at: '2026-07-27T19:59:58.888Z'
                updated_at: '2026-07-27T20:00:48.291Z'
                type: preferred_location
                channel_id: ch_UkLWZg9DAJ
                preferences: {}
                preference_schema: []
                label: Preferred location
                description: Fulfill from the location pinned on the order, when one
                  is set
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                active:
                  type: boolean
                position:
                  type: integer
                preferences:
                  type: object
                  additionalProperties: true
    delete:
      summary: Delete an order routing rule
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.channels.orderRoutingRules.delete('ch_UkLWZg9DAJ', 'orule_k5nR8xLq')
      - lang: bash
        label: Spree CLI
        source: spree api delete /channels/{channel_id}/order_routing_rules/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: rule deleted
  "/api/v3/admin/order_routing_rules/types":
    get:
      summary: List available order routing rule types
      tags:
      - Channels
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Enumerates the registered rule kinds with their labels, descriptions and preference schemas — drives the "Add rule" picker in the admin dashboard. Plugins extend the list by registering `Spree::OrderRoutingRule` subclasses via `Spree.order_routing.rules`.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: ruleTypes } = await client.orderRoutingRules.types()
      - lang: bash
        label: Spree CLI
        source: spree api get /order_routing_rules/types
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: types found
          content:
            application/json:
              example:
                data:
                - type: default_location
                  label: Default location
                  description: Prefer the stock location marked as default
                  preference_schema: []
                - type: minimize_splits
                  label: Minimize splits
                  description: Prefer the location that can fulfill the most items
                    on its own, avoiding split shipments
                  preference_schema: []
                - type: preferred_location
                  label: Preferred location
                  description: Fulfill from the location pinned on the order, when
                    one is set
                  preference_schema: []
  "/api/v3/admin/custom_field_definitions":
    get:
      summary: List custom field definitions
      tags:
      - Custom Fields
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns all defined custom fields. Filter by `?q[resource_type_eq]=Spree::Product` to narrow to one parent type.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: definitions } = await client.customFieldDefinitions.list({
            q: { resource_type_eq: 'Spree::Product' },
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /custom_field_definitions -d '{"q":{"resource_type_eq":"Spree::Product"}}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand. Use dot notation for
          nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., key,label,field_type).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: definitions returned
          content:
            application/json:
              example:
                data:
                - id: cfdef_UkLWZg9DAJ
                  namespace: specs
                  key: fabric
                  label: Title
                  field_type: short_text
                  resource_type: Spree::Product
                  storefront_visible: true
                  searchable: false
                  sortable: false
                  filter_key: cf_specs_fabric
                  created_at: '2026-07-27T20:00:12.346Z'
                  updated_at: '2026-07-27T20:00:12.346Z'
                - id: cfdef_gbHJdmfrXB
                  namespace: custom
                  key: order_notes
                  label: Order Notes
                  field_type: short_text
                  resource_type: Spree::Order
                  storefront_visible: true
                  searchable: false
                  sortable: false
                  filter_key: cf_custom_order_notes
                  created_at: '2026-07-27T20:00:12.347Z'
                  updated_at: '2026-07-27T20:00:12.347Z'
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
    post:
      summary: Create a custom field definition
      tags:
      - Custom Fields
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const definition = await client.customFieldDefinitions.create({
            namespace: 'specs',
            key: 'origin',
            label: 'Country of Origin',
            field_type: 'short_text',
            resource_type: 'Spree::Product',
            storefront_visible: true,
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /custom_field_definitions -d '{"namespace":"specs","key":"origin","label":"Country
          of Origin","field_type":"short_text","resource_type":"Spree::Product","storefront_visible":true}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: definition created
          content:
            application/json:
              example:
                id: cfdef_EfhxLZ9ck8
                namespace: specs
                key: origin
                label: Country of Origin
                field_type: short_text
                resource_type: Spree::Product
                storefront_visible: true
                searchable: false
                sortable: false
                filter_key: cf_specs_origin
                created_at: '2026-07-27T20:00:12.904Z'
                updated_at: '2026-07-27T20:00:12.904Z'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - key
              - field_type
              - resource_type
              properties:
                namespace:
                  type: string
                  description: Defaults to `custom`
                key:
                  type: string
                label:
                  type: string
                  description: Human-readable name; defaults to titleized `key`
                field_type:
                  type: string
                  description: Custom field type identifier (one of the registered
                    field-type class names).
                resource_type:
                  type: string
                  description: Owner class, e.g. `Spree::Product`
                storefront_visible:
                  type: boolean
                  description: 'When false, definition is admin-only (was `display_on:
                    back_end`)'
                searchable:
                  type: boolean
                  description: When true, values are included in storefront product
                    text search
                sortable:
                  type: boolean
                  description: When true, storefront product listings can sort by
                    this field
  "/api/v3/admin/custom_field_definitions/{id}":
    get:
      summary: Show a custom field definition
      tags:
      - Custom Fields
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const definition = await client.customFieldDefinitions.get('cfd_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /custom_field_definitions/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand. Use dot notation for
          nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., key,label,field_type).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: definition found
          content:
            application/json:
              example:
                id: cfdef_UkLWZg9DAJ
                namespace: specs
                key: fabric
                label: Title
                field_type: short_text
                resource_type: Spree::Product
                storefront_visible: true
                searchable: false
                sortable: false
                filter_key: cf_specs_fabric
                created_at: '2026-07-27T20:00:12.908Z'
                updated_at: '2026-07-27T20:00:12.908Z'
    patch:
      summary: Update a custom field definition
      tags:
      - Custom Fields
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const definition = await client.customFieldDefinitions.update('cfd_UkLWZg9DAJ', {
            label: 'Country of Origin',
            storefront_visible: false,
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /custom_field_definitions/{id} -d '{"label":"Country
          of Origin","storefront_visible":false}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: definition updated
          content:
            application/json:
              example:
                id: cfdef_UkLWZg9DAJ
                namespace: specs
                key: fabric
                label: Fabric Composition
                field_type: short_text
                resource_type: Spree::Product
                storefront_visible: false
                searchable: false
                sortable: false
                filter_key: cf_specs_fabric
                created_at: '2026-07-27T20:00:13.189Z'
                updated_at: '2026-07-27T20:00:13.470Z'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                label:
                  type: string
                storefront_visible:
                  type: boolean
                searchable:
                  type: boolean
                sortable:
                  type: boolean
    delete:
      summary: Delete a custom field definition
      tags:
      - Custom Fields
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes the definition and cascades to all custom field values referencing it.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.customFieldDefinitions.delete('cfd_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /custom_field_definitions/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: definition deleted
  "/api/v3/admin/customer_groups":
    get:
      summary: List customer groups
      tags:
      - Customer Groups
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the customer groups configured for the current store. Groups
        segment customers for targeted promotions (see the `customer_group`
        promotion rule) and reporting. The list endpoint never embeds the
        member list — fetch a single group with `?expand=customers` if you
        need them inline, or query `/admin/customers?customer_group_id_in=…`
        for paginated membership.


        **Required scope:** `read_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: groups } = await client.customerGroups.list({ page: 1, limit: 25 })
      - lang: bash
        label: Spree CLI
        source: spree api get /customer_groups -d '{"page":1,"limit":25}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name (contains)
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending (e.g., `-created_at`).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: customer groups found
          content:
            application/json:
              example:
                data:
                - id: cg_UkLWZg9DAJ
                  name: VIPs
                  description: Top spenders
                  customers_count: 0
                  created_at: '2026-07-27T20:00:13.762Z'
                  updated_at: '2026-07-27T20:00:13.762Z'
                - id: cg_gbHJdmfrXB
                  name: Wholesale
                  description:
                  customers_count: 0
                  created_at: '2026-07-27T20:00:13.763Z'
                  updated_at: '2026-07-27T20:00:13.763Z'
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/CustomerGroup"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create a customer group
      tags:
      - Customer Groups
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a customer group in the current store. `customer_ids` is
        optional; when present, customers are attached at create time.
        Pass prefixed IDs (e.g. `cus_…`) — the server decodes them
        automatically.


        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const group = await client.customerGroups.create({
            name: 'VIP customers',
            description: 'Top spenders, eligible for early access',
            customer_ids: ['cus_UkLWZg9DAJ', 'cus_QrLWXg9CAJ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customer_groups -d '{"name":"VIP customers","description":"Top
          spenders, eligible for early access","customer_ids":["cus_UkLWZg9DAJ","cus_QrLWXg9CAJ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: customer group created
          content:
            application/json:
              example:
                id: cg_EfhxLZ9ck8
                name: Wholesale 2
                description: B2B accounts
                customers_count: 1
                created_at: '2026-07-27T20:00:14.614Z'
                updated_at: '2026-07-27T20:00:14.614Z'
              schema:
                "$ref": "#/components/schemas/CustomerGroup"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                  example: Wholesale
                description:
                  type: string
                  example: B2B accounts
                  nullable: true
                customer_ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cus_UkLWZg9DAJ
  "/api/v3/admin/customer_groups/{id}":
    parameters:
    - name: id
      in: path
      required: true
      description: Customer group prefixed ID
      schema:
        type: string
    get:
      summary: Get a customer group
      tags:
      - Customer Groups
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single customer group. Pass `?expand=customers` to embed
        the full member list inline (recommended only for single-record
        reads — embed cost scales with membership size).


        **Required scope:** `read_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Pass `expand: ['customers']` to embed the group's customers in the response
          // — omit it for the much smaller index-payload shape.
          const group = await client.customerGroups.get('cg_UkLWZg9DAJ', { expand: ['customers'] })
      - lang: bash
        label: Spree CLI
        source: spree api get /customer_groups/{id} -d '{"expand":["customers"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: 'Comma-separated associations to embed. Supported: `customers`.'
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: customer group with embedded customers
          content:
            application/json:
              example:
                id: cg_UkLWZg9DAJ
                name: VIPs
                description: Top spenders
                customers_count: 1
                created_at: '2026-07-27T20:00:15.210Z'
                updated_at: '2026-07-27T20:00:15.210Z'
                customers:
                - id: cus_UkLWZg9DAJ
                  email: sheilah_olson@streich.name
                  first_name: Weston
                  last_name: Halvorson
                  phone:
                  accepts_email_marketing: false
                  full_name: Weston Halvorson
                  available_store_credit_total: '0'
                  display_available_store_credit_total: "$0.00"
                  login: sheilah_olson@streich.name
                  metadata: {}
                  last_sign_in_at:
                  current_sign_in_at:
                  created_at: '2026-07-27T20:00:15.472Z'
                  updated_at: '2026-07-27T20:00:15.472Z'
                  sign_in_count: 0
                  failed_attempts: 0
                  last_sign_in_ip:
                  current_sign_in_ip:
                  tags: []
                  internal_note_html:
                  default_billing_address_id:
                  default_shipping_address_id:
                  orders_count: 0
                  total_spent: '0.0'
                  display_total_spent: "$0.00"
                  last_order_completed_at:
                  customer_group_ids:
                  - cg_UkLWZg9DAJ
              schema:
                "$ref": "#/components/schemas/CustomerGroup"
        '404':
          description: customer group not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Customer group not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a customer group
      tags:
      - Customer Groups
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates name, description, or membership. `customer_ids` is a
        full-set replacement — the server reconciles the membership to
        match the array, adding new IDs and removing ones not present.
        Send `customer_ids: []` to clear all members.


        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // `customer_ids` is a full-set update — the model reconciles the membership
          // to match the array (adds new IDs, removes ones not present).
          const group = await client.customerGroups.update('cg_UkLWZg9DAJ', {
            name: 'VIP customers (Q1)',
            customer_ids: ['cus_UkLWZg9DAJ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /customer_groups/{id} -d '{"name":"VIP customers (Q1)","customer_ids":["cus_UkLWZg9DAJ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: customer group updated
          content:
            application/json:
              example:
                id: cg_UkLWZg9DAJ
                name: VIP customers (Q1)
                description: Top spenders
                customers_count: 0
                created_at: '2026-07-27T20:00:16.053Z'
                updated_at: '2026-07-27T20:00:16.329Z'
              schema:
                "$ref": "#/components/schemas/CustomerGroup"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: VIP customers (Q1)
                description:
                  type: string
                  example: Updated description
                  nullable: true
                customer_ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cus_UkLWZg9DAJ
    delete:
      summary: Delete a customer group
      tags:
      - Customer Groups
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes the group. Member users are not deleted; their `customer_group_users` rows are dropped.

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.customerGroups.delete('cg_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /customer_groups/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: customer group deleted
  "/api/v3/admin/customers/{customer_id}/addresses":
    get:
      summary: List customer addresses
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the customer's saved addresses.

        **Required scope:** `read_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: addresses } = await client.customers.addresses.list('cus_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /customers/{customer_id}/addresses
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., country, state).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., first_name,last_name,address1,city).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: addresses found
          content:
            application/json:
              example:
                data:
                - id: addr_UkLWZg9DAJ
                  first_name: John
                  last_name: Doe
                  full_name: John Doe
                  address1: 1 Lovely Street
                  address2: Northwest
                  postal_code: '10118'
                  city: New York
                  phone: 555-555-0199
                  company: Company
                  country_name: United States of America
                  country_iso: US
                  state_text: NY
                  state_abbr: NY
                  quick_checkout: false
                  is_default_billing: false
                  is_default_shipping: false
                  state_name: New York
                  label:
                  metadata: {}
                  created_at: '2026-07-27T20:00:17.181Z'
                  updated_at: '2026-07-27T20:00:17.181Z'
                  customer_id: cus_UkLWZg9DAJ
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create a customer address
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds a new address to the customer's address book. Pass `is_default_billing: true` or `is_default_shipping: true` to set as the default — the previous default loses its flag in the same transaction.

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const address = await client.customers.addresses.create('cus_UkLWZg9DAJ', {
            first_name: 'Jane',
            last_name: 'Doe',
            address1: '350 Fifth Avenue',
            city: 'New York',
            postal_code: '10118',
            country_iso: 'US',
            state_abbr: 'NY',
            phone: '+1 212 555 1234',
            label: 'Office',
            is_default_shipping: true,
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customers/{customer_id}/addresses -d '{"first_name":"Jane","last_name":"Doe","address1":"350
          Fifth Avenue","city":"New York","postal_code":"10118","country_iso":"US","state_abbr":"NY","phone":"+1
          212 555 1234","label":"Office","is_default_shipping":true}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      responses:
        '201':
          description: address created
          content:
            application/json:
              example:
                id: addr_gbHJdmfrXB
                first_name: Jane
                last_name: Doe
                full_name: Jane Doe
                address1: 350 Fifth Avenue
                address2:
                postal_code: '10118'
                city: New York
                phone: "+12125551234"
                company:
                country_name: United States of America
                country_iso: US
                state_text: NY
                state_abbr: NY
                quick_checkout: false
                is_default_billing: false
                is_default_shipping: false
                state_name: New York
                label: Office
                metadata: {}
                created_at: '2026-07-27T20:00:18.540Z'
                updated_at: '2026-07-27T20:00:18.540Z'
                customer_id: cus_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                first_name:
                  type: string
                last_name:
                  type: string
                address1:
                  type: string
                address2:
                  type: string
                city:
                  type: string
                postal_code:
                  type: string
                country_iso:
                  type: string
                  description: ISO-2 country code (e.g. US)
                state_abbr:
                  type: string
                  description: State/province abbreviation (e.g. NY)
                phone:
                  type: string
                company:
                  type: string
                label:
                  type: string
                is_default_billing:
                  type: boolean
                is_default_shipping:
                  type: boolean
  "/api/v3/admin/customers/{customer_id}/addresses/{id}":
    patch:
      summary: Update a customer address
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a customer address.

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const address = await client.customers.addresses.update(
            'cus_UkLWZg9DAJ',
            'addr_UkLWZg9DAJ',
            { city: 'Manhattan' },
          )
      - lang: bash
        label: Spree CLI
        source: spree api patch /customers/{customer_id}/addresses/{id} -d '{"city":"Manhattan"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: address updated
          content:
            application/json:
              example:
                id: addr_UkLWZg9DAJ
                first_name: John
                last_name: Doe
                full_name: John Doe
                address1: 3 Lovely Street
                address2: Northwest
                postal_code: '10118'
                city: Manhattan
                phone: 555-555-0199
                company: Company
                country_name: United States of America
                country_iso: US
                state_text: NY
                state_abbr: NY
                quick_checkout: false
                is_default_billing: false
                is_default_shipping: false
                state_name: New York
                label:
                metadata: {}
                created_at: '2026-07-27T20:00:18.809Z'
                updated_at: '2026-07-27T20:00:19.351Z'
                customer_id: cus_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                city:
                  type: string
                is_default_billing:
                  type: boolean
                is_default_shipping:
                  type: boolean
    delete:
      summary: Delete a customer address
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes the address. If it was a default, the customer loses that default (no auto-promotion).

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.customers.addresses.delete('cus_UkLWZg9DAJ', 'addr_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /customers/{customer_id}/addresses/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: address deleted
  "/api/v3/admin/customers/{customer_id}/credit_cards":
    get:
      summary: List customer credit cards
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the customer's saved credit cards. Useful for off-session admin charges via `POST /admin/orders/:id/payments { source_id }`.

        **Required scope:** `read_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: cards } = await client.customers.creditCards.list('cus_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /customers/{customer_id}/credit_cards
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., payment_method).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., brand,last4,month,year).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: credit cards found
          content:
            application/json:
              example:
                data:
                - id: card_UkLWZg9DAJ
                  brand: visa
                  last4: '1111'
                  month: 12
                  year: 2027
                  name: Spree Commerce
                  default: false
                  gateway_payment_profile_id:
                  customer_id: cus_UkLWZg9DAJ
                  payment_method_id: pm_UkLWZg9DAJ
                  metadata: {}
                  created_at: '2026-07-27T20:00:20.435Z'
                  updated_at: '2026-07-27T20:00:20.435Z'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
  "/api/v3/admin/customers/{customer_id}/credit_cards/{id}":
    get:
      summary: Show a customer credit card
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a saved credit card by ID.

        **Required scope:** `read_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const card = await client.customers.creditCards.get('cus_UkLWZg9DAJ', 'cc_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /customers/{customer_id}/credit_cards/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., payment_method).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., brand,last4,month,year).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: credit card found
          content:
            application/json:
              example:
                id: card_UkLWZg9DAJ
                brand: visa
                last4: '1111'
                month: 12
                year: 2027
                name: Spree Commerce
                default: false
                gateway_payment_profile_id:
                customer_id: cus_UkLWZg9DAJ
                payment_method_id: pm_UkLWZg9DAJ
                metadata: {}
                created_at: '2026-07-27T20:00:20.997Z'
                updated_at: '2026-07-27T20:00:20.997Z'
    delete:
      summary: Delete a customer credit card
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes a saved credit card.

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.customers.creditCards.delete('cus_UkLWZg9DAJ', 'cc_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /customers/{customer_id}/credit_cards/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: credit card deleted
  "/api/v3/admin/customers/{customer_id}/store_credits":
    get:
      summary: List customer store credits
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns store credits issued to the customer.

        **Required scope:** `read_store_credits` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: storeCredits } = await client.customers.storeCredits.list('cus_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /customers/{customer_id}/store_credits
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., category, store,
          created_by). Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., amount,amount_used,memo,currency).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: store credits found
          content:
            application/json:
              example:
                data:
                - id: credit_UkLWZg9DAJ
                  amount: '50.0'
                  amount_used: '0.0'
                  amount_remaining: '50.0'
                  display_amount: "$50.00"
                  display_amount_used: "$0.00"
                  display_amount_remaining: "$50.00"
                  currency: USD
                  memo:
                  metadata: {}
                  created_at: '2026-07-27T20:00:22.373Z'
                  updated_at: '2026-07-27T20:00:22.373Z'
                  customer_id: cus_UkLWZg9DAJ
                  created_by_id: admin_UkLWZg9DAJ
                  category_id: sccat_UkLWZg9DAJ
                  category_name: Exchange
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Issue a store credit to a customer
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        `created_by` is set automatically from the authenticated admin.

        **Required scope:** `write_store_credits` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const credit = await client.customers.storeCredits.create('cus_UkLWZg9DAJ', {
            amount: '25.00',
            currency: 'USD',
            category_id: 'cat_UkLWZg9DAJ',
            memo: 'Goodwill credit',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customers/{customer_id}/store_credits -d '{"amount":"25.00","currency":"USD","category_id":"cat_UkLWZg9DAJ","memo":"Goodwill
          credit"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      responses:
        '201':
          description: store credit created
          content:
            application/json:
              example:
                id: credit_gbHJdmfrXB
                amount: '25.0'
                amount_used: '0.0'
                amount_remaining: '25.0'
                display_amount: "$25.00"
                display_amount_used: "$0.00"
                display_amount_remaining: "$25.00"
                currency: USD
                memo: Goodwill
                metadata: {}
                created_at: '2026-07-27T20:00:23.466Z'
                updated_at: '2026-07-27T20:00:23.466Z'
                customer_id: cus_UkLWZg9DAJ
                created_by_id: admin_gbHJdmfrXB
                category_id: sccat_UkLWZg9DAJ
                category_name: Exchange
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - amount
              - currency
              - category_id
              properties:
                amount:
                  type: string
                  example: '50.00'
                currency:
                  type: string
                  example: USD
                category_id:
                  type: string
                  description: StoreCreditCategory ID
                memo:
                  type: string
  "/api/v3/admin/customers/{customer_id}/store_credits/{id}":
    patch:
      summary: Update a store credit
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Update memo / category / amount. The amount can only be changed if `amount_used == 0`.

        **Required scope:** `write_store_credits` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const credit = await client.customers.storeCredits.update(
            'cus_UkLWZg9DAJ',
            'sc_UkLWZg9DAJ',
            { memo: 'Reissued for damaged shipment' },
          )
      - lang: bash
        label: Spree CLI
        source: spree api patch /customers/{customer_id}/store_credits/{id} -d '{"memo":"Reissued
          for damaged shipment"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: store credit updated
          content:
            application/json:
              example:
                id: credit_UkLWZg9DAJ
                amount: '50.0'
                amount_used: '0.0'
                amount_remaining: '50.0'
                display_amount: "$50.00"
                display_amount_used: "$0.00"
                display_amount_remaining: "$50.00"
                currency: USD
                memo: Updated
                metadata: {}
                created_at: '2026-07-27T20:00:24.001Z'
                updated_at: '2026-07-27T20:00:24.282Z'
                customer_id: cus_UkLWZg9DAJ
                created_by_id: admin_UkLWZg9DAJ
                category_id: sccat_UkLWZg9DAJ
                category_name: Exchange
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: string
                  example: '50.00'
                category_id:
                  type: string
                memo:
                  type: string
    delete:
      summary: Delete a store credit
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes an unused store credit (amount_used == 0). Returns 422 otherwise.

        **Required scope:** `write_store_credits` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.customers.storeCredits.delete('cus_UkLWZg9DAJ', 'sc_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /customers/{customer_id}/store_credits/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: customer_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: store credit deleted
  "/api/v3/admin/customers":
    get:
      summary: List customers
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a paginated list of customers. Supports Ransack search/filters.

        **Required scope:** `read_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: customers } = await client.customers.list({
            search: 'jane',
            sort: '-created_at',
            limit: 25,
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /customers -d '{"search":"jane","sort":"-created_at","limit":25}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        schema:
          type: integer
      - name: q[search]
        in: query
        required: false
        description: Email + name full-text-ish search
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., addresses, store_credits).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., email,first_name,last_name).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: customers found
          content:
            application/json:
              example:
                data:
                - id: cus_UkLWZg9DAJ
                  email: jane@example.com
                  first_name: Jane
                  last_name: Doe
                  phone:
                  accepts_email_marketing: false
                  full_name: Jane Doe
                  available_store_credit_total: '0'
                  display_available_store_credit_total: "$0.00"
                  login: jane@example.com
                  metadata: {}
                  last_sign_in_at:
                  current_sign_in_at:
                  created_at: '2026-07-27T20:00:25.364Z'
                  updated_at: '2026-07-27T20:00:25.364Z'
                  sign_in_count: 0
                  failed_attempts: 0
                  last_sign_in_ip:
                  current_sign_in_ip:
                  tags: []
                  internal_note_html:
                  default_billing_address_id:
                  default_shipping_address_id:
                  orders_count: 0
                  total_spent: '0'
                  display_total_spent: "$0.00"
                  last_order_completed_at:
                  customer_group_ids: []
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create a customer
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a customer. No welcome email is sent automatically.

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const customer = await client.customers.create({
            email: 'jane@example.com',
            first_name: 'Jane',
            last_name: 'Doe',
            phone: '+1 212 555 1234',
            tags: ['wholesale'],
            accepts_email_marketing: true,
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customers -d '{"email":"jane@example.com","first_name":"Jane","last_name":"Doe","phone":"+1
          212 555 1234","tags":["wholesale"],"accepts_email_marketing":true}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: customer created
          content:
            application/json:
              example:
                id: cus_gbHJdmfrXB
                email: newcustomer@example.com
                first_name: New
                last_name: Customer
                phone:
                accepts_email_marketing: false
                full_name: New Customer
                available_store_credit_total: '0'
                display_available_store_credit_total: "$0.00"
                login:
                metadata: {}
                last_sign_in_at:
                current_sign_in_at:
                created_at: '2026-07-27T20:00:26.198Z'
                updated_at: '2026-07-27T20:00:26.198Z'
                sign_in_count: 0
                failed_attempts: 0
                last_sign_in_ip:
                current_sign_in_ip:
                tags: []
                internal_note_html:
                default_billing_address_id:
                default_shipping_address_id:
                orders_count: 0
                total_spent: '0.0'
                display_total_spent: "$0.00"
                last_order_completed_at:
                customer_group_ids: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - email
              properties:
                email:
                  type: string
                  example: new@example.com
                first_name:
                  type: string
                last_name:
                  type: string
                phone:
                  type: string
                accepts_email_marketing:
                  type: boolean
                internal_note:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
                metadata:
                  type: object
  "/api/v3/admin/customers/{id}":
    get:
      summary: Show a customer
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns full customer details including computed order stats (orders_count, total_spent, last_order_completed_at).

        **Required scope:** `read_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const customer = await client.customers.get('cus_UkLWZg9DAJ', {
            expand: ['addresses', 'store_credits'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /customers/{id} -d '{"expand":["addresses","store_credits"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Customer ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: 'Comma-separated associations: addresses, orders, store_credits,
          default_billing_address, default_shipping_address'
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., email,first_name,last_name).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: customer found
          content:
            application/json:
              example:
                id: cus_UkLWZg9DAJ
                email: jane@example.com
                first_name: Jane
                last_name: Doe
                phone:
                accepts_email_marketing: false
                full_name: Jane Doe
                available_store_credit_total: '0'
                display_available_store_credit_total: "$0.00"
                login: jane@example.com
                metadata: {}
                last_sign_in_at:
                current_sign_in_at:
                created_at: '2026-07-27T20:00:26.467Z'
                updated_at: '2026-07-27T20:00:26.467Z'
                sign_in_count: 0
                failed_attempts: 0
                last_sign_in_ip:
                current_sign_in_ip:
                tags: []
                internal_note_html:
                default_billing_address_id:
                default_shipping_address_id:
                orders_count: 0
                total_spent: '0'
                display_total_spent: "$0.00"
                last_order_completed_at:
                customer_group_ids: []
    patch:
      summary: Update a customer
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates customer attributes. `tags` replaces the full set.

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const customer = await client.customers.update('cus_UkLWZg9DAJ', {
            first_name: 'Updated',
            tags: ['wholesale', 'vip'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /customers/{id} -d '{"first_name":"Updated","tags":["wholesale","vip"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: customer updated
          content:
            application/json:
              example:
                id: cus_UkLWZg9DAJ
                email: jane@example.com
                first_name: Updated
                last_name: Doe
                phone:
                accepts_email_marketing: false
                full_name: Updated Doe
                available_store_credit_total: '0'
                display_available_store_credit_total: "$0.00"
                login: jane@example.com
                metadata: {}
                last_sign_in_at:
                current_sign_in_at:
                created_at: '2026-07-27T20:00:27.014Z'
                updated_at: '2026-07-27T20:00:27.307Z'
                sign_in_count: 0
                failed_attempts: 0
                last_sign_in_ip:
                current_sign_in_ip:
                tags: []
                internal_note_html:
                default_billing_address_id:
                default_shipping_address_id:
                orders_count: 0
                total_spent: '0.0'
                display_total_spent: "$0.00"
                last_order_completed_at:
                customer_group_ids: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                first_name:
                  type: string
                last_name:
                  type: string
                phone:
                  type: string
                accepts_email_marketing:
                  type: boolean
                internal_note:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
                metadata:
                  type: object
    delete:
      summary: Delete a customer
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes a customer. Returns 422 if the customer has any orders.

        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.customers.delete('cus_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /customers/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: customer deleted
  "/api/v3/admin/customers/bulk_add_to_groups":
    post:
      summary: Bulk-add customers to groups
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Attaches each customer in `ids` to every group in `customer_group_ids`.
        Idempotent — customers already in a group are skipped server-side.
        Groups from sibling stores are silently ignored. Returns counts of
        customers and groups that were processed (post store-scoping).


        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.customers.bulkAddToGroups({
            ids: ['cus_UkLWZg9DAJ', 'cus_QrLWXg9CAJ'],
            customer_group_ids: ['cg_UkLWZg9DAJ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customers/bulk_add_to_groups -d '{"ids":["cus_UkLWZg9DAJ","cus_QrLWXg9CAJ"],"customer_group_ids":["cg_UkLWZg9DAJ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: customers added to groups
          content:
            application/json:
              example:
                customer_count: 1
                customer_group_count: 1
              schema:
                type: object
                properties:
                  customer_count:
                    type: integer
                  customer_group_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - customer_group_ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cus_UkLWZg9DAJ
                  - cus_QrLWXg9CAJ
                customer_group_ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cg_UkLWZg9DAJ
  "/api/v3/admin/customers/bulk_remove_from_groups":
    post:
      summary: Bulk-remove customers from groups
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Detaches each customer in `ids` from every group in `customer_group_ids`.
        No-op for non-members. Groups from sibling stores are silently ignored.


        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.customers.bulkRemoveFromGroups({
            ids: ['cus_UkLWZg9DAJ'],
            customer_group_ids: ['cg_UkLWZg9DAJ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customers/bulk_remove_from_groups -d '{"ids":["cus_UkLWZg9DAJ"],"customer_group_ids":["cg_UkLWZg9DAJ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: customers removed from groups
          content:
            application/json:
              example:
                customer_count: 1
                customer_group_count: 1
              schema:
                type: object
                properties:
                  customer_count:
                    type: integer
                  customer_group_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - customer_group_ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cus_UkLWZg9DAJ
                customer_group_ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cg_UkLWZg9DAJ
  "/api/v3/admin/customers/bulk_add_tags":
    post:
      summary: Bulk-add tags to customers
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds each tag name in `tags` to every customer in `ids`. Tags are
        upserted by name; re-adding an existing tag is a no-op.


        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.customers.bulkAddTags({
            ids: ['cus_UkLWZg9DAJ', 'cus_QrLWXg9CAJ'],
            tags: ['vip', 'newsletter'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customers/bulk_add_tags -d '{"ids":["cus_UkLWZg9DAJ","cus_QrLWXg9CAJ"],"tags":["vip","newsletter"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: tags added
          content:
            application/json:
              example:
                customer_count: 1
                tag_count: 2
              schema:
                type: object
                properties:
                  customer_count:
                    type: integer
                  tag_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - tags
              properties:
                ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cus_UkLWZg9DAJ
                tags:
                  type: array
                  items:
                    type: string
                  example:
                  - vip
                  - newsletter
  "/api/v3/admin/customers/bulk_remove_tags":
    post:
      summary: Bulk-remove tags from customers
      tags:
      - Customers
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes each tag name in `tags` from every customer in `ids`. No-op
        for customers that don't carry the tag.


        **Required scope:** `write_customers` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.customers.bulkRemoveTags({
            ids: ['cus_UkLWZg9DAJ'],
            tags: ['vip'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /customers/bulk_remove_tags -d '{"ids":["cus_UkLWZg9DAJ"],"tags":["vip"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: tags removed
          content:
            application/json:
              example:
                customer_count: 1
                tag_count: 1
              schema:
                type: object
                properties:
                  customer_count:
                    type: integer
                  tag_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - tags
              properties:
                ids:
                  type: array
                  items:
                    type: string
                  example:
                  - cus_UkLWZg9DAJ
                tags:
                  type: array
                  items:
                    type: string
                  example:
                  - vip
  "/api/v3/admin/exports":
    get:
      summary: List exports
      tags:
      - Exports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns CSV exports queued or completed for the current store. Polled by the admin SPA to detect when an export finishes (`done: true`).

        **Required scope:** the read scope of the exported resource — `read_products` for product exports, `read_customers` for customer exports, etc. (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: exports } = await client.exports.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /exports
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: exports found
          content:
            application/json:
              example:
                data:
                - id: exp_UkLWZg9DAJ
                  number: EF092919737
                  format: csv
                  created_at: '2026-07-27T20:00:31.464Z'
                  updated_at: '2026-07-27T20:00:31.464Z'
                  type: products
                  user_id: admin_UkLWZg9DAJ
                  done: false
                  filename:
                  byte_size:
                  download_url:
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create an export
      tags:
      - Exports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Queues a CSV export. The `type` selects the dataset; `search_params` is an
        optional Ransack query (same shape used by the `q[...]` params on list endpoints)
        that filters which records are exported. Pass `record_selection: "all"` to
        clear the filter server-side and export everything in scope.

        Generation is asynchronous. Poll `GET /admin/exports/{id}` until `done` is `true`,
        then redirect the browser to `download_url` to fetch the file.


        **Required scope:** the read scope of the exported resource — `read_products` for product exports, `read_customers` for customer exports, etc. (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const exp = await client.exports.create({
            type: 'Spree::Exports::Products',
            search_params: { name_cont: 'shirt' }
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /exports -d '{"type":"Spree::Exports::Products","search_params":{"name_cont":"shirt"}}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: export queued
          content:
            application/json:
              example:
                id: exp_gbHJdmfrXB
                number: EF926124188
                format: csv
                created_at: '2026-07-27T20:00:31.764Z'
                updated_at: '2026-07-27T20:00:31.764Z'
                type: products
                user_id: admin_UkLWZg9DAJ
                done: false
                filename:
                byte_size:
                download_url:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - type
              properties:
                type:
                  type: string
                  enum:
                  - products
                  - orders
                  - customers
                  - product_translations
                  - gift_cards
                  - coupon_codes
                  - newsletter_subscribers
                  example: products
                record_selection:
                  type: string
                  enum:
                  - filtered
                  - all
                  description: Set to "all" to ignore search_params and export everything
                    in scope.
                  example: filtered
                search_params:
                  type: object
                  description: Ransack query hash. Same predicates accepted by the
                    list endpoint.
                  example:
                    name_cont: shirt
                  additionalProperties: true
                results_url:
                  type: string
                  description: Absolute URL of your admin exports view; the export-done
                    email uses it as the download button target. Only honored when
                    it matches one of the store's configured allowed origins.
                  example: https://admin.example.com/store_abc/exports
  "/api/v3/admin/exports/{id}":
    get:
      summary: Show an export
      tags:
      - Exports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns export status. While `done` is `false`, the SPA continues polling.

        **Required scope:** the read scope of the exported resource — `read_products` for product exports, `read_customers` for customer exports, etc. (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const exp = await client.exports.get('exp_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /exports/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: export found
          content:
            application/json:
              example:
                id: exp_UkLWZg9DAJ
                number: EF786153581
                format: csv
                created_at: '2026-07-27T20:00:32.034Z'
                updated_at: '2026-07-27T20:00:32.034Z'
                type: products
                user_id: admin_UkLWZg9DAJ
                done: false
                filename:
                byte_size:
                download_url:
    delete:
      summary: Delete an export
      tags:
      - Exports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes the export and purges its attachment.

        **Required scope:** the read scope of the exported resource — `read_products` for product exports, `read_customers` for customer exports, etc. (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.exports.delete('exp_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /exports/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: export deleted
  "/api/v3/admin/exports/{id}/download":
    get:
      summary: Download an export
      tags:
      - Exports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Streams the exported CSV with `Content-Disposition: attachment`. Returns 422 with `code: export_not_ready` while `done` is still `false`. The endpoint is JWT/API-key protected, so SPA clients must fetch it (with `Authorization` header) and trigger the browser download via a Blob URL — a top-level navigation cannot carry the JWT.

        **Required scope:** the read scope of the exported resource — `read_products` for product exports, `read_customers` for customer exports, etc. (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Fetch with the Bearer token, then drive the browser download:
          const res = await fetch(exp.download_url, {
            headers: { Authorization: `Bearer ${token}` }
          })
          const blob = await res.blob()
          const url = URL.createObjectURL(blob)
          const a = Object.assign(document.createElement('a'), {
            href: url,
            download: exp.filename
          })
          a.click()
          URL.revokeObjectURL(url)
      - lang: bash
        label: Spree CLI
        source: spree api get /exports/{id}/download
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: CSV file
          content:
            application/json: {}
            text/csv:
              schema:
                type: string
                format: binary
  "/api/v3/admin/orders/{order_id}/fulfillments":
    get:
      summary: List fulfillments
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns all shipments for an order.

        **Required scope:** `read_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: fulfillments } = await client.orders.fulfillments.list('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{order_id}/fulfillments
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., inventory_units,
          stock_location, shipping_rates). Use dot notation for nested expand (max
          4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., number,status,tracking,cost).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: fulfillments found
          content:
            application/json:
              example:
                data:
                - id: ful_UkLWZg9DAJ
                  number: H22848285025
                  tracking: U10000
                  tracking_url:
                  cost: '10.0'
                  display_cost: "$10.00"
                  total: '10.0'
                  display_total: "$10.00"
                  discount_total: '0.0'
                  display_discount_total: "$0.00"
                  additional_tax_total: '0.0'
                  display_additional_tax_total: "$0.00"
                  included_tax_total: '0.0'
                  display_included_tax_total: "$0.00"
                  tax_total: '0.0'
                  display_tax_total: "$0.00"
                  status: ready
                  fulfillment_type: shipping
                  fulfilled_at:
                  items:
                  - item_id: li_UkLWZg9DAJ
                    variant_id: variant_UkLWZg9DAJ
                    quantity: 1
                  metadata: {}
                  adjustment_total: '0.0'
                  pre_tax_amount: '0.0'
                  created_at: '2026-07-27T20:00:49.207Z'
                  updated_at: '2026-07-27T20:00:49.274Z'
                  order_id: or_UkLWZg9DAJ
                  stock_location_id: sloc_UkLWZg9DAJ
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create a fulfillment
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Manually creates a fulfillment on a completed order, bypassing order routing — for example to mirror a shipment handled by an external carrier or 3PL. Moves the requested line item quantities out of their current fulfillments; when `items` is omitted, every not-yet-shipped unit is moved. Pass `status: 'shipped'` to register an already-shipped fulfillment (fires shipped webhooks and freezes cost/carrier). When `delivery_method_id` is omitted, the fulfillment inherits the delivery method and cost of the source fulfillment(s) it fully drains — keeping the order total unchanged; partially drained splits get no carrier when shipped, and pending fulfillments are otherwise (re)priced by the standard rate engine, which selects the lowest-cost available rate. Pass `cost` to set an explicit shipping cost instead (e.g. the 3PL price) — note this changes the order total and payment state, and is guaranteed to persist only with `status: 'shipped'` (pending fulfillments are re-priced by the rate engine).

        **Required scope:** `write_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const fulfillment = await client.orders.fulfillments.create('or_UkLWZg9DAJ', {
            stock_location_id: 'sloc_UkLWZg9DAJ',
            tracking: 'INPOST-12345',
            delivery_method_id: 'dm_UkLWZg9DAJ',
            status: 'shipped',
            items: [{ item_id: 'li_UkLWZg9DAJ', quantity: 1 }],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /orders/{order_id}/fulfillments -d '{"stock_location_id":"sloc_UkLWZg9DAJ","tracking":"INPOST-12345","delivery_method_id":"dm_UkLWZg9DAJ","status":"shipped","items":[{"item_id":"li_UkLWZg9DAJ","quantity":1}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '201':
          description: fulfillment created
          content:
            application/json:
              example:
                id: ful_gbHJdmfrXB
                number: H57282126368
                tracking: INPOST-12345
                tracking_url:
                cost: '10.0'
                display_cost: "$10.00"
                total: '10.0'
                display_total: "$10.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                status: shipped
                fulfillment_type: shipping
                fulfilled_at: '2026-07-27T20:00:50Z'
                items:
                - item_id: li_UkLWZg9DAJ
                  variant_id: variant_UkLWZg9DAJ
                  quantity: 1
                metadata: {}
                adjustment_total: '0.0'
                pre_tax_amount: '0.0'
                created_at: '2026-07-27T20:00:50.223Z'
                updated_at: '2026-07-27T20:00:50.241Z'
                order_id: or_UkLWZg9DAJ
                stock_location_id: sloc_UkLWZg9DAJ
        '422':
          description: order not completed
          content:
            application/json:
              example:
                error:
                  code: processing_error
                  message: Fulfillments can only be created manually on completed
                    orders
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - stock_location_id
              properties:
                stock_location_id:
                  type: string
                  description: Stock location the fulfillment ships from
                tracking:
                  type: string
                  example: INPOST-12345
                  description: Carrier tracking number, or a full https:// tracking
                    link — a full URL is served back as tracking_url unchanged instead
                    of being templated into the delivery method tracking URL
                delivery_method_id:
                  type: string
                  description: Delivery method (carrier) to attach as the selected
                    rate. Defaults to the delivery method of the fully drained source
                    fulfillment(s)
                cost:
                  type: string
                  example: '7.42'
                  description: 'Explicit shipping cost. Defaults to the summed cost
                    of the fully drained source fulfillment(s), which keeps the order
                    total unchanged; an explicit cost changes the order total and
                    payment state. Guaranteed to persist only with status: ''shipped''
                    — pending fulfillments are re-priced by the rate engine'
                status:
                  type: string
                  enum:
                  - shipped
                  description: Pass 'shipped' to register the fulfillment as already
                    shipped
                items:
                  type: array
                  description: Line item quantities to fulfill. Omit to fulfill every
                    not-yet-shipped unit.
                  items:
                    type: object
                    required:
                    - item_id
                    - quantity
                    properties:
                      item_id:
                        type: string
                        description: Line item ID
                      quantity:
                        type: integer
                        example: 1
                metadata:
                  type: object
                  additionalProperties: true
  "/api/v3/admin/orders/{order_id}/fulfillments/{id}":
    get:
      summary: Show a shipment
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns details of a specific shipment.

        **Required scope:** `read_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const fulfillment = await client.orders.fulfillments.get('or_UkLWZg9DAJ', 'ful_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{order_id}/fulfillments/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Fulfillment ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., inventory_units,
          stock_location, shipping_rates). Use dot notation for nested expand (max
          4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., number,status,tracking,cost).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: shipment found
          content:
            application/json:
              example:
                id: ful_UkLWZg9DAJ
                number: H39128930875
                tracking: U10000
                tracking_url:
                cost: '10.0'
                display_cost: "$10.00"
                total: '10.0'
                display_total: "$10.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                status: ready
                fulfillment_type: shipping
                fulfilled_at:
                items:
                - item_id: li_UkLWZg9DAJ
                  variant_id: variant_UkLWZg9DAJ
                  quantity: 1
                metadata: {}
                adjustment_total: '0.0'
                pre_tax_amount: '0.0'
                created_at: '2026-07-27T20:00:51.524Z'
                updated_at: '2026-07-27T20:00:51.575Z'
                order_id: or_UkLWZg9DAJ
                stock_location_id: sloc_UkLWZg9DAJ
    patch:
      summary: Update a shipment
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a fulfillment (tracking, delivery rate).

        **Required scope:** `write_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const fulfillment = await client.orders.fulfillments.update('or_UkLWZg9DAJ', 'ful_UkLWZg9DAJ', {
            tracking: '1Z999AA10123456784',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/fulfillments/{id} -d '{"tracking":"1Z999AA10123456784"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Fulfillment ID
        schema:
          type: string
      responses:
        '200':
          description: shipment updated
          content:
            application/json:
              example:
                id: ful_UkLWZg9DAJ
                number: H98676755303
                tracking: 1Z999AA10123456784
                tracking_url: https://wwwapps.ups.com/WebTracking/track?track=yes&trackNums=1Z999AA10123456784
                cost: '10.0'
                display_cost: "$10.00"
                total: '10.0'
                display_total: "$10.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                status: ready
                fulfillment_type: shipping
                fulfilled_at:
                items:
                - item_id: li_UkLWZg9DAJ
                  variant_id: variant_UkLWZg9DAJ
                  quantity: 1
                metadata: {}
                adjustment_total: '0.0'
                pre_tax_amount: '0.0'
                created_at: '2026-07-27T20:00:52.169Z'
                updated_at: '2026-07-27T20:00:52.496Z'
                order_id: or_UkLWZg9DAJ
                stock_location_id: sloc_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                tracking:
                  type: string
                  example: 1Z999AA10123456784
                  description: Carrier tracking number, or a full https:// tracking
                    link served back as tracking_url unchanged
                selected_delivery_rate_id:
                  type: string
                  description: Delivery rate ID (dr_...) to select
  "/api/v3/admin/orders/{order_id}/fulfillments/{id}/fulfill":
    patch:
      summary: Fulfill a fulfillment
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Marks a fulfillment as fulfilled.

        **Required scope:** `write_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const fulfillment = await client.orders.fulfillments.fulfill('or_UkLWZg9DAJ', 'ful_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/fulfillments/{id}/fulfill -d '{
          ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Fulfillment ID
        schema:
          type: string
      responses:
        '200':
          description: fulfillment fulfilled
          content:
            application/json:
              example:
                id: ful_UkLWZg9DAJ
                number: H43758153206
                tracking: U10000
                tracking_url:
                cost: '10.0'
                display_cost: "$10.00"
                total: '10.0'
                display_total: "$10.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                status: shipped
                fulfillment_type: shipping
                fulfilled_at: '2026-07-27T20:00:53Z'
                items:
                - item_id: li_UkLWZg9DAJ
                  variant_id: variant_UkLWZg9DAJ
                  quantity: 1
                metadata: {}
                adjustment_total: '0.0'
                pre_tax_amount: '0.0'
                created_at: '2026-07-27T20:00:52.824Z'
                updated_at: '2026-07-27T20:00:53.162Z'
                order_id: or_UkLWZg9DAJ
                stock_location_id: sloc_UkLWZg9DAJ
  "/api/v3/admin/orders/{order_id}/fulfillments/{id}/cancel":
    patch:
      summary: Cancel a fulfillment
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Cancels a fulfillment.

        **Required scope:** `write_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const fulfillment = await client.orders.fulfillments.cancel('or_UkLWZg9DAJ', 'ful_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/fulfillments/{id}/cancel -d '{
          ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Fulfillment ID
        schema:
          type: string
      responses:
        '200':
          description: fulfillment canceled
          content:
            application/json:
              example:
                id: ful_UkLWZg9DAJ
                number: H28848383571
                tracking: U10000
                tracking_url:
                cost: '10.0'
                display_cost: "$10.00"
                total: '10.0'
                display_total: "$10.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                status: canceled
                fulfillment_type: shipping
                fulfilled_at:
                items:
                - item_id: li_UkLWZg9DAJ
                  variant_id: variant_UkLWZg9DAJ
                  quantity: 1
                metadata: {}
                adjustment_total: '0.0'
                pre_tax_amount: '0.0'
                created_at: '2026-07-27T20:00:53.493Z'
                updated_at: '2026-07-27T20:00:53.825Z'
                order_id: or_UkLWZg9DAJ
                stock_location_id: sloc_UkLWZg9DAJ
  "/api/v3/admin/orders/{order_id}/fulfillments/{id}/resume":
    patch:
      summary: Resume a fulfillment
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Resumes a canceled fulfillment.

        **Required scope:** `write_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const fulfillment = await client.orders.fulfillments.resume('or_UkLWZg9DAJ', 'ful_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/fulfillments/{id}/resume -d '{
          ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Fulfillment ID
        schema:
          type: string
      responses:
        '200':
          description: fulfillment resumed
          content:
            application/json:
              example:
                id: ful_UkLWZg9DAJ
                number: H41517579550
                tracking: U10000
                tracking_url:
                cost: '10.0'
                display_cost: "$10.00"
                total: '10.0'
                display_total: "$10.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                status: pending
                fulfillment_type: shipping
                fulfilled_at:
                items:
                - item_id: li_UkLWZg9DAJ
                  variant_id: variant_UkLWZg9DAJ
                  quantity: 1
                metadata: {}
                adjustment_total: '0.0'
                pre_tax_amount: '0.0'
                created_at: '2026-07-27T20:00:54.169Z'
                updated_at: '2026-07-27T20:00:54.511Z'
                order_id: or_UkLWZg9DAJ
                stock_location_id: sloc_UkLWZg9DAJ
  "/api/v3/admin/orders/{order_id}/fulfillments/{id}/split":
    patch:
      summary: Split a fulfillment
      tags:
      - Fulfillments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Transfers items from this shipment to a new shipment at a different stock location.

        **Required scope:** `write_fulfillments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const fulfillment = await client.orders.fulfillments.split('or_UkLWZg9DAJ', 'ful_UkLWZg9DAJ', {
            quantity: 1,
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/fulfillments/{id}/split -d '{"quantity":1}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Fulfillment ID
        schema:
          type: string
      responses:
        '200':
          description: fulfillment split
          content:
            application/json:
              example:
                data:
                - id: ful_gbHJdmfrXB
                  number: H90746305483
                  tracking:
                  tracking_url:
                  cost: '10.0'
                  display_cost: "$10.00"
                  total: '10.0'
                  display_total: "$10.00"
                  discount_total: '0.0'
                  display_discount_total: "$0.00"
                  additional_tax_total: '0.0'
                  display_additional_tax_total: "$0.00"
                  included_tax_total: '0.0'
                  display_included_tax_total: "$0.00"
                  tax_total: '0.0'
                  display_tax_total: "$0.00"
                  status: ready
                  fulfillment_type: shipping
                  fulfilled_at:
                  items:
                  - item_id: li_UkLWZg9DAJ
                    variant_id: variant_UkLWZg9DAJ
                    quantity: 1
                  metadata: {}
                  adjustment_total: '0.0'
                  pre_tax_amount: '0.0'
                  created_at: '2026-07-27T20:00:55.293Z'
                  updated_at: '2026-07-27T20:00:55.340Z'
                  order_id: or_UkLWZg9DAJ
                  stock_location_id: sloc_gbHJdmfrXB
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - variant_id
              - quantity
              properties:
                variant_id:
                  type: string
                  description: Variant ID
                quantity:
                  type: integer
                  example: 1
                stock_location_id:
                  type: string
                  description: Target stock location ID
  "/api/v3/admin/gift_card_batches":
    get:
      summary: List gift card batches
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the gift card batches issued by the current store. Each batch
        groups the cards generated together for a campaign or bulk-issuance
        — the cards themselves live under `/admin/gift_cards` and reference
        the batch via `gift_card_batch_id`.


        **Required scope:** `read_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: batches } = await client.giftCardBatches.list({ page: 1, limit: 25 })
      - lang: bash
        label: Spree CLI
        source: spree api get /gift_card_batches -d '{"page":1,"limit":25}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Records per page
        schema:
          type: integer
      - name: q[prefix_cont]
        in: query
        required: false
        description: Filter by prefix (contains)
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending.
        schema:
          type: string
      responses:
        '200':
          description: gift card batches found
          content:
            application/json:
              example:
                data:
                - id: gcb_UkLWZg9DAJ
                  codes_count: 2
                  currency: USD
                  prefix: WELCOME
                  created_at: '2026-07-27T20:00:32.682Z'
                  updated_at: '2026-07-27T20:00:32.682Z'
                  amount: '50.0'
                  expires_at:
                  created_by_id:
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/GiftCardBatch"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
    post:
      summary: Create a gift card batch
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Issues a batch of gift cards in a single call. The server generates
        `codes_count` cards inline for small batches (configurable via
        `Spree.config.gift_card_batch_web_limit`, default 500) or enqueues
        a background job for larger ones. Each card's code is the batch
        `prefix` followed by random hex.


        **Required scope:** `write_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const batch = await client.giftCardBatches.create({
            prefix: 'WELCOME',
            amount: '25.00',
            currency: 'USD',
            codes_count: 100,
            expires_at: '2030-12-31',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /gift_card_batches -d '{"prefix":"WELCOME","amount":"25.00","currency":"USD","codes_count":100,"expires_at":"2030-12-31"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: gift card batch created
          content:
            application/json:
              example:
                id: gcb_gbHJdmfrXB
                codes_count: 5
                currency: USD
                prefix: NEWCAMP
                created_at: '2026-07-27T20:00:33.266Z'
                updated_at: '2026-07-27T20:00:33.266Z'
                amount: '25.0'
                expires_at: '2030-12-31'
                created_by_id: admin_UkLWZg9DAJ
              schema:
                "$ref": "#/components/schemas/GiftCardBatch"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Prefix can't be blank
                  details:
                    prefix:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - prefix
              - amount
              - codes_count
              properties:
                prefix:
                  type: string
                  example: WELCOME
                  description: Lowercased and prepended to every generated code.
                amount:
                  type: string
                  example: '25.00'
                  description: Decimal amount per card, greater than zero.
                currency:
                  type: string
                  example: USD
                  description: ISO 4217 currency code. Defaults to the store currency.
                codes_count:
                  type: integer
                  example: 100
                  description: Number of cards to generate. Capped at `gift_card_batch_limit`.
                expires_at:
                  type: string
                  example: '2030-12-31'
                  nullable: true
  "/api/v3/admin/gift_card_batches/{id}":
    parameters:
    - name: id
      in: path
      required: true
      description: Gift card batch prefixed ID
      schema:
        type: string
    get:
      summary: Get a gift card batch
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single batch.

        **Required scope:** `read_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const batch = await client.giftCardBatches.get('gcb_K3zr8x')
      - lang: bash
        label: Spree CLI
        source: spree api get /gift_card_batches/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: gift card batch found
          content:
            application/json:
              example:
                id: gcb_UkLWZg9DAJ
                codes_count: 2
                currency: USD
                prefix: WELCOME
                created_at: '2026-07-27T20:00:33.564Z'
                updated_at: '2026-07-27T20:00:33.564Z'
                amount: '50.0'
                expires_at:
                created_by_id:
              schema:
                "$ref": "#/components/schemas/GiftCardBatch"
        '404':
          description: gift card batch not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Gift card batch not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/admin/gift_cards":
    get:
      summary: List gift cards
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the gift cards issued by the current store. Filter by
        `q[code_cont]` for code search, `q[user_id_eq]` for cards issued
        to a specific customer, or `q[state_eq]` for status filtering.


        **Required scope:** `read_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: giftCards } = await client.giftCards.list({
            page: 1,
            limit: 25,
            expand: ['customer', 'created_by'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /gift_cards -d '{"page":1,"limit":25,"expand":["customer","created_by"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[code_cont]
        in: query
        required: false
        description: Filter by gift card code (contains)
        schema:
          type: string
      - name: q[state_eq]
        in: query
        required: false
        description: Filter by status (active, redeemed, partially_redeemed, canceled)
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending (e.g., `-created_at`).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: gift cards found
          content:
            application/json:
              example:
                data:
                - id: gc_UkLWZg9DAJ
                  code: C249A72EFCB55D1F
                  status: active
                  currency: USD
                  amount: '50.0'
                  amount_used: '0.0'
                  amount_authorized: '0.0'
                  amount_remaining: '50.0'
                  display_amount: "$50.00"
                  display_amount_used: "$0.00"
                  display_amount_remaining: "$50.00"
                  expires_at:
                  redeemed_at:
                  expired: false
                  active: true
                  created_at: '2026-07-27T20:00:34.147Z'
                  updated_at: '2026-07-27T20:00:34.147Z'
                  customer_id:
                  created_by_id:
                - id: gc_gbHJdmfrXB
                  code: 88EC46FC5AFBB800
                  status: active
                  currency: USD
                  amount: '25.0'
                  amount_used: '0.0'
                  amount_authorized: '0.0'
                  amount_remaining: '25.0'
                  display_amount: "$25.00"
                  display_amount_used: "$0.00"
                  display_amount_remaining: "$25.00"
                  expires_at:
                  redeemed_at:
                  expired: false
                  active: true
                  created_at: '2026-07-27T20:00:34.148Z'
                  updated_at: '2026-07-27T20:00:34.148Z'
                  customer_id:
                  created_by_id:
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/GiftCard"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create a gift card
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Issues a gift card scoped to the current store. The code is
        auto-generated when omitted. `currency` defaults to the store's
        configured currency. Pass `user_id` (prefixed ID) to attach the
        card to a specific customer.


        **Required scope:** `write_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const giftCard = await client.giftCards.create({
            amount: '25.00',
            currency: 'USD',
            expires_at: '2030-12-31',
            user_id: 'cus_UkLWZg9DAJ',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /gift_cards -d '{"amount":"25.00","currency":"USD","expires_at":"2030-12-31","user_id":"cus_UkLWZg9DAJ"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: gift card created
          content:
            application/json:
              example:
                id: gc_EfhxLZ9ck8
                code: FF819AE2DC53F483
                status: active
                currency: USD
                amount: '25.0'
                amount_used: '0.0'
                amount_authorized: '0.0'
                amount_remaining: '25.0'
                display_amount: "$25.00"
                display_amount_used: "$0.00"
                display_amount_remaining: "$25.00"
                expires_at: '2030-12-31'
                redeemed_at:
                expired: false
                active: true
                created_at: '2026-07-27T20:00:34.738Z'
                updated_at: '2026-07-27T20:00:34.738Z'
                customer_id:
                created_by_id: admin_UkLWZg9DAJ
              schema:
                "$ref": "#/components/schemas/GiftCard"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Amount must be greater than 0
                  details:
                    amount:
                    - must be greater than 0
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - amount
              properties:
                amount:
                  type: string
                  example: '25.00'
                  description: Decimal amount, greater than zero.
                currency:
                  type: string
                  example: USD
                  description: ISO 4217 currency code. Defaults to the store currency.
                code:
                  type: string
                  example: WELCOME50
                  description: Optional caller-supplied code. Auto-generated when
                    omitted.
                expires_at:
                  type: string
                  example: '2030-12-31'
                  description: ISO 8601 date.
                  nullable: true
                user_id:
                  type: string
                  example: cus_UkLWZg9DAJ
                  description: Optional customer prefixed ID.
                  nullable: true
  "/api/v3/admin/gift_cards/{id}":
    parameters:
    - name: id
      in: path
      required: true
      description: Gift card prefixed ID
      schema:
        type: string
    get:
      summary: Get a gift card
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single gift card.

        **Required scope:** `read_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const giftCard = await client.giftCards.get('gc_K3zr8x', {
            expand: ['customer', 'created_by', 'orders'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /gift_cards/{id} -d '{"expand":["customer","created_by","orders"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: gift card found
          content:
            application/json:
              example:
                id: gc_UkLWZg9DAJ
                code: 92B7BC62609DC882
                status: active
                currency: USD
                amount: '50.0'
                amount_used: '0.0'
                amount_authorized: '0.0'
                amount_remaining: '50.0'
                display_amount: "$50.00"
                display_amount_used: "$0.00"
                display_amount_remaining: "$50.00"
                expires_at:
                redeemed_at:
                expired: false
                active: true
                created_at: '2026-07-27T20:00:35.062Z'
                updated_at: '2026-07-27T20:00:35.062Z'
                customer_id:
                created_by_id:
              schema:
                "$ref": "#/components/schemas/GiftCard"
        '404':
          description: gift card not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Gift card not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a gift card
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates an active gift card's editable attributes. Redeemed or
        partially-redeemed cards cannot be edited.


        **Required scope:** `write_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const giftCard = await client.giftCards.update('gc_K3zr8x', {
            amount: '75.00',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /gift_cards/{id} -d '{"amount":"75.00"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: gift card updated
          content:
            application/json:
              example:
                id: gc_UkLWZg9DAJ
                code: FD0325D1399A9589
                status: active
                currency: USD
                amount: '75.0'
                amount_used: '0.0'
                amount_authorized: '0.0'
                amount_remaining: '75.0'
                display_amount: "$75.00"
                display_amount_used: "$0.00"
                display_amount_remaining: "$75.00"
                expires_at:
                redeemed_at:
                expired: false
                active: true
                created_at: '2026-07-27T20:00:35.647Z'
                updated_at: '2026-07-27T20:00:35.931Z'
                customer_id:
                created_by_id:
              schema:
                "$ref": "#/components/schemas/GiftCard"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: string
                  example: '75.00'
                expires_at:
                  type: string
                  example: '2031-12-31'
                  nullable: true
                user_id:
                  type: string
                  example: cus_UkLWZg9DAJ
                  nullable: true
    delete:
      summary: Delete a gift card
      tags:
      - Gift Cards
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes an unused gift card. Cards that have been redeemed or
        partially redeemed cannot be deleted and return 422.


        **Required scope:** `write_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.giftCards.delete('gc_K3zr8x')
      - lang: bash
        label: Spree CLI
        source: spree api delete /gift_cards/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: gift card deleted
        '422':
          description: redeemed gift card cannot be deleted
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Gift card cannot be deleted
  "/api/v3/admin/imports":
    get:
      summary: List imports
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns CSV imports queued or completed for the current store.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: imports found
          content:
            application/json:
              example:
                data:
                - id: imp_UkLWZg9DAJ
                  number: IM204548010
                  rows_count: 0
                  created_at: '2026-07-27T20:00:36.798Z'
                  updated_at: '2026-07-27T20:00:36.806Z'
                  type: products
                  status: pending
                  owner_type: store
                  owner_id: store_UkLWZg9DAJ
                  user_id: admin_UkLWZg9DAJ
                  processing_errors:
                  preferred_delimiter: ","
                  original_filename: products_import.csv
                  original_byte_size: 3612
                  original_file_url: "/api/v3/admin/imports/imp_UkLWZg9DAJ/download"
                  completed_rows_count: 0
                  failed_rows_count: 0
                  schema_fields:
                  - name: slug
                    label: Slug
                    required: true
                  - name: sku
                    label: SKU
                    required: true
                  - name: name
                    label: Name
                    required: true
                  - name: price
                    label: Price
                    required: true
                  - name: status
                    label: Status
                    required: false
                  - name: description
                    label: Description
                    required: false
                  - name: meta_title
                    label: Meta Title
                    required: false
                  - name: meta_description
                    label: Meta Description
                    required: false
                  - name: meta_keywords
                    label: Meta Keywords
                    required: false
                  - name: tags
                    label: Tags
                    required: false
                  - name: compare_at_price
                    label: Compare at Price
                    required: false
                  - name: currency
                    label: Currency
                    required: false
                  - name: width
                    label: Width
                    required: false
                  - name: height
                    label: Height
                    required: false
                  - name: depth
                    label: Depth
                    required: false
                  - name: dimensions_unit
                    label: Dimensions Unit
                    required: false
                  - name: weight
                    label: Weight
                    required: false
                  - name: weight_unit
                    label: Weight Unit
                    required: false
                  - name: available_on
                    label: Available On
                    required: false
                  - name: discontinue_on
                    label: Discontinue On
                    required: false
                  - name: track_inventory
                    label: Track Inventory
                    required: false
                  - name: inventory_count
                    label: Inventory Count
                    required: false
                  - name: inventory_backorderable
                    label: Inventory Backorderable
                    required: false
                  - name: tax_category
                    label: Tax Category
                    required: false
                  - name: shipping_category
                    label: Shipping Category
                    required: false
                  - name: image1_src
                    label: Image 1 URL
                    required: false
                  - name: image2_src
                    label: Image 2 URL
                    required: false
                  - name: image3_src
                    label: Image 3 URL
                    required: false
                  - name: option1_name
                    label: Option 1 Name
                    required: false
                  - name: option1_value
                    label: Option 1 Value
                    required: false
                  - name: option2_name
                    label: Option 2 Name
                    required: false
                  - name: option2_value
                    label: Option 2 Value
                    required: false
                  - name: option3_name
                    label: Option 3 Name
                    required: false
                  - name: option3_value
                    label: Option 3 Value
                    required: false
                  - name: category1
                    label: Category 1
                    required: false
                  - name: category2
                    label: Category 2
                    required: false
                  - name: category3
                    label: Category 3
                    required: false
                  csv_headers: []
                  sample_row: {}
                  mappings: []
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create an import
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Queues a CSV import. Upload the file first via `POST /api/v3/admin/direct_uploads`
        and pass the returned `signed_id` as `attachment`. On success the import is in the
        `mapping` state and the response carries the mapping payload: `schema_fields`
        (the canonical columns for the type), `csv_headers`, a `sample_row`, and the
        auto-assigned `mappings`.

        Adjust mappings if needed, then call `PATCH /admin/imports/{id}/complete_mapping`
        to start processing. Poll `GET /admin/imports/{id}` while `status` is
        `completed_mapping`/`processing`; terminal statuses are `completed` and `failed`.


        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: import created in mapping state
          content:
            application/json:
              example:
                id: imp_gbHJdmfrXB
                number: IM356592378
                rows_count: 0
                created_at: '2026-07-27T20:00:37.122Z'
                updated_at: '2026-07-27T20:00:37.171Z'
                type: products
                status: mapping
                owner_type: store
                owner_id: store_UkLWZg9DAJ
                user_id: admin_UkLWZg9DAJ
                processing_errors:
                preferred_delimiter: ","
                original_filename: import.csv
                original_byte_size: 44
                original_file_url: "/api/v3/admin/imports/imp_gbHJdmfrXB/download"
                completed_rows_count: 0
                failed_rows_count: 0
                schema_fields:
                - name: slug
                  label: Slug
                  required: true
                - name: sku
                  label: SKU
                  required: true
                - name: name
                  label: Name
                  required: true
                - name: price
                  label: Price
                  required: true
                - name: status
                  label: Status
                  required: false
                - name: description
                  label: Description
                  required: false
                - name: meta_title
                  label: Meta Title
                  required: false
                - name: meta_description
                  label: Meta Description
                  required: false
                - name: meta_keywords
                  label: Meta Keywords
                  required: false
                - name: tags
                  label: Tags
                  required: false
                - name: compare_at_price
                  label: Compare at Price
                  required: false
                - name: currency
                  label: Currency
                  required: false
                - name: width
                  label: Width
                  required: false
                - name: height
                  label: Height
                  required: false
                - name: depth
                  label: Depth
                  required: false
                - name: dimensions_unit
                  label: Dimensions Unit
                  required: false
                - name: weight
                  label: Weight
                  required: false
                - name: weight_unit
                  label: Weight Unit
                  required: false
                - name: available_on
                  label: Available On
                  required: false
                - name: discontinue_on
                  label: Discontinue On
                  required: false
                - name: track_inventory
                  label: Track Inventory
                  required: false
                - name: inventory_count
                  label: Inventory Count
                  required: false
                - name: inventory_backorderable
                  label: Inventory Backorderable
                  required: false
                - name: tax_category
                  label: Tax Category
                  required: false
                - name: shipping_category
                  label: Shipping Category
                  required: false
                - name: image1_src
                  label: Image 1 URL
                  required: false
                - name: image2_src
                  label: Image 2 URL
                  required: false
                - name: image3_src
                  label: Image 3 URL
                  required: false
                - name: option1_name
                  label: Option 1 Name
                  required: false
                - name: option1_value
                  label: Option 1 Value
                  required: false
                - name: option2_name
                  label: Option 2 Name
                  required: false
                - name: option2_value
                  label: Option 2 Value
                  required: false
                - name: option3_name
                  label: Option 3 Name
                  required: false
                - name: option3_value
                  label: Option 3 Value
                  required: false
                - name: category1
                  label: Category 1
                  required: false
                - name: category2
                  label: Category 2
                  required: false
                - name: category3
                  label: Category 3
                  required: false
                csv_headers:
                - slug
                - sku
                - name
                - price
                sample_row:
                  slug: widget
                  sku: W-1
                  name: Widget
                  price: '10.00'
                mappings:
                - id: immap_UkLWZg9DAJ
                  schema_field: slug
                  file_column: slug
                  required: true
                - id: immap_gbHJdmfrXB
                  schema_field: sku
                  file_column: sku
                  required: true
                - id: immap_EfhxLZ9ck8
                  schema_field: name
                  file_column: name
                  required: true
                - id: immap_VqXmZF31wY
                  schema_field: price
                  file_column: price
                  required: true
                - id: immap_uw2YK1rnl0
                  schema_field: status
                  file_column:
                  required: false
                - id: immap_OIJLhNcSbf
                  schema_field: description
                  file_column:
                  required: false
                - id: immap_AXs1igzRC6
                  schema_field: meta_title
                  file_column:
                  required: false
                - id: immap_p6klVeMgbn
                  schema_field: meta_description
                  file_column:
                  required: false
                - id: immap_nJqfPa3Cpe
                  schema_field: meta_keywords
                  file_column:
                  required: false
                - id: immap_98FqgRua4h
                  schema_field: tags
                  file_column:
                  required: false
                - id: immap_xhoCpeNMWu
                  schema_field: compare_at_price
                  file_column:
                  required: false
                - id: immap_vEmzDoNU0H
                  schema_field: currency
                  file_column:
                  required: false
                - id: immap_2KY5XM6frI
                  schema_field: width
                  file_column:
                  required: false
                - id: immap_HOVtlDrOmL
                  schema_field: height
                  file_column:
                  required: false
                - id: immap_ed6l8wVqSM
                  schema_field: depth
                  file_column:
                  required: false
                - id: immap_s18jaGonyx
                  schema_field: dimensions_unit
                  file_column:
                  required: false
                - id: immap_GZUcnUYI5A
                  schema_field: weight
                  file_column:
                  required: false
                - id: immap_ROeNhrwyV9
                  schema_field: weight_unit
                  file_column:
                  required: false
                - id: immap_L3pHOn63Vw
                  schema_field: available_on
                  file_column:
                  required: false
                - id: immap_PQNMcnNFWw
                  schema_field: discontinue_on
                  file_column:
                  required: false
                - id: immap_C9SrJgpzQ4
                  schema_field: track_inventory
                  file_column:
                  required: false
                - id: immap_YHETxCGlb0
                  schema_field: inventory_count
                  file_column:
                  required: false
                - id: immap_5OQZnCRf8J
                  schema_field: inventory_backorderable
                  file_column:
                  required: false
                - id: immap_F0GX8NaP3Y
                  schema_field: tax_category
                  file_column:
                  required: false
                - id: immap_kOKT9MVfb0
                  schema_field: shipping_category
                  file_column:
                  required: false
                - id: immap_3uWpPTcf5W
                  schema_field: image1_src
                  file_column:
                  required: false
                - id: immap_D6Psx31WaT
                  schema_field: image2_src
                  file_column:
                  required: false
                - id: immap_msx3nOJap6
                  schema_field: image3_src
                  file_column:
                  required: false
                - id: immap_5CQZnCRf8J
                  schema_field: option1_name
                  file_column:
                  required: false
                - id: immap_M2nyloHRUQ
                  schema_field: option1_value
                  file_column:
                  required: false
                - id: immap_prklVeMgbn
                  schema_field: option2_name
                  file_column:
                  required: false
                - id: immap_so8jaGonyx
                  schema_field: option2_value
                  file_column:
                  required: false
                - id: immap_rsClYtECFI
                  schema_field: option3_name
                  file_column:
                  required: false
                - id: immap_8DR0I7fEbw
                  schema_field: option3_value
                  file_column:
                  required: false
                - id: immap_aAtNvLSUAr
                  schema_field: category1
                  file_column:
                  required: false
                - id: immap_QiA48cIW7A
                  schema_field: category2
                  file_column:
                  required: false
                - id: immap_QDA48cIW7A
                  schema_field: category3
                  file_column:
                  required: false
        '422':
          description: unknown import type
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Type can't be blank
                  details:
                    type:
                    - can't be blank
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - type
              - attachment
              properties:
                type:
                  type: string
                  enum:
                  - products
                  - customers
                  - product_translations
                  example: products
                attachment:
                  type: string
                  description: ActiveStorage signed blob id from POST /api/v3/admin/direct_uploads.
                  example: eyJfcmFpbHMiOnsiZGF0YSI6MX0=--signed
                preferred_delimiter:
                  type: string
                  enum:
                  - ","
                  - ";"
                  - "|"
                  - "\t"
                  description: CSV column separator. Defaults to a comma.
                  example: ","
                results_url:
                  type: string
                  description: Absolute URL of your admin imports view; the import-done
                    email links back to it with `?import=<id>` appended. Only honored
                    when it matches one of the store's configured allowed origins.
                  example: https://admin.example.com/store_abc/settings/imports
  "/api/v3/admin/imports/template":
    get:
      summary: Download an import template
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a CSV header row for the given import type, including the custom field columns available for the model.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: type
        in: query
        required: true
        description: Registered import type, e.g. products.
        schema:
          type: string
      responses:
        '200':
          description: CSV template
          content:
            application/json: {}
            text/csv:
              schema:
                type: string
                format: binary
  "/api/v3/admin/imports/example":
    get:
      summary: Download an example import file
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Redirects to a populated example CSV for the given import type — the same sample data `rake spree:load_sample_data` uses, pinned to the installed Spree version. Returns 404 for a type that ships no example file.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: type
        in: query
        required: true
        description: Registered import type, e.g. products.
        schema:
          type: string
      responses:
        '302':
          description: Redirect to the example CSV
  "/api/v3/admin/imports/{id}":
    get:
      summary: Show an import
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns import status and row counters. The admin dashboard polls this endpoint while `status` is `completed_mapping` or `processing`; `rows_count`, `completed_rows_count` and `failed_rows_count` drive the progress bar. The mapping payload (`csv_headers`, `sample_row`) is only present while `status` is `mapping`.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: import found
          content:
            application/json:
              example:
                id: imp_UkLWZg9DAJ
                number: IM602867622
                rows_count: 0
                created_at: '2026-07-27T20:00:38.335Z'
                updated_at: '2026-07-27T20:00:38.344Z'
                type: products
                status: pending
                owner_type: store
                owner_id: store_UkLWZg9DAJ
                user_id: admin_UkLWZg9DAJ
                processing_errors:
                preferred_delimiter: ","
                original_filename: products_import.csv
                original_byte_size: 3612
                original_file_url: "/api/v3/admin/imports/imp_UkLWZg9DAJ/download"
                completed_rows_count: 0
                failed_rows_count: 0
                schema_fields:
                - name: slug
                  label: Slug
                  required: true
                - name: sku
                  label: SKU
                  required: true
                - name: name
                  label: Name
                  required: true
                - name: price
                  label: Price
                  required: true
                - name: status
                  label: Status
                  required: false
                - name: description
                  label: Description
                  required: false
                - name: meta_title
                  label: Meta Title
                  required: false
                - name: meta_description
                  label: Meta Description
                  required: false
                - name: meta_keywords
                  label: Meta Keywords
                  required: false
                - name: tags
                  label: Tags
                  required: false
                - name: compare_at_price
                  label: Compare at Price
                  required: false
                - name: currency
                  label: Currency
                  required: false
                - name: width
                  label: Width
                  required: false
                - name: height
                  label: Height
                  required: false
                - name: depth
                  label: Depth
                  required: false
                - name: dimensions_unit
                  label: Dimensions Unit
                  required: false
                - name: weight
                  label: Weight
                  required: false
                - name: weight_unit
                  label: Weight Unit
                  required: false
                - name: available_on
                  label: Available On
                  required: false
                - name: discontinue_on
                  label: Discontinue On
                  required: false
                - name: track_inventory
                  label: Track Inventory
                  required: false
                - name: inventory_count
                  label: Inventory Count
                  required: false
                - name: inventory_backorderable
                  label: Inventory Backorderable
                  required: false
                - name: tax_category
                  label: Tax Category
                  required: false
                - name: shipping_category
                  label: Shipping Category
                  required: false
                - name: image1_src
                  label: Image 1 URL
                  required: false
                - name: image2_src
                  label: Image 2 URL
                  required: false
                - name: image3_src
                  label: Image 3 URL
                  required: false
                - name: option1_name
                  label: Option 1 Name
                  required: false
                - name: option1_value
                  label: Option 1 Value
                  required: false
                - name: option2_name
                  label: Option 2 Name
                  required: false
                - name: option2_value
                  label: Option 2 Value
                  required: false
                - name: option3_name
                  label: Option 3 Name
                  required: false
                - name: option3_value
                  label: Option 3 Value
                  required: false
                - name: category1
                  label: Category 1
                  required: false
                - name: category2
                  label: Category 2
                  required: false
                - name: category3
                  label: Category 3
                  required: false
                csv_headers: []
                sample_row: {}
                mappings: []
    delete:
      summary: Delete an import
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes the import, its rows and the uploaded file. Returns 422 while the import is being processed.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: import deleted
  "/api/v3/admin/imports/{id}/download":
    get:
      summary: Download the originally uploaded file
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Streams the CSV exactly as it was uploaded — the audit trail for what was imported. JWT/API-key protected; SPA clients fetch it with the Authorization header and trigger the browser download via a Blob URL.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: CSV file
          content:
            application/json: {}
            text/csv:
              schema:
                type: string
                format: binary
  "/api/v3/admin/imports/{id}/complete_mapping":
    patch:
      summary: Complete mapping and start processing
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Applies the submitted column mappings, then starts row processing. Omit `mappings`
        to accept the auto-assigned ones from the create response. Returns 422 when a
        required schema field is left unmapped (`details.missing_required_fields`) or a
        file column is assigned twice.


        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: mapping completed, processing queued
          content:
            application/json:
              example:
                id: imp_gbHJdmfrXB
                number: IM228704951
                rows_count: 0
                created_at: '2026-07-27T20:00:39.264Z'
                updated_at: '2026-07-27T20:00:39.330Z'
                type: products
                status: completed_mapping
                owner_type: store
                owner_id: store_UkLWZg9DAJ
                user_id: admin_UkLWZg9DAJ
                processing_errors:
                preferred_delimiter: ","
                original_filename: products_import.csv
                original_byte_size: 3612
                original_file_url: "/api/v3/admin/imports/imp_gbHJdmfrXB/download"
                completed_rows_count: 0
                failed_rows_count: 0
                schema_fields:
                - name: slug
                  label: Slug
                  required: true
                - name: sku
                  label: SKU
                  required: true
                - name: name
                  label: Name
                  required: true
                - name: price
                  label: Price
                  required: true
                - name: status
                  label: Status
                  required: false
                - name: description
                  label: Description
                  required: false
                - name: meta_title
                  label: Meta Title
                  required: false
                - name: meta_description
                  label: Meta Description
                  required: false
                - name: meta_keywords
                  label: Meta Keywords
                  required: false
                - name: tags
                  label: Tags
                  required: false
                - name: compare_at_price
                  label: Compare at Price
                  required: false
                - name: currency
                  label: Currency
                  required: false
                - name: width
                  label: Width
                  required: false
                - name: height
                  label: Height
                  required: false
                - name: depth
                  label: Depth
                  required: false
                - name: dimensions_unit
                  label: Dimensions Unit
                  required: false
                - name: weight
                  label: Weight
                  required: false
                - name: weight_unit
                  label: Weight Unit
                  required: false
                - name: available_on
                  label: Available On
                  required: false
                - name: discontinue_on
                  label: Discontinue On
                  required: false
                - name: track_inventory
                  label: Track Inventory
                  required: false
                - name: inventory_count
                  label: Inventory Count
                  required: false
                - name: inventory_backorderable
                  label: Inventory Backorderable
                  required: false
                - name: tax_category
                  label: Tax Category
                  required: false
                - name: shipping_category
                  label: Shipping Category
                  required: false
                - name: image1_src
                  label: Image 1 URL
                  required: false
                - name: image2_src
                  label: Image 2 URL
                  required: false
                - name: image3_src
                  label: Image 3 URL
                  required: false
                - name: option1_name
                  label: Option 1 Name
                  required: false
                - name: option1_value
                  label: Option 1 Value
                  required: false
                - name: option2_name
                  label: Option 2 Name
                  required: false
                - name: option2_value
                  label: Option 2 Value
                  required: false
                - name: option3_name
                  label: Option 3 Name
                  required: false
                - name: option3_value
                  label: Option 3 Value
                  required: false
                - name: category1
                  label: Category 1
                  required: false
                - name: category2
                  label: Category 2
                  required: false
                - name: category3
                  label: Category 3
                  required: false
                csv_headers: []
                sample_row: {}
                mappings:
                - id: immap_UkLWZg9DAJ
                  schema_field: slug
                  file_column: slug
                  required: true
                - id: immap_gbHJdmfrXB
                  schema_field: sku
                  file_column: sku
                  required: true
                - id: immap_EfhxLZ9ck8
                  schema_field: name
                  file_column: name
                  required: true
                - id: immap_VqXmZF31wY
                  schema_field: price
                  file_column: price
                  required: true
                - id: immap_uw2YK1rnl0
                  schema_field: status
                  file_column: status
                  required: false
                - id: immap_OIJLhNcSbf
                  schema_field: description
                  file_column: description
                  required: false
                - id: immap_AXs1igzRC6
                  schema_field: meta_title
                  file_column: meta_title
                  required: false
                - id: immap_p6klVeMgbn
                  schema_field: meta_description
                  file_column: meta_description
                  required: false
                - id: immap_nJqfPa3Cpe
                  schema_field: meta_keywords
                  file_column: meta_keywords
                  required: false
                - id: immap_98FqgRua4h
                  schema_field: tags
                  file_column: tags
                  required: false
                - id: immap_xhoCpeNMWu
                  schema_field: compare_at_price
                  file_column: compare_at_price
                  required: false
                - id: immap_vEmzDoNU0H
                  schema_field: currency
                  file_column: currency
                  required: false
                - id: immap_2KY5XM6frI
                  schema_field: width
                  file_column: width
                  required: false
                - id: immap_HOVtlDrOmL
                  schema_field: height
                  file_column: height
                  required: false
                - id: immap_ed6l8wVqSM
                  schema_field: depth
                  file_column: depth
                  required: false
                - id: immap_s18jaGonyx
                  schema_field: dimensions_unit
                  file_column: dimensions_unit
                  required: false
                - id: immap_GZUcnUYI5A
                  schema_field: weight
                  file_column: weight
                  required: false
                - id: immap_ROeNhrwyV9
                  schema_field: weight_unit
                  file_column: weight_unit
                  required: false
                - id: immap_L3pHOn63Vw
                  schema_field: available_on
                  file_column: available_on
                  required: false
                - id: immap_PQNMcnNFWw
                  schema_field: discontinue_on
                  file_column: discontinue_on
                  required: false
                - id: immap_C9SrJgpzQ4
                  schema_field: track_inventory
                  file_column: track_inventory
                  required: false
                - id: immap_YHETxCGlb0
                  schema_field: inventory_count
                  file_column: inventory_count
                  required: false
                - id: immap_5OQZnCRf8J
                  schema_field: inventory_backorderable
                  file_column: inventory_backorderable
                  required: false
                - id: immap_F0GX8NaP3Y
                  schema_field: tax_category
                  file_column: tax_category
                  required: false
                - id: immap_kOKT9MVfb0
                  schema_field: shipping_category
                  file_column:
                  required: false
                - id: immap_3uWpPTcf5W
                  schema_field: image1_src
                  file_column: image1_src
                  required: false
                - id: immap_D6Psx31WaT
                  schema_field: image2_src
                  file_column: image2_src
                  required: false
                - id: immap_msx3nOJap6
                  schema_field: image3_src
                  file_column: image3_src
                  required: false
                - id: immap_5CQZnCRf8J
                  schema_field: option1_name
                  file_column: option1_name
                  required: false
                - id: immap_M2nyloHRUQ
                  schema_field: option1_value
                  file_column: option1_value
                  required: false
                - id: immap_prklVeMgbn
                  schema_field: option2_name
                  file_column: option2_name
                  required: false
                - id: immap_so8jaGonyx
                  schema_field: option2_value
                  file_column: option2_value
                  required: false
                - id: immap_rsClYtECFI
                  schema_field: option3_name
                  file_column: option3_name
                  required: false
                - id: immap_8DR0I7fEbw
                  schema_field: option3_value
                  file_column: option3_value
                  required: false
                - id: immap_aAtNvLSUAr
                  schema_field: category1
                  file_column: category1
                  required: false
                - id: immap_QiA48cIW7A
                  schema_field: category2
                  file_column: category2
                  required: false
                - id: immap_QDA48cIW7A
                  schema_field: category3
                  file_column: category3
                  required: false
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                mappings:
                  type: array
                  description: 'Column assignments to apply before starting. `file_column:
                    null` unmaps a field.'
                  items:
                    type: object
                    required:
                    - schema_field
                    properties:
                      schema_field:
                        type: string
                        example: slug
                      file_column:
                        type: string
                        nullable: true
                        example: Product Handle
  "/api/v3/admin/imports/{id}/retry_failed_rows":
    patch:
      summary: Retry failed rows
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Re-processes the rows that failed. The import re-enters `processing`; poll `GET /admin/imports/{id}` until it completes again. Returns 422 when the import is not `completed` or has no failed rows.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: retry queued
          content:
            application/json:
              example:
                id: imp_gbHJdmfrXB
                number: IM634836351
                rows_count: 1
                created_at: '2026-07-27T20:00:39.621Z'
                updated_at: '2026-07-27T20:00:39.647Z'
                type: products
                status: processing
                owner_type: store
                owner_id: store_UkLWZg9DAJ
                user_id: admin_UkLWZg9DAJ
                processing_errors:
                preferred_delimiter: ","
                original_filename: products_import.csv
                original_byte_size: 3612
                original_file_url: "/api/v3/admin/imports/imp_gbHJdmfrXB/download"
                completed_rows_count: 0
                failed_rows_count: 1
                schema_fields:
                - name: slug
                  label: Slug
                  required: true
                - name: sku
                  label: SKU
                  required: true
                - name: name
                  label: Name
                  required: true
                - name: price
                  label: Price
                  required: true
                - name: status
                  label: Status
                  required: false
                - name: description
                  label: Description
                  required: false
                - name: meta_title
                  label: Meta Title
                  required: false
                - name: meta_description
                  label: Meta Description
                  required: false
                - name: meta_keywords
                  label: Meta Keywords
                  required: false
                - name: tags
                  label: Tags
                  required: false
                - name: compare_at_price
                  label: Compare at Price
                  required: false
                - name: currency
                  label: Currency
                  required: false
                - name: width
                  label: Width
                  required: false
                - name: height
                  label: Height
                  required: false
                - name: depth
                  label: Depth
                  required: false
                - name: dimensions_unit
                  label: Dimensions Unit
                  required: false
                - name: weight
                  label: Weight
                  required: false
                - name: weight_unit
                  label: Weight Unit
                  required: false
                - name: available_on
                  label: Available On
                  required: false
                - name: discontinue_on
                  label: Discontinue On
                  required: false
                - name: track_inventory
                  label: Track Inventory
                  required: false
                - name: inventory_count
                  label: Inventory Count
                  required: false
                - name: inventory_backorderable
                  label: Inventory Backorderable
                  required: false
                - name: tax_category
                  label: Tax Category
                  required: false
                - name: shipping_category
                  label: Shipping Category
                  required: false
                - name: image1_src
                  label: Image 1 URL
                  required: false
                - name: image2_src
                  label: Image 2 URL
                  required: false
                - name: image3_src
                  label: Image 3 URL
                  required: false
                - name: option1_name
                  label: Option 1 Name
                  required: false
                - name: option1_value
                  label: Option 1 Value
                  required: false
                - name: option2_name
                  label: Option 2 Name
                  required: false
                - name: option2_value
                  label: Option 2 Value
                  required: false
                - name: option3_name
                  label: Option 3 Name
                  required: false
                - name: option3_value
                  label: Option 3 Value
                  required: false
                - name: category1
                  label: Category 1
                  required: false
                - name: category2
                  label: Category 2
                  required: false
                - name: category3
                  label: Category 3
                  required: false
                csv_headers: []
                sample_row: {}
                mappings: []
  "/api/v3/admin/imports/{import_id}/rows":
    get:
      summary: List import rows
      tags:
      - Imports
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Paginated rows of an import — the failure report. Filter with `q[status_eq]=failed` to list only rows that could not be imported; each row carries the raw CSV `data` and its `validation_errors`.

        **Required scope:** the write scope of the imported resource — `write_products` for product imports, `write_customers` for customer imports, etc. (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: import_id
        in: path
        required: true
        schema:
          type: string
      - name: q[status_eq]
        in: query
        required: false
        description: 'Filter rows by status: pending, processing, completed, failed.'
        schema:
          type: string
      responses:
        '200':
          description: rows found
          content:
            application/json:
              example:
                data:
                - id: imrow_gbHJdmfrXB
                  row_number: 2
                  status: failed
                  validation_errors: boom
                  created_at: '2026-07-27T20:00:39.936Z'
                  updated_at: '2026-07-27T20:00:39.936Z'
                  import_id: imp_UkLWZg9DAJ
                  item_type:
                  item_id:
                  data:
                    slug: test-product
                    name: Test Product
                    price: '10.00'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
  "/api/v3/admin/markets":
    get:
      summary: List markets
      tags:
      - Markets
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the markets configured for the current store. Markets are
        store-scoped and ordered by `position` (an `acts_as_list` column —
        update the order via `PATCH /markets/{id}` with `position`).


        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: markets } = await client.markets.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /markets
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        schema:
          type: string
      - name: sort
        in: query
        required: false
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: 'Comma-separated associations to embed. Supported: `countries`.'
        schema:
          type: string
      responses:
        '200':
          description: markets found
          content:
            application/json:
              example:
                data:
                - id: mkt_UkLWZg9DAJ
                  name: EU
                  currency: USD
                  default_locale: en
                  tax_inclusive: false
                  default: false
                  country_isos:
                  - DE
                  supported_locales:
                  - en
                  created_at: '2026-07-27T20:00:41.516Z'
                  updated_at: '2026-07-27T20:00:41.516Z'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Market"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
    post:
      summary: Create a market
      tags:
      - Markets
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new market for the current store.

        - `country_isos` accepts 2-letter ISO country codes (e.g. `["DE", "FR"]`);
          the market must contain at least one country. Unknown codes are
          silently dropped.
        - `supported_locales` accepts an array of locale codes; the
          `default_locale` is always implicitly included.
        - Setting `default: true` automatically demotes the previous default
          market in the store.


        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const market = await client.markets.create({
            name: 'Europe',
            currency: 'EUR',
            default_locale: 'de',
            supported_locales: ['de', 'en', 'fr'],
            tax_inclusive: true,
            country_isos: ['DE', 'FR', 'IT'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /markets -d '{"name":"Europe","currency":"EUR","default_locale":"de","supported_locales":["de","en","fr"],"tax_inclusive":true,"country_isos":["DE","FR","IT"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: market created
          content:
            application/json:
              example:
                id: mkt_gbHJdmfrXB
                name: France only
                currency: EUR
                default_locale: fr
                tax_inclusive: true
                default: false
                country_isos:
                - FR
                supported_locales:
                - en
                - fr
                created_at: '2026-07-27T20:00:42.106Z'
                updated_at: '2026-07-27T20:00:42.106Z'
              schema:
                "$ref": "#/components/schemas/Market"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank, Currency can't be blank, Default locale
                    can't be blank, and Countries can't be blank
                  details:
                    name:
                    - can't be blank
                    currency:
                    - can't be blank
                    default_locale:
                    - can't be blank
                    countries:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Europe
                currency:
                  type: string
                  example: EUR
                  description: ISO 4217 currency code.
                default_locale:
                  type: string
                  example: de
                  description: IETF locale tag used as the market default.
                supported_locales:
                  type: array
                  items:
                    type: string
                  description: Locale codes available in this market. The default
                    is always implicitly included.
                  example:
                  - de
                  - en
                tax_inclusive:
                  type: boolean
                  default: false
                  description: Display prices with tax included.
                default:
                  type: boolean
                  default: false
                  description: Setting to true demotes the previous default.
                position:
                  type: integer
                  description: Sort order within the store; lower = first.
                country_isos:
                  type: array
                  items:
                    type: string
                  description: 2-letter ISO country codes assigned to this market.
                    At least one is required.
                  example:
                  - DE
                  - FR
              required:
              - name
              - currency
              - default_locale
              - country_isos
  "/api/v3/admin/markets/{id}":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: Get a market
      tags:
      - Markets
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const market = await client.markets.get('market_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /markets/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        schema:
          type: string
      responses:
        '200':
          description: market found
          content:
            application/json:
              example:
                id: mkt_UkLWZg9DAJ
                name: EU
                currency: USD
                default_locale: en
                tax_inclusive: false
                default: false
                country_isos:
                - DE
                supported_locales:
                - en
                created_at: '2026-07-27T20:00:42.429Z'
                updated_at: '2026-07-27T20:00:42.429Z'
              schema:
                "$ref": "#/components/schemas/Market"
        '404':
          description: market not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Market not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a market
      tags:
      - Markets
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates an existing market. Pass `country_isos` to replace the
        market's country list (full-set update), `supported_locales` to
        replace the supported locales, or `position` to reorder the market
        within the store.

        Setting `default: true` automatically demotes the previous default.


        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // `country_isos` is a full-set update — the market is reconciled to match
          // the array (adds new countries, removes ones not present). Setting
          // `default: true` demotes the previous default market in the store.
          const market = await client.markets.update('market_UkLWZg9DAJ', {
            name: 'European Union',
            tax_inclusive: true,
            country_isos: ['DE', 'FR'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /markets/{id} -d '{"name":"European Union","tax_inclusive":true,"country_isos":["DE","FR"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: market updated
          content:
            application/json:
              example:
                id: mkt_UkLWZg9DAJ
                name: European Union
                currency: USD
                default_locale: en
                tax_inclusive: true
                default: false
                country_isos:
                - DE
                supported_locales:
                - en
                created_at: '2026-07-27T20:00:43.047Z'
                updated_at: '2026-07-27T20:00:43.328Z'
              schema:
                "$ref": "#/components/schemas/Market"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                currency:
                  type: string
                default_locale:
                  type: string
                supported_locales:
                  type: array
                  items:
                    type: string
                tax_inclusive:
                  type: boolean
                default:
                  type: boolean
                position:
                  type: integer
                country_isos:
                  type: array
                  items:
                    type: string
    delete:
      summary: Delete a market
      tags:
      - Markets
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes the market (sets `deleted_at`). The default market and
        the last remaining market in a store cannot be deleted — both return
        422 with a `validation_error`.


        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Soft-deletes the market (sets `deleted_at`). The default market and the
          // last remaining market in a store cannot be deleted — both return 422.
          await client.markets.delete('market_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /markets/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: market deleted
        '422':
          description: cannot delete default or last market
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Market cannot be deleted
  "/api/v3/admin/option_types":
    get:
      summary: List option types
      tags:
      - Option Types
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a paginated list of option types.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: optionTypes } = await client.optionTypes.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /option_types
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name (contains)
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., option_values).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,label,position).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: option types found
          content:
            application/json:
              example:
                data:
                - id: opt_UkLWZg9DAJ
                  name: foo-size-1
                  label: Size
                  position: 1
                  kind: dropdown
                  metadata: {}
                  filterable: true
                  created_at: '2026-07-27T20:00:44.872Z'
                  updated_at: '2026-07-27T20:00:44.872Z'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/OptionType"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create an option type
      tags:
      - Option Types
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new option type. Supports nested option values.

        Option values can be provided inline and will be created or updated by name.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const optionType = await client.optionTypes.create({
            name: 'color',
            label: 'Color',
            option_values: [
              { name: 'red', label: 'Red' },
              { name: 'navy', label: 'Navy' },
            ],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /option_types -d '{"name":"color","label":"Color","option_values":[{"name":"red","label":"Red"},{"name":"navy","label":"Navy"}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: option type created
          content:
            application/json:
              example:
                id: opt_gbHJdmfrXB
                name: material
                label: Material
                position: 2
                kind: dropdown
                metadata: {}
                filterable: true
                created_at: '2026-07-27T20:00:45.447Z'
                updated_at: '2026-07-27T20:00:45.447Z'
              schema:
                "$ref": "#/components/schemas/OptionType"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank and Presentation can't be blank
                  details:
                    name:
                    - can't be blank
                    presentation:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: color
                label:
                  type: string
                  example: Color
                position:
                  type: integer
                  example: 1
                filterable:
                  type: boolean
                  example: true
                option_values:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                        example: red
                      label:
                        type: string
                        example: Red
                      position:
                        type: integer
              required:
              - name
              - label
  "/api/v3/admin/option_types/{id}":
    get:
      summary: Get an option type
      tags:
      - Option Types
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single option type by ID, including its option values.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const optionType = await client.optionTypes.get('ot_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /option_types/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Option type ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., option_values).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,label,position).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: option type found
          content:
            application/json:
              example:
                id: opt_UkLWZg9DAJ
                name: foo-size-5
                label: Size
                position: 1
                kind: dropdown
                metadata: {}
                filterable: true
                created_at: '2026-07-27T20:00:45.733Z'
                updated_at: '2026-07-27T20:00:45.733Z'
              schema:
                "$ref": "#/components/schemas/OptionType"
        '404':
          description: option type not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Option type not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update an option type
      tags:
      - Option Types
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates an option type. Supports updating nested option values.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const optionType = await client.optionTypes.update('ot_UkLWZg9DAJ', {
            label: 'Updated Label',
            option_values: [{ name: 'red', label: 'Crimson' }],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /option_types/{id} -d '{"label":"Updated Label","option_values":[{"name":"red","label":"Crimson"}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Option type ID
        schema:
          type: string
      responses:
        '200':
          description: option type updated
          content:
            application/json:
              example:
                id: opt_UkLWZg9DAJ
                name: foo-size-7
                label: Updated Label
                position: 1
                kind: dropdown
                metadata: {}
                filterable: true
                created_at: '2026-07-27T20:00:46.312Z'
                updated_at: '2026-07-27T20:00:46.589Z'
              schema:
                "$ref": "#/components/schemas/OptionType"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Presentation can't be blank
                  details:
                    presentation:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: color
                label:
                  type: string
                  example: Color
                position:
                  type: integer
                  example: 1
                filterable:
                  type: boolean
                  example: true
                option_values:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        description: Existing option value ID to update
                      name:
                        type: string
                        example: red
                      label:
                        type: string
                        example: Red
                      position:
                        type: integer
    delete:
      summary: Delete an option type
      tags:
      - Option Types
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes an option type.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.optionTypes.delete('ot_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /option_types/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Option type ID
        schema:
          type: string
      responses:
        '204':
          description: option type deleted
  "/api/v3/admin/orders/{order_id}/gift_cards":
    post:
      summary: Apply a gift card to an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Applies a gift card by code to the order. Returns the gift card.

        **Required scope:** `write_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.orders.giftCards.apply('or_UkLWZg9DAJ', {
            code: 'GIFT-XXXX-YYYY',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /orders/{order_id}/gift_cards -d '{"code":"GIFT-XXXX-YYYY"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '201':
          description: gift card applied
          content:
            application/json:
              example:
                id: gc_UkLWZg9DAJ
                code: C228B4B05F860A11
                status: active
                currency: USD
                amount: '10.0'
                amount_used: '10.0'
                amount_authorized: '0.0'
                amount_remaining: '0.0'
                display_amount: "$10.00"
                display_amount_used: "$10.00"
                display_amount_remaining: "$0.00"
                expires_at:
                redeemed_at:
                expired: false
                active: true
                created_at: '2026-07-27T20:00:55.684Z'
                updated_at: '2026-07-27T20:00:55.973Z'
                customer_id:
                created_by_id:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - code
              properties:
                code:
                  type: string
                  description: Gift card code
                  example: GIFT-XXXX-YYYY
  "/api/v3/admin/orders/{order_id}/gift_cards/{id}":
    delete:
      summary: Remove a gift card from an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes the gift card from the order.

        **Required scope:** `write_gift_cards` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.orders.giftCards.remove('or_UkLWZg9DAJ', 'gc_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /orders/{order_id}/gift_cards/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Gift card ID
        schema:
          type: string
      responses:
        '204':
          description: gift card removed
  "/api/v3/admin/orders/{order_id}/items":
    get:
      summary: List order items
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns all line items for an order.

        **Required scope:** `read_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: items } = await client.orders.items.list('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{order_id}/items
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., variant, variant.product).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., quantity,price,total).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: items found
          content:
            application/json:
              example:
                data:
                - id: li_UkLWZg9DAJ
                  variant_id: variant_gbHJdmfrXB
                  preorder: false
                  preorder_ships_at:
                  quantity: 2
                  currency: USD
                  name: Product 17510
                  slug: product-17510
                  options_text: 'Size: S'
                  price: '10.0'
                  display_price: "$10.00"
                  total: '20.0'
                  display_total: "$20.00"
                  adjustment_total: '0.0'
                  display_adjustment_total: "$0.00"
                  additional_tax_total: '0.0'
                  display_additional_tax_total: "$0.00"
                  included_tax_total: '0.0'
                  display_included_tax_total: "$0.00"
                  discount_total: '0.0'
                  display_discount_total: "$0.00"
                  pre_tax_amount: '20.0'
                  display_pre_tax_amount: "$20.00"
                  discounted_amount: '20.0'
                  display_discounted_amount: "$20.00"
                  display_compare_at_amount: "$0.00"
                  compare_at_amount:
                  thumbnail_url:
                  option_values:
                  - id: optval_UkLWZg9DAJ
                    option_type_id: opt_UkLWZg9DAJ
                    name: size-1
                    label: S
                    position: 1
                    color_code:
                    option_type_name: foo-size-10
                    option_type_label: Size
                    image_url:
                    metadata: {}
                    created_at: '2026-07-27T20:00:56.643Z'
                    updated_at: '2026-07-27T20:00:56.643Z'
                  digital_links: []
                  metadata: {}
                  created_at: '2026-07-27T20:00:56.921Z'
                  updated_at: '2026-07-27T20:00:56.921Z'
                  cost_price: '17.0'
                  tax_category_id: taxcat_UkLWZg9DAJ
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Add an item
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds a new line item to the order.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const item = await client.orders.items.create('or_UkLWZg9DAJ', {
            variant_id: 'variant_k5nR8xLq',
            quantity: 2,
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /orders/{order_id}/items -d '{"variant_id":"variant_k5nR8xLq","quantity":2}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '201':
          description: item added
          content:
            application/json:
              example:
                id: li_gbHJdmfrXB
                variant_id: variant_VqXmZF31wY
                preorder: false
                preorder_ships_at:
                quantity: 3
                currency: USD
                name: Product 19115
                slug: product-19115
                options_text: 'Size: S'
                price: '19.99'
                display_price: "$19.99"
                total: '59.97'
                display_total: "$59.97"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                pre_tax_amount: '59.97'
                display_pre_tax_amount: "$59.97"
                discounted_amount: '59.97'
                display_discounted_amount: "$59.97"
                display_compare_at_amount: "$0.00"
                compare_at_amount:
                thumbnail_url:
                option_values:
                - id: optval_gbHJdmfrXB
                  option_type_id: opt_gbHJdmfrXB
                  name: size-3
                  label: S
                  position: 1
                  color_code:
                  option_type_name: foo-size-12
                  option_type_label: Size
                  image_url:
                  metadata: {}
                  created_at: '2026-07-27T20:00:57.836Z'
                  updated_at: '2026-07-27T20:00:57.836Z'
                digital_links: []
                metadata: {}
                created_at: '2026-07-27T20:00:57.865Z'
                updated_at: '2026-07-27T20:00:57.865Z'
                cost_price: '17.0'
                tax_category_id: taxcat_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - variant_id
              properties:
                variant_id:
                  type: string
                  description: Prefixed variant ID
                quantity:
                  type: integer
                  default: 1
  "/api/v3/admin/orders/{order_id}/items/{id}":
    get:
      summary: Show an item
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns details of a specific line item.

        **Required scope:** `read_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const item = await client.orders.items.get('or_UkLWZg9DAJ', 'li_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{order_id}/items/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Item ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., variant, variant.product).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., quantity,price,total).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: item found
          content:
            application/json:
              example:
                id: li_UkLWZg9DAJ
                variant_id: variant_gbHJdmfrXB
                preorder: false
                preorder_ships_at:
                quantity: 2
                currency: USD
                name: Product 203163
                slug: product-203163
                options_text: 'Size: S'
                price: '10.0'
                display_price: "$10.00"
                total: '20.0'
                display_total: "$20.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                pre_tax_amount: '20.0'
                display_pre_tax_amount: "$20.00"
                discounted_amount: '20.0'
                display_discounted_amount: "$20.00"
                display_compare_at_amount: "$0.00"
                compare_at_amount:
                thumbnail_url:
                option_values:
                - id: optval_UkLWZg9DAJ
                  option_type_id: opt_UkLWZg9DAJ
                  name: size-4
                  label: S
                  position: 1
                  color_code:
                  option_type_name: foo-size-13
                  option_type_label: Size
                  image_url:
                  metadata: {}
                  created_at: '2026-07-27T20:00:57.948Z'
                  updated_at: '2026-07-27T20:00:57.948Z'
                digital_links: []
                metadata: {}
                created_at: '2026-07-27T20:00:58.238Z'
                updated_at: '2026-07-27T20:00:58.238Z'
                cost_price: '17.0'
                tax_category_id: taxcat_UkLWZg9DAJ
    patch:
      summary: Update an item
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates an order item quantity or metadata.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const item = await client.orders.items.update('or_UkLWZg9DAJ', 'li_UkLWZg9DAJ', {
            quantity: 5,
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/items/{id} -d '{"quantity":5}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Item ID
        schema:
          type: string
      responses:
        '200':
          description: item updated
          content:
            application/json:
              example:
                id: li_UkLWZg9DAJ
                variant_id: variant_gbHJdmfrXB
                preorder: false
                preorder_ships_at:
                quantity: 5
                currency: USD
                name: Product 214628
                slug: product-214628
                options_text: 'Size: S'
                price: '19.99'
                display_price: "$19.99"
                total: '99.95'
                display_total: "$99.95"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                pre_tax_amount: '99.95'
                display_pre_tax_amount: "$99.95"
                discounted_amount: '99.95'
                display_discounted_amount: "$99.95"
                display_compare_at_amount: "$0.00"
                compare_at_amount:
                thumbnail_url:
                option_values:
                - id: optval_UkLWZg9DAJ
                  option_type_id: opt_UkLWZg9DAJ
                  name: size-5
                  label: S
                  position: 1
                  color_code:
                  option_type_name: foo-size-14
                  option_type_label: Size
                  image_url:
                  metadata: {}
                  created_at: '2026-07-27T20:00:58.587Z'
                  updated_at: '2026-07-27T20:00:58.587Z'
                digital_links: []
                metadata: {}
                created_at: '2026-07-27T20:00:58.875Z'
                updated_at: '2026-07-27T20:00:59.177Z'
                cost_price: '17.0'
                tax_category_id: taxcat_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                quantity:
                  type: integer
    delete:
      summary: Remove an item
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes an item from the order.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.orders.items.delete('or_UkLWZg9DAJ', 'li_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /orders/{order_id}/items/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Item ID
        schema:
          type: string
      responses:
        '204':
          description: line item removed
  "/api/v3/admin/orders/{order_id}/store_credits":
    post:
      summary: Apply customer's store credit to an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Applies the order customer's available store credit. When `amount` is omitted, applies up to the order outstanding balance.

        **Required scope:** `write_store_credits` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const order = await client.orders.storeCredits.apply('or_UkLWZg9DAJ', {
            amount: '25.00',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /orders/{order_id}/store_credits -d '{"amount":"25.00"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '201':
          description: store credit applied
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R375407510
                email: tamra.rutherford@zboncakmarks.ca
                customer_note:
                currency: USD
                locale: en
                total_quantity: 1
                fulfillment_status:
                payment_status:
                completed_at:
                item_total: '10.0'
                display_item_total: "$10.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '110.0'
                display_total: "$110.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '60.0'
                display_amount_due: "$60.00"
                delivery_total: '100.0'
                display_delivery_total: "$100.00"
                store_credit_total: '50.0'
                display_store_credit_total: "-$50.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: draft
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at:
                approved_at:
                created_at: '2026-07-27T20:01:05.830Z'
                updated_at: '2026-07-27T20:01:05.883Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id:
                canceler_id:
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: string
                  description: Optional explicit amount; defaults to order outstanding
                    balance
    delete:
      summary: Remove store credit from an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes any applied store credit from the order.

        **Required scope:** `write_store_credits` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.orders.storeCredits.remove('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /orders/{order_id}/store_credits
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '204':
          description: store credit removed
  "/api/v3/admin/orders":
    get:
      summary: List orders
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a paginated list of orders for the current store.

        **Required scope:** `read_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: orders, meta } = await client.orders.list({
            status_eq: 'complete',
            completed_at_gt: '2026-01-01',
            sort: '-completed_at',
            limit: 25,
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /orders -d '{"status_eq":"complete","completed_at_gt":"2026-01-01","sort":"-completed_at","limit":25}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: sort
        in: query
        required: false
        description: Sort field (e.g., created_at, -created_at, completed_at)
        schema:
          type: string
      - name: q[state_eq]
        in: query
        required: false
        description: Filter by state (cart, address, delivery, payment, confirm, complete,
          canceled)
        schema:
          type: string
      - name: q[email_cont]
        in: query
        required: false
        description: Filter by email (contains)
        schema:
          type: string
      - name: q[number_eq]
        in: query
        required: false
        description: Filter by order number
        schema:
          type: string
      - name: q[completed_at_gt]
        in: query
        required: false
        description: Filter by completed after date
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., items, fulfillments,
          payments, customer, discounts, billing_address, shipping_address). Use dot
          notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., number,total,status,completed_at).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: orders found
          content:
            application/json:
              example:
                data:
                - id: or_UkLWZg9DAJ
                  market_id:
                  channel_id: ch_UkLWZg9DAJ
                  number: R138037474
                  email: anna@lednercasper.co.uk
                  customer_note:
                  currency: USD
                  locale: en
                  total_quantity: 0
                  fulfillment_status:
                  payment_status:
                  completed_at:
                  item_total: '0.0'
                  display_item_total: "$0.00"
                  adjustment_total: '0.0'
                  display_adjustment_total: "$0.00"
                  discount_total: '0.0'
                  display_discount_total: "$0.00"
                  tax_total: '0.0'
                  display_tax_total: "$0.00"
                  included_tax_total: '0.0'
                  display_included_tax_total: "$0.00"
                  additional_tax_total: '0.0'
                  display_additional_tax_total: "$0.00"
                  total: '0.0'
                  display_total: "$0.00"
                  gift_card_total: '0.0'
                  display_gift_card_total: "$0.00"
                  amount_due: '0.0'
                  display_amount_due: "$0.00"
                  delivery_total: '0.0'
                  display_delivery_total: "$0.00"
                  store_credit_total: '0.0'
                  display_store_credit_total: "$0.00"
                  covered_by_store_credit: false
                  gift_card:
                  market:
                  status: draft
                  last_ip_address:
                  considered_risky: false
                  confirmation_delivered: false
                  store_owner_notification_delivered:
                  payment_total: '0.0'
                  display_payment_total: "$0.00"
                  metadata: {}
                  canceled_at:
                  approved_at:
                  created_at: '2026-07-27T20:01:07.609Z'
                  updated_at: '2026-07-27T20:01:07.609Z'
                  preferred_stock_location_id:
                  tags: []
                  internal_note:
                  approver_id:
                  canceler_id:
                  created_by_id:
                  customer_id: cus_UkLWZg9DAJ
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create a draft order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // One-shot order create: customer, items, addresses, market, channel,
          // notes, metadata, and a coupon code in a single call. Everything
          // except `email` is optional.
          const order = await client.orders.create({
            email: 'jane@example.com',
            customer_id: 'cus_UkLWZg9DAJ',           // Existing customer; omit for guest orders
            use_customer_default_address: false,     // true to copy the customer's saved addresses

            currency: 'USD',
            market_id: 'mkt_UkLWZg9DAJ',
            channel_id: 'ch_UkLWZg9DAJ',             // Optional — defaults to the store's primary channel
            locale: 'en-US',

            // Pin the order's preferred fulfillment location. Order Routing's
            // built-in PreferredLocation rule ranks this location first when
            // it stocks the cart's items; if it doesn't, routing falls back
            // to the next rule (Minimize Splits → Default Location).
            preferred_stock_location_id: 'sloc_UkLWZg9DAJ',

            customer_note: 'Please leave at the front desk.',
            internal_note: 'VIP customer — handle with care.',
            metadata: {
              external_reference: 'subscription_invoice_2026_04',
              source: 'recurring-engine',
            },

            // Items: each variant_id + quantity. Optional metadata per line.
            items: [
              { variant_id: 'variant_k5nR8xLq', quantity: 2 },
              { variant_id: 'variant_QXyZ12abCD', quantity: 1, metadata: { gift: true } },
            ],

            // Provide addresses inline OR by ID (existing customer addresses).
            shipping_address: {
              first_name: 'Jane',
              last_name: 'Doe',
              address1: '350 Fifth Avenue',
              address2: 'Floor 42',
              city: 'New York',
              postal_code: '10118',
              country_iso: 'US',
              state_abbr: 'NY',
              phone: '+1 212 555 1234',
              company: 'Acme Inc.',
            },
            // shipping_address_id: 'addr_UkLWZg9DAJ',  // alternative to inline

            billing_address: {
              first_name: 'Jane',
              last_name: 'Doe',
              address1: '350 Fifth Avenue',
              city: 'New York',
              postal_code: '10118',
              country_iso: 'US',
              state_abbr: 'NY',
              phone: '+1 212 555 1234',
            },
            // billing_address_id: 'addr_UkLWZg9DAJ',

            // Optional. Invalid codes are non-fatal — the order is created either way.
            coupon_code: 'WELCOME10',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /orders -d '{"email":"jane@example.com","customer_id":"cus_UkLWZg9DAJ","use_customer_default_address":false,"currency":"USD","market_id":"mkt_UkLWZg9DAJ","channel_id":"ch_UkLWZg9DAJ","locale":"en-US","preferred_stock_location_id":"sloc_UkLWZg9DAJ","customer_note":"Please
          leave at the front desk.","internal_note":"VIP customer — handle with care.","metadata":{"external_reference":"subscription_invoice_2026_04","source":"recurring-engine"},"items":[{"variant_id":"variant_k5nR8xLq","quantity":2},{"variant_id":"variant_QXyZ12abCD","quantity":1,"metadata":{"gift":true}}],"shipping_address":{"first_name":"Jane","last_name":"Doe","address1":"350
          Fifth Avenue","address2":"Floor 42","city":"New York","postal_code":"10118","country_iso":"US","state_abbr":"NY","phone":"+1
          212 555 1234","company":"Acme Inc."},"billing_address":{"first_name":"Jane","last_name":"Doe","address1":"350
          Fifth Avenue","city":"New York","postal_code":"10118","country_iso":"US","state_abbr":"NY","phone":"+1
          212 555 1234"},"coupon_code":"WELCOME10"}'
      description: |-
        Creates a new draft order in one shot. Customer, items, addresses, currency,
        market, channel, locale, notes, metadata, and a coupon code can all be
        provided inline.

        Setting `preferred_stock_location_id` pins the order's preferred fulfillment
        location — Order Routing's built-in `PreferredLocation` rule consumes it
        when picking which stock location ships each shipment.

        Invalid coupon codes are non-fatal — the order is created and the failure
        is reported on the service result (not in the API response body for now).


        **Required scope:** `write_orders` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: order created with preferred_stock_location_id
          content:
            application/json:
              example:
                id: or_gbHJdmfrXB
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R933904120
                email: pinned@example.com
                customer_note:
                currency: USD
                locale: en
                total_quantity: 0
                fulfillment_status:
                payment_status:
                completed_at:
                item_total: '0.0'
                display_item_total: "$0.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '0.0'
                display_total: "$0.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '0.0'
                display_amount_due: "$0.00"
                delivery_total: '0.0'
                display_delivery_total: "$0.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: draft
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at:
                approved_at:
                created_at: '2026-07-27T20:01:09.346Z'
                updated_at: '2026-07-27T20:01:09.349Z'
                preferred_stock_location_id: sloc_UkLWZg9DAJ
                tags: []
                internal_note:
                approver_id:
                canceler_id:
                created_by_id:
                customer_id:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  example: customer@example.com
                customer_id:
                  type: string
                  description: 'Customer ID. Alias: user_id (legacy).'
                use_customer_default_address:
                  type: boolean
                  description: When true with customer_id, copies the customer's saved
                    billing/shipping addresses onto the order.
                currency:
                  type: string
                  example: USD
                market_id:
                  type: string
                  description: Market ID
                channel_id:
                  type: string
                  description: Channel ID. Defaults to the store primary channel when
                    omitted.
                preferred_stock_location_id:
                  type: string
                  description: Stock Location ID to prefer for fulfillment. Order
                    Routing's built-in PreferredLocation rule reads this and ranks
                    the location first; routing falls back to the next rule when the
                    preferred location can't cover the cart.
                locale:
                  type: string
                  example: en-US
                customer_note:
                  type: string
                  description: Public, customer-visible note
                internal_note:
                  type: string
                  description: Staff-only note
                metadata:
                  type: object
                  description: Arbitrary key/value metadata
                shipping_address:
                  type: object
                  properties:
                    first_name:
                      type: string
                    last_name:
                      type: string
                    address1:
                      type: string
                    city:
                      type: string
                    postal_code:
                      type: string
                    country_iso:
                      type: string
                    state_abbr:
                      type: string
                    phone:
                      type: string
                shipping_address_id:
                  type: string
                  description: Existing customer address ID
                billing_address:
                  type: object
                  properties:
                    first_name:
                      type: string
                    last_name:
                      type: string
                    address1:
                      type: string
                    city:
                      type: string
                    postal_code:
                      type: string
                    country_iso:
                      type: string
                    state_abbr:
                      type: string
                    phone:
                      type: string
                billing_address_id:
                  type: string
                  description: Existing customer address ID
                items:
                  type: array
                  items:
                    type: object
                    required:
                    - variant_id
                    - quantity
                    properties:
                      variant_id:
                        type: string
                        description: Variant ID
                      quantity:
                        type: integer
                        example: 1
                      metadata:
                        type: object
                coupon_code:
                  type: string
                  description: Optional. Applied non-fatally; invalid codes do not
                    block creation.
  "/api/v3/admin/orders/{id}":
    get:
      summary: Show an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns full order details including admin-only fields.

        **Required scope:** `read_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const order = await client.orders.get('or_UkLWZg9DAJ', {
            expand: ['items', 'fulfillments', 'payments', 'customer'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{id} -d '{"expand":["items","fulfillments","payments","customer"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID (e.g., or_xxx)
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., items, fulfillments,
          payments, customer, discounts, billing_address, shipping_address). Use dot
          notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., number,total,status,completed_at).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: order found
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R801110570
                email: leah.huels@bashirian.com
                customer_note:
                currency: USD
                locale: en
                total_quantity: 0
                fulfillment_status:
                payment_status:
                completed_at:
                item_total: '0.0'
                display_item_total: "$0.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '0.0'
                display_total: "$0.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '0.0'
                display_amount_due: "$0.00"
                delivery_total: '0.0'
                display_delivery_total: "$0.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: draft
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at:
                approved_at:
                created_at: '2026-07-27T20:01:09.626Z'
                updated_at: '2026-07-27T20:01:09.626Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id:
                canceler_id:
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
        '404':
          description: order not found
          content:
            application/json:
              example:
                error:
                  code: order_not_found
                  message: Order not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates an order. Supports updating email, addresses, special instructions, and line items.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const order = await client.orders.update('or_UkLWZg9DAJ', {
            email: 'updated@example.com',
            internal_note: 'VIP — gift wrap on next order',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{id} -d '{"email":"updated@example.com","internal_note":"VIP
          — gift wrap on next order"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '200':
          description: order updated
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R731181056
                email: updated@example.com
                customer_note:
                currency: USD
                locale: en
                total_quantity: 0
                fulfillment_status:
                payment_status:
                completed_at:
                item_total: '0.0'
                display_item_total: "$0.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '0.0'
                display_total: "$0.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '0.0'
                display_amount_due: "$0.00"
                delivery_total: '0.0'
                display_delivery_total: "$0.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: draft
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at:
                approved_at:
                created_at: '2026-07-27T20:01:10.730Z'
                updated_at: '2026-07-27T20:01:11.015Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id:
                canceler_id:
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                special_instructions:
                  type: string
                internal_note:
                  type: string
                channel_id:
                  type: string
                  description: Channel ID
                preferred_stock_location_id:
                  type: string
                  description: Stock Location ID to prefer for fulfillment. Re-runs
                    Order Routing's PreferredLocation rule on subsequent shipment
                    rebuilds.
                ship_address:
                  type: object
                  properties:
                    firstname:
                      type: string
                    lastname:
                      type: string
                    address1:
                      type: string
                    city:
                      type: string
                    zipcode:
                      type: string
                    country_iso:
                      type: string
                    state_abbr:
                      type: string
                    phone:
                      type: string
                bill_address:
                  type: object
                  properties:
                    firstname:
                      type: string
                    lastname:
                      type: string
                    address1:
                      type: string
                    city:
                      type: string
                    zipcode:
                      type: string
                    country_iso:
                      type: string
                    state_abbr:
                      type: string
                    phone:
                      type: string
                items:
                  type: array
                  items:
                    type: object
                    required:
                    - variant_id
                    properties:
                      variant_id:
                        type: string
                        description: Variant ID
                      quantity:
                        type: integer
                        example: 1
                      metadata:
                        type: object
    delete:
      summary: Delete a draft order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Deletes a draft order. Completed orders cannot be deleted.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.orders.delete('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /orders/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '204':
          description: order deleted
  "/api/v3/admin/orders/{id}/complete":
    patch:
      summary: Complete an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Completes an order in the `confirm` state, marking it as placed.

        Set `notify_customer: true` to send the order confirmation email.


        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const order = await client.orders.complete('or_UkLWZg9DAJ', {
            notify_customer: true,
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{id}/complete -d '{"notify_customer":true}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '200':
          description: order completed
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R339300602
                email: retha.miller@predovic.co.uk
                customer_note:
                currency: USD
                locale: en
                total_quantity: 1
                fulfillment_status: ready
                payment_status: paid
                completed_at: '2026-07-27T20:01:11.923Z'
                item_total: '10.0'
                display_item_total: "$10.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '110.0'
                display_total: "$110.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '0.0'
                display_amount_due: "$0.00"
                delivery_total: '100.0'
                display_delivery_total: "$100.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: draft
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '110.0'
                display_payment_total: "$110.00"
                metadata: {}
                canceled_at:
                approved_at:
                created_at: '2026-07-27T20:01:11.864Z'
                updated_at: '2026-07-27T20:01:11.943Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id:
                canceler_id:
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
        '422':
          description: order cannot be completed
          content:
            application/json:
              example:
                error:
                  code: order_cannot_complete
                  message: No payment found
                  details:
                    base:
                    - No payment found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                notify_customer:
                  type: boolean
                  description: Send the order confirmation email after completion.
  "/api/v3/admin/orders/{id}/cancel":
    patch:
      summary: Cancel an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Cancels a completed order.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const order = await client.orders.cancel('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{id}/cancel -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '200':
          description: order canceled
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R431148308
                email: zoraida@hamill.com
                customer_note:
                currency: USD
                locale: en
                total_quantity: 1
                fulfillment_status: canceled
                payment_status: void
                completed_at: '2026-07-27T20:01:13.171Z'
                item_total: '10.0'
                display_item_total: "$10.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '20.0'
                display_total: "$20.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: "-0.0"
                display_amount_due: "$0.00"
                delivery_total: '10.0'
                display_delivery_total: "$10.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: canceled
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at: '2026-07-27T20:01:13.457Z'
                approved_at:
                created_at: '2026-07-27T20:01:13.126Z'
                updated_at: '2026-07-27T20:01:13.511Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id:
                canceler_id: admin_UkLWZg9DAJ
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
  "/api/v3/admin/orders/{id}/approve":
    patch:
      summary: Approve an order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Approves an order (e.g., for fraud review).

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const order = await client.orders.approve('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{id}/approve -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '200':
          description: order approved
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R046415341
                email: mina_schultz@leschmohr.ca
                customer_note:
                currency: USD
                locale: en
                total_quantity: 1
                fulfillment_status:
                payment_status:
                completed_at: '2026-07-27T20:01:13.864Z'
                item_total: '10.0'
                display_item_total: "$10.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '110.0'
                display_total: "$110.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '110.0'
                display_amount_due: "$110.00"
                delivery_total: '100.0'
                display_delivery_total: "$100.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: draft
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at:
                approved_at: '2026-07-27T20:01:14.155Z'
                created_at: '2026-07-27T20:01:13.815Z'
                updated_at: '2026-07-27T20:01:13.864Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id: admin_UkLWZg9DAJ
                canceler_id:
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
  "/api/v3/admin/orders/{id}/resume":
    patch:
      summary: Resume a canceled order
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Resumes a previously canceled order.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const order = await client.orders.resume('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{id}/resume -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '200':
          description: order resumed
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R010191644
                email: michale@stracke.ca
                customer_note:
                currency: USD
                locale: en
                total_quantity: 1
                fulfillment_status: canceled
                payment_status: void
                completed_at: '2026-07-27T20:01:14.486Z'
                item_total: '10.0'
                display_item_total: "$10.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '20.0'
                display_total: "$20.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '20.0'
                display_amount_due: "$20.00"
                delivery_total: '10.0'
                display_delivery_total: "$10.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: placed
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at: '2026-07-27T20:01:14.763Z'
                approved_at:
                created_at: '2026-07-27T20:01:14.434Z'
                updated_at: '2026-07-27T20:01:14.868Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id:
                canceler_id: admin_UkLWZg9DAJ
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
  "/api/v3/admin/orders/{id}/resend_confirmation":
    post:
      summary: Resend confirmation email
      tags:
      - Orders
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Publishes the order.completed event to trigger confirmation email delivery.

        **Required scope:** `write_orders` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.orders.resendConfirmation('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api post /orders/{id}/resend_confirmation -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '200':
          description: confirmation resent
          content:
            application/json:
              example:
                id: or_UkLWZg9DAJ
                market_id:
                channel_id: ch_UkLWZg9DAJ
                number: R876299554
                email: robyn@flatley.name
                customer_note:
                currency: USD
                locale: en
                total_quantity: 1
                fulfillment_status:
                payment_status:
                completed_at: '2026-07-27T20:01:15.201Z'
                item_total: '10.0'
                display_item_total: "$10.00"
                adjustment_total: '0.0'
                display_adjustment_total: "$0.00"
                discount_total: '0.0'
                display_discount_total: "$0.00"
                tax_total: '0.0'
                display_tax_total: "$0.00"
                included_tax_total: '0.0'
                display_included_tax_total: "$0.00"
                additional_tax_total: '0.0'
                display_additional_tax_total: "$0.00"
                total: '110.0'
                display_total: "$110.00"
                gift_card_total: '0.0'
                display_gift_card_total: "$0.00"
                amount_due: '110.0'
                display_amount_due: "$110.00"
                delivery_total: '100.0'
                display_delivery_total: "$100.00"
                store_credit_total: '0.0'
                display_store_credit_total: "$0.00"
                covered_by_store_credit: false
                gift_card:
                market:
                status: draft
                last_ip_address:
                considered_risky: false
                confirmation_delivered: false
                store_owner_notification_delivered:
                payment_total: '0.0'
                display_payment_total: "$0.00"
                metadata: {}
                canceled_at:
                approved_at:
                created_at: '2026-07-27T20:01:15.155Z'
                updated_at: '2026-07-27T20:01:15.201Z'
                preferred_stock_location_id:
                tags: []
                internal_note:
                approver_id:
                canceler_id:
                created_by_id:
                customer_id: cus_UkLWZg9DAJ
  "/api/v3/admin/payment_methods":
    get:
      summary: List payment methods
      tags:
      - Payment Methods
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the store's configured payment methods. Use `source_required: true` to know which methods need a saved source.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: paymentMethods } = await client.paymentMethods.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /payment_methods
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand. Use dot notation for
          nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,type,active).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: payment methods found
          content:
            application/json:
              example:
                data:
                - id: pm_UkLWZg9DAJ
                  name: Check
                  description:
                  type: check
                  session_required: false
                  source_required: false
                  metadata: {}
                  active: true
                  auto_capture:
                  storefront_visible: true
                  position: 1
                  created_at: '2026-07-27T20:01:16.605Z'
                  updated_at: '2026-07-27T20:01:16.605Z'
                  preferences: {}
                  preference_schema: []
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
  "/api/v3/admin/payment_methods/types":
    get:
      summary: List available payment provider types
      tags:
      - Payment Methods
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the registered Spree::PaymentMethod subclasses that can be used to create new payment methods. Useful for populating a "Provider" dropdown in admin UIs.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: types } = await client.paymentMethods.types()
      - lang: bash
        label: Spree CLI
        source: spree api get /payment_methods/types
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: provider types found
          content:
            application/json:
              example:
                data:
                - type: bogus
                  label: Bogus
                  description:
                  preference_schema:
                  - key: dummy_key
                    type: string
                    default: PUBLICKEY123
                  - key: dummy_secret_key
                    type: password
                    default:
                - type: custom_payment_source_method
                  label: Custom Payment Source Method
                  description:
                  preference_schema: []
  "/api/v3/admin/payment_methods/{id}":
    get:
      summary: Show a payment method
      tags:
      - Payment Methods
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a payment method by ID.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const paymentMethod = await client.paymentMethods.get('pm_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /payment_methods/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand. Use dot notation for
          nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,type,active).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: payment method found
          content:
            application/json:
              example:
                id: pm_UkLWZg9DAJ
                name: Check
                description:
                type: check
                session_required: false
                source_required: false
                metadata: {}
                active: true
                auto_capture:
                storefront_visible: true
                position: 1
                created_at: '2026-07-27T20:01:17.183Z'
                updated_at: '2026-07-27T20:01:17.183Z'
                preferences: {}
                preference_schema: []
  "/api/v3/admin/orders/{order_id}/payments":
    get:
      summary: List payments
      tags:
      - Payments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns all payments for an order.

        **Required scope:** `read_payments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: payments } = await client.orders.payments.list('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{order_id}/payments
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., payment_method,
          source). Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., amount,status,number,response_code).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: payments found
          content:
            application/json:
              example:
                data:
                - id: py_UkLWZg9DAJ
                  payment_method_id: pm_UkLWZg9DAJ
                  response_code: BGS-f9deefbc6187
                  number: PS6MV2Q2
                  amount: '110.0'
                  display_amount: "$110.00"
                  status: completed
                  source_type: credit_card
                  source_id: card_UkLWZg9DAJ
                  source:
                    id: card_UkLWZg9DAJ
                    brand: visa
                    last4: '1111'
                    month: 12
                    year: 2027
                    name: Spree Commerce
                    default: false
                    gateway_payment_profile_id:
                    customer_id:
                    payment_method_id: pm_gbHJdmfrXB
                    metadata: {}
                    created_at: '2026-07-27T20:01:00.159Z'
                    updated_at: '2026-07-27T20:01:00.162Z'
                  metadata: {}
                  avs_response:
                  cvv_response_code:
                  cvv_response_message:
                  created_at: '2026-07-27T20:01:00.161Z'
                  updated_at: '2026-07-27T20:01:00.161Z'
                  captured_amount: '0.0'
                  order_id: or_UkLWZg9DAJ
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create a payment
      tags:
      - Payments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new payment for the order.

        **Required scope:** `write_payments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const payment = await client.orders.payments.create('or_UkLWZg9DAJ', {
            payment_method_id: 'pm_UkLWZg9DAJ',
            amount: '99.99',
            source_id: 'cc_UkLWZg9DAJ',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /orders/{order_id}/payments -d '{"payment_method_id":"pm_UkLWZg9DAJ","amount":"99.99","source_id":"cc_UkLWZg9DAJ"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '201':
          description: payment created
          content:
            application/json:
              example:
                id: py_gbHJdmfrXB
                payment_method_id: pm_EfhxLZ9ck8
                response_code:
                number: P6E9CP8T
                amount: '110.0'
                display_amount: "$110.00"
                status: checkout
                source_type:
                source_id:
                source:
                metadata: {}
                avs_response:
                cvv_response_code:
                cvv_response_message:
                created_at: '2026-07-27T20:01:01.461Z'
                updated_at: '2026-07-27T20:01:01.461Z'
                captured_amount: '0.0'
                order_id: or_gbHJdmfrXB
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - payment_method_id
              properties:
                payment_method_id:
                  type: string
                  description: Payment method ID
                amount:
                  type: string
                  example: '99.99'
                source_id:
                  type: string
                  description: Payment source ID
  "/api/v3/admin/orders/{order_id}/payments/{id}":
    get:
      summary: Show a payment
      tags:
      - Payments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns details of a specific payment.

        **Required scope:** `read_payments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const payment = await client.orders.payments.get('or_UkLWZg9DAJ', 'pay_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{order_id}/payments/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Payment ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., payment_method,
          source). Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., amount,status,number,response_code).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: payment found
          content:
            application/json:
              example:
                id: py_UkLWZg9DAJ
                payment_method_id: pm_UkLWZg9DAJ
                response_code: BGS-85157feeb11f
                number: PC6I3WMW
                amount: '110.0'
                display_amount: "$110.00"
                status: completed
                source_type: credit_card
                source_id: card_UkLWZg9DAJ
                source:
                  id: card_UkLWZg9DAJ
                  brand: visa
                  last4: '1111'
                  month: 12
                  year: 2027
                  name: Spree Commerce
                  default: false
                  gateway_payment_profile_id:
                  customer_id:
                  payment_method_id: pm_gbHJdmfrXB
                  metadata: {}
                  created_at: '2026-07-27T20:01:01.859Z'
                  updated_at: '2026-07-27T20:01:01.861Z'
                metadata: {}
                avs_response:
                cvv_response_code:
                cvv_response_message:
                created_at: '2026-07-27T20:01:01.860Z'
                updated_at: '2026-07-27T20:01:01.860Z'
                captured_amount: '0.0'
                order_id: or_UkLWZg9DAJ
  "/api/v3/admin/orders/{order_id}/payments/{id}/capture":
    patch:
      summary: Capture a payment
      tags:
      - Payments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Captures a pending payment.

        **Required scope:** `write_payments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const payment = await client.orders.payments.capture('or_UkLWZg9DAJ', 'pay_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/payments/{id}/capture -d '{ ...
          }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Payment ID
        schema:
          type: string
      responses:
        '200':
          description: payment captured
          content:
            application/json:
              example:
                id: py_UkLWZg9DAJ
                payment_method_id: pm_UkLWZg9DAJ
                response_code: BGS-10226f85112e
                number: P7TD8HCH
                amount: '110.0'
                display_amount: "$110.00"
                status: completed
                source_type: credit_card
                source_id: card_UkLWZg9DAJ
                source:
                  id: card_UkLWZg9DAJ
                  brand: visa
                  last4: '1111'
                  month: 12
                  year: 2027
                  name: Spree Commerce
                  default: false
                  gateway_payment_profile_id:
                  customer_id:
                  payment_method_id: pm_gbHJdmfrXB
                  metadata: {}
                  created_at: '2026-07-27T20:01:02.504Z'
                  updated_at: '2026-07-27T20:01:02.506Z'
                metadata: {}
                avs_response:
                cvv_response_code:
                cvv_response_message:
                created_at: '2026-07-27T20:01:02.505Z'
                updated_at: '2026-07-27T20:01:02.848Z'
                captured_amount: '110.0'
                order_id: or_UkLWZg9DAJ
        '422':
          description: capture failed
          content:
            application/json:
              example:
                error:
                  code: processing_error
                  message: 'Bogus Gateway: Forced failure'
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/admin/orders/{order_id}/payments/{id}/void":
    patch:
      summary: Void a payment
      tags:
      - Payments
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Voids a payment.

        **Required scope:** `write_payments` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const payment = await client.orders.payments.void('or_UkLWZg9DAJ', 'pay_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api patch /orders/{order_id}/payments/{id}/void -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Payment ID
        schema:
          type: string
      responses:
        '200':
          description: payment voided
          content:
            application/json:
              example:
                id: py_UkLWZg9DAJ
                payment_method_id: pm_UkLWZg9DAJ
                response_code: void-BGS-409f55320e90
                number: P5MSP7K5
                amount: '110.0'
                display_amount: "$110.00"
                status: void
                source_type: credit_card
                source_id: card_UkLWZg9DAJ
                source:
                  id: card_UkLWZg9DAJ
                  brand: visa
                  last4: '1111'
                  month: 12
                  year: 2027
                  name: Spree Commerce
                  default: false
                  gateway_payment_profile_id:
                  customer_id:
                  payment_method_id: pm_gbHJdmfrXB
                  metadata: {}
                  created_at: '2026-07-27T20:01:03.896Z'
                  updated_at: '2026-07-27T20:01:03.898Z'
                metadata: {}
                avs_response:
                cvv_response_code:
                cvv_response_message:
                created_at: '2026-07-27T20:01:03.897Z'
                updated_at: '2026-07-27T20:01:04.207Z'
                captured_amount: '0.0'
                order_id: or_UkLWZg9DAJ
  "/api/v3/admin/price_lists":
    get:
      summary: List price lists
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the price lists configured for the current store.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: priceLists } = await client.priceLists.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /price_lists
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        schema:
          type: string
      - name: q[status_eq]
        in: query
        required: false
        schema:
          type: string
      - name: sort
        in: query
        required: false
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: 'Comma-separated associations to embed. Supported: `price_rules`.'
        schema:
          type: string
      responses:
        '200':
          description: price lists found
          content:
            application/json:
              example:
                data:
                - id: pl_UkLWZg9DAJ
                  name: Wholesale
                  description:
                  status: draft
                  position: 1
                  match_policy: all
                  starts_at:
                  ends_at:
                  deleted_at:
                  created_at: '2026-07-27T20:01:17.472Z'
                  updated_at: '2026-07-27T20:01:17.472Z'
                  currently_active: false
                  products_count: 0
                  prices_count: 0
                  product_ids: []
                - id: pl_gbHJdmfrXB
                  name: Holiday
                  description:
                  status: draft
                  position: 2
                  match_policy: all
                  starts_at:
                  ends_at:
                  deleted_at:
                  created_at: '2026-07-27T20:01:17.473Z'
                  updated_at: '2026-07-27T20:01:17.473Z'
                  currently_active: false
                  products_count: 0
                  prices_count: 0
                  product_ids: []
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/PriceList"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
    post:
      summary: Create a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new draft price list.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Server-to-server one-shot create. Ship the rules that gate the list
          // and the exact per-variant prices in a single request — variants in
          // `prices` implicitly become part of the list (upserted on the unique
          // key `(variant_id, currency, price_list_id)`), so there's no need to
          // pre-declare `product_ids` separately.
          const priceList = await client.priceLists.create({
            name: 'EU wholesale',
            description: 'Tiered pricing for verified B2B customers',
            match_policy: 'all',
            starts_at: '2026-06-01T00:00:00Z',
            ends_at: '2026-09-01T00:00:00Z',
            rules: [
              {
                type: 'customer_group_rule',
                preferences: { customer_group_ids: ['cg_aBc123'] },
              },
              {
                type: 'volume_rule',
                preferences: { min_quantity: 10 },
              },
            ],
            prices: [
              {
                variant_id: 'variant_xY9',
                currency: 'USD',
                amount: '19.99',
                compare_at_amount: '24.99',
              },
              {
                variant_id: 'variant_aB7',
                currency: 'USD',
                amount: '21.99',
              },
            ],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /price_lists -d '{"name":"EU wholesale","description":"Tiered
          pricing for verified B2B customers","match_policy":"all","starts_at":"2026-06-01T00:00:00Z","ends_at":"2026-09-01T00:00:00Z","rules":[{"type":"customer_group_rule","preferences":{"customer_group_ids":["cg_aBc123"]}},{"type":"volume_rule","preferences":{"min_quantity":10}}],"prices":[{"variant_id":"variant_xY9","currency":"USD","amount":"19.99","compare_at_amount":"24.99"},{"variant_id":"variant_aB7","currency":"USD","amount":"21.99"}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: price list created (server-to-server — rules + prices, no product_ids)
          content:
            application/json:
              example:
                id: pl_EfhxLZ9ck8
                name: EU wholesale
                description:
                status: draft
                position: 3
                match_policy: all
                starts_at:
                ends_at:
                deleted_at:
                created_at: '2026-07-27T20:01:18.433Z'
                updated_at: '2026-07-27T20:01:18.435Z'
                currently_active: false
                products_count: 1
                prices_count: 2
                product_ids:
                - prod_UkLWZg9DAJ
              schema:
                "$ref": "#/components/schemas/PriceList"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                  example: EU wholesale
                description:
                  type: string
                  nullable: true
                starts_at:
                  type: string
                  nullable: true
                  example: '2026-06-01T00:00:00Z'
                ends_at:
                  type: string
                  nullable: true
                  example: '2026-09-01T00:00:00Z'
                match_policy:
                  type: string
                  enum:
                  - all
                  - any
                  example: all
                position:
                  type: integer
                  example: 1
                product_ids:
                  type: array
                  items:
                    type: string
                  description: Prefixed product ids to seed the list with.
                  example:
                  - prod_aBc123
                rules:
                  type: array
                  description: STI-typed price rules to attach on create. Existing
                    rules on the same payload via PATCH reconcile by id.
                  items:
                    type: object
                    required:
                    - type
                    properties:
                      type:
                        type: string
                        example: volume_rule
                      preferences:
                        type: object
                        additionalProperties: true
                prices:
                  type: array
                  description: 'Server-to-server alternative to `product_ids`: ship
                    the exact per-variant prices the list should contain. Each row
                    upserts on the unique key `(variant_id, currency, price_list_id)`.
                    Mix-and-match with `product_ids` is supported but typically unnecessary
                    — `prices` alone tells the server which variants belong to the
                    list and what the override amount is.'
                  items:
                    type: object
                    required:
                    - variant_id
                    - currency
                    properties:
                      variant_id:
                        type: string
                        example: variant_xY9
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        nullable: true
                        example: '19.99'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '24.99'
  "/api/v3/admin/price_lists/{id}":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: Get a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_products` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const priceList = await client.priceLists.get('pl_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /price_lists/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        schema:
          type: string
      responses:
        '200':
          description: price list found
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Wholesale
                description:
                status: draft
                position: 1
                match_policy: all
                starts_at:
                ends_at:
                deleted_at:
                created_at: '2026-07-27T20:01:18.735Z'
                updated_at: '2026-07-27T20:01:18.735Z'
                currently_active: false
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                "$ref": "#/components/schemas/PriceList"
        '404':
          description: price list not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Price list not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a price list. The optional `rules:` array reconciles nested
        STI-typed price rules in a single round-trip — existing rules update
        by `id`, new rules build, missing rules destroy. Mirrors the
        promotion editor's "save the whole thing on Save" pattern.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const priceList = await client.priceLists.update('pl_xxx', {
            name: 'Wholesale (Q3)',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /price_lists/{id} -d '{"name":"Wholesale (Q3)"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price list updated with nested rules
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Wholesale (Q3)
                description:
                status: draft
                position: 1
                match_policy: all
                starts_at:
                ends_at:
                deleted_at:
                created_at: '2026-07-27T20:01:20.309Z'
                updated_at: '2026-07-27T20:01:20.586Z'
                currently_active: false
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                "$ref": "#/components/schemas/PriceList"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                  nullable: true
                starts_at:
                  type: string
                  nullable: true
                ends_at:
                  type: string
                  nullable: true
                match_policy:
                  type: string
                  enum:
                  - all
                  - any
                position:
                  type: integer
                product_ids:
                  type: array
                  items:
                    type: string
                  description: Prefixed product ids — reconciles list membership (adds
                    + removes).
                  example:
                  - prod_aBc123
                rules:
                  type: array
                  items:
                    type: object
                    required:
                    - type
                    properties:
                      id:
                        type: string
                        nullable: true
                      type:
                        type: string
                        example: volume_rule
                      preferences:
                        type: object
                        additionalProperties: true
                prices:
                  type: array
                  description: Individual price overrides (the spreadsheet payload).
                    Each row updates by `id` if shipped, otherwise upserts on the
                    unique key `(variant_id, currency, price_list_id)`.
                  items:
                    type: object
                    oneOf:
                    - required:
                      - id
                    - required:
                      - variant_id
                      - currency
                    properties:
                      id:
                        type: string
                        example: price_aBc123
                      variant_id:
                        type: string
                        example: variant_xY9
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        nullable: true
                        example: '12.50'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '15.00'
    delete:
      summary: Delete a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes the price list. Associated prices are removed asynchronously.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.priceLists.delete('pl_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /price_lists/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: price list deleted
  "/api/v3/admin/price_lists/{id}/activate":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    patch:
      summary: Activate a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Transitions a draft / inactive list to `active`. If `starts_at` is
        in the future the list is marked `scheduled` instead, matching the
        legacy admin behaviour.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const priceList = await client.priceLists.activate('pl_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api patch /price_lists/{id}/activate -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price list activated
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Wholesale
                description:
                status: active
                position: 1
                match_policy: all
                starts_at:
                ends_at:
                deleted_at:
                created_at: '2026-07-27T20:01:20.896Z'
                updated_at: '2026-07-27T20:01:21.182Z'
                currently_active: true
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                "$ref": "#/components/schemas/PriceList"
  "/api/v3/admin/price_lists/{id}/deactivate":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    patch:
      summary: Deactivate a price list
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_products` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const priceList = await client.priceLists.deactivate('pl_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api patch /price_lists/{id}/deactivate -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price list deactivated
          content:
            application/json:
              example:
                id: pl_UkLWZg9DAJ
                name: Price List 1
                description:
                status: inactive
                position: 1
                match_policy: all
                starts_at:
                ends_at:
                deleted_at:
                created_at: '2026-07-27T20:01:21.193Z'
                updated_at: '2026-07-27T20:01:21.480Z'
                currently_active: false
                products_count: 0
                prices_count: 0
                product_ids: []
              schema:
                "$ref": "#/components/schemas/PriceList"
  "/api/v3/admin/prices":
    get:
      summary: List prices
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Generic prices endpoint covering both base prices and price-list
        overrides. Filter with Ransack: `q[price_list_id_eq]=…`,
        `q[currency_eq]=USD`, `q[price_list_id_null]=true` (base prices only).

        The admin spreadsheet uses this with server-side pagination so it
        scales past the metadata-PATCH path on `/price_lists/:id`.


        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: prices } = await client.prices.list({
            price_list_id_eq: 'pl_xxx',
            currency_eq: 'USD',
            expand: ['variant'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /prices -d '{"price_list_id_eq":"pl_xxx","currency_eq":"USD","expand":["variant"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: page
        in: query
        required: false
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        schema:
          type: integer
      - name: q[price_list_id_eq]
        in: query
        required: false
        schema:
          type: string
      - name: q[price_list_id_null]
        in: query
        required: false
        schema:
          type: boolean
      - name: q[currency_eq]
        in: query
        required: false
        schema:
          type: string
      - name: q[variant_id_eq]
        in: query
        required: false
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Comma-separated sort keys. Supports e.g. `variant_product_name,variant_id`.
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: 'Comma-separated associations to embed. Supported: `variant`.'
        schema:
          type: string
      responses:
        '200':
          description: prices found
          content:
            application/json:
              example:
                data:
                - id: price_gbHJdmfrXB
                  amount: '19.99'
                  amount_in_cents: 1999
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$19.99"
                  display_compare_at_amount:
                  price_list_id:
                  variant_id: variant_gbHJdmfrXB
                  created_at: '2026-07-27T20:01:21.537Z'
                  updated_at: '2026-07-27T20:01:21.537Z'
                - id: price_EfhxLZ9ck8
                  amount: '5.0'
                  amount_in_cents: 500
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$5.00"
                  display_compare_at_amount:
                  price_list_id: pl_UkLWZg9DAJ
                  variant_id: variant_gbHJdmfrXB
                  created_at: '2026-07-27T20:01:21.541Z'
                  updated_at: '2026-07-27T20:01:21.541Z'
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Price"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
    post:
      summary: Create a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a single price. Omit `price_list_id` to create a base price.
        For more than a handful of rows, prefer `POST /admin/prices/bulk_upsert`.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const price = await client.prices.create({
            variant_id: 'variant_xxx',
            currency: 'USD',
            amount: '19.99',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /prices -d '{"variant_id":"variant_xxx","currency":"USD","amount":"19.99"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: price created
          content:
            application/json:
              example:
                id: price_uw2YK1rnl0
                amount: '9.99'
                amount_in_cents: 999
                compare_at_amount:
                compare_at_amount_in_cents:
                currency: EUR
                display_amount: "€9.99"
                display_compare_at_amount:
                price_list_id:
                variant_id: variant_EfhxLZ9ck8
                created_at: '2026-07-27T20:01:22.180Z'
                updated_at: '2026-07-27T20:01:22.180Z'
              schema:
                "$ref": "#/components/schemas/Price"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - variant_id
              - currency
              properties:
                variant_id:
                  type: string
                  example: variant_xY9
                currency:
                  type: string
                  example: USD
                amount:
                  type: string
                  nullable: true
                  example: '19.99'
                compare_at_amount:
                  type: string
                  nullable: true
                  example: '24.99'
                price_list_id:
                  type: string
                  nullable: true
                  example: pl_aBc123
  "/api/v3/admin/prices/{id}":
    parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: Get a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_products` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const price = await client.prices.get('price_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /prices/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price found
          content:
            application/json:
              example:
                id: price_EfhxLZ9ck8
                amount: '5.0'
                amount_in_cents: 500
                compare_at_amount:
                compare_at_amount_in_cents:
                currency: USD
                display_amount: "$5.00"
                display_compare_at_amount:
                price_list_id: pl_UkLWZg9DAJ
                variant_id: variant_gbHJdmfrXB
                created_at: '2026-07-27T20:01:22.236Z'
                updated_at: '2026-07-27T20:01:22.236Z'
              schema:
                "$ref": "#/components/schemas/Price"
        '404':
          description: price not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Price not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_products` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const price = await client.prices.update('price_xxx', {
            amount: '12.34',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /prices/{id} -d '{"amount":"12.34"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: price updated
          content:
            application/json:
              example:
                id: price_EfhxLZ9ck8
                amount: '12.34'
                amount_in_cents: 1234
                compare_at_amount:
                compare_at_amount_in_cents:
                currency: USD
                display_amount: "$12.34"
                display_compare_at_amount:
                price_list_id: pl_UkLWZg9DAJ
                variant_id: variant_gbHJdmfrXB
                created_at: '2026-07-27T20:01:22.922Z'
                updated_at: '2026-07-27T20:01:23.200Z'
              schema:
                "$ref": "#/components/schemas/Price"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  type: string
                  nullable: true
                compare_at_amount:
                  type: string
                  nullable: true
    delete:
      summary: Delete a price
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes the price (acts_as_paranoid).

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.prices.delete('price_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /prices/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: price deleted
  "/api/v3/admin/prices/bulk_upsert":
    post:
      summary: Bulk-upsert prices
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Upserts a batch of prices in a single SQL round trip.

        Each row either:
        * targets an existing price by `id`, OR
        * matches on the unique key `(variant_id, currency, price_list_id)` —
          updating the existing row if one exists, creating one otherwise.

        Model callbacks (e.g. PriceHistory) are bypassed; this is a
        bulk-write fast path for the admin spreadsheet. The response
        carries `price_count` — the number of rows touched.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { price_count } = await client.prices.bulkUpsert({
            prices: [
              {
                variant_id: 'variant_xxx',
                currency: 'USD',
                price_list_id: 'pl_xxx',
                amount: '11.11',
              },
              {
                variant_id: 'variant_yyy',
                currency: 'USD',
                price_list_id: 'pl_xxx',
                amount: '22.22',
              },
            ],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /prices/bulk_upsert -d '{"prices":[{"variant_id":"variant_xxx","currency":"USD","price_list_id":"pl_xxx","amount":"11.11"},{"variant_id":"variant_yyy","currency":"USD","price_list_id":"pl_xxx","amount":"22.22"}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: prices upserted
          content:
            application/json:
              example:
                price_count: 2
              schema:
                type: object
                properties:
                  price_count:
                    type: integer
        '422':
          description: missing prices key
          content:
            application/json:
              example:
                error:
                  code: missing_prices
                  message: prices is required (send an empty array to no-op).
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - prices
              properties:
                prices:
                  type: array
                  items:
                    type: object
                    required:
                    - variant_id
                    - currency
                    properties:
                      id:
                        type: string
                        nullable: true
                        example: price_aBc123
                      variant_id:
                        type: string
                        example: variant_xY9
                      currency:
                        type: string
                        example: USD
                      price_list_id:
                        type: string
                        nullable: true
                        example: pl_aBc123
                      amount:
                        type: string
                        nullable: true
                        example: '19.99'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '24.99'
  "/api/v3/admin/prices/bulk_destroy":
    delete:
      summary: Bulk-delete prices
      tags:
      - Pricing
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes each price in `ids`. Returns the count actually destroyed.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { price_count } = await client.prices.bulkDestroy({
            ids: ['price_xxx', 'price_yyy'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api delete /prices/bulk_destroy -d '{"ids":["price_xxx","price_yyy"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: prices deleted
          content:
            application/json:
              example:
                price_count: 1
              schema:
                type: object
                properties:
                  price_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/products/{product_id}/custom_fields":
    get:
      summary: List product custom fields
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the product's custom field values.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: customFields } = await client.products.customFields.list('prod_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /products/{product_id}/custom_fields
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., custom_field_definition).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., key,value,namespace).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: custom fields found
          content:
            application/json:
              example:
                data:
                - id: cf_UkLWZg9DAJ
                  label: Title
                  type: Spree::Metafields::ShortText
                  field_type: short_text
                  key: custom.title
                  value: wool
                  created_at: '2026-07-27T20:01:24.600Z'
                  updated_at: '2026-07-27T20:01:24.600Z'
                  storefront_visible: true
                  custom_field_definition_id: cfdef_UkLWZg9DAJ
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create a product custom field
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Sets a custom field value on the product. Requires an existing CustomFieldDefinition; pass its prefixed `cfdef_…` id.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const customField = await client.products.customFields.create('prod_UkLWZg9DAJ', {
            custom_field_definition_id: 'cfdef_AbC123XyZ',
            value: 'wool',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/{product_id}/custom_fields -d '{"custom_field_definition_id":"cfdef_AbC123XyZ","value":"wool"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        schema:
          type: string
      responses:
        '201':
          description: custom field created
          content:
            application/json:
              example:
                id: cf_gbHJdmfrXB
                label: Description
                type: Spree::Metafields::LongText
                field_type: long_text
                key: custom.description
                value: A longer description
                created_at: '2026-07-27T20:01:25.214Z'
                updated_at: '2026-07-27T20:01:25.214Z'
                storefront_visible: true
                custom_field_definition_id: cfdef_gbHJdmfrXB
        '422':
          description: duplicate definition for the same product
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Metafield definition has already been taken
                  details:
                    metafield_definition_id:
                    - has already been taken
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - custom_field_definition_id
              - value
              properties:
                custom_field_definition_id:
                  type: string
                  description: Prefixed `cfdef_…` id
                value:
                  description: Value matching the definition's `field_type`
  "/api/v3/admin/products/{product_id}/custom_fields/{id}":
    get:
      summary: Show a product custom field
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_products` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const customField = await client.products.customFields.get('prod_UkLWZg9DAJ', 'cf_AbC123XyZ')
      - lang: bash
        label: Spree CLI
        source: spree api get /products/{product_id}/custom_fields/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., custom_field_definition).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., key,value,namespace).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: custom field found
          content:
            application/json:
              example:
                id: cf_UkLWZg9DAJ
                label: Title
                type: Spree::Metafields::ShortText
                field_type: short_text
                key: custom.title
                value: wool
                created_at: '2026-07-27T20:01:25.564Z'
                updated_at: '2026-07-27T20:01:25.564Z'
                storefront_visible: true
                custom_field_definition_id: cfdef_UkLWZg9DAJ
    patch:
      summary: Update a product custom field
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates the custom field's `value`. The linked definition cannot be changed — delete and recreate to switch.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const customField = await client.products.customFields.update('prod_UkLWZg9DAJ', 'cf_AbC123XyZ', {
            value: 'cotton',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /products/{product_id}/custom_fields/{id} -d '{"value":"cotton"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: custom field updated
          content:
            application/json:
              example:
                id: cf_UkLWZg9DAJ
                label: Title
                type: Spree::Metafields::ShortText
                field_type: short_text
                key: custom.title
                value: cotton
                created_at: '2026-07-27T20:01:25.883Z'
                updated_at: '2026-07-27T20:01:26.160Z'
                storefront_visible: true
                custom_field_definition_id: cfdef_UkLWZg9DAJ
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - value
              properties:
                value:
                  description: New value
    delete:
      summary: Delete a product custom field
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_products` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.products.customFields.delete('prod_UkLWZg9DAJ', 'cf_AbC123XyZ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /products/{product_id}/custom_fields/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: custom field deleted
  "/api/v3/admin/products/{product_id}/translations":
    get:
      summary: List product translations
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the full translation matrix for the product: the source value and content type per translatable field, plus the translated value for every supported locale.

        **Required scope:** `read_products` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: translations found
          content:
            application/json:
              example:
                data:
                  resource_id: prod_UkLWZg9DAJ
                  resource_type: product
                  translations:
                    de:
                      name: Espressomaschine
                      description:
                      slug: espressomaschine
                      meta_description:
                      meta_title:
                      translated_field_count: 2
                    fr:
                      name:
                      description:
                      slug:
                      meta_description:
                      meta_title:
                      translated_field_count: 0
                  fields:
                  - key: name
                    type: string
                    source: Espresso Machine
                  - key: description
                    type: html
                    source: |-
                      Similique laudantium vel neque cumque ipsam molestias harum. Veniam distinctio ducimus possimus minus ad aperiam fuga. Vero reiciendis quaerat nemo aliquam iure minus. Reprehenderit facere esse sit odio.
                      Sunt consequatur soluta exercitationem fugit. Nihil dolorem nesciunt itaque nemo harum doloribus aperiam. Similique officiis vero nobis porro deserunt accusantium perferendis. Aliquam asperiores labore ad ipsam. Rerum officia neque nisi accusantium.
                      Asperiores iusto facere atque quos occaecati. Sapiente placeat non illo perspiciatis similique cum ad quas. Impedit soluta quas quasi harum quam commodi at. Dicta provident illo numquam minus. Eos temporibus vitae omnis tempore voluptatem autem quam dolores.
                      Ducimus cum distinctio error dolorum voluptate. Iste blanditiis possimus modi impedit ducimus tempore beatae. Mollitia velit voluptas voluptates temporibus est error corrupti alias.
                      Deserunt maiores nostrum accusamus velit. Eum mollitia repellat tenetur nihil iusto possimus nobis reprehenderit. Reprehenderit maiores totam dolorem deserunt pariatur repellat.
                  - key: slug
                    type: string
                    source: espresso-machine
                  - key: meta_description
                    type: string
                    source:
                  - key: meta_title
                    type: string
                    source:
                  default_locale: en
                  supported_locales:
                  - de
                  - en
                  - fr
  "/api/v3/admin/products":
    get:
      summary: List products
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a paginated list of products for the current store.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: products } = await client.products.list({
            name_cont: 'shirt',
            status_eq: 'active',
            sort: '-created_at',
            limit: 25,
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /products -d '{"name_cont":"shirt","status_eq":"active","sort":"-created_at","limit":25}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: sort
        in: query
        required: false
        description: Sort field (e.g., name, -name, price, -price, best_selling)
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., variants, media,
          option_types, categories). Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,slug,price,status).
          id is always included.
        schema:
          type: string
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name (contains)
        schema:
          type: string
      - name: q[status_eq]
        in: query
        required: false
        description: Filter by status
        schema:
          type: string
      responses:
        '200':
          description: products found
          content:
            application/json:
              example:
                data:
                - id: prod_UkLWZg9DAJ
                  name: Product 629418
                  slug: product-629418
                  meta_title:
                  meta_description:
                  meta_keywords:
                  variant_count: 0
                  available_on:
                  preorder_ships_at:
                  purchasable: true
                  preorder: false
                  in_stock: false
                  backorderable: true
                  available: true
                  description: Possimus consequuntur molestiae mollitia hic esse culpa
                    soluta. Non fugit vel labore in id at natus. Dolore voluptatem
                    pariatur cumque dolorem tempora. Beatae explicabo architecto optio
                    quam. Sit dolore cumque adipisci doloremque ex quisquam ea. Eum
                    beatae laboriosam magni at sit ex. Maxime esse dicta natus corporis
                    exercitationem. Libero repudiandae nesciunt officia placeat. Nihil
                    voluptatibus dolor consequuntur deleniti perferendis. Magni vero
                    provident natus blanditiis placeat. Aliquam molestiae cum ullam
                    deserunt consectetur debitis. Blanditiis consequuntur minima beatae
                    perferendis. Tenetur magni deserunt odit sequi expedita in quis
                    quos. Eligendi iusto repellendus quae ratione iure. Magni fugit
                    dolor quae tempora praesentium. Quia ex facere enim ipsum facilis
                    hic. Eos facilis sapiente consequatur veritatis pariatur ad officiis.
                    Odio consequuntur rerum aspernatur maxime. Quis consequatur totam
                    eveniet quidem officiis.
                  description_html: |-
                    Possimus consequuntur molestiae mollitia hic esse culpa soluta. Non fugit vel labore in id at natus. Dolore voluptatem pariatur cumque dolorem tempora. Beatae explicabo architecto optio quam. Sit dolore cumque adipisci doloremque ex quisquam ea.
                    Eum beatae laboriosam magni at sit ex. Maxime esse dicta natus corporis exercitationem. Libero repudiandae nesciunt officia placeat. Nihil voluptatibus dolor consequuntur deleniti perferendis.
                    Magni vero provident natus blanditiis placeat. Aliquam molestiae cum ullam deserunt consectetur debitis. Blanditiis consequuntur minima beatae perferendis.
                    Tenetur magni deserunt odit sequi expedita in quis quos. Eligendi iusto repellendus quae ratione iure. Magni fugit dolor quae tempora praesentium.
                    Quia ex facere enim ipsum facilis hic. Eos facilis sapiente consequatur veritatis pariatur ad officiis. Odio consequuntur rerum aspernatur maxime. Quis consequatur totam eveniet quidem officiis.
                  default_variant_id: variant_UkLWZg9DAJ
                  thumbnail_url:
                  tags: []
                  price:
                    id: price_UkLWZg9DAJ
                    amount: '19.99'
                    amount_in_cents: 1999
                    compare_at_amount:
                    compare_at_amount_in_cents:
                    currency: USD
                    display_amount: "$19.99"
                    display_compare_at_amount:
                    price_list_id:
                    variant_id: variant_UkLWZg9DAJ
                    created_at: '2026-07-27T20:01:26.819Z'
                    updated_at: '2026-07-27T20:01:26.819Z'
                  original_price:
                  status: active
                  metadata: {}
                  deleted_at:
                  created_at: '2026-07-27T20:01:26.811Z'
                  updated_at: '2026-07-27T20:01:26.825Z'
                  tax_category_id: taxcat_UkLWZg9DAJ
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Product"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create a product
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new product. Supports nested variants with prices and option types.

        Option types and values are auto-created if they don't exist.
        Prices are upserted by currency. Stock items are upserted by stock location.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const product = await client.products.create({
            name: 'Premium T-Shirt',
            description: 'Soft, organic cotton.',
            status: 'active',
            variants: [
              {
                sku: 'TSHIRT-S-NAVY',
                options: [
                  { name: 'size', value: 'Small' },
                  { name: 'color', value: 'navy' },
                ],
                prices: [
                  { currency: 'USD', amount: '29.99' },
                  { currency: 'EUR', amount: '27.99' },
                ],
                stock_items: [{ stock_location_id: 'sloc_UkLWZg9DAJ', count_on_hand: 50 }],
              },
              {
                sku: 'TSHIRT-M-NAVY',
                options: [
                  { name: 'size', value: 'Medium' },
                  { name: 'color', value: 'navy' },
                ],
                prices: [{ currency: 'USD', amount: '29.99' }],
                stock_items: [{ stock_location_id: 'sloc_UkLWZg9DAJ', count_on_hand: 30 }],
              },
            ],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products -d '{"name":"Premium T-Shirt","description":"Soft,
          organic cotton.","status":"active","variants":[{"sku":"TSHIRT-S-NAVY","options":[{"name":"size","value":"Small"},{"name":"color","value":"navy"}],"prices":[{"currency":"USD","amount":"29.99"},{"currency":"EUR","amount":"27.99"}],"stock_items":[{"stock_location_id":"sloc_UkLWZg9DAJ","count_on_hand":50}]},{"sku":"TSHIRT-M-NAVY","options":[{"name":"size","value":"Medium"},{"name":"color","value":"navy"}],"prices":[{"currency":"USD","amount":"29.99"}],"stock_items":[{"stock_location_id":"sloc_UkLWZg9DAJ","count_on_hand":30}]}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: product created
          content:
            application/json:
              example:
                id: prod_gbHJdmfrXB
                name: New Product
                slug: new-product
                meta_title:
                meta_description:
                meta_keywords:
                variant_count: 0
                available_on:
                preorder_ships_at:
                purchasable: false
                preorder: false
                in_stock: false
                backorderable: false
                available: false
                description:
                description_html:
                default_variant_id: variant_gbHJdmfrXB
                thumbnail_url:
                tags: []
                price:
                original_price:
                status: draft
                metadata: {}
                deleted_at:
                created_at: '2026-07-27T20:01:27.491Z'
                updated_at: '2026-07-27T20:01:27.492Z'
                tax_category_id:
              schema:
                "$ref": "#/components/schemas/Product"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Premium T-Shirt
                description:
                  type: string
                slug:
                  type: string
                status:
                  type: string
                  enum:
                  - draft
                  - active
                  - archived
                tax_category_id:
                  type: string
                  description: Tax category ID
                category_ids:
                  type: array
                  items:
                    type: string
                  description: Array of category IDs
                tags:
                  type: array
                  items:
                    type: string
                  example:
                  - eco
                  - sale
                prices:
                  type: array
                  description: 'Shorthand for a simple (no-options) product: per-currency
                    prices that forward to the product''s sole variant. For products
                    with options, set prices per variant under `variants:` instead.'
                  items:
                    type: object
                    required:
                    - currency
                    - amount
                    properties:
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        example: '29.99'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '39.99'
                variants:
                  type: array
                  description: Array of variant payloads. Variants can declare multiple
                    option pairs via `options:` and per-currency prices via `prices:`.
                    Stock counts go in `stock_items:` (per stock location).
                  items:
                    type: object
                    properties:
                      sku:
                        type: string
                      options:
                        type: array
                        description: One pair per option type the variant participates
                          in (e.g. size + color). Option types and values are auto-created
                          if missing.
                        items:
                          type: object
                          required:
                          - name
                          - value
                          properties:
                            name:
                              type: string
                              example: size
                            value:
                              type: string
                              example: Small
                      prices:
                        type: array
                        description: Per-currency prices. Upserted by currency.
                        items:
                          type: object
                          required:
                          - currency
                          - amount
                          properties:
                            currency:
                              type: string
                              example: USD
                            amount:
                              type: string
                              example: '29.99'
                            compare_at_amount:
                              type: string
                              nullable: true
                              example: '39.99'
                      stock_items:
                        type: array
                        description: Per-stock-location inventory. Upserted by stock_location_id.
                        items:
                          type: object
                          required:
                          - stock_location_id
                          - count_on_hand
                          properties:
                            stock_location_id:
                              type: string
                              description: Stock location ID (e.g. sloc_xxx)
                            count_on_hand:
                              type: integer
                              example: 50
                            backorderable:
                              type: boolean
              required:
              - name
  "/api/v3/admin/products/{id}":
    get:
      summary: Get a product
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single product by ID.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const product = await client.products.get('prod_86Rf07xd4z', {
            expand: ['variants', 'option_types'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /products/{id} -d '{"expand":["variants","option_types"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Product ID (e.g., prod_xxx)
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., variants, media,
          option_types, categories). Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., name,slug,price,status).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: product found
          content:
            application/json:
              example:
                id: prod_UkLWZg9DAJ
                name: Product 663452
                slug: product-663452
                meta_title:
                meta_description:
                meta_keywords:
                variant_count: 0
                available_on:
                preorder_ships_at:
                purchasable: true
                preorder: false
                in_stock: false
                backorderable: true
                available: true
                description: Atque ipsa modi velit similique est cum nostrum. Fugit
                  expedita in laboriosam nemo id quasi itaque cupiditate. A reiciendis
                  impedit unde quisquam omnis explicabo exercitationem modi. Adipisci
                  atque consequatur quas quae eaque. Est et cupiditate nihil dolor
                  alias porro aut. Blanditiis nulla minima saepe iste. Ad natus neque
                  eligendi itaque quae. Iure dignissimos perspiciatis voluptatem incidunt
                  neque.
                description_html: |-
                  Atque ipsa modi velit similique est cum nostrum. Fugit expedita in laboriosam nemo id quasi itaque cupiditate. A reiciendis impedit unde quisquam omnis explicabo exercitationem modi. Adipisci atque consequatur quas quae eaque. Est et cupiditate nihil dolor alias porro aut.
                  Blanditiis nulla minima saepe iste. Ad natus neque eligendi itaque quae. Iure dignissimos perspiciatis voluptatem incidunt neque.
                default_variant_id: variant_UkLWZg9DAJ
                thumbnail_url:
                tags: []
                price:
                  id: price_UkLWZg9DAJ
                  amount: '19.99'
                  amount_in_cents: 1999
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$19.99"
                  display_compare_at_amount:
                  price_list_id:
                  variant_id: variant_UkLWZg9DAJ
                  created_at: '2026-07-27T20:01:27.863Z'
                  updated_at: '2026-07-27T20:01:27.863Z'
                original_price:
                status: active
                metadata: {}
                deleted_at:
                created_at: '2026-07-27T20:01:27.855Z'
                updated_at: '2026-07-27T20:01:27.869Z'
                tax_category_id: taxcat_UkLWZg9DAJ
              schema:
                "$ref": "#/components/schemas/Product"
        '404':
          description: product not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Product not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a product
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a product. Only provided fields are updated.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const product = await client.products.update('prod_86Rf07xd4z', {
            name: 'Updated Name',
            status: 'active',
            tags: ['eco', 'sale'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /products/{id} -d '{"name":"Updated Name","status":"active","tags":["eco","sale"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      responses:
        '200':
          description: product updated
          content:
            application/json:
              example:
                id: prod_UkLWZg9DAJ
                name: Updated Name
                slug: product-683541
                meta_title:
                meta_description:
                meta_keywords:
                variant_count: 0
                available_on:
                preorder_ships_at:
                purchasable: true
                preorder: false
                in_stock: false
                backorderable: true
                available: true
                description: Adipisci ratione accusamus vitae consequatur sint accusantium
                  quod at. Enim cumque earum quibusdam saepe itaque. Natus similique
                  illo numquam maxime mollitia magnam dolor dolorem. Illum minus adipisci
                  facere magni minima. Debitis sint quaerat reprehenderit fugiat perspiciatis
                  magni. Officia nisi sint magni cumque quam illum. Consectetur velit
                  recusandae pariatur consequatur officiis neque. Similique cumque
                  non officiis maiores. Illum minus molestias alias nemo ad sapiente
                  neque. At pariatur assumenda nihil voluptates saepe accusantium
                  dolorum. Dignissimos officiis iste inventore a repellendus accusamus.
                  Dolor itaque et nesciunt optio tenetur laborum.
                description_html: |-
                  Adipisci ratione accusamus vitae consequatur sint accusantium quod at. Enim cumque earum quibusdam saepe itaque. Natus similique illo numquam maxime mollitia magnam dolor dolorem. Illum minus adipisci facere magni minima. Debitis sint quaerat reprehenderit fugiat perspiciatis magni.
                  Officia nisi sint magni cumque quam illum. Consectetur velit recusandae pariatur consequatur officiis neque. Similique cumque non officiis maiores.
                  Illum minus molestias alias nemo ad sapiente neque. At pariatur assumenda nihil voluptates saepe accusantium dolorum. Dignissimos officiis iste inventore a repellendus accusamus. Dolor itaque et nesciunt optio tenetur laborum.
                default_variant_id: variant_UkLWZg9DAJ
                thumbnail_url:
                tags: []
                price:
                  id: price_UkLWZg9DAJ
                  amount: '19.99'
                  amount_in_cents: 1999
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$19.99"
                  display_compare_at_amount:
                  price_list_id:
                  variant_id: variant_UkLWZg9DAJ
                  created_at: '2026-07-27T20:01:28.495Z'
                  updated_at: '2026-07-27T20:01:28.495Z'
                original_price:
                status: active
                metadata: {}
                deleted_at:
                created_at: '2026-07-27T20:01:28.485Z'
                updated_at: '2026-07-27T20:01:28.786Z'
                tax_category_id: taxcat_UkLWZg9DAJ
              schema:
                "$ref": "#/components/schemas/Product"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Premium T-Shirt
                description:
                  type: string
                slug:
                  type: string
                status:
                  type: string
                  enum:
                  - draft
                  - active
                  - archived
                tax_category_id:
                  type: string
                  description: Tax category ID
                category_ids:
                  type: array
                  items:
                    type: string
                  description: Array of category IDs
                tags:
                  type: array
                  items:
                    type: string
                  example:
                  - eco
                  - sale
                prices:
                  type: array
                  description: 'Shorthand for a simple (no-options) product: per-currency
                    prices that forward to the product''s sole variant. For products
                    with options, set prices per variant under `variants:` instead.'
                  items:
                    type: object
                    required:
                    - currency
                    - amount
                    properties:
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        example: '29.99'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '39.99'
                variants:
                  type: array
                  description: Array of variant payloads. Variants can declare multiple
                    option pairs via `options:` and per-currency prices via `prices:`.
                    Stock counts go in `stock_items:` (per stock location).
                  items:
                    type: object
                    properties:
                      sku:
                        type: string
                      options:
                        type: array
                        description: One pair per option type the variant participates
                          in (e.g. size + color). Option types and values are auto-created
                          if missing.
                        items:
                          type: object
                          required:
                          - name
                          - value
                          properties:
                            name:
                              type: string
                              example: size
                            value:
                              type: string
                              example: Small
                      prices:
                        type: array
                        description: Per-currency prices. Upserted by currency.
                        items:
                          type: object
                          required:
                          - currency
                          - amount
                          properties:
                            currency:
                              type: string
                              example: USD
                            amount:
                              type: string
                              example: '29.99'
                            compare_at_amount:
                              type: string
                              nullable: true
                              example: '39.99'
                      stock_items:
                        type: array
                        description: Per-stock-location inventory. Upserted by stock_location_id.
                        items:
                          type: object
                          required:
                          - stock_location_id
                          - count_on_hand
                          properties:
                            stock_location_id:
                              type: string
                              description: Stock location ID (e.g. sloc_xxx)
                            count_on_hand:
                              type: integer
                              example: 50
                            backorderable:
                              type: boolean
    delete:
      summary: Delete a product
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes a product.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.products.delete('prod_86Rf07xd4z')
      - lang: bash
        label: Spree CLI
        source: spree api delete /products/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      responses:
        '204':
          description: product deleted
  "/api/v3/admin/products/bulk_status_update":
    post:
      summary: Bulk-update product status
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Sets `status` on each product in `ids`. Reindexes the affected products
        for search. Cross-store IDs are silently dropped. Returns counts.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkStatusUpdate({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
            status: 'archived',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/bulk_status_update -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"],"status":"archived"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: cross-store products silently dropped
          content:
            application/json:
              example:
                product_count: 0
                status: archived
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
                  status:
                    type: string
        '422':
          description: invalid status
          content:
            application/json:
              example:
                error:
                  code: invalid_status
                  message: Invalid status
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - status
              properties:
                ids:
                  type: array
                  items:
                    type: string
                  example:
                  - prod_UkLWZg9DAJ
                status:
                  type: string
                  enum:
                  - draft
                  - active
                  - archived
                  example: archived
  "/api/v3/admin/products/bulk_add_to_categories":
    post:
      summary: Bulk-add products to categories
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Attaches each product in `ids` to every category (taxon) in `category_ids`.
        Categories from sibling stores are silently ignored.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkAddToCategories({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
            category_ids: ['cat_AbC123XyZ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/bulk_add_to_categories -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"],"category_ids":["cat_AbC123XyZ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: products added to categories
          content:
            application/json:
              example:
                product_count: 1
                category_count: 1
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
                  category_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - category_ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
                category_ids:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/products/bulk_remove_from_categories":
    post:
      summary: Bulk-remove products from categories
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Detaches each product in `ids` from every category in `category_ids`.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkRemoveFromCategories({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
            category_ids: ['cat_AbC123XyZ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/bulk_remove_from_categories -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"],"category_ids":["cat_AbC123XyZ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: products removed from categories
          content:
            application/json:
              example:
                product_count: 1
                category_count: 1
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - category_ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
                category_ids:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/products/bulk_add_to_channels":
    post:
      summary: Bulk-add products to channels
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Publishes each product in `ids` on every channel in `channel_ids`. Idempotent —
        re-publishing on an existing channel is a no-op. Channels from sibling stores
        are silently ignored.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkAddToChannels({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
            channel_ids: ['channel_AbC123XyZ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/bulk_add_to_channels -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"],"channel_ids":["channel_AbC123XyZ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: products published on channels
          content:
            application/json:
              example:
                product_count: 1
                channel_count: 1
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
                  channel_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - channel_ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
                channel_ids:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/products/bulk_remove_from_channels":
    post:
      summary: Bulk-remove products from channels
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Unpublishes each product in `ids` from every channel in `channel_ids`.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkRemoveFromChannels({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
            channel_ids: ['channel_AbC123XyZ'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/bulk_remove_from_channels -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"],"channel_ids":["channel_AbC123XyZ"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: products unpublished from channels
          content:
            application/json:
              example:
                product_count: 1
                channel_count: 1
                removed: 1
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
                  channel_count:
                    type: integer
                  removed:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - channel_ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
                channel_ids:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/products/bulk_add_tags":
    post:
      summary: Bulk-add tags to products
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds each tag name in `tags` to every product in `ids`. Tags are upserted by name.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkAddTags({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
            tags: ['summer', 'sale'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/bulk_add_tags -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"],"tags":["summer","sale"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: tags added
          content:
            application/json:
              example:
                product_count: 1
                tag_count: 2
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
                  tag_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - tags
              properties:
                ids:
                  type: array
                  items:
                    type: string
                tags:
                  type: array
                  items:
                    type: string
                  example:
                  - summer
                  - sale
  "/api/v3/admin/products/bulk_remove_tags":
    post:
      summary: Bulk-remove tags from products
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes each tag in `tags` from every product in `ids`.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkRemoveTags({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
            tags: ['summer'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/bulk_remove_tags -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"],"tags":["summer"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: tags removed
          content:
            application/json:
              example:
                product_count: 1
                tag_count: 1
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              - tags
              properties:
                ids:
                  type: array
                  items:
                    type: string
                tags:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/products/bulk_destroy":
    delete:
      summary: Bulk-delete products
      tags:
      - Products
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes each product in `ids`. Returns the count actually destroyed.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const result = await client.products.bulkDestroy({
            ids: ['prod_UkLWZg9DAJ', 'prod_9XbR2kQwLm'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api delete /products/bulk_destroy -d '{"ids":["prod_UkLWZg9DAJ","prod_9XbR2kQwLm"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: products deleted
          content:
            application/json:
              example:
                product_count: 1
              schema:
                type: object
                properties:
                  product_count:
                    type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
  "/api/v3/admin/promotions/{promotion_id}/coupon_codes":
    parameters:
    - name: promotion_id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: List coupon codes for a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the auto-generated coupon codes for a multi-code promotion. Single-code promotions store the code on the promotion itself; this endpoint returns an empty list for them.

        **Required scope:** `read_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: coupons } = await client.promotions.couponCodes.list('promo_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /promotions/{promotion_id}/coupon_codes
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: coupon codes found
          content:
            application/json:
              example:
                data:
                - id: coupon_UkLWZg9DAJ
                  code: AAA111
                  state: unused
                  created_at: '2026-07-27T20:00:12.052Z'
                  updated_at: '2026-07-27T20:00:12.052Z'
                  promotion_id: promo_UkLWZg9DAJ
                  order_id:
                - id: coupon_gbHJdmfrXB
                  code: BBB222
                  state: unused
                  created_at: '2026-07-27T20:00:12.053Z'
                  updated_at: '2026-07-27T20:00:12.053Z'
                  promotion_id: promo_UkLWZg9DAJ
                  order_id:
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
  "/api/v3/admin/promotions/{promotion_id}/promotion_actions":
    parameters:
    - name: promotion_id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: List actions for a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_promotions` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: actions } = await client.promotions.actions.list('promo_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /promotions/{promotion_id}/promotion_actions
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: actions found
          content:
            application/json:
              example:
                data:
                - id: pact_UkLWZg9DAJ
                  created_at: '2026-07-27T20:01:32.814Z'
                  updated_at: '2026-07-27T20:01:32.814Z'
                  type: free_shipping
                  promotion_id: promo_UkLWZg9DAJ
                  preferences: {}
                  preference_schema: []
                  label: Free shipping
                  calculator:
                  line_items:
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create an action on a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds a new action to a promotion. The `type` is the wire shorthand from `GET /promotion_actions/types` (e.g. `free_shipping`, `create_item_adjustments`). Fully-qualified Ruby class names are also accepted for backward compatibility.

        **Required scope:** `write_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const action = await client.promotions.actions.create('promo_UkLWZg9DAJ', {
            type: 'free_shipping',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /promotions/{promotion_id}/promotion_actions -d '{"type":"free_shipping"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: action created
          content:
            application/json:
              example:
                id: pact_UkLWZg9DAJ
                created_at: '2026-07-27T20:01:33.424Z'
                updated_at: '2026-07-27T20:01:33.424Z'
                type: free_shipping
                promotion_id: promo_UkLWZg9DAJ
                preferences: {}
                preference_schema: []
                label: Free shipping
                calculator:
                line_items:
        '422':
          description: unknown action type
          content:
            application/json:
              example:
                error:
                  code: unknown_promotion_action_type
                  message: Unknown type
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  example: free_shipping
                preferences:
                  type: object
                  additionalProperties: true
              required:
              - type
  "/api/v3/admin/promotions/{promotion_id}/promotion_actions/{id}":
    parameters:
    - name: promotion_id
      in: path
      required: true
      schema:
        type: string
    - name: id
      in: path
      required: true
      schema:
        type: string
    delete:
      summary: Delete an action from a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_promotions` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.promotions.actions.delete('promo_UkLWZg9DAJ', 'promoact_k5nR8xLq')
      - lang: bash
        label: Spree CLI
        source: spree api delete /promotions/{promotion_id}/promotion_actions/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: action deleted
  "/api/v3/admin/promotions/{promotion_id}/promotion_rules":
    parameters:
    - name: promotion_id
      in: path
      required: true
      schema:
        type: string
    get:
      summary: List rules for a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_promotions` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: rules } = await client.promotions.rules.list('promo_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /promotions/{promotion_id}/promotion_rules
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: rules found
          content:
            application/json:
              example:
                data:
                - id: prorule_UkLWZg9DAJ
                  created_at: '2026-07-27T20:01:34.013Z'
                  updated_at: '2026-07-27T20:01:34.013Z'
                  type: currency
                  promotion_id: promo_UkLWZg9DAJ
                  preferences:
                    currency: USD
                  preference_schema:
                  - key: currency
                    type: string
                    default:
                  label: Currency
                  product_ids:
                  category_ids:
                  customer_ids:
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create a rule on a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Adds a new rule to a promotion. The `type` is the wire shorthand from `GET /promotion_rules/types` (e.g. `currency`, `item_total`, `product`). Fully-qualified Ruby class names are also accepted for backward compatibility.

        **Required scope:** `write_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const rule = await client.promotions.rules.create('promo_UkLWZg9DAJ', {
            type: 'currency',
            preferences: { currency: 'EUR' },
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /promotions/{promotion_id}/promotion_rules -d '{"type":"currency","preferences":{"currency":"EUR"}}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: rule created with preferences
          content:
            application/json:
              example:
                id: prorule_UkLWZg9DAJ
                created_at: '2026-07-27T20:01:34.570Z'
                updated_at: '2026-07-27T20:01:34.570Z'
                type: currency
                promotion_id: promo_UkLWZg9DAJ
                preferences:
                  currency: EUR
                preference_schema:
                - key: currency
                  type: string
                  default:
                label: Currency
                product_ids:
                category_ids:
                customer_ids:
        '422':
          description: unknown rule type
          content:
            application/json:
              example:
                error:
                  code: unknown_promotion_rule_type
                  message: Unknown type
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  example: currency
                preferences:
                  type: object
                  additionalProperties: true
              required:
              - type
  "/api/v3/admin/promotions/{promotion_id}/promotion_rules/{id}":
    parameters:
    - name: promotion_id
      in: path
      required: true
      schema:
        type: string
    - name: id
      in: path
      required: true
      schema:
        type: string
    patch:
      summary: Update a rule's preferences
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_promotions` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const rule = await client.promotions.rules.update('promo_UkLWZg9DAJ', 'promorule_k5nR8xLq', {
            preferences: { currency: 'USD' },
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /promotions/{promotion_id}/promotion_rules/{id} -d
          '{"preferences":{"currency":"USD"}}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: rule updated
          content:
            application/json:
              example:
                id: prorule_UkLWZg9DAJ
                created_at: '2026-07-27T20:01:34.856Z'
                updated_at: '2026-07-27T20:01:35.136Z'
                type: currency
                promotion_id: promo_UkLWZg9DAJ
                preferences:
                  currency: GBP
                preference_schema:
                - key: currency
                  type: string
                  default:
                label: Currency
                product_ids:
                category_ids:
                customer_ids:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                preferences:
                  type: object
                  additionalProperties: true
    delete:
      summary: Delete a rule from a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_promotions` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.promotions.rules.delete('promo_UkLWZg9DAJ', 'promorule_k5nR8xLq')
      - lang: bash
        label: Spree CLI
        source: spree api delete /promotions/{promotion_id}/promotion_rules/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: rule deleted
  "/api/v3/admin/promotions":
    get:
      summary: List promotions
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the store's promotions, including manual coupon and automatic promotions.

        **Required scope:** `read_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: promotions } = await client.promotions.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /promotions
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: promotions found
          content:
            application/json:
              example:
                data:
                - id: promo_UkLWZg9DAJ
                  name: Summer Sale
                  description:
                  code: summer
                  starts_at: '2026-07-27T20:01:35.424Z'
                  expires_at:
                  usage_limit:
                  match_policy: all
                  path:
                  kind: coupon_code
                  multi_codes: false
                  number_of_codes:
                  code_prefix:
                  promotion_category_id:
                  metadata: {}
                  created_at: '2026-07-27T20:01:35.424Z'
                  updated_at: '2026-07-27T20:01:35.424Z'
                  action_ids: []
                  rule_ids: []
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new promotion. `code` is required for single-code coupon promotions;
        pass `multi_codes: true` with `number_of_codes` to auto-generate a batch.

        Rules and actions can be created in the same request by passing arrays of
        `{ type, preferences, ... }` rows. The server reconciles to the desired set:
        new rows are built, existing rows (by `id`) are updated, omitted rows are removed.


        **Required scope:** `write_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Single coupon code, no rules/actions
          const promotion = await client.promotions.create({
            name: 'Black Friday',
            code: 'BLACKFRIDAY',
            starts_at: '2026-11-29T00:00:00Z',
            expires_at: '2026-12-01T00:00:00Z',
          })

          // One-shot: promotion + rules + actions in a single request
          const blackFriday = await client.promotions.create({
            name: 'Black Friday',
            code: 'BLACKFRIDAY',
            kind: 'coupon_code',
            starts_at: '2026-11-29T00:00:00Z',
            expires_at: '2026-12-01T00:00:00Z',
            match_policy: 'all',
            rules: [
              {
                type: 'currency',
                preferences: { currency: 'USD' },
              },
              {
                type: 'item_total',
                preferences: { amount_min: 100, operator_min: 'gte' },
              },
              {
                type: 'product',
                preferences: { match_policy: 'any' },
                product_ids: ['prod_abc123', 'prod_def456'],
              },
            ],
            actions: [
              {
                type: 'create_item_adjustments',
                calculator: {
                  type: 'percent_on_line_item',
                  preferences: { percent: 25 },
                },
              },
              { type: 'free_shipping' },
            ],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /promotions -d '{"name":"Black Friday","code":"BLACKFRIDAY","starts_at":"2026-11-29T00:00:00Z","expires_at":"2026-12-01T00:00:00Z"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: promotion created with rules and actions
          content:
            application/json:
              example:
                id: promo_gbHJdmfrXB
                name: Black Friday
                description:
                code: blackfriday-os
                starts_at: '2026-07-27T20:01:36.335Z'
                expires_at:
                usage_limit:
                match_policy: all
                path:
                kind: coupon_code
                multi_codes: false
                number_of_codes:
                code_prefix:
                promotion_category_id:
                metadata: {}
                created_at: '2026-07-27T20:01:36.335Z'
                updated_at: '2026-07-27T20:01:36.353Z'
                action_ids:
                - pact_UkLWZg9DAJ
                - pact_gbHJdmfrXB
                rule_ids:
                - prorule_UkLWZg9DAJ
                - prorule_gbHJdmfrXB
                - prorule_EfhxLZ9ck8
        '422':
          description: invalid params
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank and Code can't be blank
                  details:
                    name:
                    - can't be blank
                    code:
                    - can't be blank
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                code:
                  type: string
                  nullable: true
                description:
                  type: string
                  nullable: true
                starts_at:
                  type: string
                  format: date-time
                  nullable: true
                expires_at:
                  type: string
                  format: date-time
                  nullable: true
                usage_limit:
                  type: integer
                  nullable: true
                match_policy:
                  type: string
                  enum:
                  - all
                  - any
                kind:
                  type: string
                  enum:
                  - coupon_code
                  - automatic
                multi_codes:
                  type: boolean
                number_of_codes:
                  type: integer
                  nullable: true
                code_prefix:
                  type: string
                  nullable: true
                promotion_category_id:
                  type: string
                  nullable: true
                rules:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                        example: currency
                      preferences:
                        type: object
                        additionalProperties: true
                      product_ids:
                        type: array
                        items:
                          type: string
                      category_ids:
                        type: array
                        items:
                          type: string
                      customer_ids:
                        type: array
                        items:
                          type: string
                    required:
                    - type
                actions:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                        example: free_shipping
                      preferences:
                        type: object
                        additionalProperties: true
                      calculator:
                        type: object
                        properties:
                          type:
                            type: string
                            example: flat_percent_item_total
                          preferences:
                            type: object
                            additionalProperties: true
                    required:
                    - type
              required:
              - name
  "/api/v3/admin/promotions/{id}":
    get:
      summary: Show a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_promotions` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const promotion = await client.promotions.get('promo_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /promotions/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: promotion found
          content:
            application/json:
              example:
                id: promo_UkLWZg9DAJ
                name: Summer Sale
                description:
                code: summer
                starts_at: '2026-07-27T20:01:36.644Z'
                expires_at:
                usage_limit:
                match_policy: all
                path:
                kind: coupon_code
                multi_codes: false
                number_of_codes:
                code_prefix:
                promotion_category_id:
                metadata: {}
                created_at: '2026-07-27T20:01:36.644Z'
                updated_at: '2026-07-27T20:01:36.644Z'
                action_ids: []
                rule_ids: []
    patch:
      summary: Update a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a promotion. The `rules` and `actions` arrays are treated as
        a *desired set* — rows with `id` update in place, rows without `id` are
        built fresh, and any existing row not present in the array is destroyed.
        Pass `rules: []` or `actions: []` to clear them.


        **Required scope:** `write_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Basic field update
          await client.promotions.update(promotionId, {
            description: 'Updated description',
          })

          // One-shot: rewrite rules + actions in a single request
          await client.promotions.update(promotionId, {
            name: 'Holiday Sale',
            rules: [
              // Update an existing rule by id — `preferences` overwrite the prior set
              {
                id: 'prorule_existing',
                type: 'currency',
                preferences: { currency: 'EUR' },
              },
              // Add a new rule
              {
                type: 'item_total',
                preferences: { amount_min: 50, operator_min: 'gte' },
              },
            ],
            actions: [
              // Swap calculator type on an existing action
              {
                id: 'proaction_existing',
                type: 'create_item_adjustments',
                calculator: {
                  type: 'percent_on_line_item',
                  preferences: { percent: 15 },
                },
              },
            ],
          })

          // Remove all rules/actions
          await client.promotions.update(promotionId, {
            rules: [],
            actions: [],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /promotions/{id} -d '{"description":"Updated description"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: rules and actions cleared with empty arrays
          content:
            application/json:
              example:
                id: promo_UkLWZg9DAJ
                name: Summer Sale
                description:
                code: summer
                starts_at: '2026-07-27T20:01:37.511Z'
                expires_at:
                usage_limit:
                match_policy: all
                path:
                kind: coupon_code
                multi_codes: false
                number_of_codes:
                code_prefix:
                promotion_category_id:
                metadata: {}
                created_at: '2026-07-27T20:01:37.511Z'
                updated_at: '2026-07-27T20:01:37.790Z'
                action_ids: []
                rule_ids: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                  nullable: true
                code:
                  type: string
                  nullable: true
                starts_at:
                  type: string
                  format: date-time
                  nullable: true
                expires_at:
                  type: string
                  format: date-time
                  nullable: true
                usage_limit:
                  type: integer
                  nullable: true
                match_policy:
                  type: string
                  enum:
                  - all
                  - any
                kind:
                  type: string
                  enum:
                  - coupon_code
                  - automatic
                promotion_category_id:
                  type: string
                  nullable: true
                rules:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        nullable: true
                        description: Pass to update an existing rule; omit to build
                          a new one
                      type:
                        type: string
                        example: currency
                      preferences:
                        type: object
                        additionalProperties: true
                      product_ids:
                        type: array
                        items:
                          type: string
                      category_ids:
                        type: array
                        items:
                          type: string
                      customer_ids:
                        type: array
                        items:
                          type: string
                    required:
                    - type
                actions:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        nullable: true
                      type:
                        type: string
                        example: free_shipping
                      preferences:
                        type: object
                        additionalProperties: true
                      calculator:
                        type: object
                        properties:
                          type:
                            type: string
                            example: flat_percent_item_total
                          preferences:
                            type: object
                            additionalProperties: true
                    required:
                    - type
    delete:
      summary: Delete a promotion
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_promotions` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.promotions.delete('promo_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /promotions/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: promotion deleted
  "/api/v3/admin/promotion_actions/types":
    get:
      summary: List available promotion action types
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the registered Spree::PromotionAction subclasses with their preference schemas. Used by admin UIs to populate the "Add action" picker and render generic preference forms.

        **Required scope:** `read_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: actionTypes } = await client.promotionActions.types()
      - lang: bash
        label: Spree CLI
        source: spree api get /promotion_actions/types
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: action types found
          content:
            application/json:
              example:
                data:
                - type: create_line_items
                  label: Create line items
                  description:
                  preference_schema: []
                - type: create_item_adjustments
                  label: Create per-line-item adjustment
                  description:
                  preference_schema: []
                - type: create_adjustment
                  label: Create whole-order adjustment
                  description:
                  preference_schema: []
                - type: free_shipping
                  label: Free shipping
                  description:
                  preference_schema: []
  "/api/v3/admin/promotion_rules/types":
    get:
      summary: List available promotion rule types
      tags:
      - Promotions
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the registered Spree::PromotionRule subclasses with their preference schemas.

        **Required scope:** `read_promotions` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: ruleTypes } = await client.promotionRules.types()
      - lang: bash
        label: Spree CLI
        source: spree api get /promotion_rules/types
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: rule types found
          content:
            application/json:
              example:
                data:
                - type: category
                  label: Categories
                  description:
                  preference_schema:
                  - key: match_policy
                    type: string
                    default: any
                - type: channel
                  label: Channel(s)
                  description:
                  preference_schema:
                  - key: channel_ids
                    type: array
                    default: []
                - type: country
                  label: Country
                  description:
                  preference_schema:
                  - key: country_isos
                    type: array
                    default: []
                  - key: country_id
                    type: integer
                    default:
                  - key: country_iso
                    type: string
                    default:
                - type: currency
                  label: Currency
                  description:
                  preference_schema:
                  - key: currency
                    type: string
                    default:
                - type: customer_group
                  label: Customer Group(s)
                  description:
                  preference_schema:
                  - key: customer_group_ids
                    type: array
                    default: []
                - type: customer
                  label: Customers
                  description:
                  preference_schema: []
                - type: first_order
                  label: First order
                  description:
                  preference_schema: []
                - type: item_total
                  label: Item total
                  description:
                  preference_schema:
                  - key: amount_min
                    type: decimal
                    default: 100.0
                  - key: operator_min
                    type: string
                    default: ">"
                  - key: amount_max
                    type: decimal
                    default:
                  - key: operator_max
                    type: string
                    default: "<"
                - type: market
                  label: Market(s)
                  description:
                  preference_schema:
                  - key: market_ids
                    type: array
                    default: []
                - type: one_use_per_user
                  label: One Use Per User
                  description:
                  preference_schema: []
                - type: customer_logged_in
                  label: Only logged in customers
                  description:
                  preference_schema: []
                - type: option_value
                  label: Option Value(s)
                  description:
                  preference_schema:
                  - key: match_policy
                    type: string
                    default: any
                  - key: eligible_values
                    type: array
                    default: []
                - type: product
                  label: Product(s)
                  description:
                  preference_schema:
                  - key: match_policy
                    type: string
                    default: any
  "/api/v3/admin/orders/{order_id}/refunds":
    get:
      summary: List refunds
      tags:
      - Refunds
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns all refunds for an order.

        **Required scope:** `read_refunds` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: refunds } = await client.orders.refunds.list('or_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /orders/{order_id}/refunds
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., payment, refund_reason).
          Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., amount,reason,transaction_id).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: refunds found
          content:
            application/json:
              example:
                data: []
                meta:
                  page: 1
                  limit: 25
                  count: 0
                  pages: 1
                  from: 0
                  to: 0
                  in: 0
                  previous:
                  next:
    post:
      summary: Create a refund
      tags:
      - Refunds
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a refund for a payment on the order. The refund is automatically processed via the payment gateway.

        **Required scope:** `write_refunds` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const refund = await client.orders.refunds.create('or_UkLWZg9DAJ', {
            payment_id: 'pay_UkLWZg9DAJ',
            amount: '5.00',
            refund_reason_id: 'refrsn_UkLWZg9DAJ',
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /orders/{order_id}/refunds -d '{"payment_id":"pay_UkLWZg9DAJ","amount":"5.00","refund_reason_id":"refrsn_UkLWZg9DAJ"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: order_id
        in: path
        required: true
        description: Order ID
        schema:
          type: string
      responses:
        '201':
          description: refund created
          content:
            application/json:
              example:
                id: re_UkLWZg9DAJ
                transaction_id: BGS-2cd1ddfbf9fc
                amount: '5.0'
                payment_id: py_UkLWZg9DAJ
                refund_reason_id: rr_UkLWZg9DAJ
                reimbursement_id:
                metadata: {}
                created_at: '2026-07-27T20:01:05.524Z'
                updated_at: '2026-07-27T20:01:05.524Z'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - payment_id
              - amount
              properties:
                payment_id:
                  type: string
                  description: Payment ID
                amount:
                  type: string
                  example: '10.00'
                refund_reason_id:
                  type: string
                  description: Refund reason ID
  "/api/v3/admin/locales":
    get:
      summary: List supported locales
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the locales a merchant can translate content into for the current store, with the default and right-to-left flags.

        **Required scope:** `read_settings` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: locales found
          content:
            application/json:
              example:
                data:
                - code: de
                  name: de
                  default: false
                  rtl: false
                - code: en
                  name: English
                  default: true
                  rtl: false
                - code: fr
                  name: fr
                  default: false
                  rtl: false
  "/api/v3/admin/store_credit_categories":
    get:
      summary: List store credit categories
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the configured store credit categories. Categories classify
        store credits (e.g., "Goodwill", "Gift Card", "Refund") and surface
        in the admin UI as a dropdown when issuing or editing a store
        credit. Category names matching `Spree::Config[:non_expiring_credit_types]`
        are flagged via `non_expiring: true`.


        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: categories } = await client.storeCreditCategories.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /store_credit_categories
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name (contains)
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending (e.g., `-created_at`).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: store credit categories found
          content:
            application/json:
              example:
                data:
                - id: sccat_UkLWZg9DAJ
                  name: Goodwill
                  created_at: '2026-07-27T20:01:41.294Z'
                  updated_at: '2026-07-27T20:01:41.294Z'
                  non_expiring: false
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/StoreCreditCategory"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/admin/store_credit_categories/{id}":
    parameters:
    - name: id
      in: path
      required: true
      description: Store credit category ID
      schema:
        type: string
    get:
      summary: Get a store credit category
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single store credit category by prefixed ID.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const category = await client.storeCreditCategories.get('sccat_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /store_credit_categories/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: store credit category found
          content:
            application/json:
              example:
                id: sccat_UkLWZg9DAJ
                name: Goodwill
                created_at: '2026-07-27T20:01:41.591Z'
                updated_at: '2026-07-27T20:01:41.591Z'
                non_expiring: false
              schema:
                "$ref": "#/components/schemas/StoreCreditCategory"
        '404':
          description: store credit category not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Store credit category not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/admin/store":
    get:
      summary: Get the current store
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the current store configuration. The store is resolved from the request context (host or admin selection); there is no `id` parameter.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const store = await client.store.get()
      - lang: bash
        label: Spree CLI
        source: spree api get /store
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: current store
          content:
            application/json:
              example:
                id: store_UkLWZg9DAJ
                metadata: {}
                name: Spree Test Store
                code: spree_1
                preferred_storefront_url:
                default_currency: USD
                default_locale: en
                mail_from_address: no-reply@example.com
                customer_support_email: support@example.com
                new_order_notifications_email: store-owner@example.com
                preferred_send_consumer_transactional_emails: true
                preferred_admin_locale:
                preferred_timezone: UTC
                preferred_weight_unit: lb
                preferred_unit_system: imperial
                preferred_storefront_access: public
                preferred_guest_checkout: true
                preferred_order_routing_strategy: Spree::OrderRouting::Strategy::Rules
                created_at: '2026-07-27T19:59:58.874Z'
                updated_at: '2026-07-27T20:01:42.184Z'
                url: http://www.example.com:3000
                api_url: http://www.example.com:3000
                setup_tasks:
                - name: setup_payment_method
                  done: false
                - name: add_products
                  done: false
                - name: set_customer_support_email
                  done: true
                - name: setup_taxes_collection
                  done: false
                - name: setup_storefront
                  done: false
                supported_currencies:
                - USD
                supported_locales:
                - en
                available_locales:
                - aa
                - ab
                - ae
                - af
                - ak
                - am
                - an
                - ar
                - as
                - av
                - ay
                - az
                - ba
                - be
                - bg
                - bh
                - bi
                - bm
                - bn
                - bo
                - br
                - bs
                - ca
                - ce
                - ch
                - co
                - cr
                - cs
                - cu
                - cv
                - cy
                - da
                - de
                - de-AT
                - de-CH
                - dv
                - dz
                - ee
                - el
                - en
                - en-AU
                - en-CA
                - en-GB
                - en-IN
                - en-NZ
                - eo
                - es
                - es-419
                - es-MX
                - et
                - eu
                - fa
                - ff
                - fi
                - fj
                - fo
                - fr
                - fr-CA
                - fy
                - ga
                - gd
                - gl
                - gn
                - gu
                - gv
                - ha
                - he
                - hi
                - ho
                - hr
                - ht
                - hu
                - hy
                - hz
                - ia
                - id
                - ie
                - ig
                - ii
                - ik
                - io
                - is
                - it
                - iu
                - ja
                - jv
                - ka
                - kg
                - ki
                - kj
                - kk
                - kl
                - km
                - kn
                - ko
                - kr
                - ks
                - ku
                - kv
                - kw
                - ky
                - la
                - lb
                - lg
                - li
                - ln
                - lo
                - lt
                - lu
                - lv
                - mg
                - mh
                - mi
                - mk
                - ml
                - mn
                - mr
                - ms
                - mt
                - my
                - na
                - nb
                - nd
                - ne
                - ng
                - nl
                - nn
                - 'no'
                - nr
                - nv
                - ny
                - oc
                - oj
                - om
                - or
                - os
                - pa
                - pi
                - pl
                - ps
                - pt
                - pt-BR
                - pt-PT
                - qu
                - rm
                - rn
                - ro
                - ru
                - rw
                - sa
                - sc
                - sd
                - se
                - sg
                - si
                - sk
                - sl
                - sm
                - sn
                - so
                - sq
                - sr
                - ss
                - st
                - su
                - sv
                - sw
                - ta
                - te
                - tg
                - th
                - ti
                - tk
                - tl
                - tn
                - to
                - tr
                - ts
                - tt
                - tw
                - ty
                - ug
                - uk
                - ur
                - uz
                - ve
                - vi
                - vo
                - wa
                - wo
                - xh
                - yi
                - yo
                - za
                - zh-CN
                - zh-HK
                - zh-TW
                - zu
                logo_url:
                mailer_logo_url:
              schema:
                "$ref": "#/components/schemas/Store"
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update the current store
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates the current store configuration.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const store = await client.store.update({
            name: 'My Store'
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /store -d '{"name":"My Store"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: store updated
          content:
            application/json:
              example:
                id: store_UkLWZg9DAJ
                metadata: {}
                name: Renamed Store
                code: spree_1
                preferred_storefront_url:
                default_currency: USD
                default_locale: en
                mail_from_address: no-reply@example.com
                customer_support_email: support@example.com
                new_order_notifications_email: store-owner@example.com
                preferred_send_consumer_transactional_emails: true
                preferred_admin_locale:
                preferred_timezone: UTC
                preferred_weight_unit: lb
                preferred_unit_system: imperial
                preferred_storefront_access: public
                preferred_guest_checkout: true
                preferred_order_routing_strategy: Spree::OrderRouting::Strategy::Rules
                created_at: '2026-07-27T19:59:58.874Z'
                updated_at: '2026-07-27T20:01:42.800Z'
                url: http://www.example.com:3000
                api_url: http://www.example.com:3000
                setup_tasks:
                - name: setup_payment_method
                  done: false
                - name: add_products
                  done: false
                - name: set_customer_support_email
                  done: true
                - name: setup_taxes_collection
                  done: false
                - name: setup_storefront
                  done: false
                supported_currencies:
                - USD
                supported_locales:
                - en
                available_locales:
                - aa
                - ab
                - ae
                - af
                - ak
                - am
                - an
                - ar
                - as
                - av
                - ay
                - az
                - ba
                - be
                - bg
                - bh
                - bi
                - bm
                - bn
                - bo
                - br
                - bs
                - ca
                - ce
                - ch
                - co
                - cr
                - cs
                - cu
                - cv
                - cy
                - da
                - de
                - de-AT
                - de-CH
                - dv
                - dz
                - ee
                - el
                - en
                - en-AU
                - en-CA
                - en-GB
                - en-IN
                - en-NZ
                - eo
                - es
                - es-419
                - es-MX
                - et
                - eu
                - fa
                - ff
                - fi
                - fj
                - fo
                - fr
                - fr-CA
                - fy
                - ga
                - gd
                - gl
                - gn
                - gu
                - gv
                - ha
                - he
                - hi
                - ho
                - hr
                - ht
                - hu
                - hy
                - hz
                - ia
                - id
                - ie
                - ig
                - ii
                - ik
                - io
                - is
                - it
                - iu
                - ja
                - jv
                - ka
                - kg
                - ki
                - kj
                - kk
                - kl
                - km
                - kn
                - ko
                - kr
                - ks
                - ku
                - kv
                - kw
                - ky
                - la
                - lb
                - lg
                - li
                - ln
                - lo
                - lt
                - lu
                - lv
                - mg
                - mh
                - mi
                - mk
                - ml
                - mn
                - mr
                - ms
                - mt
                - my
                - na
                - nb
                - nd
                - ne
                - ng
                - nl
                - nn
                - 'no'
                - nr
                - nv
                - ny
                - oc
                - oj
                - om
                - or
                - os
                - pa
                - pi
                - pl
                - ps
                - pt
                - pt-BR
                - pt-PT
                - qu
                - rm
                - rn
                - ro
                - ru
                - rw
                - sa
                - sc
                - sd
                - se
                - sg
                - si
                - sk
                - sl
                - sm
                - sn
                - so
                - sq
                - sr
                - ss
                - st
                - su
                - sv
                - sw
                - ta
                - te
                - tg
                - th
                - ti
                - tk
                - tl
                - tn
                - to
                - tr
                - ts
                - tt
                - tw
                - ty
                - ug
                - uk
                - ur
                - uz
                - ve
                - vi
                - vo
                - wa
                - wo
                - xh
                - yi
                - yo
                - za
                - zh-CN
                - zh-HK
                - zh-TW
                - zu
                logo_url:
                mailer_logo_url:
              schema:
                "$ref": "#/components/schemas/Store"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Site Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: My Store
                preferred_admin_locale:
                  type: string
                  example: en
                preferred_timezone:
                  type: string
                  example: UTC
                preferred_weight_unit:
                  type: string
                  example: kg
                preferred_unit_system:
                  type: string
                  example: metric
  "/api/v3/admin/tags":
    get:
      summary: List tags
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: Returns tag names for a given taggable type. Used for autocomplete
        in tag inputs on products, orders, and customers.
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: tags } = await client.tags.list({
            taggable_type: 'Spree::User',
            q: 'vip',
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /tags -d '{"taggable_type":"Spree::User","q":"vip"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: taggable_type
        in: query
        required: true
        description: Taggable type (`Spree::Product`, `Spree::Order`, or `Spree::User`)
        schema:
          type: string
      - name: q
        in: query
        required: false
        description: Optional case-insensitive substring filter
        schema:
          type: string
      responses:
        '200':
          description: tags found
          content:
            application/json:
              example:
                data:
                - name: vip
                - name: wholesale
        '422':
          description: invalid taggable type
          content:
            application/json:
              example:
                error:
                  code: invalid_taggable_type
                  message: taggable_type must be one of Spree::Product, Spree::Order,
                    Spree::LegacyUser
  "/api/v3/admin/translatable_resources":
    get:
      summary: List translatable resources
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns every translatable resource type and its translatable fields (key + content type), so clients can render translation editors generically.

        **Required scope:** `read_settings` (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: translatable resources found
          content:
            application/json:
              example:
                data:
                - resource_type: option_type
                  fields:
                  - key: label
                    type: string
                  readable: true
                - resource_type: option_value
                  fields:
                  - key: label
                    type: string
                  readable: false
                - resource_type: product
                  fields:
                  - key: name
                    type: string
                  - key: description
                    type: html
                  - key: slug
                    type: string
                  - key: meta_description
                    type: string
                  - key: meta_title
                    type: string
                  readable: true
                - resource_type: category
                  fields:
                  - key: name
                    type: string
                  - key: pretty_name
                    type: string
                  - key: description
                    type: html
                  - key: permalink
                    type: string
                  readable: true
                - resource_type: taxonomy
                  fields:
                  - key: name
                    type: string
                  readable: false
                - resource_type: store
                  fields:
                  - key: name
                    type: string
                  - key: meta_description
                    type: string
                  - key: meta_keywords
                    type: string
                  - key: seo_title
                    type: string
                  - key: customer_support_email
                    type: string
                  - key: address
                    type: string
                  - key: contact_phone
                    type: string
                  readable: false
                - resource_type: policy
                  fields:
                  - key: name
                    type: string
                  - key: body
                    type: html
                  readable: false
  "/api/v3/admin/translations/batch":
    post:
      summary: Batch upsert translations
      tags:
      - Settings
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Atomically upserts translations across many records of (possibly) different translatable resource types in one request — e.g. an option type and all its option values in one save. A flat list of independent registry writes; all entries succeed or none do.

        **Required scope:** `write_<resource>` for every resource type in the batch (for API-key authentication) (for API-key authentication).
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: translations upserted
          content:
            application/json:
              example:
                data:
                - resource_id: opt_UkLWZg9DAJ
                  resource_type: option_type
                  translations:
                    de:
                      label: Größe
                      translated_field_count: 1
                    fr:
                      label:
                      translated_field_count: 0
                  default_locale: en
                  supported_locales:
                  - de
                  - en
                  - fr
                - resource_id: optval_UkLWZg9DAJ
                  resource_type: option_value
                  translations:
                    de:
                      label: Klein
                      translated_field_count: 1
                    fr:
                      label:
                      translated_field_count: 0
                  default_locale: en
                  supported_locales:
                  - de
                  - en
                  - fr
        '422':
          description: unsupported locale rolls back the whole batch
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: 'Unsupported locale(s): es'
                  details:
                    translations:
                      '0':
                      - 'Unsupported locale(s): es'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - translations
              properties:
                translations:
                  type: array
                  items:
                    type: object
                    required:
                    - resource_type
                    - resource_id
                    - values
                    properties:
                      resource_type:
                        type: string
                        description: Translatable resource type token, e.g. `option_type`
                      resource_id:
                        type: string
                        description: Prefixed id of the record
                      values:
                        type: object
                        description: 'Map of locale code to { field: value }'
                        additionalProperties:
                          type: object
                          additionalProperties: true
  "/api/v3/admin/admin_users":
    get:
      summary: List staff
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns admin users with at least one role assignment on the current store.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: staff } = await client.adminUsers.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /admin_users
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: staff found
          content:
            application/json:
              example:
                data:
                - id: admin_UkLWZg9DAJ
                  email: dalia_jacobs@mante.co.uk
                  first_name: Dean
                  last_name: King
                  full_name: Dean King
                  selected_locale:
                  created_at: '2026-07-27T19:59:59.194Z'
                  updated_at: '2026-07-27T19:59:59.194Z'
                  avatar_url:
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
                  stores:
                  - id: store_UkLWZg9DAJ
                    name: Spree Test Store
                    code: spree_1
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
  "/api/v3/admin/admin_users/{id}":
    get:
      summary: Show a staff member
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `read_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const staff = await client.adminUsers.get('admin_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /admin_users/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: staff member found
          content:
            application/json:
              example:
                id: admin_UkLWZg9DAJ
                email: alena.lowe@oreilly.name
                first_name: Pauline
                last_name: Bergnaum
                full_name: Pauline Bergnaum
                selected_locale:
                created_at: '2026-07-27T19:59:59.533Z'
                updated_at: '2026-07-27T19:59:59.533Z'
                avatar_url:
                roles:
                - id: role_UkLWZg9DAJ
                  name: admin
                stores:
                - id: store_UkLWZg9DAJ
                  name: Spree Test Store
                  code: spree_1
    patch:
      summary: Update a staff member
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates name fields and reassigns roles for the current store. `role_ids` is a complete replacement — roles not in the array are removed for this store.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const staff = await client.adminUsers.update('admin_xxx', {
            first_name: 'Ada',
            role_ids: ['role_xxx']
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /admin_users/{id} -d '{"first_name":"Ada","role_ids":["role_xxx"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: staff member updated
          content:
            application/json:
              example:
                id: admin_UkLWZg9DAJ
                email: annis_white@hirthe.ca
                first_name: Renamed
                last_name: Dibbert
                full_name: Renamed Dibbert
                selected_locale:
                created_at: '2026-07-27T19:59:59.836Z'
                updated_at: '2026-07-27T19:59:59.858Z'
                avatar_url:
                roles:
                - id: role_UkLWZg9DAJ
                  name: admin
                stores:
                - id: store_UkLWZg9DAJ
                  name: Spree Test Store
                  code: spree_1
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                first_name:
                  type: string
                  example: Ada
                last_name:
                  type: string
                  example: Lovelace
                role_ids:
                  type: array
                  items:
                    type: string
    delete:
      summary: Remove a staff member from this store
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Removes the user's role assignments on the current store. The account is preserved — the user keeps access to any other stores.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.adminUsers.delete('admin_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /admin_users/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: staff removed from store
  "/api/v3/admin/invitations":
    get:
      summary: List invitations
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns invitations for the current store, including pending and accepted.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: invitations } = await client.invitations.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /invitations
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: invitations found
          content:
            application/json:
              example:
                data:
                - id: inv_UkLWZg9DAJ
                  email: kimberly.lebsack@berge.ca
                  status: pending
                  created_at: '2026-07-27T20:00:40.233Z'
                  updated_at: '2026-07-27T20:00:40.233Z'
                  expires_at: '2026-08-10T20:00:40.227Z'
                  role_id: role_UkLWZg9DAJ
                  role_name: admin
                  inviter_email: aaron@ortiz.com
                  acceptance_url: "/accept-invitation/inv_UkLWZg9DAJ?token=v8dYAmdtYLK9oGXRkXhxjpN8"
                  invitee_exists: false
                  store:
                    id: store_UkLWZg9DAJ
                    name: Spree Test Store
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
    post:
      summary: Create an invitation
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Invites a teammate by email. The invitation is scoped to the current store and carries the chosen role; on accept, a `RoleUser` is created via the invitation's `after_accept` callback.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const invitation = await client.invitations.create({
            email: 'ada@example.com',
            role_id: 'role_xxx'
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /invitations -d '{"email":"ada@example.com","role_id":"role_xxx"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '201':
          description: invitation created
          content:
            application/json:
              example:
                id: inv_gbHJdmfrXB
                email: new-staff@example.com
                status: pending
                created_at: '2026-07-27T20:00:40.581Z'
                updated_at: '2026-07-27T20:00:40.581Z'
                expires_at: '2026-08-10T20:00:40.577Z'
                role_id: role_UkLWZg9DAJ
                role_name: admin
                inviter_email: miesha_maggio@nikolauscartwright.co.uk
                acceptance_url: "/accept-invitation/inv_gbHJdmfrXB?token=imsi6bATMRCejdokMfCiwnLd"
                invitee_exists: false
                store:
                  id: store_UkLWZg9DAJ
                  name: Spree Test Store
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - email
              - role_id
              properties:
                email:
                  type: string
                  example: ada@example.com
                role_id:
                  type: string
                  example: role_xxx
  "/api/v3/admin/invitations/{id}":
    delete:
      summary: Revoke an invitation
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: "**Required scope:** `write_settings` (for API-key authentication)."
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.invitations.delete('inv_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /invitations/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: invitation revoked
  "/api/v3/admin/invitations/{id}/resend":
    patch:
      summary: Resend an invitation
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Issues a fresh token and dispatches the invitation email again.

        **Required scope:** `write_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const invitation = await client.invitations.resend('inv_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api patch /invitations/{id}/resend -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: invitation resent
          content:
            application/json:
              example:
                id: inv_UkLWZg9DAJ
                email: lenita.cremin@reichert.com
                status: pending
                created_at: '2026-07-27T20:00:41.168Z'
                updated_at: '2026-07-27T20:00:41.168Z'
                expires_at: '2026-08-10T20:00:41.166Z'
                role_id: role_UkLWZg9DAJ
                role_name: admin
                inviter_email: leonardo_murazik@leuschke.us
                acceptance_url: "/accept-invitation/inv_UkLWZg9DAJ?token=1gxEHnAgHyTVekF6SdcT9ji3"
                invitee_exists: false
                store:
                  id: store_UkLWZg9DAJ
                  name: Spree Test Store
  "/api/v3/admin/roles":
    get:
      summary: List roles
      tags:
      - Staff
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the roles available for staff role pickers. Roles are global, not per-store.

        **Required scope:** `read_settings` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: roles } = await client.roles.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /roles
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: roles found
          content:
            application/json:
              example:
                data:
                - id: role_UkLWZg9DAJ
                  name: admin
                  created_at: '2026-07-27T20:01:38.681Z'
                  updated_at: '2026-07-27T20:01:38.681Z'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
  "/api/v3/admin/stock_locations":
    get:
      summary: List stock locations
      tags:
      - Stock Locations
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns the configured stock locations. Stock locations are global
        (shared across stores). Filter with Ransack predicates such as
        `q[active_eq]`, `q[kind_eq]`, `q[pickup_enabled_eq]`, or
        `q[name_cont]`.

        Pickup-related attributes (`kind`, `pickup_enabled`,
        `pickup_stock_policy`, `pickup_ready_in_minutes`,
        `pickup_instructions`) drive merchant pickup support at checkout —
        customers can collect orders from any active location with
        `pickup_enabled: true`.


        **Required scope:** `read_stock` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: stockLocations } = await client.stockLocations.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /stock_locations
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name (contains)
        schema:
          type: string
      - name: q[active_eq]
        in: query
        required: false
        description: Filter by active status
        schema:
          type: boolean
      - name: q[kind_eq]
        in: query
        required: false
        description: 'Filter by kind (built-in: ''warehouse'', ''store'', ''fulfillment_center'')'
        schema:
          type: string
      - name: q[pickup_enabled_eq]
        in: query
        required: false
        description: Filter by pickup-enabled flag
        schema:
          type: boolean
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending (e.g., `-created_at`).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: stock locations found
          content:
            application/json:
              example:
                data:
                - id: sloc_UkLWZg9DAJ
                  state_abbr: STATE_ABBR_50
                  name: Brooklyn warehouse
                  address1: 1600 Pennsylvania Ave NW
                  city: Washington
                  zipcode: '20500'
                  country_iso: US
                  country_name: United States of America
                  state_text: STATE_ABBR_50
                  admin_name:
                  address2:
                  state_name:
                  phone: "(202) 456-1111"
                  company:
                  active: true
                  default: false
                  backorderable_default: true
                  propagate_all_variants: false
                  kind: warehouse
                  pickup_enabled: false
                  pickup_stock_policy: local
                  pickup_ready_in_minutes:
                  pickup_instructions:
                  created_at: '2026-07-27T20:01:38.982Z'
                  updated_at: '2026-07-27T20:01:38.982Z'
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/StockLocation"
                  meta:
                    "$ref": "#/components/schemas/PaginationMeta"
                required:
                - data
                - meta
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create a stock location
      tags:
      - Stock Locations
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new stock location.

        Setting `default: true` automatically demotes the previous default
        location.


        **Required scope:** `write_stock` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const stockLocation = await client.stockLocations.create({
            name: 'Brooklyn warehouse',
            kind: 'warehouse',
            country_iso: 'US',
            state_abbr: 'NY',
            city: 'Brooklyn',
            zipcode: '11201',
            pickup_enabled: true,
            pickup_stock_policy: 'local',
            pickup_ready_in_minutes: 60,
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /stock_locations -d '{"name":"Brooklyn warehouse","kind":"warehouse","country_iso":"US","state_abbr":"NY","city":"Brooklyn","zipcode":"11201","pickup_enabled":true,"pickup_stock_policy":"local","pickup_ready_in_minutes":60}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: stock location created
          content:
            application/json:
              example:
                id: sloc_gbHJdmfrXB
                state_abbr:
                name: Manhattan store
                address1:
                city:
                zipcode:
                country_iso:
                country_name:
                state_text:
                admin_name:
                address2:
                state_name:
                phone:
                company:
                active: true
                default: false
                backorderable_default: false
                propagate_all_variants: false
                kind: store
                pickup_enabled: true
                pickup_stock_policy: local
                pickup_ready_in_minutes: 30
                pickup_instructions:
                created_at: '2026-07-27T20:01:39.576Z'
                updated_at: '2026-07-27T20:01:39.576Z'
              schema:
                "$ref": "#/components/schemas/StockLocation"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Name can't be blank
                  details:
                    name:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Brooklyn warehouse
                admin_name:
                  type: string
                  nullable: true
                  description: Internal name shown only in the admin
                active:
                  type: boolean
                  example: true
                default:
                  type: boolean
                  description: Setting to true demotes the previous default.
                kind:
                  type: string
                  enum:
                  - warehouse
                  - store
                  - fulfillment_center
                  description: Categorizes the location.
                  example: warehouse
                propagate_all_variants:
                  type: boolean
                backorderable_default:
                  type: boolean
                address1:
                  type: string
                  nullable: true
                address2:
                  type: string
                  nullable: true
                city:
                  type: string
                  nullable: true
                zipcode:
                  type: string
                  nullable: true
                phone:
                  type: string
                  nullable: true
                company:
                  type: string
                  nullable: true
                country_iso:
                  type: string
                  nullable: true
                  description: ISO-3166 alpha-2 country code (e.g. "US").
                state_abbr:
                  type: string
                  nullable: true
                  description: State / province abbreviation (e.g. "NY"). Resolved
                    against the selected country.
                state_name:
                  type: string
                  nullable: true
                  description: Free-text state for countries without a states list.
                pickup_enabled:
                  type: boolean
                pickup_stock_policy:
                  type: string
                  enum:
                  - local
                  - any
                  description: "'local' = items at this location only; 'any' = transfer-eligible
                    (ship-to-store)."
                pickup_ready_in_minutes:
                  type: number
                  nullable: true
                  minimum: 0
                pickup_instructions:
                  type: string
                  nullable: true
              required:
              - name
  "/api/v3/admin/stock_locations/{id}":
    parameters:
    - name: id
      in: path
      required: true
      description: Stock location ID
      schema:
        type: string
    get:
      summary: Get a stock location
      tags:
      - Stock Locations
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single stock location by prefixed ID.

        **Required scope:** `read_stock` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const stockLocation = await client.stockLocations.get('sloc_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api get /stock_locations/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: stock location found
          content:
            application/json:
              example:
                id: sloc_UkLWZg9DAJ
                state_abbr: STATE_ABBR_54
                name: Brooklyn warehouse
                address1: 1600 Pennsylvania Ave NW
                city: Washington
                zipcode: '20500'
                country_iso: US
                country_name: United States of America
                state_text: STATE_ABBR_54
                admin_name:
                address2:
                state_name:
                phone: "(202) 456-1111"
                company:
                active: true
                default: false
                backorderable_default: true
                propagate_all_variants: false
                kind: warehouse
                pickup_enabled: false
                pickup_stock_policy: local
                pickup_ready_in_minutes:
                pickup_instructions:
                created_at: '2026-07-27T20:01:39.872Z'
                updated_at: '2026-07-27T20:01:39.872Z'
              schema:
                "$ref": "#/components/schemas/StockLocation"
        '404':
          description: stock location not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Stock location not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a stock location
      tags:
      - Stock Locations
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates an existing stock location. Same address-field conventions as
        the create endpoint.

        Setting `default: true` automatically demotes the previous default.


        **Required scope:** `write_stock` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const stockLocation = await client.stockLocations.update('sloc_UkLWZg9DAJ', {
            pickup_enabled: true,
            pickup_ready_in_minutes: 45,
            pickup_instructions: 'Enter through the back door, ring the bell.',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /stock_locations/{id} -d '{"pickup_enabled":true,"pickup_ready_in_minutes":45,"pickup_instructions":"Enter
          through the back door, ring the bell."}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: stock location updated
          content:
            application/json:
              example:
                id: sloc_UkLWZg9DAJ
                state_abbr: STATE_ABBR_56
                name: Renamed warehouse
                address1: 1600 Pennsylvania Ave NW
                city: Washington
                zipcode: '20500'
                country_iso: US
                country_name: United States of America
                state_text: STATE_ABBR_56
                admin_name:
                address2:
                state_name:
                phone: "(202) 456-1111"
                company:
                active: true
                default: false
                backorderable_default: true
                propagate_all_variants: false
                kind: warehouse
                pickup_enabled: true
                pickup_stock_policy: local
                pickup_ready_in_minutes: 45
                pickup_instructions:
                created_at: '2026-07-27T20:01:40.444Z'
                updated_at: '2026-07-27T20:01:40.721Z'
              schema:
                "$ref": "#/components/schemas/StockLocation"
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Pickup stock policy is not included in the list
                  details:
                    pickup_stock_policy:
                    - is not included in the list
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                admin_name:
                  type: string
                  nullable: true
                active:
                  type: boolean
                default:
                  type: boolean
                kind:
                  type: string
                  enum:
                  - warehouse
                  - store
                  - fulfillment_center
                propagate_all_variants:
                  type: boolean
                backorderable_default:
                  type: boolean
                address1:
                  type: string
                  nullable: true
                address2:
                  type: string
                  nullable: true
                city:
                  type: string
                  nullable: true
                zipcode:
                  type: string
                  nullable: true
                phone:
                  type: string
                  nullable: true
                company:
                  type: string
                  nullable: true
                country_iso:
                  type: string
                  nullable: true
                state_abbr:
                  type: string
                  nullable: true
                state_name:
                  type: string
                  nullable: true
                pickup_enabled:
                  type: boolean
                pickup_stock_policy:
                  type: string
                  enum:
                  - local
                  - any
                pickup_ready_in_minutes:
                  type: number
                  nullable: true
                  minimum: 0
                pickup_instructions:
                  type: string
                  nullable: true
    delete:
      summary: Delete a stock location
      tags:
      - Stock Locations
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes the stock location (sets `deleted_at`). Existing
        fulfillments that referenced it keep the historical record via
        `Spree::StockLocation.with_deleted`.


        **Required scope:** `write_stock` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.stockLocations.delete('sloc_UkLWZg9DAJ')
      - lang: bash
        label: Spree CLI
        source: spree api delete /stock_locations/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '204':
          description: stock location deleted
  "/api/v3/admin/products/{product_id}/variants":
    get:
      summary: List product variants
      tags:
      - Variants
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a paginated list of variants for a product, including the master variant.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const { data: variants } = await client.products.variants.list('prod_86Rf07xd4z', {
            expand: ['prices', 'stock_items'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /products/{product_id}/variants -d '{"expand":["prices","stock_items"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., images, prices,
          stock_items, option_values). Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., sku,price,stock).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: variants found
          content:
            application/json:
              example:
                data:
                - id: variant_UkLWZg9DAJ
                  product_id: prod_UkLWZg9DAJ
                  sku: SKU-103
                  options_text: ''
                  track_inventory: true
                  media_count: 0
                  preorder_ships_at:
                  thumbnail_url:
                  purchasable: false
                  in_stock: false
                  backorderable: false
                  preorder: false
                  weight: 0.0
                  height:
                  width:
                  depth:
                  price:
                    id:
                    amount:
                    amount_in_cents: 0
                    compare_at_amount:
                    compare_at_amount_in_cents:
                    currency: USD
                    display_amount: "$0.00"
                    display_compare_at_amount:
                    price_list_id:
                  original_price:
                  option_values: []
                  metadata: {}
                  position: 1
                  cost_price: '17.0'
                  cost_currency: USD
                  barcode:
                  weight_unit: lb
                  dimensions_unit:
                  backorder_limit:
                  deleted_at:
                  created_at: '2026-07-27T20:01:45.101Z'
                  updated_at: '2026-07-27T20:01:45.109Z'
                  preorderable: false
                  tax_category_id: taxcat_UkLWZg9DAJ
                  available_stock: 0
                  reserved_quantity: 0
                  total_on_hand: 0
                  product_name: Product 8414
                - id: variant_gbHJdmfrXB
                  product_id: prod_UkLWZg9DAJ
                  sku: SKU-104
                  options_text: 'Size: S'
                  track_inventory: true
                  media_count: 0
                  preorder_ships_at:
                  thumbnail_url:
                  purchasable: true
                  in_stock: false
                  backorderable: true
                  preorder: false
                  weight: 179.91
                  height: 136.1
                  width: 137.55
                  depth: 198.67
                  price:
                    id: price_gbHJdmfrXB
                    amount: '19.99'
                    amount_in_cents: 1999
                    compare_at_amount:
                    compare_at_amount_in_cents:
                    currency: USD
                    display_amount: "$19.99"
                    display_compare_at_amount:
                    price_list_id:
                  original_price:
                  option_values:
                  - id: optval_UkLWZg9DAJ
                    option_type_id: opt_UkLWZg9DAJ
                    name: size-19
                    label: S
                    position: 1
                    color_code:
                    option_type_name: foo-size-28
                    option_type_label: Size
                    image_url:
                    metadata: {}
                    created_at: '2026-07-27T20:01:45.123Z'
                    updated_at: '2026-07-27T20:01:45.123Z'
                  metadata: {}
                  position: 2
                  cost_price: '17.0'
                  cost_currency: USD
                  barcode:
                  weight_unit: lb
                  dimensions_unit:
                  backorder_limit:
                  deleted_at:
                  created_at: '2026-07-27T20:01:45.121Z'
                  updated_at: '2026-07-27T20:01:45.131Z'
                  preorderable: false
                  tax_category_id: taxcat_UkLWZg9DAJ
                  available_stock: 0
                  reserved_quantity: 0
                  total_on_hand: 0
                  product_name: Product 8414
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
    post:
      summary: Create a variant
      tags:
      - Variants
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new variant for a product. Supports nested prices and stock items.

        Option types and values are auto-created if they don't exist.
        Prices are upserted by currency. Stock items are upserted by stock location.


        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const variant = await client.products.variants.create('prod_86Rf07xd4z', {
            sku: 'TSHIRT-L-NAVY',
            options: [
              { name: 'size', value: 'Large' },
              { name: 'color', value: 'navy' },
            ],
            prices: [
              { currency: 'USD', amount: '29.99', compare_at_amount: '34.99' },
              { currency: 'EUR', amount: '27.99' },
            ],
            stock_items: [{ stock_location_id: 'sloc_UkLWZg9DAJ', count_on_hand: 25 }],
          })
      - lang: bash
        label: Spree CLI
        source: spree api post /products/{product_id}/variants -d '{"sku":"TSHIRT-L-NAVY","options":[{"name":"size","value":"Large"},{"name":"color","value":"navy"}],"prices":[{"currency":"USD","amount":"29.99","compare_at_amount":"34.99"},{"currency":"EUR","amount":"27.99"}],"stock_items":[{"stock_location_id":"sloc_UkLWZg9DAJ","count_on_hand":25}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      responses:
        '201':
          description: variant created
          content:
            application/json:
              example:
                id: variant_EfhxLZ9ck8
                product_id: prod_UkLWZg9DAJ
                sku: NEW-SKU-001
                options_text: 'Size: XL'
                track_inventory: true
                media_count: 0
                preorder_ships_at:
                thumbnail_url:
                purchasable: false
                in_stock: false
                backorderable: false
                preorder: false
                weight: 0.0
                height:
                width:
                depth:
                price:
                  id: price_EfhxLZ9ck8
                  amount: '24.99'
                  amount_in_cents: 2499
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$24.99"
                  display_compare_at_amount:
                  price_list_id:
                original_price:
                option_values:
                - id: optval_gbHJdmfrXB
                  option_type_id: opt_gbHJdmfrXB
                  name: xl
                  label: XL
                  position: 1
                  color_code:
                  option_type_name: size
                  option_type_label: Size
                  image_url:
                  metadata: {}
                  created_at: '2026-07-27T20:01:45.783Z'
                  updated_at: '2026-07-27T20:01:45.783Z'
                metadata: {}
                position: 3
                cost_price:
                cost_currency: USD
                barcode:
                weight_unit: lb
                dimensions_unit:
                backorder_limit:
                deleted_at:
                created_at: '2026-07-27T20:01:45.786Z'
                updated_at: '2026-07-27T20:01:45.788Z'
                preorderable: false
                tax_category_id: taxcat_UkLWZg9DAJ
                available_stock: 0
                reserved_quantity: 0
                total_on_hand: 0
                product_name: Product 852654
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Option value variants can't be blank
                  details:
                    option_value_variants:
                    - can't be blank
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - options
              properties:
                sku:
                  type: string
                  example: SKU-001
                cost_price:
                  type: string
                  example: '10.00'
                cost_currency:
                  type: string
                  example: USD
                weight:
                  type: number
                height:
                  type: number
                width:
                  type: number
                depth:
                  type: number
                weight_unit:
                  type: string
                dimensions_unit:
                  type: string
                track_inventory:
                  type: boolean
                tax_category_id:
                  type: string
                options:
                  type: array
                  description: Required. A variant created here is always non-master,
                    so it must declare at least one option pair (e.g. size + color)
                    or creation fails with 422. One pair per option type the variant
                    participates in. Option types and values are auto-created if missing.
                  items:
                    type: object
                    required:
                    - name
                    - value
                    properties:
                      name:
                        type: string
                        example: size
                      value:
                        type: string
                        example: Small
                position:
                  type: integer
                barcode:
                  type: string
                prices:
                  type: array
                  description: Per-currency prices. Upserted by currency.
                  items:
                    type: object
                    required:
                    - currency
                    - amount
                    properties:
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        example: '29.99'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '39.99'
                stock_items:
                  type: array
                  description: Per-stock-location inventory. Upserted by stock_location_id.
                  items:
                    type: object
                    required:
                    - stock_location_id
                    - count_on_hand
                    properties:
                      stock_location_id:
                        type: string
                        description: Stock location ID (e.g. sloc_xxx)
                      count_on_hand:
                        type: integer
                        example: 50
                      backorderable:
                        type: boolean
  "/api/v3/admin/products/{product_id}/variants/{id}":
    get:
      summary: Get a variant
      tags:
      - Variants
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single variant by ID.

        **Required scope:** `read_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const variant = await client.products.variants.get('prod_86Rf07xd4z', 'variant_k5nR8xLq', {
            expand: ['prices', 'stock_items'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api get /products/{product_id}/variants/{id} -d '{"expand":["prices","stock_items"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Variant ID
        schema:
          type: string
      - name: expand
        in: query
        required: false
        description: Comma-separated associations to expand (e.g., images, prices,
          stock_items, option_values). Use dot notation for nested expand (max 4 levels).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include (e.g., sku,price,stock).
          id is always included.
        schema:
          type: string
      responses:
        '200':
          description: variant found
          content:
            application/json:
              example:
                id: variant_gbHJdmfrXB
                product_id: prod_UkLWZg9DAJ
                sku: SKU-110
                options_text: 'Size: S'
                track_inventory: true
                media_count: 0
                preorder_ships_at:
                thumbnail_url:
                purchasable: true
                in_stock: false
                backorderable: true
                preorder: false
                weight: 117.12
                height: 75.32
                width: 133.58
                depth: 44.31
                price:
                  id: price_gbHJdmfrXB
                  amount: '19.99'
                  amount_in_cents: 1999
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$19.99"
                  display_compare_at_amount:
                  price_list_id:
                original_price:
                option_values:
                - id: optval_UkLWZg9DAJ
                  option_type_id: opt_UkLWZg9DAJ
                  name: size-22
                  label: S
                  position: 1
                  color_code:
                  option_type_name: foo-size-31
                  option_type_label: Size
                  image_url:
                  metadata: {}
                  created_at: '2026-07-27T20:01:46.177Z'
                  updated_at: '2026-07-27T20:01:46.177Z'
                metadata: {}
                position: 2
                cost_price: '17.0'
                cost_currency: USD
                barcode:
                weight_unit: lb
                dimensions_unit:
                backorder_limit:
                deleted_at:
                created_at: '2026-07-27T20:01:46.175Z'
                updated_at: '2026-07-27T20:01:46.186Z'
                preorderable: false
                tax_category_id: taxcat_UkLWZg9DAJ
                available_stock: 0
                reserved_quantity: 0
                total_on_hand: 0
                product_name: Product 871094
        '404':
          description: variant not found
          content:
            application/json:
              example:
                error:
                  code: variant_not_found
                  message: Variant not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a variant
      tags:
      - Variants
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates a variant. Only provided fields are updated.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const variant = await client.products.variants.update('prod_86Rf07xd4z', 'variant_k5nR8xLq', {
            sku: 'UPDATED-SKU',
            stock_items: [
              { stock_location_id: 'sloc_UkLWZg9DAJ', count_on_hand: 75 },
            ],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /products/{product_id}/variants/{id} -d '{"sku":"UPDATED-SKU","stock_items":[{"stock_location_id":"sloc_UkLWZg9DAJ","count_on_hand":75}]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Variant ID
        schema:
          type: string
      responses:
        '200':
          description: variant updated
          content:
            application/json:
              example:
                id: variant_gbHJdmfrXB
                product_id: prod_UkLWZg9DAJ
                sku: UPDATED-SKU
                options_text: 'Size: S'
                track_inventory: true
                media_count: 0
                preorder_ships_at:
                thumbnail_url:
                purchasable: true
                in_stock: false
                backorderable: true
                preorder: false
                weight: 107.24
                height: 81.79
                width: 3.9
                depth: 36.62
                price:
                  id: price_gbHJdmfrXB
                  amount: '19.99'
                  amount_in_cents: 1999
                  compare_at_amount:
                  compare_at_amount_in_cents:
                  currency: USD
                  display_amount: "$19.99"
                  display_compare_at_amount:
                  price_list_id:
                original_price:
                option_values:
                - id: optval_UkLWZg9DAJ
                  option_type_id: opt_UkLWZg9DAJ
                  name: size-24
                  label: S
                  position: 1
                  color_code:
                  option_type_name: foo-size-33
                  option_type_label: Size
                  image_url:
                  metadata: {}
                  created_at: '2026-07-27T20:01:46.848Z'
                  updated_at: '2026-07-27T20:01:46.848Z'
                metadata: {}
                position: 2
                cost_price: '17.0'
                cost_currency: USD
                barcode:
                weight_unit: lb
                dimensions_unit:
                backorder_limit:
                deleted_at:
                created_at: '2026-07-27T20:01:46.845Z'
                updated_at: '2026-07-27T20:01:47.142Z'
                preorderable: false
                tax_category_id: taxcat_UkLWZg9DAJ
                available_stock: 0
                reserved_quantity: 0
                total_on_hand: 0
                product_name: Product 896054
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                sku:
                  type: string
                  example: SKU-001
                cost_price:
                  type: string
                  example: '10.00'
                cost_currency:
                  type: string
                  example: USD
                weight:
                  type: number
                height:
                  type: number
                width:
                  type: number
                depth:
                  type: number
                weight_unit:
                  type: string
                dimensions_unit:
                  type: string
                track_inventory:
                  type: boolean
                tax_category_id:
                  type: string
                options:
                  type: array
                  description: One pair per option type the variant participates in
                    (e.g. size + color). Option types and values are auto-created
                    if missing.
                  items:
                    type: object
                    required:
                    - name
                    - value
                    properties:
                      name:
                        type: string
                        example: size
                      value:
                        type: string
                        example: Small
                position:
                  type: integer
                barcode:
                  type: string
                prices:
                  type: array
                  description: Per-currency prices. Upserted by currency.
                  items:
                    type: object
                    required:
                    - currency
                    - amount
                    properties:
                      currency:
                        type: string
                        example: USD
                      amount:
                        type: string
                        example: '29.99'
                      compare_at_amount:
                        type: string
                        nullable: true
                        example: '39.99'
                stock_items:
                  type: array
                  description: Per-stock-location inventory. Upserted by stock_location_id.
                  items:
                    type: object
                    required:
                    - stock_location_id
                    - count_on_hand
                    properties:
                      stock_location_id:
                        type: string
                        description: Stock location ID (e.g. sloc_xxx)
                      count_on_hand:
                        type: integer
                        example: 50
                      backorderable:
                        type: boolean
    delete:
      summary: Delete a variant
      tags:
      - Variants
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes a variant.

        **Required scope:** `write_products` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.products.variants.delete('prod_86Rf07xd4z', 'variant_k5nR8xLq')
      - lang: bash
        label: Spree CLI
        source: spree api delete /products/{product_id}/variants/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: product_id
        in: path
        required: true
        description: Product ID
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Variant ID
        schema:
          type: string
      responses:
        '204':
          description: variant deleted
  "/api/v3/admin/webhook_endpoints/{webhook_endpoint_id}/deliveries":
    parameters:
    - name: webhook_endpoint_id
      in: path
      required: true
      description: Parent webhook endpoint ID
      schema:
        type: string
    get:
      summary: List webhook deliveries
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns delivery attempts for the given endpoint, most recent first.
        Each row carries the original request payload, the response code
        (when the receiver replied), the execution time, and any transport
        error — everything needed to audit failures and decide whether to
        redeliver.


        **Required scope:** `read_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const deliveries = await client.webhookEndpoints.deliveries.list('whe_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /webhook_endpoints/{webhook_endpoint_id}/deliveries
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[event_name_eq]
        in: query
        required: false
        description: Filter by event name (exact)
        schema:
          type: string
      - name: q[success_eq]
        in: query
        required: false
        description: Filter by success flag
        schema:
          type: boolean
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending (e.g., `-delivered_at`).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: deliveries found
          content:
            application/json:
              example:
                data:
                - id: whd_gbHJdmfrXB
                  event_name: order.created
                  event_id:
                  response_code: 500
                  execution_time: 200
                  error_type:
                  request_errors:
                  response_body:
                  success: false
                  created_at: '2026-07-27T20:01:47.791Z'
                  updated_at: '2026-07-27T20:01:47.791Z'
                  delivered_at: '2026-07-27T20:01:47.791Z'
                  payload:
                    event: order.created
                    data:
                      id: 1
                  webhook_endpoint_id: whe_UkLWZg9DAJ
                  webhook_endpoint_url: https://shop.example.com/webhooks
                - id: whd_UkLWZg9DAJ
                  event_name: order.created
                  event_id:
                  response_code: 200
                  execution_time: 150
                  error_type:
                  request_errors:
                  response_body:
                  success: true
                  created_at: '2026-07-27T20:01:47.790Z'
                  updated_at: '2026-07-27T20:01:47.790Z'
                  delivered_at: '2026-07-27T20:01:47.789Z'
                  payload:
                    event: order.created
                    data:
                      id: 1
                  webhook_endpoint_id: whe_UkLWZg9DAJ
                  webhook_endpoint_url: https://shop.example.com/webhooks
                meta:
                  page: 1
                  limit: 25
                  count: 2
                  pages: 1
                  from: 1
                  to: 2
                  in: 2
                  previous:
                  next:
        '404':
          description: parent webhook endpoint not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Webhook endpoint not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/admin/webhook_endpoints/{webhook_endpoint_id}/deliveries/{id}":
    parameters:
    - name: webhook_endpoint_id
      in: path
      required: true
      description: Parent webhook endpoint ID
      schema:
        type: string
    - name: id
      in: path
      required: true
      description: Webhook delivery ID
      schema:
        type: string
    get:
      summary: Get a webhook delivery
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single delivery attempt with the full request payload and
        the response body the receiver returned. Use this for ad-hoc debug
        of failed deliveries.


        **Required scope:** `read_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const delivery = await client.webhookEndpoints.deliveries.get('whe_xxx', 'whd_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /webhook_endpoints/{webhook_endpoint_id}/deliveries/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: delivery found
          content:
            application/json:
              example:
                id: whd_gbHJdmfrXB
                event_name: order.created
                event_id:
                response_code: 500
                execution_time: 200
                error_type:
                request_errors:
                response_body:
                success: false
                created_at: '2026-07-27T20:01:48.872Z'
                updated_at: '2026-07-27T20:01:48.872Z'
                delivered_at: '2026-07-27T20:01:48.872Z'
                payload:
                  event: order.created
                  data:
                    id: 1
                webhook_endpoint_id: whe_UkLWZg9DAJ
                webhook_endpoint_url: https://shop.example.com/webhooks
        '404':
          description: delivery not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Webhook delivery not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
  "/api/v3/admin/webhook_endpoints/{webhook_endpoint_id}/deliveries/{id}/redeliver":
    parameters:
    - name: webhook_endpoint_id
      in: path
      required: true
      description: Parent webhook endpoint ID
      schema:
        type: string
    - name: id
      in: path
      required: true
      description: Webhook delivery ID to redeliver
      schema:
        type: string
    post:
      summary: Redeliver a webhook delivery
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new delivery row with the same payload + event_name and
        queues it. The original row is preserved for audit history.


        **Required scope:** `write_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Creates a new delivery row with the same payload + event_name and queues
          // it. The original row is preserved for audit history.
          const delivery = await client.webhookEndpoints.deliveries.redeliver('whe_xxx', 'whd_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api post /webhook_endpoints/{webhook_endpoint_id}/deliveries/{id}/redeliver
          -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: redelivery queued
          content:
            application/json:
              example:
                id: whd_EfhxLZ9ck8
                event_name: order.created
                event_id:
                response_code:
                execution_time:
                error_type:
                request_errors:
                response_body:
                success:
                created_at: '2026-07-27T20:01:49.983Z'
                updated_at: '2026-07-27T20:01:49.983Z'
                delivered_at:
                payload:
                  event: order.created
                  data:
                    id: 1
                webhook_endpoint_id: whe_UkLWZg9DAJ
                webhook_endpoint_url: https://shop.example.com/webhooks
  "/api/v3/admin/webhook_endpoints":
    get:
      summary: List webhook endpoints
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns outbound webhook subscriptions for the current store. Each
        endpoint receives a signed POST when any subscribed event fires.
        `secret_key` is `null` on list reads — the plaintext is delivered
        exactly once on create.


        **Required scope:** `read_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const endpoints = await client.webhookEndpoints.list()
      - lang: bash
        label: Spree CLI
        source: spree api get /webhook_endpoints
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Number of records per page
        schema:
          type: integer
      - name: q[name_cont]
        in: query
        required: false
        description: Filter by name (contains)
        schema:
          type: string
      - name: q[url_cont]
        in: query
        required: false
        description: Filter by URL (contains)
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Sort by field. Prefix with `-` for descending (e.g., `-created_at`).
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: webhook endpoints found
          content:
            application/json:
              example:
                data:
                - id: whe_UkLWZg9DAJ
                  name: Order pipeline
                  url: https://shop.example.com/webhooks/orders
                  active: true
                  subscriptions:
                  - order.created
                  - order.completed
                  - product.created
                  disabled_reason:
                  created_at: '2026-07-27T20:01:50.024Z'
                  updated_at: '2026-07-27T20:01:50.024Z'
                  disabled_at:
                  secret_key:
                  last_delivery_at:
                  recent_delivery_count: 0
                  recent_failure_count: 0
                  total_delivery_count: 0
                  successful_delivery_count: 0
                  failed_delivery_count: 0
                meta:
                  page: 1
                  limit: 25
                  count: 1
                  pages: 1
                  from: 1
                  to: 1
                  in: 1
                  previous:
                  next:
        '401':
          description: unauthorized
          content:
            application/json:
              example:
                error:
                  code: authentication_required
                  message: Authentication required
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    post:
      summary: Create a webhook endpoint
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a new outbound webhook subscription. The plaintext
        `secret_key` is returned **once** in this response — persist it
        immediately to verify incoming webhook signatures. Subsequent reads
        return `null` for the secret. Pass an empty `subscriptions` array or
        omit it to receive every event.


        **Required scope:** `write_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const endpoint = await client.webhookEndpoints.create({
            name: 'Order pipeline',
            url: 'https://example.com/webhooks/orders',
            active: true,
            subscriptions: ['order.completed', 'order.canceled'],
          })

          // The plaintext `secret_key` is returned exactly once on create — persist it
          // immediately so you can verify incoming webhook signatures. Subsequent reads
          // will return `null`.
          const signingSecret = endpoint.secret_key
      - lang: bash
        label: Spree CLI
        source: spree api post /webhook_endpoints -d '{"name":"Order pipeline","url":"https://example.com/webhooks/orders","active":true,"subscriptions":["order.completed","order.canceled"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: webhook endpoint created — secret_key returned once
          content:
            application/json:
              example:
                id: whe_gbHJdmfrXB
                name: CI integration
                url: https://ci.example.com/webhooks
                active: true
                subscriptions:
                - order.completed
                disabled_reason:
                created_at: '2026-07-27T20:01:50.936Z'
                updated_at: '2026-07-27T20:01:50.936Z'
                disabled_at:
                secret_key: 90ad965cc1c4d99ff9b7d7cf3b8f926a4658097c48c0271d492a5b059fd1620b
                last_delivery_at:
                recent_delivery_count: 0
                recent_failure_count: 0
                total_delivery_count: 0
                successful_delivery_count: 0
                failed_delivery_count: 0
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: |-
                    Url Translation missing. Options considered were:
                    - en.activerecord.errors.models.spree/webhook_endpoint.attributes.url.invalid_url
                    - en.activerecord.errors.models.spree/webhook_endpoint.invalid_url
                    - en.activerecord.errors.messages.invalid_url
                    - en.errors.attributes.url.invalid_url
                    - en.errors.messages.invalid_url
                  details:
                    url:
                    - |-
                      Translation missing. Options considered were:
                      - en.activerecord.errors.models.spree/webhook_endpoint.attributes.url.invalid_url
                      - en.activerecord.errors.models.spree/webhook_endpoint.invalid_url
                      - en.activerecord.errors.messages.invalid_url
                      - en.errors.attributes.url.invalid_url
                      - en.errors.messages.invalid_url
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - url
              properties:
                name:
                  type: string
                  example: Order pipeline
                url:
                  type: string
                  example: https://example.com/webhooks/orders
                active:
                  type: boolean
                  example: true
                subscriptions:
                  type: array
                  items:
                    type: string
                  example:
                  - order.completed
                  - order.canceled
  "/api/v3/admin/webhook_endpoints/{id}":
    parameters:
    - name: id
      in: path
      required: true
      description: Webhook endpoint ID
      schema:
        type: string
    get:
      summary: Get a webhook endpoint
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Returns a single webhook endpoint by prefixed ID.

        **Required scope:** `read_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const endpoint = await client.webhookEndpoints.get('whe_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api get /webhook_endpoints/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Comma-separated list of fields to include. id is always included.
        schema:
          type: string
      responses:
        '200':
          description: webhook endpoint found
          content:
            application/json:
              example:
                id: whe_UkLWZg9DAJ
                name: Order pipeline
                url: https://shop.example.com/webhooks/orders
                active: true
                subscriptions:
                - order.created
                - order.completed
                - product.created
                disabled_reason:
                created_at: '2026-07-27T20:01:51.455Z'
                updated_at: '2026-07-27T20:01:51.455Z'
                disabled_at:
                secret_key:
                last_delivery_at:
                recent_delivery_count: 0
                recent_failure_count: 0
                total_delivery_count: 0
                successful_delivery_count: 0
                failed_delivery_count: 0
        '404':
          description: webhook endpoint not found
          content:
            application/json:
              example:
                error:
                  code: record_not_found
                  message: Webhook endpoint not found
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
    patch:
      summary: Update a webhook endpoint
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Updates name, URL, active flag, or the event subscription list.
        Toggling `active` here is equivalent to calling `disable`/`enable`
        without an audit reason.


        **Required scope:** `write_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          const endpoint = await client.webhookEndpoints.update('whe_xxx', {
            name: 'Order pipeline (v2)',
            subscriptions: ['order.completed', 'order.canceled', 'order.paid'],
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /webhook_endpoints/{id} -d '{"name":"Order pipeline
          (v2)","subscriptions":["order.completed","order.canceled","order.paid"]}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: webhook endpoint updated
          content:
            application/json:
              example:
                id: whe_UkLWZg9DAJ
                name: Order pipeline (renamed)
                url: https://shop.example.com/webhooks/orders
                active: true
                subscriptions:
                - order.created
                - order.completed
                - product.created
                disabled_reason:
                created_at: '2026-07-27T20:01:52.504Z'
                updated_at: '2026-07-27T20:01:52.803Z'
                disabled_at:
                secret_key:
                last_delivery_at:
                recent_delivery_count: 0
                recent_failure_count: 0
                total_delivery_count: 0
                successful_delivery_count: 0
                failed_delivery_count: 0
        '422':
          description: validation error
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: |-
                    Url Translation missing. Options considered were:
                    - en.activerecord.errors.models.spree/webhook_endpoint.attributes.url.invalid_url
                    - en.activerecord.errors.models.spree/webhook_endpoint.invalid_url
                    - en.activerecord.errors.messages.invalid_url
                    - en.errors.attributes.url.invalid_url
                    - en.errors.messages.invalid_url
                  details:
                    url:
                    - |-
                      Translation missing. Options considered were:
                      - en.activerecord.errors.models.spree/webhook_endpoint.attributes.url.invalid_url
                      - en.activerecord.errors.models.spree/webhook_endpoint.invalid_url
                      - en.activerecord.errors.messages.invalid_url
                      - en.errors.attributes.url.invalid_url
                      - en.errors.messages.invalid_url
              schema:
                "$ref": "#/components/schemas/ErrorResponse"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                url:
                  type: string
                active:
                  type: boolean
                subscriptions:
                  type: array
                  items:
                    type: string
    delete:
      summary: Delete a webhook endpoint
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Soft-deletes the endpoint and stops future deliveries.

        **Required scope:** `write_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          await client.webhookEndpoints.delete('whe_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api delete /webhook_endpoints/{id}
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '204':
          description: webhook endpoint deleted
  "/api/v3/admin/webhook_endpoints/{id}/send_test":
    parameters:
    - name: id
      in: path
      required: true
      description: Webhook endpoint ID
      schema:
        type: string
    post:
      summary: Send a test delivery
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Creates a `webhook.test` delivery record and queues it. Use this to
        verify the endpoint is reachable and your signature verification
        accepts Spree's payloads.


        **Required scope:** `write_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Fires a synthetic `webhook.test` delivery so you can verify the endpoint is
          // reachable and your signature-verification code accepts Spree's payloads.
          const delivery = await client.webhookEndpoints.sendTest('whe_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api post /webhook_endpoints/{id}/send_test -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '201':
          description: test delivery queued
          content:
            application/json:
              example:
                id: whd_UkLWZg9DAJ
                event_name: webhook.test
                event_id:
                response_code:
                execution_time:
                error_type:
                request_errors:
                response_body:
                success:
                created_at: '2026-07-27T20:01:54.161Z'
                updated_at: '2026-07-27T20:01:54.161Z'
                delivered_at:
                payload:
                  id: e8144392-1d31-4f81-9f14-2dda90cc63f9
                  name: webhook.test
                  created_at: '2026-07-27T20:01:54Z'
                  data:
                    message: This is a test webhook from Spree.
                  metadata:
                    spree_version: 5.6.0
                webhook_endpoint_id: whe_UkLWZg9DAJ
                webhook_endpoint_url: https://shop.example.com/webhooks/orders
  "/api/v3/admin/webhook_endpoints/{id}/enable":
    parameters:
    - name: id
      in: path
      required: true
      description: Webhook endpoint ID
      schema:
        type: string
    patch:
      summary: Re-enable a webhook endpoint
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Re-enables an endpoint that was manually or automatically disabled.

        **Required scope:** `write_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Re-enable an endpoint that was auto-disabled after repeated delivery failures.
          const endpoint = await client.webhookEndpoints.enable('whe_xxx')
      - lang: bash
        label: Spree CLI
        source: spree api patch /webhook_endpoints/{id}/enable -d '{ ... }'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: webhook endpoint enabled
          content:
            application/json:
              example:
                id: whe_UkLWZg9DAJ
                name: Order pipeline
                url: https://shop.example.com/webhooks/orders
                active: true
                subscriptions:
                - order.created
                - order.completed
                - product.created
                disabled_reason:
                created_at: '2026-07-27T20:01:54.198Z'
                updated_at: '2026-07-27T20:01:54.477Z'
                disabled_at:
                secret_key:
                last_delivery_at:
                recent_delivery_count: 0
                recent_failure_count: 0
                total_delivery_count: 0
                successful_delivery_count: 0
                failed_delivery_count: 0
  "/api/v3/admin/webhook_endpoints/{id}/disable":
    parameters:
    - name: id
      in: path
      required: true
      description: Webhook endpoint ID
      schema:
        type: string
    patch:
      summary: Disable a webhook endpoint
      tags:
      - Webhooks
      security:
      - api_key: []
        bearer_auth: []
      description: |-
        Manually pauses an endpoint. Unlike auto-disable (triggered after
        repeated delivery failures), no notification email is sent.


        **Required scope:** `write_webhooks` (for API-key authentication).
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: |-
          import { createAdminClient } from '@spree/admin-sdk'

          const client = createAdminClient({
            baseUrl: 'https://your-store.com',
            secretKey: 'sk_xxx',
          })

          // Pause an endpoint without deleting it. The optional `reason` is shown next
          // to the disabled indicator in the admin.
          const endpoint = await client.webhookEndpoints.disable('whe_xxx', {
            reason: 'Investigating elevated 5xx rate',
          })
      - lang: bash
        label: Spree CLI
        source: spree api patch /webhook_endpoints/{id}/disable -d '{"reason":"Investigating
          elevated 5xx rate"}'
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: Authorization
        in: header
        required: true
        description: Bearer token for admin authentication
        schema:
          type: string
      responses:
        '200':
          description: webhook endpoint disabled
          content:
            application/json:
              example:
                id: whe_UkLWZg9DAJ
                name: Order pipeline
                url: https://shop.example.com/webhooks/orders
                active: false
                subscriptions:
                - order.created
                - order.completed
                - product.created
                disabled_reason: Investigating
                created_at: '2026-07-27T20:01:54.602Z'
                updated_at: '2026-07-27T20:01:54.891Z'
                disabled_at: '2026-07-27T20:01:54.891Z'
                secret_key:
                last_delivery_at:
                recent_delivery_count: 0
                recent_failure_count: 0
                total_delivery_count: 0
                successful_delivery_count: 0
                failed_delivery_count: 0
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  example: Investigating elevated 5xx rate
servers:
- url: http://{defaultHost}
  variables:
    defaultHost:
      default: localhost:3000
tags:
- name: Authentication
  description: Admin user login, logout, token refresh, and current user profile
- name: Allowed Origins
  description: CORS allowlist for storefront and admin client origins
- name: API Keys
  description: Secret and publishable API keys
- name: Categories
  description: Hierarchical product categories — tree management, repositioning, and
    product assignments
- name: Channels
  description: Sales channels, product publication across channels, and per-channel
    order routing rules
- name: Custom Fields
  description: Custom field definitions for products, variants, customers, and other
    resources
- name: Customer Groups
  description: Customer groups for segmenting customers (e.g. wholesale, VIP) used
    by pricing and promotions
- name: Customers
  description: Customer profiles, addresses, credit cards, and store credits
- name: Exports
  description: Async CSV exports of admin resources
- name: Fulfillments
  description: Order fulfillments — shipments, fulfill, cancel, resume, split
- name: Gift Cards
  description: Gift cards and gift card batches
- name: Imports
  description: Async CSV imports of admin resources, with per-row status and failed-row
    retry
- name: Markets
  description: Markets — geographic groupings of countries used for pricing, tax,
    and fulfillment rules
- name: Option Types
  description: Option types and option values used to build product variants (e.g.
    Size, Color)
- name: Orders
  description: Orders, order items, applied gift cards, and applied store credits
- name: Payment Methods
  description: Configured payment providers and their available types
- name: Payments
  description: Order payments — list, capture, void
- name: Pricing
  description: Prices and price lists for currency-, market-, and customer-group-specific
    pricing
- name: Products
  description: Products, taxons/categories, product custom field values, and bulk
    product operations
- name: Promotions
  description: Promotions, promotion rules, promotion actions, and coupon codes
- name: Refunds
  description: Order refunds
- name: Settings
  description: Store-level settings — store profile, tags, store credit categories
- name: Staff
  description: Admin users, roles, and invitations to the store
- name: Stock Locations
  description: Warehouses and physical fulfillment locations
- name: Variants
  description: Product variants — the individual SKUs (size/color combinations) sold
    under a product
- name: Webhooks
  description: Webhook endpoints and webhook delivery history
components:
  securitySchemes:
    api_key:
      type: apiKey
      name: x-spree-api-key
      in: header
      description: Secret API key for admin access
    bearer_auth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token for admin user authentication
  schemas:
    PaginationMeta:
      type: object
      properties:
        page:
          type: integer
          example: 1
        limit:
          type: integer
          example: 25
        count:
          type: integer
          example: 100
          description: Total number of records
        pages:
          type: integer
          example: 4
          description: Total number of pages
        from:
          type: integer
          example: 1
          description: Index of first record on this page
        to:
          type: integer
          example: 25
          description: Index of last record on this page
        in:
          type: integer
          example: 25
          description: Number of records on this page
        previous:
          type: integer
          nullable: true
          example:
          description: Previous page number
        next:
          type: integer
          nullable: true
          example: 2
          description: Next page number
      required:
      - page
      - limit
      - count
      - pages
      - from
      - to
      - in
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: record_not_found
            message:
              type: string
              example: Record not found
            details:
              type: object
              description: Field-specific validation errors
              nullable: true
              example:
                name:
                - is too short
                - is required
                email:
                - is invalid
          required:
          - code
          - message
      required:
      - error
      example:
        error:
          code: validation_error
          message: Validation failed
          details:
            name:
            - is too short
            email:
            - is invalid
    AuthResponse:
      type: object
      properties:
        token:
          type: string
          description: JWT access token
        user:
          "$ref": "#/components/schemas/AdminUser"
      required:
      - token
      - user
    PermissionRule:
      type: object
      description: A single permission rule (CanCanCan rule). Rules are applied in
        order, last-matching-wins.
      properties:
        allow:
          type: boolean
          description: true for `can`, false for `cannot`
        actions:
          type: array
          items:
            type: string
          description: Action names, e.g. ["read", "update"] or ["manage"]
        subjects:
          type: array
          items:
            type: string
          description: Subject class names, e.g. ["Spree::Product"] or ["all"]
        has_conditions:
          type: boolean
          description: True if the server-side rule has per-record conditions. The
            SPA shows the action optimistically and handles 403 from the API.
      required:
      - allow
      - actions
      - subjects
      - has_conditions
    MeResponse:
      type: object
      description: Current admin user profile and serialized permissions
      properties:
        user:
          "$ref": "#/components/schemas/AdminUser"
        permissions:
          type: array
          items:
            "$ref": "#/components/schemas/PermissionRule"
      required:
      - user
      - permissions
    ImportSchemaField:
      type: object
      description: A canonical column of an import type, including per-store custom
        field columns
      properties:
        name:
          type: string
          description: Canonical field name used in mappings
          example: slug
        label:
          type: string
          description: Human-readable label
          example: Slug
        required:
          type: boolean
          description: Whether the field must be mapped before processing
      required:
      - name
      - label
      - required
    CheckoutRequirement:
      type: object
      properties:
        step:
          type: string
          description: Checkout step this requirement belongs to
          example: payment
        field:
          type: string
          description: Field that needs to be satisfied
          example: payment
        message:
          type: string
          description: Human-readable requirement message
          example: Add a payment method
      required:
      - step
      - field
      - message
    CartWarning:
      type: object
      description: A warning about a cart issue (e.g., item removed due to stock change)
      properties:
        code:
          type: string
          description: Machine-readable warning code
          example: line_item_removed
        message:
          type: string
          description: Human-readable warning message
          example: Blue T-Shirt was removed because it was sold out
        line_item_id:
          type: string
          nullable: true
          description: Prefixed line item ID (when applicable)
          example: li_abc123
        variant_id:
          type: string
          nullable: true
          description: Prefixed variant ID (when applicable)
          example: variant_abc123
      required:
      - code
      - message
    FulfillmentManifestItem:
      type: object
      description: An item within a fulfillment — which line item and how many units
        are in this fulfillment
      properties:
        item_id:
          type: string
          description: Line item ID
          example: li_abc123
        variant_id:
          type: string
          description: Variant ID
          example: variant_abc123
        quantity:
          type: integer
          description: Quantity in this fulfillment
          example: 2
      required:
      - item_id
      - variant_id
      - quantity
    AdminUserRoleAssignment:
      type: object
      description: A role assignment for the current store on a staff member
      properties:
        id:
          type: string
          description: Prefixed role ID
          example: role_abc123
        name:
          type: string
          description: Role name
          example: admin
      required:
      - id
      - name
    AdminUserStore:
      type: object
      description: A store the staff member can access through a role assignment
      properties:
        id:
          type: string
          description: Prefixed store ID
          example: store_abc123
        name:
          type: string
          description: Store name
          example: My Store
        code:
          type: string
          description: Store code
          example: my-store
      required:
      - id
      - name
      - code
    PreferenceField:
      type: object
      description: A single configurable preference on a payment method, promotion
        rule/action, or calculator. The frontend uses `type` + `default` to render
        a sensible input.
      properties:
        key:
          type: string
          example: amount_min
        type:
          type: string
          example: decimal
          description: string | text | password | integer | decimal | boolean | array
            | hash
        default:
          description: Default value (any JSON type), null when there is no default
          nullable: true
      required:
      - key
      - type
    PromotionActionCalculator:
      type: object
      description: The action's nested calculator (when the action carries one — null
        for actions like `free_shipping`)
      properties:
        type:
          type: string
          example: flat_rate
          description: Wire shorthand for the calculator subclass
        label:
          type: string
          example: Flat Rate
        preferences:
          type: object
          additionalProperties: true
        preference_schema:
          type: array
          items:
            "$ref": "#/components/schemas/PreferenceField"
      required:
      - type
      - label
      - preferences
      - preference_schema
    PromotionActionLineItem:
      type: object
      description: One row in a `create_line_items` action — the variant added to
        the order and how many
      properties:
        variant_id:
          type: string
          example: variant_abc123
        quantity:
          type: integer
          example: 1
      required:
      - variant_id
      - quantity
    Address:
      type: object
      properties:
        id:
          type: string
        first_name:
          type: string
          nullable: true
        last_name:
          type: string
          nullable: true
        full_name:
          type: string
        address1:
          type: string
          nullable: true
        address2:
          type: string
          nullable: true
        postal_code:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        company:
          type: string
          nullable: true
        country_name:
          type: string
        country_iso:
          type: string
        state_text:
          type: string
          nullable: true
        state_abbr:
          type: string
          nullable: true
        quick_checkout:
          type: boolean
        is_default_billing:
          type: boolean
        is_default_shipping:
          type: boolean
        state_name:
          type: string
          nullable: true
        label:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        customer_id:
          type: string
          nullable: true
      required:
      - id
      - first_name
      - last_name
      - full_name
      - address1
      - address2
      - postal_code
      - city
      - phone
      - company
      - country_name
      - country_iso
      - state_text
      - state_abbr
      - quick_checkout
      - is_default_billing
      - is_default_shipping
      - state_name
      - label
      - metadata
      - created_at
      - updated_at
      - customer_id
      x-typelizer: true
    Adjustment:
      type: object
      properties:
        id:
          type: string
        label:
          type: string
        display_amount:
          type: string
        included:
          type: boolean
        created_at:
          type: string
        updated_at:
          type: string
        amount:
          type: string
        order_id:
          type: string
          nullable: true
      required:
      - id
      - label
      - display_amount
      - included
      - created_at
      - updated_at
      - amount
      - order_id
      x-typelizer: true
    AdminUser:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        first_name:
          type: string
          nullable: true
        last_name:
          type: string
          nullable: true
        full_name:
          type: string
          nullable: true
        selected_locale:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        avatar_url:
          type: string
          nullable: true
        roles:
          type: array
          items:
            "$ref": "#/components/schemas/AdminUserRoleAssignment"
        stores:
          type: array
          items:
            "$ref": "#/components/schemas/AdminUserStore"
      required:
      - id
      - email
      - first_name
      - last_name
      - full_name
      - selected_locale
      - created_at
      - updated_at
      - avatar_url
      - roles
      - stores
      x-typelizer: true
    AllowedOrigin:
      type: object
      properties:
        id:
          type: string
        origin:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - origin
      - created_at
      - updated_at
      x-typelizer: true
    ApiKey:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        key_type:
          type: string
        token_prefix:
          type: string
          nullable: true
        scopes:
          type: array
          items:
            type: string
        created_at:
          type: string
        updated_at:
          type: string
        revoked_at:
          type: string
          nullable: true
        last_used_at:
          type: string
          nullable: true
        channel_id:
          type: string
          nullable: true
        plaintext_token:
          type: string
          nullable: true
        created_by_email:
          type: string
          nullable: true
      required:
      - id
      - name
      - key_type
      - token_prefix
      - scopes
      - created_at
      - updated_at
      - revoked_at
      - last_used_at
      - channel_id
      - plaintext_token
      - created_by_email
      x-typelizer: true
    Category:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        permalink:
          type: string
        position:
          type: number
        depth:
          type: number
        meta_title:
          type: string
          nullable: true
        meta_description:
          type: string
          nullable: true
        meta_keywords:
          type: string
          nullable: true
        children_count:
          type: number
        parent_id:
          type: string
          nullable: true
        description:
          type: string
        description_html:
          type: string
        image_url:
          type: string
          nullable: true
        square_image_url:
          type: string
          nullable: true
        is_root:
          type: boolean
        is_child:
          type: boolean
        is_leaf:
          type: boolean
        parent:
          "$ref": "#/components/schemas/Category"
        children:
          type: array
          items:
            "$ref": "#/components/schemas/Category"
        ancestors:
          type: array
          items:
            "$ref": "#/components/schemas/Category"
        custom_fields:
          type: array
          items:
            "$ref": "#/components/schemas/CustomField"
        translations:
          type: object
        metadata:
          type: object
        pretty_name:
          type: string
        lft:
          type: number
        rgt:
          type: number
        products_count:
          type: number
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - name
      - permalink
      - position
      - depth
      - meta_title
      - meta_description
      - meta_keywords
      - children_count
      - parent_id
      - description
      - description_html
      - image_url
      - square_image_url
      - is_root
      - is_child
      - is_leaf
      - metadata
      - pretty_name
      - lft
      - rgt
      - products_count
      - created_at
      - updated_at
      x-typelizer: true
    Channel:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        code:
          type: string
        active:
          type: boolean
        default:
          type: boolean
        storefront_access:
          type: string
        guest_checkout:
          type: boolean
        preferred_order_routing_strategy:
          type: string
          nullable: true
        preferred_storefront_access:
          type: string
          nullable: true
        preferred_guest_checkout:
          type: boolean
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - name
      - code
      - active
      - default
      - storefront_access
      - guest_checkout
      - preferred_order_routing_strategy
      - preferred_storefront_access
      - preferred_guest_checkout
      - created_at
      - updated_at
      x-typelizer: true
    Country:
      type: object
      properties:
        iso:
          type: string
        iso3:
          type: string
        name:
          type: string
        states_required:
          type: boolean
        zipcode_required:
          type: boolean
        states:
          type: array
          items:
            "$ref": "#/components/schemas/State"
        market:
          allOf:
          - "$ref": "#/components/schemas/Market"
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - iso
      - iso3
      - name
      - states_required
      - zipcode_required
      - created_at
      - updated_at
      x-typelizer: true
    CouponCode:
      type: object
      properties:
        id:
          type: string
        code:
          type: string
        state:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        promotion_id:
          type: string
        order_id:
          type: string
          nullable: true
      required:
      - id
      - code
      - state
      - created_at
      - updated_at
      - promotion_id
      - order_id
      x-typelizer: true
    CreditCard:
      type: object
      properties:
        id:
          type: string
        brand:
          type: string
        last4:
          type: string
        month:
          type: number
        year:
          type: number
        name:
          type: string
          nullable: true
        default:
          type: boolean
        gateway_payment_profile_id:
          type: string
          nullable: true
        customer_id:
          type: string
          nullable: true
        payment_method_id:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - brand
      - last4
      - month
      - year
      - name
      - default
      - gateway_payment_profile_id
      - customer_id
      - payment_method_id
      - metadata
      - created_at
      - updated_at
      x-typelizer: true
    CustomFieldDefinition:
      type: object
      properties:
        id:
          type: string
        namespace:
          type: string
        key:
          type: string
        label:
          type: string
        field_type:
          type: string
          enum:
          - short_text
          - long_text
          - rich_text
          - number
          - boolean
          - json
        resource_type:
          type: string
        storefront_visible:
          type: boolean
        searchable:
          type: boolean
        sortable:
          type: boolean
        filter_key:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - namespace
      - key
      - label
      - field_type
      - resource_type
      - storefront_visible
      - searchable
      - sortable
      - filter_key
      - created_at
      - updated_at
      x-typelizer: true
    CustomField:
      type: object
      properties:
        id:
          type: string
        label:
          type: string
        type:
          type: string
          deprecated: true
        field_type:
          type: string
          enum:
          - short_text
          - long_text
          - rich_text
          - number
          - boolean
          - json
        key:
          type: string
        value:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        storefront_visible:
          type: boolean
        custom_field_definition_id:
          type: string
      required:
      - id
      - label
      - type
      - field_type
      - key
      - value
      - created_at
      - updated_at
      - storefront_visible
      - custom_field_definition_id
      x-typelizer: true
    CustomerGroup:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        customers_count:
          type: number
        created_at:
          type: string
        updated_at:
          type: string
        customers:
          type: array
          items:
            "$ref": "#/components/schemas/Customer"
      required:
      - id
      - name
      - description
      - customers_count
      - created_at
      - updated_at
      x-typelizer: true
    Customer:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        first_name:
          type: string
          nullable: true
        last_name:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        accepts_email_marketing:
          type: boolean
        full_name:
          type: string
        available_store_credit_total:
          type: string
        display_available_store_credit_total:
          type: string
        addresses:
          type: array
          items:
            "$ref": "#/components/schemas/Address"
        default_billing_address:
          allOf:
          - "$ref": "#/components/schemas/Address"
          nullable: true
        default_shipping_address:
          allOf:
          - "$ref": "#/components/schemas/Address"
          nullable: true
        newsletter_subscriber:
          allOf:
          - "$ref": "#/components/schemas/NewsletterSubscriber"
          nullable: true
        customer_groups:
          type: array
          items:
            "$ref": "#/components/schemas/CustomerGroup"
        login:
          type: string
          nullable: true
        metadata:
          type: object
        last_sign_in_at:
          type: string
          nullable: true
        current_sign_in_at:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        sign_in_count:
          type: number
        failed_attempts:
          type: number
        last_sign_in_ip:
          type: string
          nullable: true
        current_sign_in_ip:
          type: string
          nullable: true
        tags:
          type: array
          items:
            type: string
        internal_note_html:
          type: string
          nullable: true
        default_billing_address_id:
          type: string
          nullable: true
        default_shipping_address_id:
          type: string
          nullable: true
        orders_count:
          type: number
        total_spent:
          type: string
        display_total_spent:
          type: string
        last_order_completed_at:
          type: string
          nullable: true
        orders:
          type: array
          items:
            "$ref": "#/components/schemas/Order"
        store_credits:
          type: array
          items:
            "$ref": "#/components/schemas/StoreCredit"
        customer_group_ids:
          type: array
          items:
            type: string
      required:
      - id
      - email
      - first_name
      - last_name
      - phone
      - accepts_email_marketing
      - full_name
      - available_store_credit_total
      - display_available_store_credit_total
      - login
      - metadata
      - last_sign_in_at
      - current_sign_in_at
      - created_at
      - updated_at
      - sign_in_count
      - failed_attempts
      - last_sign_in_ip
      - current_sign_in_ip
      - tags
      - internal_note_html
      - default_billing_address_id
      - default_shipping_address_id
      - orders_count
      - total_spent
      - display_total_spent
      - last_order_completed_at
      - customer_group_ids
      x-typelizer: true
    DeliveryMethod:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        code:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - name
      - code
      - created_at
      - updated_at
      x-typelizer: true
    DeliveryRate:
      type: object
      properties:
        id:
          type: string
        delivery_method_id:
          type: string
        name:
          type: string
        selected:
          type: boolean
        cost:
          type: string
        total:
          type: string
        additional_tax_total:
          type: string
        included_tax_total:
          type: string
        tax_total:
          type: string
        display_cost:
          type: string
        display_total:
          type: string
        display_additional_tax_total:
          type: string
        display_included_tax_total:
          type: string
        display_tax_total:
          type: string
        delivery_method:
          "$ref": "#/components/schemas/DeliveryMethod"
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - delivery_method_id
      - name
      - selected
      - cost
      - total
      - additional_tax_total
      - included_tax_total
      - tax_total
      - display_cost
      - display_total
      - display_additional_tax_total
      - display_included_tax_total
      - display_tax_total
      - created_at
      - updated_at
      x-typelizer: true
    DigitalLink:
      type: object
      properties:
        id:
          type: string
        access_counter:
          type: number
        filename:
          type: string
        content_type:
          type: string
        download_url:
          type: string
        authorizable:
          type: boolean
        expired:
          type: boolean
        access_limit_exceeded:
          type: boolean
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - access_counter
      - filename
      - content_type
      - download_url
      - authorizable
      - expired
      - access_limit_exceeded
      - created_at
      - updated_at
      x-typelizer: true
    Discount:
      type: object
      properties:
        id:
          type: string
        promotion_id:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        code:
          type: string
          nullable: true
        amount:
          type: string
        display_amount:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - promotion_id
      - name
      - description
      - code
      - amount
      - display_amount
      - created_at
      - updated_at
      x-typelizer: true
    Export:
      type: object
      properties:
        id:
          type: string
        number:
          type: string
        format:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        type:
          type: string
          nullable: true
        user_id:
          type: string
          nullable: true
        done:
          type: boolean
        filename:
          type: string
          nullable: true
        byte_size:
          type: number
          nullable: true
        download_url:
          type: string
          nullable: true
      required:
      - id
      - number
      - format
      - created_at
      - updated_at
      - type
      - user_id
      - done
      - filename
      - byte_size
      - download_url
      x-typelizer: true
    Fulfillment:
      type: object
      properties:
        id:
          type: string
        number:
          type: string
        tracking:
          type: string
          nullable: true
        tracking_url:
          type: string
          nullable: true
        cost:
          type: string
        display_cost:
          type: string
        total:
          type: string
        display_total:
          type: string
        discount_total:
          type: string
        display_discount_total:
          type: string
        additional_tax_total:
          type: string
        display_additional_tax_total:
          type: string
        included_tax_total:
          type: string
        display_included_tax_total:
          type: string
        tax_total:
          type: string
        display_tax_total:
          type: string
        status:
          type: string
        fulfillment_type:
          type: string
        fulfilled_at:
          type: string
          nullable: true
        items:
          type: array
          items:
            "$ref": "#/components/schemas/FulfillmentManifestItem"
        delivery_method:
          "$ref": "#/components/schemas/DeliveryMethod"
        stock_location:
          "$ref": "#/components/schemas/StockLocation"
        delivery_rates:
          type: array
          items:
            "$ref": "#/components/schemas/DeliveryRate"
        metadata:
          type: object
        adjustment_total:
          type: string
        pre_tax_amount:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        order_id:
          type: string
          nullable: true
        stock_location_id:
          type: string
          nullable: true
        order:
          "$ref": "#/components/schemas/Order"
        adjustments:
          type: array
          items:
            "$ref": "#/components/schemas/Adjustment"
      required:
      - id
      - number
      - tracking
      - tracking_url
      - cost
      - display_cost
      - total
      - display_total
      - discount_total
      - display_discount_total
      - additional_tax_total
      - display_additional_tax_total
      - included_tax_total
      - display_included_tax_total
      - tax_total
      - display_tax_total
      - status
      - fulfillment_type
      - fulfilled_at
      - items
      - metadata
      - adjustment_total
      - pre_tax_amount
      - created_at
      - updated_at
      - order_id
      - stock_location_id
      x-typelizer: true
    GiftCardBatch:
      type: object
      properties:
        id:
          type: string
        codes_count:
          type: number
        currency:
          type: string
          nullable: true
        prefix:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        amount:
          type: string
          nullable: true
        expires_at:
          type: string
          nullable: true
        created_by_id:
          type: string
          nullable: true
      required:
      - id
      - codes_count
      - currency
      - prefix
      - created_at
      - updated_at
      - amount
      - expires_at
      - created_by_id
      x-typelizer: true
    GiftCard:
      type: object
      properties:
        id:
          type: string
        code:
          type: string
        status:
          type: string
        currency:
          type: string
        amount:
          type: string
        amount_used:
          type: string
        amount_authorized:
          type: string
        amount_remaining:
          type: string
        display_amount:
          type: string
        display_amount_used:
          type: string
        display_amount_remaining:
          type: string
        expires_at:
          type: string
          nullable: true
        redeemed_at:
          type: string
          nullable: true
        expired:
          type: boolean
        active:
          type: boolean
        created_at:
          type: string
        updated_at:
          type: string
        customer_id:
          type: string
          nullable: true
        created_by_id:
          type: string
          nullable: true
        customer:
          "$ref": "#/components/schemas/Customer"
        created_by:
          "$ref": "#/components/schemas/AdminUser"
        gift_card_batch:
          "$ref": "#/components/schemas/GiftCardBatch"
        orders:
          type: array
          items:
            "$ref": "#/components/schemas/Order"
      required:
      - id
      - code
      - status
      - currency
      - amount
      - amount_used
      - amount_authorized
      - amount_remaining
      - display_amount
      - display_amount_used
      - display_amount_remaining
      - expires_at
      - redeemed_at
      - expired
      - active
      - created_at
      - updated_at
      - customer_id
      - created_by_id
      x-typelizer: true
    ImportMapping:
      type: object
      properties:
        id:
          type: string
        schema_field:
          type: string
        file_column:
          type: string
          nullable: true
        required:
          type: boolean
      required:
      - id
      - schema_field
      - file_column
      - required
      x-typelizer: true
    ImportRow:
      type: object
      properties:
        id:
          type: string
        row_number:
          type: number
        status:
          type: string
        validation_errors:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        import_id:
          type: string
          nullable: true
        item_type:
          type: string
          nullable: true
        item_id:
          type: string
          nullable: true
        data:
          type: object
      required:
      - id
      - row_number
      - status
      - validation_errors
      - created_at
      - updated_at
      - import_id
      - item_type
      - item_id
      - data
      x-typelizer: true
    Import:
      type: object
      properties:
        id:
          type: string
        number:
          type: string
        rows_count:
          type: number
        created_at:
          type: string
        updated_at:
          type: string
        type:
          type: string
          nullable: true
        status:
          type: string
        owner_type:
          type: string
          nullable: true
        owner_id:
          type: string
          nullable: true
        user_id:
          type: string
          nullable: true
        processing_errors:
          type: string
          nullable: true
        preferred_delimiter:
          type: string
        original_filename:
          type: string
          nullable: true
        original_byte_size:
          type: number
          nullable: true
        original_file_url:
          type: string
          nullable: true
        completed_rows_count:
          type: number
        failed_rows_count:
          type: number
        schema_fields:
          type: array
          items:
            "$ref": "#/components/schemas/ImportSchemaField"
        csv_headers:
          type: array
          items:
            type: string
        sample_row:
          type: object
        mappings:
          type: array
          items:
            "$ref": "#/components/schemas/ImportMapping"
      required:
      - id
      - number
      - rows_count
      - created_at
      - updated_at
      - type
      - status
      - owner_type
      - owner_id
      - user_id
      - processing_errors
      - preferred_delimiter
      - original_filename
      - original_byte_size
      - original_file_url
      - completed_rows_count
      - failed_rows_count
      - schema_fields
      - csv_headers
      - sample_row
      - mappings
      x-typelizer: true
    Invitation:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        status:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        expires_at:
          type: string
        role_id:
          type: string
        role_name:
          type: string
        inviter_email:
          type: string
        acceptance_url:
          type: string
        invitee_exists:
          type: boolean
        store:
          type: object
      required:
      - id
      - email
      - status
      - created_at
      - updated_at
      - expires_at
      - role_id
      - role_name
      - inviter_email
      - acceptance_url
      - invitee_exists
      - store
      x-typelizer: true
    LineItem:
      type: object
      properties:
        id:
          type: string
        variant_id:
          type: string
        preorder:
          type: boolean
        preorder_ships_at:
          type: string
          nullable: true
        quantity:
          type: number
        currency:
          type: string
        name:
          type: string
        slug:
          type: string
        options_text:
          type: string
        price:
          type: string
        display_price:
          type: string
        total:
          type: string
        display_total:
          type: string
        adjustment_total:
          type: string
        display_adjustment_total:
          type: string
        additional_tax_total:
          type: string
        display_additional_tax_total:
          type: string
        included_tax_total:
          type: string
        display_included_tax_total:
          type: string
        discount_total:
          type: string
        display_discount_total:
          type: string
        pre_tax_amount:
          type: string
        display_pre_tax_amount:
          type: string
        discounted_amount:
          type: string
        display_discounted_amount:
          type: string
        display_compare_at_amount:
          type: string
          nullable: true
        compare_at_amount:
          type: string
          nullable: true
        thumbnail_url:
          type: string
          nullable: true
        option_values:
          type: array
          items:
            "$ref": "#/components/schemas/OptionValue"
        digital_links:
          type: array
          items:
            "$ref": "#/components/schemas/DigitalLink"
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        cost_price:
          type: string
          nullable: true
        tax_category_id:
          type: string
          nullable: true
        variant:
          "$ref": "#/components/schemas/Variant"
        tax_category:
          "$ref": "#/components/schemas/TaxCategory"
        adjustments:
          type: array
          items:
            "$ref": "#/components/schemas/Adjustment"
      required:
      - id
      - variant_id
      - preorder
      - preorder_ships_at
      - quantity
      - currency
      - name
      - slug
      - options_text
      - price
      - display_price
      - total
      - display_total
      - adjustment_total
      - display_adjustment_total
      - additional_tax_total
      - display_additional_tax_total
      - included_tax_total
      - display_included_tax_total
      - discount_total
      - display_discount_total
      - pre_tax_amount
      - display_pre_tax_amount
      - discounted_amount
      - display_discounted_amount
      - display_compare_at_amount
      - compare_at_amount
      - thumbnail_url
      - option_values
      - digital_links
      - metadata
      - created_at
      - updated_at
      - cost_price
      - tax_category_id
      x-typelizer: true
    Market:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        currency:
          type: string
        default_locale:
          type: string
        tax_inclusive:
          type: boolean
        default:
          type: boolean
        country_isos:
          type: array
          items:
            type: string
        supported_locales:
          type: array
          items:
            type: string
        countries:
          type: array
          items:
            "$ref": "#/components/schemas/Country"
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - name
      - currency
      - default_locale
      - tax_inclusive
      - default
      - country_isos
      - supported_locales
      - created_at
      - updated_at
      x-typelizer: true
    Media:
      type: object
      properties:
        id:
          type: string
        product_id:
          type: string
          nullable: true
        variant_ids:
          type: array
          items:
            type: string
        position:
          type: number
        alt:
          type: string
          nullable: true
        media_type:
          type: string
        focal_point_x:
          type: number
          nullable: true
        focal_point_y:
          type: number
          nullable: true
        external_video_url:
          type: string
          nullable: true
        original_url:
          type: string
          nullable: true
        mini_url:
          type: string
          nullable: true
        small_url:
          type: string
          nullable: true
        medium_url:
          type: string
          nullable: true
        large_url:
          type: string
          nullable: true
        xlarge_url:
          type: string
          nullable: true
        og_image_url:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        viewable_id:
          type: string
        download_url:
          type: string
          nullable: true
        metadata:
          type: object
        viewable_type:
          type: string
      required:
      - id
      - product_id
      - variant_ids
      - position
      - alt
      - media_type
      - focal_point_x
      - focal_point_y
      - external_video_url
      - original_url
      - mini_url
      - small_url
      - medium_url
      - large_url
      - xlarge_url
      - og_image_url
      - created_at
      - updated_at
      - viewable_id
      - download_url
      - metadata
      - viewable_type
      x-typelizer: true
    NewsletterSubscriber:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        verified:
          type: boolean
        verified_at:
          type: string
          nullable: true
        customer_id:
          type: string
          nullable: true
      required:
      - id
      - email
      - created_at
      - updated_at
      - verified
      - verified_at
      - customer_id
      x-typelizer: true
    OptionType:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        label:
          type: string
        position:
          type: number
        kind:
          type: string
        translations:
          type: object
        metadata:
          type: object
        filterable:
          type: boolean
        created_at:
          type: string
        updated_at:
          type: string
        option_values:
          type: array
          items:
            "$ref": "#/components/schemas/OptionValue"
      required:
      - id
      - name
      - label
      - position
      - kind
      - metadata
      - filterable
      - created_at
      - updated_at
      x-typelizer: true
    OptionValue:
      type: object
      properties:
        id:
          type: string
        option_type_id:
          type: string
        name:
          type: string
        label:
          type: string
        position:
          type: number
        color_code:
          type: string
          nullable: true
        option_type_name:
          type: string
        option_type_label:
          type: string
        image_url:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        option_type:
          "$ref": "#/components/schemas/OptionType"
      required:
      - id
      - option_type_id
      - name
      - label
      - position
      - color_code
      - option_type_name
      - option_type_label
      - image_url
      - metadata
      - created_at
      - updated_at
      x-typelizer: true
    OrderRoutingRule:
      type: object
      properties:
        id:
          type: string
        position:
          type: number
        active:
          type: boolean
        created_at:
          type: string
        updated_at:
          type: string
        type:
          type: string
        channel_id:
          type: string
        preferences:
          type: object
        preference_schema:
          type: object
        label:
          type: string
        description:
          type: string
      required:
      - id
      - position
      - active
      - created_at
      - updated_at
      - type
      - channel_id
      - preferences
      - preference_schema
      - label
      - description
      x-typelizer: true
    Order:
      type: object
      properties:
        id:
          type: string
        market_id:
          type: string
          nullable: true
        channel_id:
          type: string
          nullable: true
        number:
          type: string
        email:
          type: string
        customer_note:
          type: string
          nullable: true
        currency:
          type: string
        locale:
          type: string
          nullable: true
        total_quantity:
          type: number
        fulfillment_status:
          type: string
          nullable: true
        payment_status:
          type: string
          nullable: true
        completed_at:
          type: string
          nullable: true
        item_total:
          type: string
        display_item_total:
          type: string
        adjustment_total:
          type: string
        display_adjustment_total:
          type: string
        discount_total:
          type: string
        display_discount_total:
          type: string
        tax_total:
          type: string
        display_tax_total:
          type: string
        included_tax_total:
          type: string
        display_included_tax_total:
          type: string
        additional_tax_total:
          type: string
        display_additional_tax_total:
          type: string
        total:
          type: string
        display_total:
          type: string
        gift_card_total:
          type: string
        display_gift_card_total:
          type: string
        amount_due:
          type: string
        display_amount_due:
          type: string
        delivery_total:
          type: string
        display_delivery_total:
          type: string
        store_credit_total:
          type: string
        display_store_credit_total:
          type: string
        covered_by_store_credit:
          type: boolean
        discounts:
          type: array
          items:
            "$ref": "#/components/schemas/Discount"
        items:
          type: array
          items:
            "$ref": "#/components/schemas/LineItem"
        fulfillments:
          type: array
          items:
            "$ref": "#/components/schemas/Fulfillment"
        payments:
          type: array
          items:
            "$ref": "#/components/schemas/Payment"
        billing_address:
          allOf:
          - "$ref": "#/components/schemas/Address"
          nullable: true
        shipping_address:
          allOf:
          - "$ref": "#/components/schemas/Address"
          nullable: true
        gift_card:
          allOf:
          - "$ref": "#/components/schemas/GiftCard"
          nullable: true
        market:
          allOf:
          - "$ref": "#/components/schemas/Market"
          nullable: true
        status:
          type: string
        last_ip_address:
          type: string
          nullable: true
        considered_risky:
          type: boolean
        confirmation_delivered:
          type: boolean
        store_owner_notification_delivered:
          type: boolean
        payment_total:
          type: string
        display_payment_total:
          type: string
        metadata:
          type: object
        canceled_at:
          type: string
          nullable: true
        approved_at:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        preferred_stock_location_id:
          type: string
          nullable: true
        tags:
          type: array
          items:
            type: string
        internal_note:
          type: string
          nullable: true
        approver_id:
          type: string
          nullable: true
        canceler_id:
          type: string
          nullable: true
        created_by_id:
          type: string
          nullable: true
        customer_id:
          type: string
          nullable: true
        channel:
          "$ref": "#/components/schemas/Channel"
        preferred_stock_location:
          "$ref": "#/components/schemas/StockLocation"
        payment_methods:
          type: array
          items:
            "$ref": "#/components/schemas/PaymentMethod"
        customer:
          "$ref": "#/components/schemas/Customer"
        approver:
          "$ref": "#/components/schemas/Customer"
        canceler:
          "$ref": "#/components/schemas/Customer"
        created_by:
          "$ref": "#/components/schemas/Customer"
        adjustments:
          type: array
          items:
            "$ref": "#/components/schemas/Adjustment"
        return_authorizations:
          type: array
          items:
            "$ref": "#/components/schemas/ReturnAuthorization"
        reimbursements:
          type: array
          items:
            "$ref": "#/components/schemas/Reimbursement"
      required:
      - id
      - market_id
      - channel_id
      - number
      - email
      - customer_note
      - currency
      - locale
      - total_quantity
      - fulfillment_status
      - payment_status
      - completed_at
      - item_total
      - display_item_total
      - adjustment_total
      - display_adjustment_total
      - discount_total
      - display_discount_total
      - tax_total
      - display_tax_total
      - included_tax_total
      - display_included_tax_total
      - additional_tax_total
      - display_additional_tax_total
      - total
      - display_total
      - gift_card_total
      - display_gift_card_total
      - amount_due
      - display_amount_due
      - delivery_total
      - display_delivery_total
      - store_credit_total
      - display_store_credit_total
      - covered_by_store_credit
      - gift_card
      - market
      - status
      - last_ip_address
      - considered_risky
      - confirmation_delivered
      - store_owner_notification_delivered
      - payment_total
      - display_payment_total
      - metadata
      - canceled_at
      - approved_at
      - created_at
      - updated_at
      - preferred_stock_location_id
      - tags
      - internal_note
      - approver_id
      - canceler_id
      - created_by_id
      - customer_id
      x-typelizer: true
    PaymentMethod:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        type:
          type: string
        session_required:
          type: boolean
        source_required:
          type: boolean
        metadata:
          type: object
        active:
          type: boolean
        auto_capture:
          type: boolean
          nullable: true
        storefront_visible:
          type: boolean
        position:
          type: number
        created_at:
          type: string
        updated_at:
          type: string
        preferences:
          type: object
        preference_schema:
          type: object
      required:
      - id
      - name
      - description
      - type
      - session_required
      - source_required
      - metadata
      - active
      - auto_capture
      - storefront_visible
      - position
      - created_at
      - updated_at
      - preferences
      - preference_schema
      x-typelizer: true
    Payment:
      type: object
      properties:
        id:
          type: string
        payment_method_id:
          type: string
        response_code:
          type: string
          nullable: true
        number:
          type: string
        amount:
          type: string
        display_amount:
          type: string
        status:
          type: string
        source_type:
          type: string
          nullable: true
          enum:
          - credit_card
          - store_credit
          - payment_source
        source_id:
          type: string
          nullable: true
        source:
          anyOf:
          - "$ref": "#/components/schemas/CreditCard"
          - "$ref": "#/components/schemas/StoreCredit"
          - "$ref": "#/components/schemas/PaymentSource"
          nullable: true
        payment_method:
          "$ref": "#/components/schemas/PaymentMethod"
        metadata:
          type: object
        avs_response:
          type: string
          nullable: true
        cvv_response_code:
          type: string
          nullable: true
        cvv_response_message:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        captured_amount:
          type: string
        order_id:
          type: string
          nullable: true
        order:
          "$ref": "#/components/schemas/Order"
        refunds:
          type: array
          items:
            "$ref": "#/components/schemas/Refund"
      required:
      - id
      - payment_method_id
      - response_code
      - number
      - amount
      - display_amount
      - status
      - source_type
      - source_id
      - source
      - metadata
      - avs_response
      - cvv_response_code
      - cvv_response_message
      - created_at
      - updated_at
      - captured_amount
      - order_id
      x-typelizer: true
    PaymentSource:
      type: object
      properties:
        id:
          type: string
        gateway_payment_profile_id:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - gateway_payment_profile_id
      - metadata
      - created_at
      - updated_at
      x-typelizer: true
    PriceHistory:
      type: object
      properties:
        id:
          type: string
        amount:
          type: string
        amount_in_cents:
          type: number
        currency:
          type: string
        display_amount:
          type: string
        recorded_at:
          type: string
        variant_id:
          type: string
        price_id:
          type: string
        compare_at_amount:
          type: string
          nullable: true
        created_at:
          type: string
      required:
      - id
      - amount
      - amount_in_cents
      - currency
      - display_amount
      - recorded_at
      - variant_id
      - price_id
      - compare_at_amount
      - created_at
      x-typelizer: true
    PriceList:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        status:
          type: string
        position:
          type: number
        match_policy:
          type: string
        starts_at:
          type: string
          nullable: true
        ends_at:
          type: string
          nullable: true
        deleted_at:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        currently_active:
          type: boolean
        products_count:
          type: number
        prices_count:
          type: number
        product_ids:
          type: array
          items:
            type: string
        price_rules:
          type: array
          items:
            "$ref": "#/components/schemas/PriceRule"
      required:
      - id
      - name
      - description
      - status
      - position
      - match_policy
      - starts_at
      - ends_at
      - deleted_at
      - created_at
      - updated_at
      - currently_active
      - products_count
      - prices_count
      - product_ids
      x-typelizer: true
    PriceRule:
      type: object
      properties:
        id:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        type:
          type: string
        price_list_id:
          type: string
        preferences:
          type: object
        preference_schema:
          type: array
          items:
            "$ref": "#/components/schemas/PreferenceField"
        label:
          type: string
        description:
          type: string
          nullable: true
        markets:
          type: array
          items:
            "$ref": "#/components/schemas/Market"
        customer_groups:
          type: array
          items:
            "$ref": "#/components/schemas/CustomerGroup"
        channels:
          type: array
          items:
            "$ref": "#/components/schemas/Channel"
        customers:
          type: array
          items:
            "$ref": "#/components/schemas/Customer"
      required:
      - id
      - created_at
      - updated_at
      - type
      - price_list_id
      - preferences
      - preference_schema
      - label
      - description
      x-typelizer: true
    Price:
      type: object
      properties:
        id:
          type: string
        amount:
          type: string
          nullable: true
        amount_in_cents:
          type: number
          nullable: true
        compare_at_amount:
          type: string
          nullable: true
        compare_at_amount_in_cents:
          type: number
          nullable: true
        currency:
          type: string
          nullable: true
        display_amount:
          type: string
          nullable: true
        display_compare_at_amount:
          type: string
          nullable: true
        price_list_id:
          type: string
          nullable: true
        variant_id:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        variant:
          "$ref": "#/components/schemas/Variant"
      required:
      - id
      - amount
      - amount_in_cents
      - compare_at_amount
      - compare_at_amount_in_cents
      - currency
      - display_amount
      - display_compare_at_amount
      - price_list_id
      - variant_id
      - created_at
      - updated_at
      x-typelizer: true
    ProductPublication:
      type: object
      properties:
        id:
          type: string
        published_at:
          type: string
          nullable: true
        unpublished_at:
          type: string
          nullable: true
        product_id:
          type: string
        channel_id:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - published_at
      - unpublished_at
      - product_id
      - channel_id
      - created_at
      - updated_at
      x-typelizer: true
    Product:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        slug:
          type: string
        meta_title:
          type: string
          nullable: true
        meta_description:
          type: string
          nullable: true
        meta_keywords:
          type: string
          nullable: true
        variant_count:
          type: number
        available_on:
          type: string
          nullable: true
        preorder_ships_at:
          type: string
          nullable: true
        purchasable:
          type: boolean
        preorder:
          type: boolean
        in_stock:
          type: boolean
        backorderable:
          type: boolean
        available:
          type: boolean
        description:
          type: string
          nullable: true
        description_html:
          type: string
          nullable: true
        default_variant_id:
          type: string
        thumbnail_url:
          type: string
          nullable: true
        tags:
          type: array
          items:
            type: string
        price:
          allOf:
          - "$ref": "#/components/schemas/Price"
          nullable: true
        original_price:
          allOf:
          - "$ref": "#/components/schemas/Price"
          nullable: true
        primary_media:
          "$ref": "#/components/schemas/Media"
        media:
          type: array
          items:
            "$ref": "#/components/schemas/Media"
        variants:
          type: array
          items:
            "$ref": "#/components/schemas/Variant"
        default_variant:
          "$ref": "#/components/schemas/Variant"
        option_types:
          type: array
          items:
            "$ref": "#/components/schemas/OptionType"
        option_values:
          type: array
          items:
            "$ref": "#/components/schemas/OptionValue"
        categories:
          type: array
          items:
            "$ref": "#/components/schemas/Category"
        custom_fields:
          type: array
          items:
            "$ref": "#/components/schemas/CustomField"
        prior_price:
          allOf:
          - "$ref": "#/components/schemas/PriceHistory"
          nullable: true
        translations:
          type: object
        status:
          type: string
        metadata:
          type: object
        deleted_at:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        tax_category_id:
          type: string
          nullable: true
        product_publications:
          type: array
          items:
            "$ref": "#/components/schemas/ProductPublication"
        channels:
          type: array
          items:
            "$ref": "#/components/schemas/Channel"
      required:
      - id
      - name
      - slug
      - meta_title
      - meta_description
      - meta_keywords
      - variant_count
      - available_on
      - preorder_ships_at
      - purchasable
      - preorder
      - in_stock
      - backorderable
      - available
      - description
      - description_html
      - default_variant_id
      - thumbnail_url
      - tags
      - price
      - original_price
      - status
      - metadata
      - deleted_at
      - created_at
      - updated_at
      - tax_category_id
      x-typelizer: true
    PromotionAction:
      type: object
      properties:
        id:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        type:
          type: string
        promotion_id:
          type: string
        preferences:
          type: object
        preference_schema:
          type: array
          items:
            "$ref": "#/components/schemas/PreferenceField"
        label:
          type: string
        calculator:
          allOf:
          - "$ref": "#/components/schemas/PromotionActionCalculator"
          nullable: true
        line_items:
          type: array
          items:
            "$ref": "#/components/schemas/PromotionActionLineItem"
          nullable: true
      required:
      - id
      - created_at
      - updated_at
      - type
      - promotion_id
      - preferences
      - preference_schema
      - label
      - calculator
      - line_items
      x-typelizer: true
    PromotionRule:
      type: object
      properties:
        id:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        type:
          type: string
        promotion_id:
          type: string
        preferences:
          type: object
        preference_schema:
          type: array
          items:
            "$ref": "#/components/schemas/PreferenceField"
        label:
          type: string
        product_ids:
          type: array
          items:
            type: string
          nullable: true
        category_ids:
          type: array
          items:
            type: string
          nullable: true
        customer_ids:
          type: array
          items:
            type: string
          nullable: true
        products:
          type: array
          items:
            "$ref": "#/components/schemas/Product"
        categories:
          type: array
          items:
            "$ref": "#/components/schemas/Category"
        customers:
          type: array
          items:
            "$ref": "#/components/schemas/Customer"
        customer_groups:
          type: array
          items:
            "$ref": "#/components/schemas/CustomerGroup"
        countries:
          type: array
          items:
            "$ref": "#/components/schemas/Country"
        channels:
          type: array
          items:
            "$ref": "#/components/schemas/Channel"
        markets:
          type: array
          items:
            "$ref": "#/components/schemas/Market"
      required:
      - id
      - created_at
      - updated_at
      - type
      - promotion_id
      - preferences
      - preference_schema
      - label
      - product_ids
      - category_ids
      - customer_ids
      x-typelizer: true
    Promotion:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        code:
          type: string
          nullable: true
        starts_at:
          type: string
          nullable: true
        expires_at:
          type: string
          nullable: true
        usage_limit:
          type: number
          nullable: true
        match_policy:
          type: string
          enum:
          - all
          - any
        path:
          type: string
          nullable: true
        kind:
          type: string
          enum:
          - coupon_code
          - automatic
        multi_codes:
          type: boolean
        number_of_codes:
          type: number
          nullable: true
        code_prefix:
          type: string
          nullable: true
        promotion_category_id:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        action_ids:
          type: array
          items:
            type: string
        rule_ids:
          type: array
          items:
            type: string
      required:
      - id
      - name
      - description
      - code
      - starts_at
      - expires_at
      - usage_limit
      - match_policy
      - path
      - kind
      - multi_codes
      - number_of_codes
      - code_prefix
      - promotion_category_id
      - metadata
      - created_at
      - updated_at
      - action_ids
      - rule_ids
      x-typelizer: true
    Refund:
      type: object
      properties:
        id:
          type: string
        transaction_id:
          type: string
          nullable: true
        amount:
          type: string
          nullable: true
        payment_id:
          type: string
          nullable: true
        refund_reason_id:
          type: string
          nullable: true
        reimbursement_id:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        payment:
          "$ref": "#/components/schemas/Payment"
        reimbursement:
          "$ref": "#/components/schemas/Reimbursement"
      required:
      - id
      - transaction_id
      - amount
      - payment_id
      - refund_reason_id
      - reimbursement_id
      - metadata
      - created_at
      - updated_at
      x-typelizer: true
    Reimbursement:
      type: object
      properties:
        id:
          type: string
        number:
          type: string
        reimbursement_status:
          type: string
          nullable: true
        total:
          type: string
          nullable: true
        order_id:
          type: string
          nullable: true
        customer_return_id:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        order:
          "$ref": "#/components/schemas/Order"
      required:
      - id
      - number
      - reimbursement_status
      - total
      - order_id
      - customer_return_id
      - created_at
      - updated_at
      x-typelizer: true
    ReturnAuthorization:
      type: object
      properties:
        id:
          type: string
        number:
          type: string
        status:
          type: string
        order_id:
          type: string
          nullable: true
        stock_location_id:
          type: string
          nullable: true
        return_authorization_reason_id:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        order:
          "$ref": "#/components/schemas/Order"
        stock_location:
          "$ref": "#/components/schemas/StockLocation"
      required:
      - id
      - number
      - status
      - order_id
      - stock_location_id
      - return_authorization_reason_id
      - created_at
      - updated_at
      x-typelizer: true
    Role:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - name
      - created_at
      - updated_at
      x-typelizer: true
    SetupTask:
      type: object
      properties:
        name:
          type: string
        done:
          type: boolean
      required:
      - name
      - done
      x-typelizer: true
    State:
      type: object
      properties:
        abbr:
          type: string
        name:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - abbr
      - name
      - created_at
      - updated_at
      x-typelizer: true
    StockItem:
      type: object
      properties:
        id:
          type: string
        count_on_hand:
          type: number
        backorderable:
          type: boolean
        stock_location_id:
          type: string
          nullable: true
        variant_id:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        allocated_count:
          type: number
        available_count:
          type: number
        stock_location:
          "$ref": "#/components/schemas/StockLocation"
        variant:
          "$ref": "#/components/schemas/Variant"
      required:
      - id
      - count_on_hand
      - backorderable
      - stock_location_id
      - variant_id
      - metadata
      - created_at
      - updated_at
      - allocated_count
      - available_count
      x-typelizer: true
    StockLocation:
      type: object
      properties:
        id:
          type: string
        state_abbr:
          type: string
          nullable: true
        name:
          type: string
        address1:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        zipcode:
          type: string
          nullable: true
        country_iso:
          type: string
          nullable: true
        country_name:
          type: string
          nullable: true
        state_text:
          type: string
          nullable: true
        admin_name:
          type: string
          nullable: true
        address2:
          type: string
          nullable: true
        state_name:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        company:
          type: string
          nullable: true
        active:
          type: boolean
        default:
          type: boolean
        backorderable_default:
          type: boolean
        propagate_all_variants:
          type: boolean
        kind:
          type: string
        pickup_enabled:
          type: boolean
        pickup_stock_policy:
          type: string
        pickup_ready_in_minutes:
          type: number
          nullable: true
        pickup_instructions:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - state_abbr
      - name
      - address1
      - city
      - zipcode
      - country_iso
      - country_name
      - state_text
      - admin_name
      - address2
      - state_name
      - phone
      - company
      - active
      - default
      - backorderable_default
      - propagate_all_variants
      - kind
      - pickup_enabled
      - pickup_stock_policy
      - pickup_ready_in_minutes
      - pickup_instructions
      - created_at
      - updated_at
      x-typelizer: true
    StockReservation:
      type: object
      properties:
        id:
          type: string
        stock_item_id:
          type: string
        line_item_id:
          type: string
        order_id:
          type: string
        variant_id:
          type: string
          nullable: true
        stock_location_id:
          type: string
          nullable: true
        quantity:
          type: number
        expires_at:
          type: string
        active:
          type: boolean
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - stock_item_id
      - line_item_id
      - order_id
      - variant_id
      - stock_location_id
      - quantity
      - expires_at
      - active
      - created_at
      - updated_at
      x-typelizer: true
    StockTransfer:
      type: object
      properties:
        id:
          type: string
        number:
          type: string
        reference:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        source_location_id:
          type: string
          nullable: true
        destination_location_id:
          type: string
          nullable: true
        source_location:
          "$ref": "#/components/schemas/StockLocation"
        destination_location:
          "$ref": "#/components/schemas/StockLocation"
      required:
      - id
      - number
      - reference
      - metadata
      - created_at
      - updated_at
      - source_location_id
      - destination_location_id
      x-typelizer: true
    StoreCreditCategory:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        non_expiring:
          type: boolean
      required:
      - id
      - name
      - created_at
      - updated_at
      - non_expiring
      x-typelizer: true
    StoreCredit:
      type: object
      properties:
        id:
          type: string
        amount:
          type: string
        amount_used:
          type: string
        amount_remaining:
          type: string
        display_amount:
          type: string
        display_amount_used:
          type: string
        display_amount_remaining:
          type: string
        currency:
          type: string
        memo:
          type: string
          nullable: true
        metadata:
          type: object
        created_at:
          type: string
        updated_at:
          type: string
        customer_id:
          type: string
          nullable: true
        created_by_id:
          type: string
          nullable: true
        category_id:
          type: string
          nullable: true
        category_name:
          type: string
          nullable: true
      required:
      - id
      - amount
      - amount_used
      - amount_remaining
      - display_amount
      - display_amount_used
      - display_amount_remaining
      - currency
      - memo
      - metadata
      - created_at
      - updated_at
      - customer_id
      - created_by_id
      - category_id
      - category_name
      x-typelizer: true
    Store:
      type: object
      properties:
        id:
          type: string
        metadata:
          type: object
        name:
          type: string
        code:
          type: string
        preferred_storefront_url:
          type: string
          nullable: true
        default_currency:
          type: string
        default_locale:
          type: string
        mail_from_address:
          type: string
          nullable: true
        customer_support_email:
          type: string
          nullable: true
        new_order_notifications_email:
          type: string
          nullable: true
        preferred_send_consumer_transactional_emails:
          type: boolean
        preferred_admin_locale:
          type: string
          nullable: true
        preferred_timezone:
          type: string
        preferred_weight_unit:
          type: string
        preferred_unit_system:
          type: string
        preferred_storefront_access:
          type: string
        preferred_guest_checkout:
          type: boolean
        preferred_order_routing_strategy:
          type: string
        created_at:
          type: string
        updated_at:
          type: string
        url:
          type: string
        api_url:
          type: string
        setup_tasks:
          type: array
          items:
            "$ref": "#/components/schemas/SetupTask"
        supported_currencies:
          type: array
          items:
            type: string
        supported_locales:
          type: array
          items:
            type: string
        available_locales:
          type: array
          items:
            type: string
        logo_url:
          type: string
          nullable: true
        mailer_logo_url:
          type: string
          nullable: true
      required:
      - id
      - metadata
      - name
      - code
      - preferred_storefront_url
      - default_currency
      - default_locale
      - mail_from_address
      - customer_support_email
      - new_order_notifications_email
      - preferred_send_consumer_transactional_emails
      - preferred_admin_locale
      - preferred_timezone
      - preferred_weight_unit
      - preferred_unit_system
      - preferred_storefront_access
      - preferred_guest_checkout
      - preferred_order_routing_strategy
      - created_at
      - updated_at
      - url
      - api_url
      - setup_tasks
      - supported_currencies
      - supported_locales
      - available_locales
      - logo_url
      - mailer_logo_url
      x-typelizer: true
    TaxCategory:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        tax_code:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        is_default:
          type: boolean
        created_at:
          type: string
        updated_at:
          type: string
      required:
      - id
      - name
      - tax_code
      - description
      - is_default
      - created_at
      - updated_at
      x-typelizer: true
    Variant:
      type: object
      properties:
        id:
          type: string
        product_id:
          type: string
        sku:
          type: string
          nullable: true
        options_text:
          type: string
        track_inventory:
          type: boolean
        media_count:
          type: number
        preorder_ships_at:
          type: string
          nullable: true
        thumbnail_url:
          type: string
          nullable: true
        purchasable:
          type: boolean
        in_stock:
          type: boolean
        backorderable:
          type: boolean
        preorder:
          type: boolean
        weight:
          type: number
          nullable: true
        height:
          type: number
          nullable: true
        width:
          type: number
          nullable: true
        depth:
          type: number
          nullable: true
        price:
          "$ref": "#/components/schemas/Price"
        original_price:
          allOf:
          - "$ref": "#/components/schemas/Price"
          nullable: true
        primary_media:
          "$ref": "#/components/schemas/Media"
        media:
          type: array
          items:
            "$ref": "#/components/schemas/Media"
        option_values:
          type: array
          items:
            "$ref": "#/components/schemas/OptionValue"
        custom_fields:
          type: array
          items:
            "$ref": "#/components/schemas/CustomField"
        prior_price:
          allOf:
          - "$ref": "#/components/schemas/PriceHistory"
          nullable: true
        metadata:
          type: object
        position:
          type: number
        cost_price:
          type: string
          nullable: true
        cost_currency:
          type: string
          nullable: true
        barcode:
          type: string
          nullable: true
        weight_unit:
          type: string
          nullable: true
        dimensions_unit:
          type: string
          nullable: true
        backorder_limit:
          type: number
          nullable: true
        deleted_at:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        preorderable:
          type: boolean
        tax_category_id:
          type: string
          nullable: true
        available_stock:
          type: number
          nullable: true
        reserved_quantity:
          type: number
        total_on_hand:
          type: number
          nullable: true
        product_name:
          type: string
        prices:
          type: array
          items:
            "$ref": "#/components/schemas/Price"
        stock_items:
          type: array
          items:
            "$ref": "#/components/schemas/StockItem"
      required:
      - id
      - product_id
      - sku
      - options_text
      - track_inventory
      - media_count
      - preorder_ships_at
      - thumbnail_url
      - purchasable
      - in_stock
      - backorderable
      - preorder
      - weight
      - height
      - width
      - depth
      - price
      - original_price
      - option_values
      - metadata
      - position
      - cost_price
      - cost_currency
      - barcode
      - weight_unit
      - dimensions_unit
      - backorder_limit
      - deleted_at
      - created_at
      - updated_at
      - preorderable
      - tax_category_id
      - available_stock
      - reserved_quantity
      - total_on_hand
      - product_name
      x-typelizer: true
    WebhookDelivery:
      type: object
      properties:
        id:
          type: string
        event_name:
          type: string
        event_id:
          type: string
          nullable: true
        response_code:
          type: number
          nullable: true
        execution_time:
          type: number
          nullable: true
        error_type:
          type: string
          nullable: true
        request_errors:
          type: string
          nullable: true
        response_body:
          type: string
          nullable: true
        success:
          type: boolean
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        delivered_at:
          type: string
          nullable: true
        payload:
          type: object
        webhook_endpoint_id:
          type: string
        webhook_endpoint_url:
          type: string
      required:
      - id
      - event_name
      - event_id
      - response_code
      - execution_time
      - error_type
      - request_errors
      - response_body
      - success
      - created_at
      - updated_at
      - delivered_at
      - payload
      - webhook_endpoint_id
      - webhook_endpoint_url
      x-typelizer: true
    WebhookEndpoint:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
          nullable: true
        url:
          type: string
        active:
          type: boolean
        subscriptions:
          type: array
          items:
            type: string
        disabled_reason:
          type: string
          nullable: true
        created_at:
          type: string
        updated_at:
          type: string
        disabled_at:
          type: string
          nullable: true
        secret_key:
          type: string
          nullable: true
        last_delivery_at:
          type: string
          nullable: true
        recent_delivery_count:
          type: number
        recent_failure_count:
          type: number
        total_delivery_count:
          type: number
        successful_delivery_count:
          type: number
        failed_delivery_count:
          type: number
      required:
      - id
      - name
      - url
      - active
      - subscriptions
      - disabled_reason
      - created_at
      - updated_at
      - disabled_at
      - secret_key
      - last_delivery_at
      - recent_delivery_count
      - recent_failure_count
      - total_delivery_count
      - successful_delivery_count
      - failed_delivery_count
      x-typelizer: true
