openapi: 3.0.3
info:
  title: PUP - Seller Account API v1
  description: >
    PUP is the universal player profile for padel. This API provides seller account management.
  version: 1.0.0

servers:
  - url: https://api.gopup.app
    description: Development server

x-tagGroups:
  - name: Seller
    tags:
      - sellers
      - team-members
      - wallet

tags:
  - name: sellers
    x-displayName: "Sellers"
    description: Create, search, update and manage seller accounts
  - name: team-members
    x-displayName: "Team Members"
    description: Manage team members and invitations
  - name: wallet
    x-displayName: "Wallet"
    description: Operations related to seller wallet and transactions

security:
  - OAuth2:
      - urn:pup:seller:read
  - PAT: []

paths:
  /seller/v1/new:
    post:
      tags:
        - sellers
      operationId: createSellerAccount
      summary: Create a new seller account
      description: Creates a new seller account.
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSellerAccountRequest'
      responses:
        '201':
          description: Seller account created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateSellerAccountCreated'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/search:
    get:
      tags:
        - sellers
      operationId: searchSellerAccounts
      summary: Search seller accounts
      description: Lists seller accounts with optional filters.
      security:
        - OAuth2:
            - urn:pup:seller:read
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: term
          in: query
          required: false
          schema:
            type: string
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 0
            default: 0
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchSellerAccountsResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/seller/{id}:
    get:
      tags:
        - sellers
      operationId: findSellerAccountById
      summary: Find seller account by ID
      description: Returns a seller account by ID.
      security:
        - OAuth2:
            - urn:pup:seller:read
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Seller account details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SellerAccountResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

    patch:
      tags:
        - sellers
      operationId: updateSellerAccount
      summary: Update seller account
      description: Updates seller account details.
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSellerAccountRequest'
      responses:
        '204':
          description: Seller account updated
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/seller/{id}/tax:
    get:
      tags:
        - sellers
      operationId: getSellerAccountTax
      summary: Get seller tax rate
      description: Returns the tax rate of a seller account by ID. Only accessible to seller-tax-admin.
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Seller tax rate
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetSellerAccountTaxResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

    put:
      tags:
        - sellers
      operationId: updateSellerAccountTax
      summary: Update seller tax rate
      description: Updates the tax rate for a seller account. Only accessible to seller-tax-admin.
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSellerAccountTaxRequest'
      responses:
        '204':
          description: Seller tax rate updated
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/seller/{id}/wallet:
    get:
      deprecated: true
      tags:
        - wallet
      summary: Get seller wallet
      description: Returns the seller's wallet balance and details. Requires user to have manage permissions on the seller account.
      operationId: getSellerWallet
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: id
          in: path
          required: true
          description: Seller ID
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: "018f4a3e-4f5a-7123-8abc-def012345001"
      responses:
        '200':
          description: Wallet details retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - User is not a manager of this seller account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Seller wallet not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Generic error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /seller/v1/seller/{id}/wallet/transactions:
    get:
      deprecated: true
      tags:
        - wallet
      summary: Get seller wallet transactions
      description: Returns the seller's wallet transaction history with pagination and filtering. Requires user to have manage permissions on the seller account.
      operationId: getSellerWalletTransactions
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: id
          in: path
          required: true
          description: Seller ID
          schema:
            type: string
            minLength: 1
            maxLength: 64
          example: "018f4a3e-4f5a-7123-8abc-def012345001"
        - name: transaction_type
          in: query
          required: false
          description: Filter by transaction type
          schema:
            type: string
            enum: [challenge_reward, spend_credits, purchase_credits, reversal, platform_fee, refund, escrow_funding]
          example: "spend_credits"
        - name: date_range
          in: query
          required: false
          description: Recorded-at date range to search. Defaults to the previous UTC calendar month when `year_month` is absent.
          schema:
            $ref: '#/components/schemas/WalletTransactionDateRange'
        - name: year_month
          in: query
          required: false
          description: Exact recorded month to browse, formatted as YYYY-MM. When provided, it takes precedence over date_range.
          schema:
            type: string
            pattern: '^\d{4}-(0[1-9]|1[0-2])$'
          example: '2026-04'
        - name: after_id
          in: query
          required: false
          description: Cursor for fetching older transactions than the referenced transaction ID.
          schema:
            type: string
          example: "018f23b2-6a18-7c6e-b5f2-7a22b5f7a001"
        - name: before_id
          in: query
          required: false
          description: Cursor for fetching newer transactions than the referenced transaction ID.
          schema:
            type: string
          example: "018f23b2-6a18-7c6e-b5f2-7a22b5f7a001"
        - name: limit
          in: query
          required: false
          description: Limit for pagination (default 20, max 100)
          schema:
            type: integer
            format: int32
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: Transaction history retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionsResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - User is not a manager of this seller account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Seller wallet not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Generic error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /seller/v1/{seller_account_id}/team-members/invitations:
    get:
      tags:
        - team-members
      summary: List pending seller team member invitations
      description: Returns the list of pending team member invitations for a seller account. Only owners/managers can view.
      operationId: listSellerTeamInvitations
      parameters:
        - in: path
          name: seller_account_id
          required: true
          schema:
            type: string
          description: The seller account ID
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      responses:
        '200':
          description: List of pending team invitations retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SellerTeamInvitationListResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Seller account not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Generic error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/{seller_account_id}/team-members/invitations/{invitation_id}:
    delete:
      tags:
        - team-members
      summary: Delete/cancel a pending seller team member invitation
      description: Cancels and deletes a pending team member invitation.
      operationId: deleteSellerTeamInvitation
      parameters:
        - in: path
          name: seller_account_id
          required: true
          schema:
            type: string
          description: The seller account ID
        - in: path
          name: invitation_id
          required: true
          schema:
            type: string
          description: The invitation ID
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      responses:
        '204':
          description: Invitation deleted successfully
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Invitation not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/{seller_account_id}/team-members:
    get:
      tags:
        - team-members
      summary: List seller team members
      description: Returns the list of team members for a seller account. Any team member can view the list.
      operationId: listSellerTeamMembers
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: seller_account_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Team members retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TeamMemberListResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      tags:
        - team-members
      operationId: addSellerTeamMember
      summary: Add seller team member
      description: Adds a manager or owner to the seller account team.
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: seller_account_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddSellerTeamMemberRequest'
      responses:
        '200':
          description: Member added successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddSellerTeamMemberResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/{seller_account_id}/team-members/{user_id}:
    delete:
      tags:
        - team-members
      operationId: removeSellerTeamMember
      summary: Remove seller team member
      description: Removes a team member from the seller account.
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      parameters:
        - name: seller_account_id
          in: path
          required: true
          schema:
            type: string
        - name: user_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Member removed successfully
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /seller/v1/logo:
    put:
      tags:
        - sellers
      operationId: uploadSellerLogo
      summary: Upload seller logo
      description: Uploads a new logo for the seller account
      security:
        - OAuth2:
            - urn:pup:seller:manage
        - PAT: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                seller_account_id:
                  type: string
                  description: The seller account ID
                logo:
                  type: string
                  format: binary
                  description: The logo file to upload (JPG, PNG, WebP)
              required:
                - seller_account_id
                - logo
      responses:
        '204':
          description: Logo uploaded successfully
        '400':
          description: Invalid input or file too large
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  securitySchemes:
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://oauth2.gopup.app/oauth2/auth
          tokenUrl: https://oauth2.gopup.app/oauth2/token
          scopes:
            urn:pup:seller:read: Read seller accounts
            urn:pup:seller:manage: Manage seller accounts
    PAT:
      type: http
      scheme: bearer
      bearerFormat: PAT
      description: Personal Access Token

  schemas:
    CreateSellerAccountRequest:
      type: object
      required:
        - name
        - address
        - contact
      properties:
        name:
          type: string
          minLength: 3
          maxLength: 100
          example: "Amsterdam Padel Sales"
        description:
          type: string
          nullable: true
          example: "Official padel gear distributor"
        address:
          $ref: '#/components/schemas/Address'
        contact:
          $ref: '#/components/schemas/Contact'

    CreateSellerAccountCreated:
      type: object
      required:
        - id
      properties:
        id:
          type: string
          example: "550e8400-e29b-41d4-a716-446655440000"

    UpdateSellerAccountRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 3
          maxLength: 100
          example: "Amsterdam Padel Sales"
        description:
          type: string
          nullable: true
          example: "Official padel gear distributor"
        address:
          $ref: '#/components/schemas/Address'
        contact:
          $ref: '#/components/schemas/Contact'

    AddSellerTeamMemberResponse:
      type: object
      required:
        - invited
      properties:
        invited:
          type: boolean
          description: Whether the user was invited via email (not yet registered)
          example: true

    AddSellerTeamMemberRequest:
      type: object
      required:
        - role
      properties:
        username:
          type: string
          description: Username of the user to add
          example: "johndoe"
        email:
          type: string
          format: email
          description: Email of the user to add
          example: "john@example.com"
        role:
          type: string
          enum: [manager, owner]
          example: "manager"
        locale:
          type: string
          enum: [en, en_GB, en-GB, nl, nl_NL, nl-NL]
          default: nl_NL
          description: Optional locale for the invitation email
          example: "nl"

    SellerTeamInvitationResponse:
      type: object
      required:
        - id
        - email
        - role
        - created_at
      properties:
        id:
          type: string
          description: Unique invitation ID
          example: "invitation-123"
        email:
          type: string
          description: Masked email of the invitee
          example: "j***e@e******.com"
        role:
          type: string
          enum: [manager, owner]
          description: Role assigned to the invitee
          example: "manager"
        created_at:
          type: string
          format: date-time
          description: Timestamp when the invitation was created
          example: "2026-06-11T12:00:00Z"

    SellerTeamInvitationListResponse:
      type: object
      required:
        - invitations
      properties:
        invitations:
          type: array
          items:
            $ref: '#/components/schemas/SellerTeamInvitationResponse'

    TeamMemberListResponse:
      type: object
      required:
        - members
      properties:
        members:
          type: array
          items:
            $ref: '#/components/schemas/TeamMember'

    TeamMember:
      type: object
      required:
        - user_id
        - username
        - first_name
        - last_name
        - role
      properties:
        user_id:
          type: string
          example: "550e8400-e29b-41d4-a716-446655440000"
        username:
          type: string
          example: "johndoe"
        first_name:
          type: string
          example: "John"
        last_name:
          type: string
          example: "Doe"
        role:
          type: string
          enum: [manager, owner]
          example: "manager"

    SellerAccount:
      type: object
      required:
        - id
        - name
        - address
        - contact
        - ledger_account_id
      properties:
        id:
          type: string
          example: "550e8400-e29b-41d4-a716-446655440000"
        name:
          type: string
          example: "Amsterdam Padel Sales"
        description:
          type: string
          nullable: true
          example: "Official padel gear distributor"
        logo_url:
          type: string
          nullable: true
          format: uri
        address:
          $ref: '#/components/schemas/Address'
        contact:
          $ref: '#/components/schemas/Contact'
        ledger_account_id:
          type: string
          description: Unique identifier for the seller's ledger account
          example: "seller:550e8400-e29b-41d4-a716-446655440000"

    SellerAccountResponse:
      type: object
      required:
        - seller
      properties:
        seller:
          $ref: '#/components/schemas/SellerAccount'

    SearchSellerAccountsResponse:
      type: object
      required:
        - hits
        - meta
      properties:
        hits:
          type: array
          items:
            $ref: '#/components/schemas/SellerAccount'
        meta:
          $ref: '#/components/schemas/ResponseMetaMany'

    Address:
      type: object
      required:
        - street
        - city
        - postal_code
        - country
      properties:
        street:
          type: string
          minLength: 3
          maxLength: 200
          example: "Main Street 123"
        city:
          type: string
          minLength: 2
          maxLength: 100
          example: "Amsterdam"
        postal_code:
          type: string
          minLength: 2
          maxLength: 20
          example: "1012 AB"
        country:
          type: string
          description: ISO 3166-1 alpha-2 country code
          example: "NL"
        additional_information:
          type: string
          nullable: true
          maxLength: 1000
          example: "Apartment 4B"
        geolocation:
          type: object
          nullable: true
          description: Optional geolocation coordinates
          required:
            - latitude
            - longitude
          properties:
            latitude:
              type: number
              format: float
              minimum: -90
              maximum: 90
            longitude:
              type: number
              format: float
              minimum: -180
              maximum: 180

    Contact:
      type: object
      required:
        - name
        - email
        - phone
      properties:
        name:
          type: string
          minLength: 3
          maxLength: 100
          example: "John Doe"
        email:
          type: string
          format: email
          example: "contact@example.com"
        phone:
          type: string
          minLength: 7
          maxLength: 20
          pattern: '^[0-9\s\-()+]+$'
          example: "+31 20 1234567"
        website:
          type: string
          nullable: true
          pattern: '^$|^([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$|^https?:\/\/([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(:[0-9]{1,5})?(\/[^\s?#]*)?(\?[^\s#]*)?(#[^\s]*)?$'
          example: "example.com"

    ResponseMetaMany:
      type: object
      required:
        - pagination
      properties:
        pagination:
          type: object
          required:
            - total
            - returned
            - offset
            - limit
          properties:
            total:
              $ref: '#/components/schemas/CollectionTotal'
            returned:
              type: integer
              format: int32
              description: Number of items in this response
            offset:
              type: integer
              format: int32
              description: Offset used in the request
            limit:
              type: integer
              format: int32
              description: Limit used in the request
            next:
              type: string
              nullable: true
              description: Relative path to next page
            previous:
              type: string
              nullable: true
              description: Relative path to previous page

    Error:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          example: "An error message"
        code:
          type: string
          enum:
            - MALFORMED_REQUEST
            - INVALID_INPUT
            - UNAUTHORIZED
            - INSUFFICIENT_SCOPE
            - ACCESS_DENIED
            - RESOURCE_NOT_FOUND
            - RESOURCE_EXISTS
            - CONFLICT
            - ACTION_BLOCKED
            - INTERNAL_ERROR
        details:
          type: string
          nullable: true
          example: "Optional context or validation details"
      description: Generic error response

    CollectionTotal:
      type: object
      required:
        - value
        - relation
      properties:
        value:
          type: integer
          format: int64
          description: Exact total count or lower-bound count for the full result set
          example: 145
        relation:
          type: string
          description: Whether value is exact or a lower bound
          enum:
            - exact
            - gte

    UpdateSellerAccountTaxRequest:
      type: object
      required:
        - tax_rate_percent
      properties:
        tax_rate_percent:
          type: number
          format: double
          example: 5.5

    WalletResponse:
      type: object
      required:
        - wallet
      properties:
        wallet:
          $ref: '#/components/schemas/Wallet'

    Wallet:
      type: object
      required:
        - account_id
        - balance
        - currency
        - status
        - opened_at
      properties:
        account_id:
          type: string
          description: Unique identifier for the wallet account
          example: "seller:018f4a3e-4f5a-7123-8abc-def012345001"
        balance:
          type: integer
          description: Current balance in credits
          example: 5000
        currency:
          type: string
          description: Currency code
          example: "PUP"
        status:
          type: string
          description: Account status
          example: "open"
        opened_at:
          type: string
          format: date-time
          description: Timestamp when the wallet was opened
          example: "2024-01-01T00:00:00Z"
        closed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the wallet was closed (if applicable)
          example: null

    TransactionsResponse:
      type: object
      required:
        - hits
        - meta
      properties:
        hits:
          type: array
          items:
            $ref: '#/components/schemas/Transaction'
          description: Array of transactions
        meta:
          $ref: '#/components/schemas/WalletTransactionsResponseMetaMany'

    Transaction:
      type: object
      required:
        - transaction_id
        - type
        - amount
        - counterparty_account_id
        - description
        - created_at
      properties:
        transaction_id:
          type: string
          description: Unique transaction identifier
          example: "tx-abc123"
        type:
          type: string
          description: Type of transaction
          example: "spend_credits"
        amount:
          type: integer
          description: Transaction amount (positive for credit, negative for debit)
          example: -100
        counterparty_account_id:
          type: string
          description: The account ID of the other party in the transaction (where funds came from or went to)
          example: "user:550e8400-e29b-41d4-a716-446655440000"
        context:
          allOf:
            - $ref: '#/components/schemas/TransactionContext'
          nullable: true
          description: Immutable structured context for client-side transaction rendering
        description:
          type: string
          description: Human-readable fallback description. Use `type` and `context` for machine-readable UX.
          example: "Purchased Court Booking"
        created_at:
          type: string
          format: date-time
          description: Timestamp when the transaction was recorded
          example: "2024-01-15T10:30:00Z"

    TransactionContext:
      oneOf:
        - $ref: '#/components/schemas/OrderPurchaseTransactionContext'
        - $ref: '#/components/schemas/OrderRefundTransactionContext'
        - $ref: '#/components/schemas/OrderTaxTransactionContext'
        - $ref: '#/components/schemas/OrderTaxRefundTransactionContext'
      discriminator:
        propertyName: kind
        mapping:
          order_purchase: '#/components/schemas/OrderPurchaseTransactionContext'
          order_refund: '#/components/schemas/OrderRefundTransactionContext'
          order_tax: '#/components/schemas/OrderTaxTransactionContext'
          order_tax_refund: '#/components/schemas/OrderTaxRefundTransactionContext'

    OrderPurchaseTransactionContext:
      type: object
      required:
        - kind
        - source
        - reference
        - details
      properties:
        kind:
          type: string
          enum: [order_purchase]
          example: "order_purchase"
        source:
          type: string
          enum: [order]
          example: "order"
        reference:
          $ref: '#/components/schemas/OrderTransactionContextReference'
        details:
          $ref: '#/components/schemas/OrderPurchaseTransactionContextDetails'

    OrderPurchaseTransactionContextDetails:
      type: object
      required:
        - order_id
        - reward_id
        - reward_title
        - price_amount
      properties:
        order_id:
          type: string
          example: "order-123"
        reward_id:
          type: string
          example: "reward-456"
        reward_title:
          type: string
          example: "Free Court Booking"
        price_amount:
          type: integer
          example: 100

    OrderRefundTransactionContext:
      type: object
      required:
        - kind
        - source
        - reference
        - details
      properties:
        kind:
          type: string
          enum: [order_refund]
          example: "order_refund"
        source:
          type: string
          enum: [order]
          example: "order"
        reference:
          $ref: '#/components/schemas/OrderTransactionContextReference'
        details:
          $ref: '#/components/schemas/OrderRefundTransactionContextDetails'

    OrderRefundTransactionContextDetails:
      type: object
      required:
        - order_id
        - reward_id
        - reward_title
        - price_amount
      properties:
        order_id:
          type: string
          example: "order-123"
        reward_id:
          type: string
          example: "reward-456"
        reward_title:
          type: string
          example: "Free Court Booking"
        price_amount:
          type: integer
          example: 100
        cancellation_reason:
          type: string
          nullable: true
          example: "User cancellation"

    OrderTaxTransactionContext:
      type: object
      required:
        - kind
        - source
        - reference
        - details
      properties:
        kind:
          type: string
          enum: [order_tax]
          example: "order_tax"
        source:
          type: string
          enum: [order]
          example: "order"
        reference:
          $ref: '#/components/schemas/OrderTransactionContextReference'
        details:
          $ref: '#/components/schemas/OrderTaxTransactionContextDetails'

    OrderTaxTransactionContextDetails:
      type: object
      required:
        - order_id
        - reward_id
        - reward_title
        - price_amount
        - tax_amount
        - tax_rate_percent
        - user_id
      properties:
        order_id:
          type: string
          example: "order-123"
        reward_id:
          type: string
          example: "reward-456"
        reward_title:
          type: string
          example: "Free Court Booking"
        price_amount:
          type: integer
          example: 100
        tax_amount:
          type: integer
          example: 10
        tax_rate_percent:
          type: number
          format: double
          example: 10.0
        user_id:
          type: string
          example: "user-789"

    OrderTaxRefundTransactionContext:
      type: object
      required:
        - kind
        - source
        - reference
        - details
      properties:
        kind:
          type: string
          enum: [order_tax_refund]
          example: "order_tax_refund"
        source:
          type: string
          enum: [order]
          example: "order"
        reference:
          $ref: '#/components/schemas/OrderTransactionContextReference'
        details:
          $ref: '#/components/schemas/OrderTaxRefundTransactionContextDetails'

    OrderTaxRefundTransactionContextDetails:
      type: object
      required:
        - order_id
        - reward_id
        - reward_title
        - price_amount
        - tax_amount
        - tax_rate_percent
        - user_id
      properties:
        order_id:
          type: string
          example: "order-123"
        reward_id:
          type: string
          example: "reward-456"
        reward_title:
          type: string
          example: "Free Court Booking"
        price_amount:
          type: integer
          example: 100
        tax_amount:
          type: integer
          example: 10
        tax_rate_percent:
          type: number
          format: double
          example: 10.0
        user_id:
          type: string
          example: "user-789"
        cancellation_reason:
          type: string
          nullable: true
          example: "User cancellation"
        original_transaction_id:
          type: string
          nullable: true
        
    OrderTransactionContextReference:
      type: object
      required:
        - type
        - id
      properties:
        type:
          type: string
          enum: [order, order_refund, order_tax, order_tax_refund]
          example: "order"
        id:
          type: string
          example: "order-123"

    WalletTransactionsResponseMetaMany:
      type: object
      required:
        - pagination
      properties:
        pagination:
          $ref: '#/components/schemas/WalletTransactionPagination'

    WalletTransactionPagination:
      type: object
      required:
        - limit
      properties:
        limit:
          type: integer
          format: int32
          description: Limit used in the request
        next:
          type: string
          nullable: true
          description: Cursor for next page
        previous:
          type: string
          nullable: true
          description: Cursor for previous page

    WalletTransactionDateRange:
      type: string
      enum:
        - today
        - yesterday
        - this_week
        - last_week
        - last_month
        - last_30_days
        - last_3_months
      example: last_30_days

    GetSellerAccountTaxResponse:
      type: object
      required:
        - tax_rate_percent
      properties:
        tax_rate_percent:
          type: number
          format: double
          example: 5.5
