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

tags:
  - name: sellers
    x-displayName: "Sellers"
    description: Create, search, update and manage seller accounts and team members

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_account_id}/team-members:
    get:
      tags:
        - sellers
      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:
        - sellers
      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:
        '204':
          description: Member added 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/{seller_account_id}/team-members/{user_id}:
    delete:
      tags:
        - sellers
      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'

    AddSellerTeamMemberRequest:
      type: object
      required:
        - userId
        - role
      properties:
        userId:
          type: string
          example: "user-123"
        role:
          type: string
          enum: [manager, owner]
          example: "manager"

    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
      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'

    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"
        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
      properties:
        error:
          type: string
          example: "An error message"
      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
