Spree Commerce Authentication API

Admin user login, logout, token refresh, and current user profile

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/spree-authentication-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

spree-authentication-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Admin Account / Address Authentication 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.\n\n## Authentication\n\nThe Admin API requires a secret API key passed in the `x-spree-api-key` header.\nSecret API keys can be generated in the Spree admin dashboard.\n\n## Response Format\n\nAll responses are JSON. List endpoints return paginated responses with `data` and `meta` keys.\nSingle resource endpoints return a flat JSON object.\n\n## Resource IDs\n\nEvery resource is identified by an opaque string ID (e.g. `prod_86Rf07xd4z`,\n`variant_k5nR8xLq`, `or_UkLWZg9DAJ`). Use these IDs everywhere — URL paths,\nrequest bodies, and Ransack filters all accept them directly.\n\n## Error Handling\n\nErrors return a consistent format:\n```json\n{\n  \"error\": {\n    \"code\": \"validation_error\",\n    \"message\": \"Validation failed\",\n    \"details\": { \"name\": [\"can't be blank\"] }\n  }\n}\n```\n"
  version: v3
servers:
- url: http://{defaultHost}
  variables:
    defaultHost:
      default: localhost:3000
tags:
- name: Authentication
  description: Admin user login, logout, token refresh, and current user profile
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.


        Dispatches by the `provider` field to a strategy registered in

        `Spree.admin_authentication_strategies`. When `provider` is omitted it

        defaults to `email`, which uses the built-in email/password strategy.


        To plug in a third-party identity provider (Okta, Azure AD, Google

        Workspace SSO, a custom JWT issuer, SAML, etc.), register a

        `Spree::Authentication::Strategies::BaseStrategy` subclass under a

        provider key, then send `{ "provider": "<your_key>", ... }` with the

        fields your strategy requires. The endpoint returns the same Spree-issued

        JWT regardless of which strategy authenticated the request.

        '
      x-codeSamples:
      - lang: javascript
        label: Spree Admin SDK
        source: "import { createAdminClient } from '@spree/admin-sdk'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\n// The refresh token is set as an HttpOnly cookie; only `token` and `user` come back in the body.\nconst auth = await client.auth.login({\n  email: 'admin@example.com',\n  password: 'password123',\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: login successful
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJhZG1pbiIsImp0aSI6ImUyMzYxNTc5LWMxZDMtNDc0Yi1hM2E1LTcwNWMzYTZmMGUxYSIsImlzcyI6InNwcmVlIiwiYXVkIjoiYWRtaW5fYXBpIiwiZXhwIjoxNzgxMjg1MzI3fQ.5GaxxoaCeEEpGgum01ZV0z56ZpHDWaFSyX_KvEob3ws
                user:
                  id: admin_UkLWZg9DAJ
                  email: admin@example.com
                  first_name: Lisandra
                  last_name: Dare
                  full_name: Lisandra Dare
                  created_at: '2026-06-12T17:23:47.304Z'
                  updated_at: '2026-06-12T17:23:47.304Z'
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
              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 registered

                  strategy class; the remaining fields are forwarded to the strategy''s

                  `authenticate` method. Required fields depend on the registered strategy

                  — consult its documentation.

                  '
                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'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\n// Driven entirely by the HttpOnly refresh-token cookie + CSRF header (set by the SDK).\nconst auth = await client.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.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJhZG1pbiIsImp0aSI6IjYxNTkwZmYyLWEwMTctNDUyZi05ZjQ3LTBhM2JhYWZlYWQ0YiIsImlzcyI6InNwcmVlIiwiYXVkIjoiYWRtaW5fYXBpIiwiZXhwIjoxNzgxMjg1MzI4fQ.l53NCGqm7_mD8L54Wq7AB86HGHqolGJEplh7Dg_QqJw
                user:
                  id: admin_UkLWZg9DAJ
                  email: admin@example.com
                  first_name: Lavonda
                  last_name: Bogan
                  full_name: Lavonda Bogan
                  created_at: '2026-06-12T17:23:48.682Z'
                  updated_at: '2026-06-12T17:23:48.682Z'
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
              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'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nawait client.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'\n\nconst client = createAdminClient({\n  baseUrl: 'https://your-store.com',\n  secretKey: 'sk_xxx',\n})\n\nconst me = await client.me.get()\nif (me.permissions.some((r) => r.allow && r.actions.includes('manage') && r.subjects.includes('Spree::Product'))) {\n  // show \"Create product\" button\n}"
      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: loralee@bodeolson.name
                  first_name: Thelma
                  last_name: Cronin
                  full_name: Thelma Cronin
                  created_at: '2026-06-12T17:24:22.538Z'
                  updated_at: '2026-06-12T17:24:22.538Z'
                  roles:
                  - id: role_UkLWZg9DAJ
                    name: admin
                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'
  /api/v3/store/auth/login:
    post:
      summary: Login
      tags:
      - Authentication
      security:
      - api_key: []
      description: 'Authenticates a customer and returns a JWT access token + refresh token.


        Dispatches by the `provider` field to a strategy registered in

        `Spree.store_authentication_strategies`. When `provider` is omitted it

        defaults to `email`, which uses the built-in email/password strategy.


        To plug in a third-party identity provider (Auth0, Okta, Firebase, a

        custom JWT issuer, SAML, etc.), register a `Spree::Authentication::Strategies::BaseStrategy`

        subclass under a provider key, then send `{ "provider": "<your_key>", ... }`

        with the fields your strategy requires. The endpoint returns the same

        Spree-issued JWT + refresh token regardless of which strategy authenticated

        the request.

        '
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n  baseUrl: 'https://your-store.com',\n  publishableKey: '<api-key>',\n})\n\nconst auth = await client.auth.login({\n  email: 'customer@example.com',\n  password: 'password123',\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: login successful
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjY0NjcwM2Q0LWY5ZjAtNDlmMi05ZmZkLTA3YTZhY2I5YWZkZiIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjE1fQ.jlz2KHxYkB1Dd9ucl26zy6E5M7dFB5q9g-Qw0YjsX50
                refresh_token: MQ9QZ1ToR8QocZoDd4ggC8yN
                user:
                  id: cus_UkLWZg9DAJ
                  email: test@example.com
                  first_name: Colette
                  last_name: Hegmann
                  phone: null
                  accepts_email_marketing: false
                  full_name: Colette Hegmann
                  available_store_credit_total: '0'
                  display_available_store_credit_total: $0.00
                  addresses: []
                  default_billing_address: null
                  default_shipping_address: null
              schema:
                $ref: '#/components/schemas/AuthResponse_2'
        '401':
          description: missing API key
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              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: customer@example.com
                  password:
                    type: string
                    example: password123
                required:
                - email
                - password
              - title: ProviderLogin
                description: 'Provider-dispatched login. The `provider` key selects a registered

                  strategy class; the remaining fields are forwarded to the strategy''s

                  `authenticate` method. Required fields depend on the registered strategy

                  — consult its documentation.

                  '
                type: object
                properties:
                  provider:
                    type: string
                    example: auth0
                    description: Registered provider key (anything other than `email`).
                    not:
                      enum:
                      - email
                required:
                - provider
                additionalProperties: true
  /api/v3/store/auth/refresh:
    post:
      summary: Refresh token
      tags:
      - Authentication
      security:
      - api_key: []
      description: Exchanges a refresh token for a new access JWT and rotated refresh token. No Authorization header needed.
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n  baseUrl: 'https://your-store.com',\n  publishableKey: '<api-key>',\n})\n\nconst auth = await client.auth.refresh({\n  refresh_token: 'rt_xxx',\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '200':
          description: token refreshed
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjNmZjU3NWU0LTVmNmItNDVjOC04MzIzLTIzMDMyMzVjZTkzMiIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjE2fQ.OuCk-UNe-asA8DvK2yKMkp94BQz9PN_Z7_SnReeIRYE
                refresh_token: qLuZDRo8LqywXFThqPM5V2Ug
                user:
                  id: cus_UkLWZg9DAJ
                  email: test@example.com
                  first_name: Debi
                  last_name: Tillman
                  phone: null
                  accepts_email_marketing: false
                  full_name: Debi Tillman
                  available_store_credit_total: '0'
                  display_available_store_credit_total: $0.00
                  addresses: []
                  default_billing_address: null
                  default_shipping_address: null
              schema:
                $ref: '#/components/schemas/AuthResponse_2'
        '401':
          description: missing or invalid refresh token
          content:
            application/json:
              example:
                error:
                  code: invalid_refresh_token
                  message: Invalid or expired refresh token
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                refresh_token:
                  type: string
                  description: Refresh token from login response
              required:
              - refresh_token
  /api/v3/store/auth/logout:
    post:
      summary: Logout
      tags:
      - Authentication
      security:
      - api_key: []
      description: Revokes the submitted refresh token. The refresh token itself is the credential — no Authorization header is required, so a client with an expired access JWT can still log out.
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n  baseUrl: 'https://your-store.com',\n  publishableKey: '<api-key>',\n})\n\nawait client.auth.logout({\n  refresh_token: 'rt_xxx',\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '204':
          description: logout without refresh token (no-op)
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                refresh_token:
                  type: string
                  description: Refresh token to revoke
  /api/v3/store/password_resets:
    post:
      summary: Request a password reset
      tags:
      - Authentication
      security:
      - api_key: []
      description: Sends a password reset email if an account exists for the given email address. Always returns 202 Accepted to prevent email enumeration.
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n  baseUrl: 'https://your-store.com',\n  publishableKey: '<api-key>',\n})\n\nawait client.passwordResets.create({\n  email: 'customer@example.com',\n  redirect_url: 'https://myshop.com/reset-password',\n})"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      responses:
        '202':
          description: email not found (same response to prevent enumeration)
          content:
            application/json:
              example:
                message: If an account exists for that email, password reset instructions have been sent.
              schema:
                type: object
                properties:
                  message:
                    type: string
        '401':
          description: missing API key
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  example: customer@example.com
                  description: Email address of the account to reset
                redirect_url:
                  type: string
                  format: uri
                  example: https://myshop.com/reset-password
                  description: URL to redirect the user to after clicking the reset link. Validated against the store's allowed origins.
              required:
              - email
  /api/v3/store/password_resets/{token}:
    patch:
      summary: Reset password with token
      tags:
      - Authentication
      security:
      - api_key: []
      description: Resets the password using a token received via email. Returns a JWT token on success (auto-login).
      x-codeSamples:
      - lang: javascript
        label: Spree SDK
        source: "import { createClient } from '@spree/sdk'\n\nconst client = createClient({\n  baseUrl: 'https://your-store.com',\n  publishableKey: '<api-key>',\n})\n\nconst auth = await client.passwordResets.update(\n  'reset-token-from-email',\n  {\n    password: 'newsecurepassword',\n    password_confirmation: 'newsecurepassword',\n  }\n)"
      parameters:
      - name: x-spree-api-key
        in: header
        required: true
        schema:
          type: string
      - name: token
        in: path
        required: true
        description: Password reset token from the email
        schema:
          type: string
      responses:
        '200':
          description: password reset successful
          content:
            application/json:
              example:
                token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJjdXN0b21lciIsImp0aSI6IjU1YjA5Yzc4LTUzMTYtNDRjYy05ZjJiLThmN2E2MzViMmRlNSIsImlzcyI6InNwcmVlIiwiYXVkIjoic3RvcmVfYXBpIiwiZXhwIjoxNzc5ODE1NjI4fQ.FX2Te4WfdAu3kN_fvvfHsH92_axvIZTI1d8Zmw8R1mE
                refresh_token: Be2HUCjiJVRjgidFuYU7GRRh
                user:
                  id: cus_UkLWZg9DAJ
                  email: customer@example.com
                  first_name: Randa
                  last_name: O'Hara
                  phone: null
                  accepts_email_marketing: false
                  full_name: Randa O'Hara
                  available_store_credit_total: '0'
                  display_available_store_credit_total: $0.00
                  addresses: []
                  default_billing_address: null
                  default_shipping_address: null
              schema:
                $ref: '#/components/schemas/AuthResponse_2'
        '422':
          description: password confirmation mismatch
          content:
            application/json:
              example:
                error:
                  code: validation_error
                  message: Password confirmation doesn't match Password
                  details:
                    password_confirmation:
                    - doesn't match Password
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: missing API key
          content:
            application/json:
              example:
                error:
                  code: invalid_token
                  message: Valid API key required
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
                  minLength: 6
                  example: newsecurepassword
                password_confirmation:
                  type: string
                  example: newsecurepassword
              required:
              - password
              - password_confirmation
components:
  schemas:
    AuthResponse:
      type: object
      properties:
        token:
          type: string
          description: JWT access token
        user:
          $ref: '#/components/schemas/AdminUser'
      required:
      - token
      - user
    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
    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
        created_at:
          type: string
        updated_at:
          type: string
        roles:
          type: array
          items:
            $ref: '#/components/schemas/AdminUserRoleAssignment'
      required:
      - id
      - email
      - first_name
      - last_name
      - full_name
      - created_at
      - updated_at
      - roles
      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
      required:
      - id
      - email
      - first_name
      - last_name
      - phone
      - accepts_email_marketing
      - full_name
      - available_store_credit_total
      - display_available_store_credit_total
      - addresses
      - default_billing_address
      - default_shipping_address
      x-typelizer: true
    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
      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
      x-typelizer: true
    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
    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
    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
    AuthResponse_2:
      type: object
      properties:
        token:
          type: string
          description: JWT access token
        refresh_token:
          type: string
          description: Refresh token for obtaining new access tokens
        user:
          $ref: '#/components/schemas/Customer'
      required:
      - token
      - refresh_token
      - user
  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
x-tagGroups:
- name: Authentication
  tags:
  - Authentication
- name: Produ

# --- truncated at 32 KB (32 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spree/refs/heads/main/openapi/spree-authentication-api-openapi.yml