openapi: 3.1.0
info:
  title: 'Zoyee Site API'
  description: 'Zoyee Site API Documentation. Authenticate via Laravel Passport (OAuth2 password grant) at `/oauth/token`.'
  contact:
    name: 'Shah Sawood'
    email: shahsawoodshnwari@gmail.com
  license:
    name: 'MIT License'
    url: 'https://opensource.org/licenses/MIT'
  version: 1.0.0
servers:
  -
    url: 'https://zoyee-site.test'
    description: 'Local server'
  -
    url: 'https://api.benton.com'
    description: 'Production server'
  -
    url: /api/v1
paths:
  /api/v1/admin/roles:
    get:
      tags:
        - 'Access (Admin)'
      summary: 'List roles'
      description: 'List all roles with permissions. Requires roles::View permission.'
      operationId: ba885ab94fffa13e34518483f21982c1
      responses:
        200:
          description: 'Role list'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/RoleResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
    post:
      tags:
        - 'Access (Admin)'
      summary: 'Create role'
      description: 'Create a new role. Requires roles::Create permission.'
      operationId: a09ec1557f0ac8bf82fdf463a8dc35d8
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreRoleRequestBody'
      responses:
        201:
          description: 'Role created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  '/api/v1/admin/roles/{id}':
    put:
      tags:
        - 'Access (Admin)'
      summary: 'Update role'
      description: 'Update a role. Requires roles::Update permission.'
      operationId: e43e89f979540ef045a827e1ddbc6f7c
      parameters:
        -
          name: id
          in: path
          description: 'Role ID'
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateRoleRequestBody'
      responses:
        200:
          description: 'Role updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    delete:
      tags:
        - 'Access (Admin)'
      summary: 'Delete role'
      description: 'Delete a role. Requires roles::Delete permission.'
      operationId: 3762490f4585bd1d2a00d6304b988203
      parameters:
        -
          name: id
          in: path
          description: 'Role ID'
          required: true
          schema:
            type: integer
      responses:
        204:
          description: 'Role deleted'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/admin/roles/{id}/permissions':
    post:
      tags:
        - 'Access (Admin)'
      summary: 'Assign permissions to role'
      description: 'Sync permissions for a role. Requires roles::Assign permission.'
      operationId: dd660443b39b05c304f9bab1d793be75
      parameters:
        -
          name: id
          in: path
          description: 'Role ID'
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssignPermissionsRequestBody'
      responses:
        200:
          description: 'Permissions assigned'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/admin/users:
    get:
      tags:
        - 'Access (Admin)'
      summary: 'List users'
      description: 'Paginated list of users with roles. Requires users::View permission.'
      operationId: a01acc62824c840d57f0e786980bf0c2
      parameters:
        -
          name: page
          in: query
          description: 'Page number'
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated user list'
          content:
            application/json:
              schema:
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/UserResponse'
                type: object
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
  '/api/v1/admin/users/{id}/approve':
    post:
      tags:
        - 'Access (Admin)'
      summary: 'Approve user'
      description: 'Set user status to active. Requires users::Approve permission.'
      operationId: 5e13437b52cdbc6080dbc5d338c62089
      parameters:
        -
          name: id
          in: path
          description: 'User ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'User approved'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserActionResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/admin/users/{id}/suspend':
    post:
      tags:
        - 'Access (Admin)'
      summary: 'Suspend user'
      description: 'Set user status to suspended. Optional reason. Requires users::Suspend permission.'
      operationId: 6fcdcc204d69217f9bfe4e35f8de51f0
      parameters:
        -
          name: id
          in: path
          description: 'User ID'
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SuspendUserRequestBody'
      responses:
        200:
          description: 'User suspended'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserActionResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/me/profile:
    get:
      tags:
        - Access
      summary: 'Get current user profile'
      description: 'Returns the authenticated user profile.'
      operationId: 6ba5c6f0a7deac5942f671fcdd566aed
      responses:
        200:
          description: Profile
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProfileResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
  /api/v1/me/cart:
    get:
      tags:
        - Cart
      summary: 'Get cart'
      description: 'Current user cart with items and reservations.'
      operationId: 7e7e968dfa39b71a7ba5bdba1b17a108
      responses:
        200:
          description: Cart
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
  /api/v1/me/cart/items:
    post:
      tags:
        - Cart
      summary: 'Add cart item'
      description: 'Add a product to the cart (creates reservation).'
      operationId: ae0557b61b594fd9bff3f25fc5276932
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddCartItemRequestBody'
      responses:
        201:
          description: 'Item added'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        422:
          description: 'Validation / insufficient stock'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  '/api/v1/me/cart/items/{id}':
    delete:
      tags:
        - Cart
      summary: 'Remove cart item'
      operationId: a65fab0b3a814407884e5ba02682d66a
      parameters:
        -
          name: id
          in: path
          description: 'Cart item ID'
          required: true
          schema:
            type: integer
      responses:
        204:
          description: Removed
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    patch:
      tags:
        - Cart
      summary: 'Update cart item'
      description: 'Update quantity; use 0 to remove.'
      operationId: be3bbf61104223e9fb44bf7af8783bb2
      parameters:
        -
          name: id
          in: path
          description: 'Cart item ID'
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCartItemRequestBody'
      responses:
        200:
          description: 'Updated or removed'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/me/checkout:
    post:
      tags:
        - Cart
      summary: Checkout
      description: 'Create order from cart. Optionally apply credit and set payment/shipping.'
      operationId: 728fc9ef77748f187ba047b4794f1fcd
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CheckoutRequestBody'
      responses:
        201:
          description: 'Order created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CheckoutSuccessResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        422:
          description: 'Validation / insufficient credit or cart invalid'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/admin/categories:
    get:
      tags:
        - 'Catalog (Admin)'
      summary: 'List categories'
      description: 'Paginated list of categories. Requires categories::View permission.'
      operationId: 28d2c154a67f401e03aeea257b7b0582
      parameters:
        -
          name: page
          in: query
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated category list'
          content:
            application/json:
              schema:
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CategoryResponse'
                type: object
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
    post:
      tags:
        - 'Catalog (Admin)'
      summary: 'Create category'
      description: 'Create a new category. Requires categories::Create permission.'
      operationId: 3d9179d86eaa92a52f9d5165413b9021
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreCategoryRequestBody'
      responses:
        201:
          description: 'Category created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CategoryResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  '/api/v1/admin/categories/{id}':
    put:
      tags:
        - 'Catalog (Admin)'
      summary: 'Update category'
      description: 'Update a category. Requires categories::Update permission.'
      operationId: 17ad714c9d495b1a9bd563754ddc8ff7
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCategoryRequestBody'
      responses:
        200:
          description: 'Category updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CategoryResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    delete:
      tags:
        - 'Catalog (Admin)'
      summary: 'Delete category'
      description: 'Delete a category. Requires categories::Delete permission.'
      operationId: 41bcb24f4fd531f7b3a7292e51ae715a
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        204:
          description: 'Category deleted'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/admin/products:
    get:
      tags:
        - 'Catalog (Admin)'
      summary: 'List products (admin)'
      description: 'Paginated list of all products. Requires products::View permission.'
      operationId: b99549f107851e9357822cc821d3b871
      parameters:
        -
          name: page
          in: query
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated product list'
          content:
            application/json:
              schema:
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ProductResponse'
                type: object
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
    post:
      tags:
        - 'Catalog (Admin)'
      summary: 'Create product'
      description: 'Create a new product. Requires products::Create permission.'
      operationId: 190c4f3dd6a69160f76195103540fd61
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreProductRequestBody'
      responses:
        201:
          description: 'Product created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  '/api/v1/admin/products/{id}':
    put:
      tags:
        - 'Catalog (Admin)'
      summary: 'Update product'
      description: 'Update a product. Requires products::Update permission.'
      operationId: 62bdac1bd07f4f13f5f9f8a770086c9b
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProductRequestBody'
      responses:
        200:
          description: 'Product updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    delete:
      tags:
        - 'Catalog (Admin)'
      summary: 'Delete product'
      description: 'Delete a product. Requires products::Delete permission.'
      operationId: f1a832de1a4036209391e9a3550bf8ba
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        204:
          description: 'Product deleted'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/admin/products/bulk-import:
    post:
      tags:
        - 'Catalog (Admin)'
      summary: 'Bulk import products'
      description: 'Queue bulk product import. Requires products::BulkImport permission.'
      operationId: f08eb73d136438254518483c29c70b3c
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkImportProductsRequestBody'
      responses:
        202:
          description: 'Import queued'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/admin/products/bulk-images:
    post:
      tags:
        - 'Catalog (Admin)'
      summary: 'Bulk upload product images'
      description: 'Queue bulk image upload for a product (multipart/form-data: product_id, images[]). Requires products::BulkImages permission.'
      operationId: 12ac509177c40a00c628f5ac6d980782
      responses:
        202:
          description: 'Upload queued'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/products:
    get:
      tags:
        - Catalog
      summary: 'List products'
      description: 'Public paginated list of active products.'
      operationId: c4407243169fe500d167d36047b01cda
      parameters:
        -
          name: page
          in: query
          description: 'Page number'
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated product list'
      security: []
  '/api/v1/products/{slug}':
    get:
      tags:
        - Catalog
      summary: 'Get product by slug'
      description: 'Public product details by slug. Price/stock visible only when authenticated.'
      operationId: 56a694711e6b05098ffed73ba7ef160d
      parameters:
        -
          name: slug
          in: path
          description: 'Product slug'
          required: true
          schema:
            type: string
      responses:
        200:
          description: Product
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
      security: []
  /api/v1/admin/credit/issue:
    post:
      tags:
        - 'Credit (Admin)'
      summary: 'Issue credit'
      description: 'Issue credit to a user. Requires credit::Issue permission.'
      operationId: 5dcadb98c34dc3c1ab0dc679c9db3591
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreditIssueRequestBody'
      responses:
        200:
          description: 'Credit issued'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/admin/credit/deduct:
    post:
      tags:
        - 'Credit (Admin)'
      summary: 'Deduct credit'
      description: 'Deduct credit from a user. Requires credit::Deduct permission.'
      operationId: a4611280072c21977f35d0ab1b3cffe1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreditDeductRequestBody'
      responses:
        200:
          description: 'Credit deducted'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error / insufficient balance'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/me/credit:
    get:
      tags:
        - Credit
      summary: 'Get credit balance'
      description: 'Current user credit balance.'
      operationId: ab703c2cdd12bbf8ee32db5f16603b62
      responses:
        200:
          description: 'Credit balance'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
  /api/v1/me/credit/ledger:
    get:
      tags:
        - Credit
      summary: 'Get credit ledger'
      description: 'Paginated credit transaction history for the current user.'
      operationId: 3e0aff57414c1a8a735141160bba9b9c
      parameters:
        -
          name: page
          in: query
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated ledger'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
  /api/v1/admin/accounts:
    get:
      tags:
        - 'Customers (Admin)'
      summary: 'List accounts'
      description: 'Paginated list of accounts with filters. Requires accounts::View permission.'
      operationId: a47e69d4f2d271ab6a1ad8d54d0a6806
      parameters:
        -
          name: page
          in: query
          description: 'Page number'
          schema:
            type: integer
        -
          name: per_page
          in: query
          description: 'Items per page'
          schema:
            type: integer
            default: 20
        -
          name: search
          in: query
          description: 'Search by name or contact email'
          schema:
            type: string
        -
          name: is_enabled
          in: query
          description: 'Filter by enabled status'
          schema:
            type: boolean
        -
          name: is_flagged
          in: query
          description: 'Filter by flagged status'
          schema:
            type: boolean
        -
          name: customer_group_id
          in: query
          description: 'Filter by customer group'
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated account list'
          content:
            application/json:
              schema:
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AccountResponse'
                type: object
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
    post:
      tags:
        - 'Customers (Admin)'
      summary: 'Create account'
      description: 'Create a new account. Requires accounts::Create permission.'
      operationId: ddaf6de5607a5a3a1419bac984f36d94
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreAccountRequestBody'
      responses:
        201:
          description: 'Account created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/admin/accounts/summary:
    get:
      tags:
        - 'Customers (Admin)'
      summary: 'Get account summary'
      description: 'Returns total, enabled, and flagged counts. Requires accounts::View permission.'
      operationId: ff63bb7b18f5b5ecc9df15428802e21a
      responses:
        200:
          description: 'Account summary'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountSummaryResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
  '/api/v1/admin/accounts/{id}':
    get:
      tags:
        - 'Customers (Admin)'
      summary: 'Get account details'
      description: 'Returns a single account with contacts and addresses. Requires accounts::View permission.'
      operationId: 63dd63211556f94c41f41983485efa54
      parameters:
        -
          name: id
          in: path
          description: 'Account ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'Account details'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    put:
      tags:
        - 'Customers (Admin)'
      summary: 'Update account'
      description: 'Update an account. Requires accounts::Update permission.'
      operationId: 01297fc4ee3f0140165f5b238aecff46
      parameters:
        -
          name: id
          in: path
          description: 'Account ID'
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAccountRequestBody'
      responses:
        200:
          description: 'Account updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    delete:
      tags:
        - 'Customers (Admin)'
      summary: 'Delete account'
      description: 'Soft delete an account. Requires accounts::Delete permission.'
      operationId: c50aa675d307224cfc94413d1de93f7a
      parameters:
        -
          name: id
          in: path
          description: 'Account ID'
          required: true
          schema:
            type: integer
      responses:
        204:
          description: 'Account deleted'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/admin/accounts/{id}/toggle-enabled':
    post:
      tags:
        - 'Customers (Admin)'
      summary: 'Toggle account enabled status'
      description: 'Toggle the enabled status of an account. Requires accounts::Update permission.'
      operationId: 9ca06952f90aae77d147af41e5da5223
      parameters:
        -
          name: id
          in: path
          description: 'Account ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'Account toggled'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/admin/accounts/{id}/toggle-flagged':
    post:
      tags:
        - 'Customers (Admin)'
      summary: 'Toggle account flagged status'
      description: 'Toggle the flagged status of an account. Requires accounts::Update permission.'
      operationId: d3b078e172bd242f0fc38d470a22507f
      parameters:
        -
          name: id
          in: path
          description: 'Account ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'Account toggled'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/admin/opportunities:
    get:
      tags:
        - 'Customers (Admin)'
      summary: 'List opportunities'
      description: 'Paginated list of opportunities with filters. Requires opportunities::View permission.'
      operationId: 4099eb4c2e255f7e362362f49d691ee9
      parameters:
        -
          name: page
          in: query
          description: 'Page number'
          schema:
            type: integer
        -
          name: per_page
          in: query
          description: 'Items per page'
          schema:
            type: integer
            default: 20
        -
          name: search
          in: query
          description: 'Search by account name or contact email'
          schema:
            type: string
        -
          name: status
          in: query
          description: 'Filter by status'
          schema:
            type: string
            enum:
              - new
              - working
              - converted
              - lost
        -
          name: sales_rep_id
          in: query
          description: 'Filter by sales rep'
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated opportunity list'
          content:
            application/json:
              schema:
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/OpportunityResponse'
                type: object
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
    post:
      tags:
        - 'Customers (Admin)'
      summary: 'Create opportunity'
      description: 'Create a new opportunity. Requires opportunities::Create permission.'
      operationId: bf07c0febb50f8bf085bb9a8adc046e2
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreOpportunityRequestBody'
      responses:
        201:
          description: 'Opportunity created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpportunityResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/admin/opportunities/summary:
    get:
      tags:
        - 'Customers (Admin)'
      summary: 'Get opportunity summary'
      description: 'Returns counts by status. Requires opportunities::View permission.'
      operationId: 25627d7b877f975e9f6639ace77b7c4b
      responses:
        200:
          description: 'Opportunity summary'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpportunitySummaryResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
  '/api/v1/admin/opportunities/{id}':
    get:
      tags:
        - 'Customers (Admin)'
      summary: 'Get opportunity details'
      description: 'Returns a single opportunity. Requires opportunities::View permission.'
      operationId: d7441c2997043bad39a3b74843b03b90
      parameters:
        -
          name: id
          in: path
          description: 'Opportunity ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'Opportunity details'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpportunityResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    put:
      tags:
        - 'Customers (Admin)'
      summary: 'Update opportunity'
      description: 'Update an opportunity. Requires opportunities::Update permission.'
      operationId: ed960270e8b06ce65ba864d0f649bad7
      parameters:
        -
          name: id
          in: path
          description: 'Opportunity ID'
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOpportunityRequestBody'
      responses:
        200:
          description: 'Opportunity updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpportunityResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    delete:
      tags:
        - 'Customers (Admin)'
      summary: 'Delete opportunity'
      description: 'Soft delete an opportunity. Requires opportunities::Delete permission.'
      operationId: e14d68d23aa3c4118bfc6073bd15236b
      parameters:
        -
          name: id
          in: path
          description: 'Opportunity ID'
          required: true
          schema:
            type: integer
      responses:
        204:
          description: 'Opportunity deleted'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/admin/opportunities/{id}/convert':
    post:
      tags:
        - 'Customers (Admin)'
      summary: 'Convert opportunity to account'
      description: 'Convert an opportunity to a full account. Requires opportunities::Convert permission.'
      operationId: ccf8c8cddd18a4b100189ecb3b900e36
      parameters:
        -
          name: id
          in: path
          description: 'Opportunity ID'
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConvertOpportunityRequestBody'
      responses:
        200:
          description: 'Opportunity converted'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpportunityResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/admin/opportunities/{id}/mark-lost':
    post:
      tags:
        - 'Customers (Admin)'
      summary: 'Mark opportunity as lost'
      description: 'Mark an opportunity as lost. Requires opportunities::Update permission.'
      operationId: d1e03061259fa8c26a548ddd05fa2066
      parameters:
        -
          name: id
          in: path
          description: 'Opportunity ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'Opportunity marked as lost'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpportunityResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/me/orders/{orderId}/invoice':
    get:
      tags:
        - Invoices
      summary: 'Get invoice (JSON)'
      description: 'Invoice details for an order belonging to the current user.'
      operationId: 0dc3be06ff9da813e995285887458d20
      parameters:
        -
          name: orderId
          in: path
          description: 'Order ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'Invoice data'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  '/api/v1/me/orders/{orderId}/invoice.pdf':
    get:
      tags:
        - Invoices
      summary: 'Download invoice PDF'
      description: 'Download invoice as PDF for an order belonging to the current user.'
      operationId: 48cba63737b1dcb9f93b47f17819bb74
      parameters:
        -
          name: orderId
          in: path
          description: 'Order ID'
          required: true
          schema:
            type: integer
      responses:
        200:
          description: 'PDF file'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/admin/orders:
    get:
      tags:
        - 'Orders (Admin)'
      summary: 'List orders'
      description: 'Paginated list of all orders. Requires orders::View permission.'
      operationId: e5c3267a5b16d9b5a4772478ebcec62b
      parameters:
        -
          name: page
          in: query
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated order list'
          content:
            application/json:
              schema:
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/OrderResponse'
                type: object
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
  '/api/v1/admin/orders/{id}/status':
    patch:
      tags:
        - 'Orders (Admin)'
      summary: 'Update order status'
      description: 'Transition order to a new status (state machine). Requires orders::UpdateStatus permission.'
      operationId: 706788146083242658a0485dcc07fca0
      parameters:
        -
          name: id
          in: path
          description: 'Order ID'
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderUpdateStatusRequestBody'
      responses:
        200:
          description: 'Order status updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
        422:
          description: 'Invalid transition'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  /api/v1/me/orders:
    get:
      tags:
        - Orders
      summary: 'List my orders'
      description: 'Paginated list of orders for the current user.'
      operationId: b5ae8cf28a5ba0e390f50c5f89d2650a
      parameters:
        -
          name: page
          in: query
          schema:
            type: integer
      responses:
        200:
          description: 'Paginated order list'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
  '/api/v1/me/orders/{id}':
    get:
      tags:
        - Orders
      summary: 'Get order'
      description: 'Order details for the current user.'
      operationId: 3ee3498f9336288c8c27ef46f853d5c5
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        200:
          description: Order
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/admin/payment-methods:
    get:
      tags:
        - 'Payments (Admin)'
      summary: 'List payment methods'
      description: 'List all payment methods. Requires paymentMethods::View permission.'
      operationId: 6f8da5d517e8fa3c69add16721716ec7
      responses:
        200:
          description: 'Payment method list'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PaymentMethodResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
    post:
      tags:
        - 'Payments (Admin)'
      summary: 'Create payment method'
      description: 'Create a payment method. Requires paymentMethods::Create permission.'
      operationId: 3e14a2468939c3a3ecd31f550821d385
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StorePaymentMethodRequestBody'
      responses:
        201:
          description: 'Payment method created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentMethodResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  '/api/v1/admin/payment-methods/{id}':
    put:
      tags:
        - 'Payments (Admin)'
      summary: 'Update payment method'
      description: 'Update a payment method. Requires paymentMethods::Update permission.'
      operationId: 37c8978f4b885fdfcfcaca02c4f95cea
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePaymentMethodRequestBody'
      responses:
        200:
          description: 'Payment method updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentMethodResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    delete:
      tags:
        - 'Payments (Admin)'
      summary: 'Delete payment method'
      description: 'Delete a payment method. Requires paymentMethods::Delete permission.'
      operationId: 4042cff8ada3a621af6da603949992cf
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        204:
          description: 'Payment method deleted'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/admin/reporting/summary:
    get:
      tags:
        - 'Reporting (Admin)'
      summary: 'Reporting summary'
      description: 'Admin metrics: total orders, revenue, users count, credit issued/used. Requires reporting::View permission.'
      operationId: da40b67295608130e186a9a25d3107f5
      responses:
        200:
          description: 'Summary metrics'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportingSummaryResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
  /api/v1/admin/shipping-methods:
    get:
      tags:
        - 'Shipping (Admin)'
      summary: 'List shipping methods'
      description: 'List all shipping methods. Requires shippingMethods::View permission.'
      operationId: bfe9397cfa09745753fcbf4bb8c741ca
      responses:
        200:
          description: 'Shipping method list'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ShippingMethodResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
    post:
      tags:
        - 'Shipping (Admin)'
      summary: 'Create shipping method'
      description: 'Create a shipping method. Requires shippingMethods::Create permission.'
      operationId: d1a08509ddeda03ad3fa97ca5fe1e401
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreShippingMethodRequestBody'
      responses:
        201:
          description: 'Shipping method created'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShippingMethodResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        422:
          description: 'Validation error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
  '/api/v1/admin/shipping-methods/{id}':
    put:
      tags:
        - 'Shipping (Admin)'
      summary: 'Update shipping method'
      description: 'Update a shipping method. Requires shippingMethods::Update permission.'
      operationId: e3d7d6a8a538cd89fabb292f31f9c15d
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateShippingMethodRequestBody'
      responses:
        200:
          description: 'Shipping method updated'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShippingMethodResponse'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
    delete:
      tags:
        - 'Shipping (Admin)'
      summary: 'Delete shipping method'
      description: 'Delete a shipping method. Requires shippingMethods::Delete permission.'
      operationId: 046239a7bafe14ea66df99db34022dab
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        204:
          description: 'Shipping method deleted'
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedResponse'
        403:
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
        404:
          description: 'Not found'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundResponse'
  /api/v1/oauth/token:
    post:
      tags:
        - Authentication
      summary: 'Issue access token (Password Grant)'
      description: 'Exchange username and password for an access token. Use the returned `access_token` in the Authorization header as `Bearer {access_token}`. Password grant requires a valid `g-recaptcha-response` (reCAPTCHA v2) in production when `RECAPTCHA_SECRET_KEY` is set.'
      operationId: 80e0ddf19ccaf0748938a5b542e7137e
      requestBody:
        required: true
        content:
          application/json:
            schema:
              required:
                - grant_type
                - client_id
                - client_secret
                - username
                - password
              properties:
                grant_type:
                  type: string
                  example: password
                client_id:
                  description: 'OAuth2 client ID'
                  type: string
                client_secret:
                  description: 'OAuth2 client secret'
                  type: string
                username:
                  description: 'User email'
                  type: string
                password:
                  description: 'User password'
                  type: string
                g-recaptcha-response:
                  description: 'Required for grant_type `password`: Google reCAPTCHA v2 token, verified server-side. Omit for other grants on this route.'
                  type: string
              type: object
      responses:
        200:
          description: 'Access token and refresh token'
        401:
          description: 'Invalid credentials'
        422:
          description: 'reCAPTCHA missing or invalid (password grant)'
      security: []
  /api/v1/oauth/token/refresh:
    post:
      tags:
        - Authentication
      summary: 'Refresh access token'
      description: 'Exchange a refresh_token for a new access token.'
      operationId: 662e05a9bb6a4c869083cb09a9d449b9
      requestBody:
        required: true
        content:
          application/json:
            schema:
              required:
                - grant_type
                - client_id
                - client_secret
                - refresh_token
              properties:
                grant_type:
                  type: string
                  example: refresh_token
                client_id:
                  type: string
                client_secret:
                  type: string
                refresh_token:
                  type: string
              type: object
      responses:
        200:
          description: 'New access token'
        401:
          description: 'Invalid or expired refresh token'
      security: []
components:
  schemas:
    ConflictResponse:
      title: 'Conflict Response'
      description: 'The request conflicts with the current state of the resource (e.g. attendance already recorded).'
      properties:
        message:
          description: 'Conflict description.'
          type: string
          example: 'Attendance already recorded for this student on this date.'
      type: object
    ForbiddenResponse:
      title: 'Forbidden Response'
      description: 'The response when the user is forbidden from the resource.'
      properties:
        message:
          description: 'The action you are trying to perform is forbidden.'
          type: string
          example: Forbidden
      type: object
    InternalServerErrorResponse:
      title: 'Internal Server Error Response'
      description: 'The response when the server is unable to handle the request.'
      properties:
        message:
          description: 'Contains the error message of the exception.'
          type: string
          example: 'Internal Server Error'
      type: object
    NotFoundResponse:
      title: 'Not Found Response'
      description: 'The requested resource was not found.'
      properties:
        message:
          description: 'The requested resource was not found.'
          type: string
          example: 'Not Found'
      type: object
    UnauthorizedResponse:
      title: 'Unauthorized Response'
      description: 'The response when the user is not authenticated.'
      properties:
        message:
          description: 'The user is not authenticated.'
          type: string
          example: Unauthorized
      type: object
    UnprocessableEntityResponse:
      title: 'Unprocessable Entity Response'
      description: 'The response when the request cannot be processed.'
      properties:
        message:
          description: 'The main error message.'
          type: string
          example: 'These credentials do not match our records.'
        errors:
          description: 'Detailed validation errors.'
          properties:
            email:
              description: 'List of errors related to the email field.'
              type: array
              items:
                type: string
                example: 'These credentials do not match our records.'
          type: object
      type: object
    AddCartItemRequestBody:
      title: 'Add Cart Item Request'
      description: 'Request body for adding a product to the cart.'
      required:
        - product_id
        - quantity
      properties:
        product_id:
          description: 'Product ID'
          type: integer
        quantity:
          description: Quantity
          type: integer
          minimum: 1
      type: object
    AssignPermissionsRequestBody:
      title: 'Assign Permissions Request'
      description: 'Request body for assigning permissions to a role.'
      properties:
        permissions:
          description: 'List of permission names'
          type: array
          items:
            type: string
      type: object
    BulkImportProductsRequestBody:
      title: 'Bulk Import Products Request'
      description: 'Request body for bulk product import.'
      required:
        - items
      properties:
        items:
          type: array
          items:
            required:
              - name
              - slug
              - price
              - stock
            properties:
              name:
                type: string
              slug:
                type: string
              price:
                type: number
              stock:
                type: integer
            type: object
      type: object
    CheckoutRequestBody:
      title: 'Checkout Request'
      description: 'Request body for checkout (create order from cart).'
      properties:
        payment_method_id:
          description: 'Payment method ID'
          type:
            - integer
            - 'null'
        credit_amount:
          description: 'Amount of credit to apply'
          type:
            - number
            - 'null'
          format: float
          minimum: 0
        shipping_address:
          description: 'Shipping address key-value pairs'
          type:
            - object
            - 'null'
      type: object
    ConvertOpportunityRequestBody:
      title: 'Convert Opportunity Request'
      required:
        - account_id
      properties:
        account_id:
          description: 'The ID of the account to link to'
          type: integer
          example: 1
      type: object
    CreditDeductRequestBody:
      title: 'Credit Deduct Request'
      description: 'Request body for deducting credit from a user.'
      required:
        - user_id
        - amount
      properties:
        user_id:
          description: 'User ID'
          type: integer
        amount:
          description: 'Amount to deduct'
          type: number
          format: float
          minimum: 0.01
        reference:
          description: 'Reference note'
          type:
            - string
            - 'null'
          maxLength: 255
      type: object
    CreditIssueRequestBody:
      title: 'Credit Issue Request'
      description: 'Request body for issuing credit to a user.'
      required:
        - user_id
        - amount
      properties:
        user_id:
          description: 'User ID'
          type: integer
        amount:
          description: 'Amount to issue'
          type: number
          format: float
          minimum: 0.01
        reference:
          description: 'Reference note'
          type:
            - string
            - 'null'
          maxLength: 255
      type: object
    OrderUpdateStatusRequestBody:
      title: 'Order Update Status Request'
      description: 'Request body for updating order status.'
      required:
        - status
      properties:
        status:
          description: 'Target status'
          type: string
          enum:
            - confirmed
            - packed
            - shipped
            - delivered
            - cancelled
        note:
          description: 'Optional note for audit'
          type:
            - string
            - 'null'
      type: object
    StoreAccountRequestBody:
      title: 'Store Account Request'
      required:
        - name
      properties:
        name:
          type: string
          maxLength: 255
          example: 'Bluewater Reef Aquatics'
        customer_group_id:
          type:
            - integer
            - 'null'
          example: 1
        is_enabled:
          type: boolean
          default: true
        is_flagged:
          type: boolean
          default: false
        website:
          type:
            - string
            - 'null'
          format: uri
          example: 'https://example.com'
        tax_id:
          type:
            - string
            - 'null'
          maxLength: 100
        business_since:
          type:
            - string
            - 'null'
          format: date
          example: '2020-01-15'
        coral_system_gallons:
          type:
            - string
            - 'null'
          maxLength: 100
        sales_rep_id:
          type:
            - integer
            - 'null'
          example: 1
        notes:
          type:
            - string
            - 'null'
      type: object
    StoreCategoryRequestBody:
      title: 'Store Category Request'
      description: 'Request body for creating a category.'
      required:
        - name
      properties:
        name:
          description: 'Category name'
          type: string
          maxLength: 255
        slug:
          description: 'URL slug'
          type:
            - string
            - 'null'
          maxLength: 255
        parent_id:
          description: 'Parent category ID'
          type:
            - integer
            - 'null'
      type: object
    StoreOpportunityRequestBody:
      title: 'Store Opportunity Request'
      required:
        - account_name
      properties:
        account_name:
          type: string
          maxLength: 255
          example: 'Bluewater Reef Aquatics'
        status:
          type: string
          default: new
          enum:
            - new
            - working
            - converted
            - lost
        customer_group_id:
          type:
            - integer
            - 'null'
          example: 1
        main_contact_email:
          type:
            - string
            - 'null'
          format: email
          example: contact@example.com
        main_contact_name:
          type:
            - string
            - 'null'
          maxLength: 255
        main_contact_phone:
          type:
            - string
            - 'null'
          maxLength: 50
        sales_rep_id:
          type:
            - integer
            - 'null'
          example: 1
        website:
          type:
            - string
            - 'null'
          format: uri
          example: 'https://example.com'
        tax_id:
          type:
            - string
            - 'null'
          maxLength: 100
        business_since:
          type:
            - string
            - 'null'
          format: date
          example: '2020-01-15'
        coral_system_gallons:
          type:
            - string
            - 'null'
          maxLength: 100
        notes:
          type:
            - string
            - 'null'
      type: object
    StorePaymentMethodRequestBody:
      title: 'Store Payment Method Request'
      description: 'Request body for creating a payment method.'
      required:
        - name
        - type
      properties:
        name:
          type: string
          maxLength: 255
        type:
          type: string
          maxLength: 255
        is_active:
          type: boolean
          default: true
      type: object
    StoreProductRequestBody:
      title: 'Store Product Request'
      description: 'Request body for creating a product.'
      required:
        - name
        - slug
        - price
        - stock
      properties:
        name:
          type: string
          maxLength: 255
        slug:
          type: string
          maxLength: 255
        description:
          type:
            - string
            - 'null'
        price:
          type: number
          format: float
          minimum: 0
        stock:
          type: integer
          minimum: 0
        is_active:
          type: boolean
          default: true
        categories:
          description: 'Category IDs'
          type: array
          items:
            type: integer
      type: object
    StoreRoleRequestBody:
      title: 'Store Role Request'
      description: 'Request body for creating a role.'
      required:
        - name
      properties:
        name:
          description: 'Role name'
          type: string
          maxLength: 255
        guard_name:
          description: 'Guard name'
          type: string
          enum:
            - web
            - api
      type: object
    StoreShippingMethodRequestBody:
      title: 'Store Shipping Method Request'
      description: 'Request body for creating a shipping method.'
      required:
        - name
        - type
      properties:
        name:
          type: string
          maxLength: 255
        type:
          type: string
          maxLength: 255
        is_active:
          type: boolean
          default: true
        config:
          description: 'Optional config key-value'
          type:
            - object
            - 'null'
      type: object
    SuspendUserRequestBody:
      title: 'Suspend User Request'
      description: 'Optional request body when suspending a user.'
      properties:
        reason:
          description: 'Reason for suspension'
          type:
            - string
            - 'null'
      type: object
    UpdateAccountRequestBody:
      title: 'Update Account Request'
      properties:
        name:
          type: string
          maxLength: 255
          example: 'Bluewater Reef Aquatics'
        customer_group_id:
          type:
            - integer
            - 'null'
          example: 1
        is_enabled:
          type: boolean
        is_flagged:
          type: boolean
        website:
          type:
            - string
            - 'null'
          format: uri
          example: 'https://example.com'
        tax_id:
          type:
            - string
            - 'null'
          maxLength: 100
        business_since:
          type:
            - string
            - 'null'
          format: date
          example: '2020-01-15'
        coral_system_gallons:
          type:
            - string
            - 'null'
          maxLength: 100
        sales_rep_id:
          type:
            - integer
            - 'null'
          example: 1
        notes:
          type:
            - string
            - 'null'
      type: object
    UpdateCartItemRequestBody:
      title: 'Update Cart Item Request'
      description: 'Request body for updating cart item quantity.'
      required:
        - quantity
      properties:
        quantity:
          description: 'New quantity (0 to remove).'
          type: integer
          minimum: 0
      type: object
    UpdateCategoryRequestBody:
      title: 'Update Category Request'
      description: 'Request body for updating a category.'
      properties:
        name:
          type: string
          maxLength: 255
        slug:
          type: string
          maxLength: 255
        parent_id:
          type:
            - integer
            - 'null'
      type: object
    UpdateOpportunityRequestBody:
      title: 'Update Opportunity Request'
      properties:
        account_name:
          type: string
          maxLength: 255
          example: 'Bluewater Reef Aquatics'
        status:
          type: string
          enum:
            - new
            - working
            - converted
            - lost
        customer_group_id:
          type:
            - integer
            - 'null'
          example: 1
        main_contact_email:
          type:
            - string
            - 'null'
          format: email
          example: contact@example.com
        main_contact_name:
          type:
            - string
            - 'null'
          maxLength: 255
        main_contact_phone:
          type:
            - string
            - 'null'
          maxLength: 50
        sales_rep_id:
          type:
            - integer
            - 'null'
          example: 1
        website:
          type:
            - string
            - 'null'
          format: uri
          example: 'https://example.com'
        tax_id:
          type:
            - string
            - 'null'
          maxLength: 100
        business_since:
          type:
            - string
            - 'null'
          format: date
          example: '2020-01-15'
        coral_system_gallons:
          type:
            - string
            - 'null'
          maxLength: 100
        notes:
          type:
            - string
            - 'null'
      type: object
    UpdatePaymentMethodRequestBody:
      title: 'Update Payment Method Request'
      description: 'Request body for updating a payment method.'
      properties:
        name:
          type: string
          maxLength: 255
        type:
          type: string
          maxLength: 255
        is_active:
          type: boolean
      type: object
    UpdateProductRequestBody:
      title: 'Update Product Request'
      description: 'Request body for updating a product.'
      properties:
        name:
          type: string
          maxLength: 255
        slug:
          type: string
          maxLength: 255
        description:
          type:
            - string
            - 'null'
        price:
          type: number
          format: float
          minimum: 0
        stock:
          type: integer
          minimum: 0
        is_active:
          type: boolean
        categories:
          type: array
          items:
            type: integer
      type: object
    UpdateRoleRequestBody:
      title: 'Update Role Request'
      description: 'Request body for updating a role.'
      properties:
        name:
          description: 'Role name'
          type: string
          maxLength: 255
      type: object
    UpdateShippingMethodRequestBody:
      title: 'Update Shipping Method Request'
      description: 'Request body for updating a shipping method.'
      properties:
        name:
          type: string
          maxLength: 255
        type:
          type: string
          maxLength: 255
        is_active:
          type: boolean
        config:
          type:
            - object
            - 'null'
      type: object
    AccountAddressResponse:
      title: 'Account Address Response'
      required:
        - id
        - type
        - address_1
        - city
        - state
        - zip
        - country
      properties:
        id:
          type: integer
          example: 1
        type:
          type: string
          enum:
            - bill_to
            - ship_to
          example: ship_to
        location_name:
          type:
            - string
            - 'null'
          example: 'Main Warehouse'
        first_name:
          type:
            - string
            - 'null'
          example: John
        last_name:
          type:
            - string
            - 'null'
          example: Doe
        full_name:
          type:
            - string
            - 'null'
          example: 'John Doe'
        company:
          type:
            - string
            - 'null'
          example: 'Acme Inc'
        phone:
          type:
            - string
            - 'null'
          example: +1-555-123-4567
        address_1:
          type: string
          example: '123 Main St'
        address_2:
          type:
            - string
            - 'null'
          example: 'Suite 100'
        city:
          type: string
          example: 'Los Angeles'
        state:
          type: string
          example: CA
        zip:
          type: string
          example: '90001'
        country:
          type: string
          example: US
        full_address:
          type: string
          example: '123 Main St, Suite 100, Los Angeles, CA 90001, US'
        location_zoning:
          type:
            - string
            - 'null'
        external_id:
          type:
            - string
            - 'null'
        is_default:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
      type: object
    AccountContactResponse:
      title: 'Account Contact Response'
      required:
        - id
        - email
      properties:
        id:
          type: integer
          example: 1
        first_name:
          type:
            - string
            - 'null'
          example: John
        last_name:
          type:
            - string
            - 'null'
          example: Doe
        full_name:
          type:
            - string
            - 'null'
          example: 'John Doe'
        email:
          type: string
          example: john@example.com
        phone:
          type:
            - string
            - 'null'
          example: +1-555-123-4567
        type:
          type: string
          enum:
            - main
            - billing
            - shipping
            - viewer
          example: main
        role:
          type: string
          enum:
            - manager
            - buyer
            - viewer
            - administrator
          example: buyer
        is_primary:
          type: boolean
          example: true
        send_invitation:
          type: boolean
          example: false
        created_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
      type: object
    AccountResponse:
      title: 'Account Response'
      required:
        - id
        - name
        - slug
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: 'Bluewater Reef Aquatics'
        slug:
          type: string
          example: bluewater-reef-aquatics
        customer_group:
          properties:
            id:
              type: integer
              example: 1
            name:
              type: string
              example: 'Wholesale Tier 1'
            slug:
              type: string
              example: wholesale-tier-1
          type:
            - object
            - 'null'
        is_enabled:
          type: boolean
          example: true
        is_flagged:
          type: boolean
          example: false
        website:
          type:
            - string
            - 'null'
          example: 'https://example.com'
        tax_id:
          type:
            - string
            - 'null'
          example: 12-3456789
        business_since:
          type:
            - string
            - 'null'
          format: date
          example: '2020-01-15'
        coral_system_gallons:
          type:
            - string
            - 'null'
          example: '500'
        sales_rep:
          properties:
            id:
              type: integer
              example: 1
            name:
              type: string
              example: 'John Doe'
            email:
              type: string
              example: john@example.com
          type:
            - object
            - 'null'
        contacts_count:
          type:
            - integer
            - 'null'
          example: 3
        contacts:
          type:
            - array
            - 'null'
          items:
            $ref: '#/components/schemas/AccountContactResponse'
        addresses:
          type:
            - array
            - 'null'
          items:
            $ref: '#/components/schemas/AccountAddressResponse'
        notes:
          type:
            - string
            - 'null'
        created_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
      type: object
    AccountSummaryResponse:
      title: 'Account Summary Response'
      properties:
        total:
          type: integer
          example: 150
        enabled:
          type: integer
          example: 145
        flagged:
          type: integer
          example: 5
      type: object
    CategoryResponse:
      title: 'Category Response'
      required:
        - id
        - name
      properties:
        id:
          type: integer
        name:
          type: string
        slug:
          type:
            - string
            - 'null'
        parent_id:
          type:
            - integer
            - 'null'
      type: object
    CheckoutSuccessResponse:
      title: 'Checkout Success Response'
      required:
        - order_id
        - message
      properties:
        order_id:
          type: integer
        message:
          type: string
          example: 'Order created'
      type: object
    CreditBalanceResponse:
      title: 'Credit Balance Response'
      required:
        - balance
      properties:
        balance:
          type: number
          format: float
      type: object
    ErrorResponse:
      title: 'Error Response'
      description: 'Generic error response with message and optional validation errors.'
      properties:
        message:
          description: 'Error message'
          type: string
        errors:
          description: 'Validation errors (field name => array of message strings)'
          type: object
      type: object
    InvoiceResponse:
      title: 'Invoice Response'
      required:
        - id
        - invoice_number
        - total
      properties:
        id:
          type: integer
        invoice_number:
          type: string
        invoice_date:
          type: string
          format: date
        customer_name:
          type: string
        customer_email:
          type: string
        items:
          type: array
          items:
            type: object
        subtotal:
          type: number
          format: float
        tax_amount:
          type:
            - number
            - 'null'
          format: float
        total:
          type: number
          format: float
        credit_used:
          type: number
          format: float
        payment_method_name:
          type:
            - string
            - 'null'
        transaction_reference:
          type:
            - string
            - 'null'
        transaction_status:
          type:
            - string
            - 'null'
        shipping_address:
          type:
            - object
            - 'null'
        shipping_method_name:
          type:
            - string
            - 'null'
        tracking_number:
          type:
            - string
            - 'null'
        estimated_delivery_at:
          type:
            - string
            - 'null'
          format: date-time
      type: object
    MessageResponse:
      title: 'Message Response'
      description: 'Simple success response with a message.'
      required:
        - message
      properties:
        message:
          type: string
          example: Success
      type: object
    OpportunityResponse:
      title: 'Opportunity Response'
      required:
        - id
        - account_name
        - status
      properties:
        id:
          type: integer
          example: 1
        account_name:
          type: string
          example: 'Bluewater Reef Aquatics'
        status:
          type: string
          enum:
            - new
            - working
            - converted
            - lost
          example: new
        account:
          properties:
            id:
              type: integer
              example: 1
            name:
              type: string
              example: 'Bluewater Reef Aquatics'
            slug:
              type: string
              example: bluewater-reef-aquatics
          type:
            - object
            - 'null'
        customer_group:
          properties:
            id:
              type: integer
              example: 1
            name:
              type: string
              example: 'Wholesale Tier 1'
            slug:
              type: string
              example: wholesale-tier-1
          type:
            - object
            - 'null'
        main_contact_email:
          type:
            - string
            - 'null'
          example: contact@example.com
        main_contact_name:
          type:
            - string
            - 'null'
          example: 'John Doe'
        main_contact_phone:
          type:
            - string
            - 'null'
          example: +1-555-123-4567
        sales_rep:
          properties:
            id:
              type: integer
              example: 1
            name:
              type: string
              example: 'John Doe'
            email:
              type: string
              example: john@example.com
          type:
            - object
            - 'null'
        website:
          type:
            - string
            - 'null'
          example: 'https://example.com'
        tax_id:
          type:
            - string
            - 'null'
          example: 12-3456789
        business_since:
          type:
            - string
            - 'null'
          format: date
          example: '2020-01-15'
        coral_system_gallons:
          type:
            - string
            - 'null'
          example: '500'
        notes:
          type:
            - string
            - 'null'
        converted_at:
          type:
            - string
            - 'null'
          format: date-time
          example: '2026-04-24T10:00:00Z'
        created_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-04-24T10:00:00Z'
      type: object
    OpportunitySummaryResponse:
      title: 'Opportunity Summary Response'
      properties:
        total:
          type: integer
          example: 136
        new:
          type: integer
          example: 20
        working:
          type: integer
          example: 80
        converted:
          type: integer
          example: 30
        lost:
          type: integer
          example: 6
      type: object
    OrderResponse:
      title: 'Order Response'
      required:
        - id
        - total
        - status
      properties:
        id:
          type: integer
        total:
          type: number
          format: float
        status:
          type: string
        credit_used:
          type:
            - number
            - 'null'
          format: float
        created_at:
          type:
            - string
            - 'null'
          format: date-time
        items:
          type:
            - array
            - 'null'
          items:
            type: object
        tracking_number:
          type:
            - string
            - 'null'
        estimated_delivery_at:
          type:
            - string
            - 'null'
          format: date-time
      type: object
    PaymentMethodResponse:
      title: 'Payment Method Response'
      required:
        - id
        - name
        - type
      properties:
        id:
          type: integer
        name:
          type: string
        type:
          type: string
        is_active:
          type: boolean
      type: object
    ProductResponse:
      title: 'Product Response'
      required:
        - id
        - name
        - slug
      properties:
        id:
          type: integer
        name:
          type: string
        slug:
          type: string
        description:
          type:
            - string
            - 'null'
        price:
          description: 'Only when authenticated'
          type:
            - number
            - 'null'
          format: float
        stock:
          description: 'Only when authenticated'
          type:
            - integer
            - 'null'
        is_active:
          type:
            - boolean
            - 'null'
        categories:
          type:
            - array
            - 'null'
          items:
            $ref: '#/components/schemas/CategoryResponse'
      type: object
    ProfileResponse:
      title: 'Profile Response'
      description: 'Current user profile (me).'
      required:
        - id
        - name
        - email
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: 'John Doe'
        email:
          type: string
          format: email
          example: john@example.com
        email_verified_at:
          description: 'ISO 8601'
          type:
            - string
            - 'null'
          format: date-time
      type: object
    ReportingSummaryResponse:
      title: 'Reporting Summary Response'
      required:
        - total_orders
        - revenue
        - users_count
        - credit_issued_sum
        - credit_used_sum
      properties:
        total_orders:
          type: integer
        revenue:
          type: number
          format: float
        users_count:
          type: integer
        credit_issued_sum:
          type: number
          format: float
        credit_used_sum:
          type: number
          format: float
      type: object
    RoleResponse:
      title: 'Role Response'
      description: 'Role with optional permissions.'
      required:
        - id
        - name
        - guard_name
      properties:
        id:
          type: integer
        name:
          type: string
        guard_name:
          type: string
        permissions:
          type:
            - array
            - 'null'
          items:
            type: string
      type: object
    ShippingMethodResponse:
      title: 'Shipping Method Response'
      required:
        - id
        - name
        - type
      properties:
        id:
          type: integer
        name:
          type: string
        type:
          type: string
        is_active:
          type: boolean
        config:
          type:
            - object
            - 'null'
      type: object
    UserActionResponse:
      title: 'User Action Response'
      description: 'Response for approve/suspend with message and updated user.'
      required:
        - message
        - user
      properties:
        message:
          type: string
          example: 'User approved'
        user:
          $ref: '#/components/schemas/UserResponse'
      type: object
    UserResponse:
      title: 'User Response'
      description: 'User with optional status and roles.'
      required:
        - id
        - name
        - email
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email
        email_verified_at:
          type:
            - string
            - 'null'
          format: date-time
        created_at:
          type:
            - string
            - 'null'
          format: date-time
        updated_at:
          type:
            - string
            - 'null'
          format: date-time
        status:
          type:
            - string
            - 'null'
          enum:
            - pending
            - active
            - suspended
        roles:
          type:
            - array
            - 'null'
          items:
            type: string
      type: object
  securitySchemes:
    bearerAuth:
      type: http
      description: 'Laravel Passport token. Obtain via POST /oauth/token (password grant).'
      bearerFormat: JWT
      scheme: bearer
security:
  -
    bearerAuth: []
tags:
  -
    name: 'Access (Admin)'
    description: 'Access (Admin)'
  -
    name: Access
    description: Access
  -
    name: Cart
    description: Cart
  -
    name: 'Catalog (Admin)'
    description: 'Catalog (Admin)'
  -
    name: Catalog
    description: Catalog
  -
    name: 'Credit (Admin)'
    description: 'Credit (Admin)'
  -
    name: Credit
    description: Credit
  -
    name: 'Customers (Admin)'
    description: 'Customers (Admin)'
  -
    name: Invoices
    description: Invoices
  -
    name: 'Orders (Admin)'
    description: 'Orders (Admin)'
  -
    name: Orders
    description: Orders
  -
    name: 'Payments (Admin)'
    description: 'Payments (Admin)'
  -
    name: 'Reporting (Admin)'
    description: 'Reporting (Admin)'
  -
    name: 'Shipping (Admin)'
    description: 'Shipping (Admin)'
  -
    name: Authentication
    description: Authentication
