openapi: 3.0.0
paths:
  /memory/usage:
    get:
      operationId: MemoryController.getMemoryUsage
      parameters: []
      responses:
        '200':
          description: ''
      summary: Get current memory usage
      tags: &ref_0
        - Memory Monitoring
  /memory/gc:
    post:
      operationId: MemoryController.forceGC
      parameters: []
      responses:
        '201':
          description: ''
      summary: Force garbage collection
      tags: *ref_0
  /memory/test-leak:
    get:
      operationId: MemoryController.testMemoryLeak
      parameters: []
      responses:
        '200':
          description: ''
      summary: Test memory leak detection with heap diff
      tags: *ref_0
  /v2/media/content/{token}:
    get:
      operationId: MediaDeliveryController.content
      parameters:
        - name: token
          required: true
          in: path
          schema:
            type: string
        - name: download
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - MediaDelivery
  /v2/integrations/stream/tokens:
    get:
      operationId: StreamController.tokens
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Mint short-lived Stream Feeds + Stream Chat tokens for the caller. 503
        when Stream is not configured.
      tags: &ref_1
        - 'Integrations: Stream'
  /v2/integrations/stream/status:
    get:
      operationId: StreamController.status
      parameters: []
      responses:
        '200':
          description: ''
      summary: Adapter health — enabled flag + region. Does not hit Stream upstream.
      tags: *ref_1
  /v2/admin/platform-health:
    get:
      operationId: PlatformHealthController.snapshot
      parameters: []
      responses:
        '200':
          description: ''
      tags:
        - 'Admin: Platform Health'
  /v2/admin/observability/queues:
    get:
      operationId: ObservabilityV2Controller.queues
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_2
        - 'Admin: Observability v2'
  /v2/admin/observability/errors:
    get:
      operationId: ObservabilityV2Controller.errors
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_2
  /v2/admin/observability/slo:
    get:
      operationId: ObservabilityV2Controller.slo
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_2
  /v2/admin/observability/pagerduty:
    get:
      operationId: ObservabilityV2Controller.pagerDuty
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_2
  /v2/admin/observability/pagerduty/test:
    post:
      operationId: ObservabilityV2Controller.testPagerDuty
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_2
  /v2/admin/observability/metrics:
    get:
      operationId: OtelMetricsController.metricsJson
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_3
        - 'Admin: Observability'
  /v2/admin/observability/metrics.prom:
    get:
      operationId: OtelMetricsController.metricsProm
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_3
  /v2/admin/observability/otlp-status:
    get:
      operationId: OtelMetricsController.otlpStatus
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_3
  /v2/admin/observability/otlp/export-now:
    post:
      operationId: OtelMetricsController.otlpExportNow
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_3
  /v2/observability/metrics-status:
    get:
      operationId: OtelMetricsPublicController.status
      parameters: []
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Observability'
  /health:
    get:
      operationId: HealthController.check
      parameters: []
      responses:
        '200':
          description: The Health Check is successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  info:
                    type: object
                    example: &ref_4
                      database: &ref_5
                        status: up
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  error:
                    type: object
                    example: {}
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  details:
                    type: object
                    example: *ref_4
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
        '503':
          description: The Health Check is not successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: error
                  info:
                    type: object
                    example: *ref_4
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  error:
                    type: object
                    example:
                      redis: &ref_6
                        status: down
                        message: Could not connect
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  details:
                    type: object
                    example:
                      database: *ref_5
                      redis: *ref_6
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
      tags: &ref_7
        - Server Health
  /health/live:
    get:
      operationId: HealthController.live
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_7
  /health/ready:
    get:
      operationId: HealthController.ready
      parameters: []
      responses:
        '200':
          description: The Health Check is successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  info:
                    type: object
                    example: &ref_8
                      database: &ref_9
                        status: up
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  error:
                    type: object
                    example: {}
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  details:
                    type: object
                    example: *ref_8
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
        '503':
          description: The Health Check is not successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: error
                  info:
                    type: object
                    example: *ref_8
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  error:
                    type: object
                    example:
                      redis: &ref_10
                        status: down
                        message: Could not connect
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
                    nullable: true
                  details:
                    type: object
                    example:
                      database: *ref_9
                      redis: *ref_10
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                      additionalProperties: true
      tags: *ref_7
  /v2/admins/challenge-badge-requests:
    get:
      operationId: AdminChallengeBadgeRequestsController.list
      parameters:
        - &ref_11
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending_admin_approval
              - completed
              - rejected
      responses:
        '200':
          description: ''
      tags: &ref_12
        - 'Admin: Challenge Badge Requests'
  /v2/admins/challenge-badge-requests/{id}:
    get:
      operationId: AdminChallengeBadgeRequestsController.findOne
      parameters:
        - *ref_11
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_12
  /v2/admins/challenge-badge-requests/{id}/complete:
    post:
      operationId: AdminChallengeBadgeRequestsController.complete
      parameters:
        - *ref_11
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBadgeDto'
      responses:
        '201':
          description: ''
      tags: *ref_12
  /v2/admins/challenge-badge-requests/{id}/reject:
    post:
      operationId: AdminChallengeBadgeRequestsController.reject
      parameters:
        - *ref_11
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RejectBadgeRequestDto'
      responses:
        '201':
          description: ''
      tags: *ref_12
  /v2/geo/search:
    get:
      operationId: GeoController.search
      parameters:
        - name: q
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Forward geocode an address query (autocomplete).
      tags: &ref_13
        - Geo
  /v2/geo/reverse:
    get:
      operationId: GeoController.reverse
      parameters:
        - name: lat
          required: true
          in: query
          schema:
            type: string
        - name: lng
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Reverse geocode a lat/lng to an address.
      tags: *ref_13
  /v2/auth/oauth/status:
    get:
      operationId: AuthController.oauthStatus
      parameters: []
      responses:
        '200':
          description: ''
      summary: OAuth provider configuration status.
      tags: &ref_14
        - Auth
  /v2/auth/methods:
    get:
      operationId: AuthController.loginMethods
      parameters:
        - name: role
          required: true
          in: query
          schema:
            type: string
        - name: client
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Which login methods are available here.
      tags: *ref_14
  /v2/auth/oauth/google:
    post:
      operationId: AuthController.oauthGoogle
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OAuthLoginDto'
      responses:
        '200':
          description: ''
      summary: Sign in with a Google ID token.
      tags: *ref_14
  /v2/auth/oauth/apple/session:
    post:
      operationId: AuthController.appleOAuthSession
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppleOAuthSessionDto'
      responses:
        '201':
          description: ''
      summary: Create a one-time Apple OAuth state and nonce.
      tags: *ref_14
  /v2/auth/oauth/apple/callback:
    post:
      operationId: AuthController.appleOAuthCallback
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppleOAuthCallbackDto'
      responses:
        '302':
          description: ''
      summary: Apple browser form_post callback for Android.
      tags: *ref_14
  /v2/auth/oauth/apple/web/exchange:
    post:
      operationId: AuthController.oauthAppleWeb
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppleOAuthWebExchangeDto'
      responses:
        '200':
          description: ''
      summary: Exchange a browser-bound Apple callback.
      tags: *ref_14
  /v2/auth/oauth/apple:
    post:
      operationId: AuthController.oauthApple
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppleOAuthLoginDto'
      responses:
        '200':
          description: ''
      summary: Exchange and verify an Apple authorization, then sign in.
      tags: *ref_14
  /v2/auth/send-otp:
    post:
      operationId: AuthController.sendOTP
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendOTPDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                example:
                  statusCode: 201
                  message: Success
                  data:
                    statusCode: 201
                    message: Success
                    data:
                      flash: true
                      message: OTP sent successfully!
        '400':
          description: ''
          content:
            application/json:
              schema:
                example:
                  message:
                    - phoneNumber must be a valid phone number
                  error: Bad Request
                  statusCode: 400
      summary: Send the OTP
      tags: *ref_14
  /v2/auth/verify-otp:
    post:
      operationId: AuthController.verifyOTP
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyOTPDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                example:
                  statusCode: 200
                  message: Success
                  data:
                    statusCode: 201
                    message: Success
                    data:
                      id: ca462431-34da-42a7-9b7f-70e9fbcff541
                      phoneNumber: '+918779939352'
                      createdAt: '2025-01-02T05:42:04.198Z'
                      updatedAt: '2025-01-03T08:51:00.443Z'
                      accessToken: >-
                        eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjYTQ2MjQzMS0zNGRhLTQyYTctOWI3Zi03MGU5ZmJjZmY1NDEiLCJwaG9uZU51bWJlciI6Iis5MTg3Nzk5MzkzNTIiLCJyb2xlIjoidXNlciIsImlhdCI6MTczNTkwMzMwNywiZXhwIjoxNzM1OTA0MjA3fQ.HPTAOtFgQf1r1-940hxSI0tAa9Khi3-r8RtL-8mRBAY
                      refreshToken: >-
                        eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjYTQ2MjQzMS0zNGRhLTQyYTctOWI3Zi03MGU5ZmJjZmY1NDEiLCJwaG9uZU51bWJlciI6Iis5MTg3Nzk5MzkzNTIiLCJyb2xlIjoidXNlciIsImlhdCI6MTczNTkwMzMwNywiZXhwIjoxNzM2NTA4MTA3fQ.YeUn_rEkXkjrcrgFKupiFVbNPDciRKNsJ57sGnoKhBM
                      message: Default OTP Verified Successfully!
        '400':
          description: ''
          content:
            application/json:
              schema:
                example:
                  message:
                    - >-
                      role must be one of the following values: user, organizer,
                      admin
                    - phoneNumber must be a valid phone number
                  error: Bad Request
                  statusCode: 400
      summary: Verify the OTP
      tags: *ref_14
  /v2/auth/refresh-tokens:
    post:
      operationId: AuthController.refreshTokens
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                example:
                  statusCode: 200
                  message: Success
                  data:
                    accessToken: >-
                      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiY2NjYTFkNS1kYmI1LTRkZTktYWY4NS1iZTkyNmMzOGI3MjgiLCJwaG9uZU51bWJlciI6Iis5MTg3Nzk5MzkzNTIiLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MzU5NjYzNTksImV4cCI6MTczNTk2NzI1OX0.e-TvspH8-3DHIaRURbYvzoJejtR5Q7oHtii307Vx9UY
                    refreshToken: >-
                      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiY2NjYTFkNS1kYmI1LTRkZTktYWY4NS1iZTkyNmMzOGI3MjgiLCJwaG9uZU51bWJlciI6Iis5MTg3Nzk5MzkzNTIiLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MzU5NjYzNTksImV4cCI6MTczODU1ODM1OX0.HHuxL_pp_BGgGd0As243iRyl7Sv_81NdtexaPERkiKE
        '401':
          description: ''
          content:
            application/json:
              schema:
                example:
                  message: Unauthorized
                  statusCode: 401
        '403':
          description: ''
          content:
            application/json:
              schema:
                example:
                  message: Access Denied
                  error: Forbidden
                  statusCode: 403
      summary: Refresh Tokens
      tags: *ref_14
  /v2/auth/web/session:
    post:
      operationId: AuthController.establishWebSession
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_14
  /v2/auth/web/logout:
    post:
      operationId: AuthController.clearWebSession
      parameters: []
      responses:
        '204':
          description: ''
      tags: *ref_14
  /v2/auth/logout:
    post:
      operationId: AuthController.logout
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                example:
                  statusCode: 200
                  message: Success
                  data:
                    generatedMaps: []
                    raw: []
                    affected: 1
        '401':
          description: ''
          content:
            application/json:
              schema:
                example:
                  message: Unauthorized
                  statusCode: 401
      summary: Logout from the session
      tags: *ref_14
  /v2/auth/step-up/verify:
    post:
      operationId: AuthController.stepUpVerify
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Step-up auth: re-verify the caller via OTP for a sensitive op (account
        delete, wallet withdraw, payment-method edit).
      tags: *ref_14
  /v2/auth/check-email:
    get:
      operationId: AuthController.checkEmailExists
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_14
  /v2/auth/check-phone-number:
    get:
      operationId: AuthController.checkPhoneNumberExists
      parameters:
        - name: phoneNumber
          required: true
          in: query
          description: Phone number to check for existence
          schema:
            example: '+917710957578'
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_14
  /v2/auth/bind-phone:
    post:
      operationId: AuthController.bindPhone
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BindPhoneDto'
      responses:
        '200':
          description: ''
      summary: >-
        Attach a first phone number to the current (email/OAuth) account. Send
        the OTP first via POST /auth/send-otp, then submit it here.
      tags: *ref_14
  /v2/auth/verify-token:
    get:
      operationId: AuthController.verifyToken
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                example:
                  statusCode: 200
                  message: Success
                  data:
                    message: Token is valid
                    isValid: true
                    role: user
                    data:
                      id: ca462431-34da-42a7-9b7f-70e9fbcff541
                      phoneNumber: '+918779939352'
                      email: user@example.com
                      firstName: John
                      lastName: Doe
                      createdAt: '2025-01-02T05:42:04.198Z'
                      updatedAt: '2025-01-03T08:51:00.443Z'
        '401':
          description: Token is expired or invalid
          content:
            application/json:
              schema:
                example:
                  message: Unauthorized
                  statusCode: 401
      summary: Verify if token is valid and get user data
      tags: *ref_14
  /v2/auth/totp/enroll:
    post:
      operationId: TotpController.enroll
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Begin TOTP enrollment. Returns otpauth URL + a scannable QR code (PNG
        data URI) + 10 recovery codes; show the codes ONCE and ask the user to
        save them off-platform.
      tags: &ref_15
        - 'Auth: 2FA TOTP'
  /v2/auth/totp/confirm:
    post:
      operationId: TotpController.confirm
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Confirm TOTP enrollment with the first code from the authenticator.
        Flips totpEnabledAt and from then on login demands a code.
      tags: *ref_15
  /v2/auth/totp/disable:
    post:
      operationId: TotpController.disable
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Disable TOTP. Requires the current code or a recovery code — prevents
        silent second-factor removal via stolen AT.
      tags: *ref_15
  /v2/auth/totp/status:
    get:
      operationId: TotpController.status
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Read the caller's current TOTP status. Unlike the access-token claim
        (stamped at login), this reflects live DB state — safe to re-check on
        every Security-screen mount.
      tags: *ref_15
  /v2/auth/totp/verify:
    post:
      operationId: TotpController.verify
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Verify a TOTP code against the caller's enrollment. Used by
        `@RequiresStepUp`-style flows that prefer TOTP to OTP.
      tags: *ref_15
  /v2/auth/sessions:
    get:
      operationId: AuthSessionsController.list
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        List the caller's auth sessions. Includes active + revoked; UI should
        hide revoked older than 30 days.
      tags: &ref_16
        - 'Auth: Sessions'
  /v2/auth/sessions/{id}:
    delete:
      operationId: AuthSessionsController.revoke
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Revoke one session by id.
      tags: *ref_16
  /v2/auth/sessions/revoke-others:
    post:
      operationId: AuthSessionsController.revokeOthers
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Revoke every session belonging to the caller EXCEPT the current one.
        "Log out everywhere else."
      tags: *ref_16
  /v2/auth/passkey/register/options:
    post:
      operationId: PasskeyController.registerOptions
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Begin passkey registration. Returns options to pass into
        navigator.credentials.create().
      tags: &ref_17
        - 'Auth: Passkeys'
  /v2/auth/passkey/register/verify:
    post:
      operationId: PasskeyController.registerVerify
      parameters: []
      responses:
        '200':
          description: ''
      summary: Finish passkey registration by submitting the authenticator response.
      tags: *ref_17
  /v2/auth/passkey/authenticate/options:
    post:
      operationId: PasskeyController.authenticateOptions
      parameters: []
      responses:
        '200':
          description: ''
      summary: Begin passkey authentication (step-up path).
      tags: *ref_17
  /v2/auth/passkey/authenticate/verify:
    post:
      operationId: PasskeyController.authenticateVerify
      parameters: []
      responses:
        '200':
          description: ''
      summary: Finish passkey authentication.
      tags: *ref_17
  /v2/auth/passkey:
    get:
      operationId: PasskeyController.list
      parameters: []
      responses:
        '200':
          description: ''
      summary: List registered passkeys for the caller.
      tags: *ref_17
  /v2/auth/passkey/{id}:
    delete:
      operationId: PasskeyController.revoke
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Revoke one passkey.
      tags: *ref_17
  /v2/auth/email/send-verification:
    post:
      operationId: EmailVerificationController.send
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Queue an email verification link for the authenticated user. Required
        before emails leave the inbox (deliverability).
      tags: &ref_18
        - 'Auth: Email verification'
  /v2/auth/email/verify:
    get:
      operationId: EmailVerificationController.verify
      parameters:
        - name: token
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Verify an email by the token minted at send-verification. Public because
        it's hit from the user's inbox.
      tags: *ref_18
  /v2/auth/email/send-otp:
    post:
      operationId: EmailAuthController.sendOtp
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendEmailOtpDto'
      responses:
        '200':
          description: ''
      summary: >-
        Email a 4-digit login code. Creates no account on its own. Pass
        role=organizer to send it under the organizer-branded template instead.
      tags: &ref_19
        - 'Auth: Email login'
  /v2/auth/email/verify-otp:
    post:
      operationId: EmailAuthController.verifyOtp
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyEmailOtpDto'
      responses:
        '200':
          description: ''
      summary: >-
        Verify an email login code and return a session. Links to an existing
        account when the address is already known. role=organizer resolves into
        an Organizer account instead of an athlete — never creates one.
      tags: *ref_19
  /v2/auth/identities:
    get:
      operationId: IdentitiesController.list
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List the sign-in methods linked to my account.
      tags: &ref_20
        - 'Auth: Linked sign-in methods'
  /v2/auth/identities/{id}:
    delete:
      operationId: IdentitiesController.unlink
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Detach a sign-in method. Refused when it is the only one left on the
        account.
      tags: *ref_20
  /v2/admins/me:
    get:
      operationId: AdminsController.getMe
      parameters:
        - &ref_21
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_22
        - Admins
  /v2/admins/send-otp:
    post:
      operationId: AdminsController.sendOTP
      parameters:
        - *ref_21
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendOTPDto'
      responses:
        '201':
          description: ''
      tags: *ref_22
  /v2/admins/bootstrap:
    post:
      operationId: AdminsController.bootstrapAdmin
      parameters:
        - *ref_21
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAdminDto'
      responses:
        '201':
          description: ''
      tags: *ref_22
  /v2/admins:
    post:
      operationId: createOneBaseAdminsControllerAdmin
      parameters:
        - *ref_21
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Admin'
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Admin'
      summary: Create a single Admin
      tags: *ref_22
    get:
      operationId: getManyBaseAdminsControllerAdmin
      parameters:
        - *ref_21
        - name: fields
          description: >-
            Selects resource fields. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#select"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: csv
          schema:
            type: array
            items:
              type: string
        - name: s
          description: >-
            Adds search condition. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#search"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: string
        - name: filter
          description: >-
            Adds filter condition. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#filter"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: or
          description: >-
            Adds OR condition. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#or"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: sort
          description: >-
            Adds sort by field. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#sort"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: join
          description: >-
            Adds relational resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#join"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: limit
          description: >-
            Limit amount of resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#limit"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: integer
        - name: offset
          description: >-
            Offset amount of resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#offset"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: integer
        - name: page
          description: >-
            Page portion of resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#page"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: integer
        - name: cache
          description: >-
            Reset cache (if was enabled). <a
            href="https://github.com/nestjsx/crud/wiki/Requests#cache"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            minimum: 0
            maximum: 1
            type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetManyAdminResponseDto'
      summary: Retrieve multiple Admins
      tags: *ref_22
  /v2/admins/{id}:
    get:
      operationId: getOneBaseAdminsControllerAdmin
      parameters:
        - *ref_21
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: fields
          description: >-
            Selects resource fields. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#select"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: csv
          schema:
            type: array
            items:
              type: string
        - name: join
          description: >-
            Adds relational resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#join"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: cache
          description: >-
            Reset cache (if was enabled). <a
            href="https://github.com/nestjsx/crud/wiki/Requests#cache"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            minimum: 0
            maximum: 1
            type: integer
      responses:
        '200':
          description: Get one base response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Admin'
      summary: Retrieve a single Admin
      tags: *ref_22
    patch:
      operationId: updateOneBaseAdminsControllerAdmin
      parameters:
        - *ref_21
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Admin'
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Admin'
      summary: Update a single Admin
      tags: *ref_22
    delete:
      operationId: deleteOneBaseAdminsControllerAdmin
      parameters:
        - *ref_21
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200': {}
      summary: Delete a single Admin
      tags: *ref_22
    put:
      operationId: replaceOneBaseAdminsControllerAdmin
      parameters:
        - *ref_21
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Admin'
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Admin'
      summary: Replace a single Admin
      tags: *ref_22
  /v2/admins/handle/check:
    get:
      operationId: AdminsController.checkHandleAvailability
      parameters:
        - *ref_21
        - name: handle
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_22
  /v2/admins/handle/{handle}:
    get:
      operationId: AdminsController.getAdminByHandle
      parameters:
        - *ref_21
        - name: handle
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_22
  /v2/admins/notification-preferences/me:
    get:
      operationId: AdminsController.getMyNotificationPreference
      parameters:
        - *ref_21
      responses:
        '200':
          description: ''
      tags: *ref_22
    patch:
      operationId: AdminsController.updateMyNotificationPreference
      parameters:
        - *ref_21
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAdminNotificationPreferenceDto'
      responses:
        '200':
          description: ''
      tags: *ref_22
  /v2/admins/bulk:
    post:
      operationId: createManyBaseAdminsControllerAdmin
      parameters:
        - *ref_21
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateManyAdminDto'
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Admin'
      summary: Create multiple Admins
      tags: *ref_22
  /v2/admin/users/{userId}/impersonate:
    post:
      operationId: AdminImpersonationController.start
      parameters:
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Start an impersonation session. Returns a short-lived USER-role access
        token for the target user. Reason is required and logged.
      tags: &ref_23
        - 'Admin: Impersonation'
  /v2/admin/impersonation/end:
    post:
      operationId: AdminImpersonationController.end
      parameters:
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        End an impersonation session. Revokes the minted token so the session
        dies before its TTL.
      tags: *ref_23
  /v2/admin/admins/{adminId}/require-totp:
    post:
      operationId: AdminTotpEnforcementController.toggle
      parameters:
        - name: adminId
          required: true
          in: path
          schema:
            type: string
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Flip `totpRequiredAt` for another admin. Forces enrollment on their next
        login (or clears the forcing clock when {required:false}).
      tags: &ref_24
        - 'Admin: 2FA enforcement'
  /v2/admin/admins/{adminId}/reset-totp:
    post:
      operationId: AdminTotpEnforcementController.reset
      parameters:
        - name: adminId
          required: true
          in: path
          schema:
            type: string
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Reset another admin's TOTP enrollment (lost device / peer-enforcement).
        Clears their existing secret and immediately re-forces enrollment on
        next login. Cannot target yourself — use POST /v2/auth/totp/disable
        (requires your current code) for self-service.
      tags: *ref_24
  /v2/admin-permissions:
    get:
      operationId: AdminPermissionsEditorController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_25
        - 'Admin: Permission editor'
  /v2/admin-permissions/{id}:
    get:
      operationId: AdminPermissionsEditorController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_25
    patch:
      operationId: AdminPermissionsEditorController.updatePermissions
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_25
  /v2/admin/official-partners/benefit-definitions:
    get:
      operationId: AdminOfficialPartnersController.definitions
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_26
        - 'Admin: Official Partners'
  /v2/admin/official-partners/candidates:
    get:
      operationId: AdminOfficialPartnersController.candidates
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_26
  /v2/admin/official-partners:
    get:
      operationId: AdminOfficialPartnersController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_26
    post:
      operationId: AdminOfficialPartnersController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertOfficialPartnerDto'
      responses:
        '201':
          description: ''
      summary: Create an Organizer/Club official partnership
      tags: *ref_26
  /v2/admin/official-partners/exclusive-tab:
    get:
      operationId: AdminOfficialPartnersController.exclusiveTab
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_26
    put:
      operationId: AdminOfficialPartnersController.upsertExclusiveTab
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertOfficialPartnerExclusiveTabDto'
      responses:
        '200':
          description: ''
      summary: Configure the single athlete exclusive partner tab
      tags: *ref_26
  /v2/admin/official-partners/exclusive-tab/targets:
    get:
      operationId: AdminOfficialPartnersController.exclusiveTabTargets
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_26
  /v2/admin/official-partners/{id}:
    get:
      operationId: AdminOfficialPartnersController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_26
    patch:
      operationId: AdminOfficialPartnersController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertOfficialPartnerDto'
      responses:
        '200':
          description: ''
      summary: Update an Official Repeak Partner record
      tags: *ref_26
    delete:
      operationId: AdminOfficialPartnersController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RemoveOfficialPartnerDto'
      responses:
        '200':
          description: ''
      summary: Remove an Official Repeak Partner record
      tags: *ref_26
  /v2/admin/official-partners/logo-images:
    post:
      operationId: AdminOfficialPartnersController.uploadLogoImage
      parameters: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - logoImage
              properties:
                logoImage:
                  type: string
                  format: binary
      responses:
        '201':
          description: ''
      summary: Upload an Official Partner image logo
      tags: *ref_26
  /v2/official-partners/exclusive-tab/config:
    get:
      operationId: OfficialPartnersController.exclusiveTab
      parameters:
        - name: if-none-match
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get the active admin-managed athlete navigation partner tab
      tags: &ref_27
        - Official Partners
  /v2/official-partners/{subjectType}/{subjectId}:
    get:
      operationId: OfficialPartnersController.getActive
      parameters:
        - name: subjectType
          required: true
          in: path
          schema:
            type: string
        - name: subjectId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get the active, public-safe partnership projection
      tags: *ref_27
  /v2/admin/mobile-experiences/options:
    get:
      operationId: AdminMobileExperiencesController.options
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_28
        - 'Admin: Mobile Experiences'
  /v2/admin/mobile-experiences:
    get:
      operationId: AdminMobileExperiencesController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: purpose
          required: true
          in: query
          schema:
            type: string
        - name: search
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_28
    post:
      operationId: AdminMobileExperiencesController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertMobileExperienceDto'
      responses:
        '201':
          description: ''
      tags: *ref_28
  /v2/admin/mobile-experiences/destinations:
    get:
      operationId: AdminMobileExperiencesController.destinations
      parameters:
        - name: route
          required: true
          in: query
          schema:
            type: string
        - name: search
          required: true
          in: query
          schema:
            type: string
        - name: id
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_28
  /v2/admin/mobile-experiences/destinations/search:
    get:
      operationId: AdminMobileExperiencesController.destinationOptions
      parameters:
        - name: route
          required: true
          in: query
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: id
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_28
  /v2/admin/mobile-experiences/{id}:
    get:
      operationId: AdminMobileExperiencesController.get
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_28
    patch:
      operationId: AdminMobileExperiencesController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertMobileExperienceDto'
      responses:
        '200':
          description: ''
      tags: *ref_28
    delete:
      operationId: AdminMobileExperiencesController.archive
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_28
  /v2/admin/mobile-experiences/{id}/analytics:
    get:
      operationId: AdminMobileExperiencesController.analyticsForCampaign
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_28
  /v2/admin/mobile-experiences/{id}/eligibility:
    get:
      operationId: AdminMobileExperiencesController.eligibilityForAthlete
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_28
  /v2/admin/mobile-experiences/media:
    post:
      operationId: AdminMobileExperiencesController.upload
      parameters: []
      responses:
        '201':
          description: ''
      summary: Upload one promotional image or MP4 creative
      tags: *ref_28
  /v2/admin/mobile-experiences/{id}/publish:
    post:
      operationId: AdminMobileExperiencesController.publish
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_28
  /v2/admin/mobile-experiences/{id}/pause:
    post:
      operationId: AdminMobileExperiencesController.pause
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_28
  /v2/users/me/promotions:
    get:
      operationId: PromotionalDeliveryController.list
      parameters:
        - name: placement
          required: true
          in: query
          schema:
            type: string
        - name: sessionId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_29
        - bearer: []
      tags: &ref_30
        - 'Athlete: Promotional Content'
  /v2/users/me/promotions/{promotionId}/impression:
    post:
      operationId: PromotionalDeliveryController.impression
      parameters:
        - name: promotionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_29
      tags: *ref_30
  /v2/users/me/promotions/{promotionId}/click:
    post:
      operationId: PromotionalDeliveryController.click
      parameters:
        - name: promotionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_29
      tags: *ref_30
  /v2/organizer/promotions:
    get:
      operationId: OrganizerPromotionsController.list
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_31
        - bearer: []
      tags: &ref_32
        - 'Organizer: Promotions'
  /v2/organizer/promotions/{promotionId}/analytics:
    get:
      operationId: OrganizerPromotionsController.detail
      parameters:
        - name: promotionId
          required: true
          in: path
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_31
      tags: *ref_32
  /v2/organizers/{organizerId}/shipping/pickup-address:
    get:
      operationId: OrganizersController.organizerPickupAddress
      parameters:
        - &ref_33
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_34
        - Organizers
    post:
      operationId: OrganizersController.saveOrganizerPickupAddress
      parameters:
        - *ref_33
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_34
  /v2/organizers/me/memberships:
    get:
      operationId: OrganizersController.getMyMemberships
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      summary: List my organizer memberships + roles.
      tags: *ref_34
  /v2/organizers/me/onboarding-status:
    get:
      operationId: OrganizersController.getMyOnboardingStatus
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      summary: Get my organizer onboarding journey status (PRD §32.2).
      tags: *ref_34
  /v2/organizers/send-otp:
    post:
      operationId: OrganizersController.sendOTP
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendOTPDto'
      responses:
        '201':
          description: ''
      tags: *ref_34
  /v2/organizers:
    post:
      operationId: OrganizersController.createOrganizer
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Name of the Organizer
                phoneNumber:
                  type: string
                  description: Phone number
                email:
                  type: string
                  description: Email address
                companyName:
                  type: string
                  description: Company name
                commission:
                  type: number
                  description: Commission percentage
                isActive:
                  type: boolean
                  description: Is active
                approvalStatus:
                  type: string
                  description: Approval status
                reviewReason:
                  type: string
                  description: Review reason
                companyLogoFile:
                  type: string
                  format: binary
                  description: Company logo image file
      responses:
        '201':
          description: ''
      summary: Create a new organizer
      tags: *ref_34
    get:
      operationId: OrganizersController.getOrganizers
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      tags: *ref_34
  /v2/organizers/create:
    post:
      operationId: OrganizersController.createOrganizerIfNotExists
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Name of the Organizer
                phoneNumber:
                  type: string
                  description: Phone number
                email:
                  type: string
                  description: Email address
                companyName:
                  type: string
                  description: Company name
                companyLogo:
                  type: string
                  format: binary
                  description: Company logo image file
      responses:
        '201':
          description: ''
      summary: Create organizer if not exists (Public)
      tags: *ref_34
  /v2/organizers/create/verified:
    post:
      description: >-
        Uses the authenticated user phone as proof and does not send a second
        signup OTP.
      operationId: OrganizersController.createOrganizerForVerifiedUser
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/CreateOrganizerIfNotExistsDto'
      responses:
        '201':
          description: ''
      summary: Create an organizer after phone verification
      tags: *ref_34
  /v2/organizers/{id}:
    get:
      operationId: OrganizersController.getOrganizer
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      tags: *ref_34
    patch:
      operationId: OrganizersController.updateOrganizer
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Name of the Organizer
                phoneNumber:
                  type: string
                  description: Phone number
                email:
                  type: string
                  description: Email address
                companyName:
                  type: string
                  description: Company name
                commission:
                  type: number
                  description: Commission percentage
                isActive:
                  type: boolean
                  description: Is active
                approvalStatus:
                  type: string
                  description: Approval status
                reviewReason:
                  type: string
                  description: Review reason
                companyLogoFile:
                  type: string
                  format: binary
                  description: Company logo image file
                companyBannerFile:
                  type: string
                  format: binary
                  description: Company banner image file
                headline:
                  type: string
                  description: Short tagline / headline for the organizer
                about:
                  type: string
                  description: Bio / description (about section)
                city:
                  type: string
                  description: City
                state:
                  type: string
                  description: State
                links:
                  type: string
                  description: >-
                    JSON string with social/web links: { "website": "...",
                    "youtube": "...", "instagram": "..." }
                pickupLocation:
                  type: string
                  description: >-
                    Shiprocket pickup location name, as registered in this
                    organizer’s own Shiprocket dashboard
      responses:
        '200':
          description: ''
      summary: Update organizer
      tags: *ref_34
    delete:
      operationId: OrganizersController.deleteOrganizer
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      tags: *ref_34
  /v2/organizers/{id}/business-kyc:
    post:
      description: >-
        Public endpoint for organizers to submit KYC documents. Required:
        businessRegistrationCertificate, panCard, and either
        gstRegistrationCertificate OR declarationForm (signed).
      operationId: OrganizersController.createOrganizerBusinessKyc
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - businessRegistrationCertificate
                - panCard
              properties:
                bankAccountDetails[accountNumber]:
                  type: string
                  description: Bank account number (Optional)
                bankAccountDetails[ifscCode]:
                  type: string
                  description: IFSC code of the bank branch (Optional)
                websiteOrAppUrl:
                  type: string
                  description: Website or app URL of the organizer
                businessDescription:
                  type: string
                  description: Brief description of the business
                businessRegistrationCertificate:
                  type: string
                  format: binary
                  description: Business registration certificate (Required)
                gstRegistrationCertificate:
                  type: string
                  format: binary
                  description: >-
                    GST registration certificate (Required if no declaration
                    form)
                declarationForm:
                  type: string
                  format: binary
                  description: Signed declaration form (Required if no GST certificate)
                shopEstablishmentLicense:
                  type: string
                  format: binary
                  description: Shop establishment license (Optional)
                panCard:
                  type: string
                  format: binary
                  description: PAN card document (Required)
                aadhaarCard:
                  type: string
                  format: binary
                  description: Aadhaar card document (Optional)
                addressProof:
                  type: string
                  format: binary
                  description: Address proof document (Optional)
                cancelledCheque:
                  type: string
                  format: binary
                  description: Cancelled cheque (Optional)
                bankAccountProof:
                  type: string
                  format: binary
                  description: Bank account proof (Optional)
      responses:
        '201':
          description: ''
      summary: Submit business KYC documents (Public)
      tags: *ref_34
    patch:
      description: >-
        Public endpoint for organizers to update KYC documents. Use this when
        documents were uploaded incorrectly or when approval was rejected. All
        fields are optional - only provided documents will be updated.
      operationId: OrganizersController.updateOrganizerBusinessKyc
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                bankAccountDetails[accountNumber]:
                  type: string
                  description: Bank account number (Optional)
                bankAccountDetails[ifscCode]:
                  type: string
                  description: IFSC code of the bank branch (Optional)
                websiteOrAppUrl:
                  type: string
                  description: Website or app URL of the organizer
                businessDescription:
                  type: string
                  description: Brief description of the business
                businessRegistrationCertificate:
                  type: string
                  format: binary
                  description: Business registration certificate (Optional)
                gstRegistrationCertificate:
                  type: string
                  format: binary
                  description: GST registration certificate (Optional)
                declarationForm:
                  type: string
                  format: binary
                  description: Signed declaration form (Optional)
                shopEstablishmentLicense:
                  type: string
                  format: binary
                  description: Shop establishment license (Optional)
                panCard:
                  type: string
                  format: binary
                  description: PAN card document (Optional)
                aadhaarCard:
                  type: string
                  format: binary
                  description: Aadhaar card document (Optional)
                addressProof:
                  type: string
                  format: binary
                  description: Address proof document (Optional)
                cancelledCheque:
                  type: string
                  format: binary
                  description: Cancelled cheque (Optional)
                bankAccountProof:
                  type: string
                  format: binary
                  description: Bank account proof (Optional)
      responses:
        '200':
          description: ''
      summary: Update business KYC documents (Public)
      tags: *ref_34
    get:
      description: >-
        Get business KYC details for an organizer. Admin can view any organizer,
        organizer can only view their own.
      operationId: OrganizersController.getOrganizerBusinessKyc
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      summary: Get business KYC documents by organizer ID
      tags: *ref_34
  /v2/organizers/{id}/toggle:
    patch:
      operationId: OrganizersController.toggleOrganizerStatus
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      tags: *ref_34
  /v2/organizers/{id}/declaration-form:
    get:
      description: >-
        Get the declaration form template filled with organizer data. Returns
        missing required fields if any.
      operationId: OrganizersController.getDeclarationForm
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      summary: Get declaration form with organizer data (Public)
      tags: *ref_34
  /v2/organizers/{id}/declaration-form-details:
    patch:
      description: >-
        Update organizer details required for declaration form (PAN number,
        address, etc.)
      operationId: OrganizersController.updateDeclarationFormDetails
      parameters:
        - *ref_33
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrganizerDeclarationDetailsDto'
      responses:
        '200':
          description: ''
      summary: Update declaration form details (Public)
      tags: *ref_34
  /v2/organizers/{id}/declaration-form/download:
    get:
      description: >-
        Download the declaration form as PDF. All required fields must be filled
        before downloading.
      operationId: OrganizersController.downloadDeclarationFormPdf
      parameters:
        - *ref_33
      responses:
        '200':
          description: ''
      summary: Download declaration form as PDF (Public)
      tags: *ref_34
  /v2/organizers/{id}/kyc/resubmit:
    post:
      description: >-
        Allows a REJECTED organizer to trigger a resubmit without a JWT. The
        organizer proves their identity by knowing their own organizerId
        (received in the verify-otp response). KYC must be in REJECTED or
        RESUBMIT state.
      operationId: OrganizersController.resubmitKycPublic
      parameters:
        - *ref_33
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Resubmit KYC after rejection — no auth required (Public)
      tags: *ref_34
  /v2/organizers/{orgId}/events:
    get:
      description: >-
        Get a list of events belonging to an organizer. Used for selecting event
        redirects in ad creation.
      operationId: OrganizersController.getOrganizerEvents
      parameters:
        - *ref_33
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get organizer's events for ad redirect selection
      tags: *ref_34
  /v2/organizations/{idOrSlug}:
    get:
      operationId: PublicOrganizationsController.getPublic
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Public organization detail by id or slug.
      tags:
        - 'Public: Organizations'
  /v2/organizer/team/activity:
    get:
      operationId: OrganizerTeamController.activity
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: before
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_35
        - 'Organizer: Team'
  /v2/organizer/team:
    get:
      operationId: OrganizerTeamController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_35
  /v2/organizer/team/invite:
    post:
      operationId: OrganizerTeamController.invite
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_35
  /v2/organizer/team/{id}:
    patch:
      operationId: OrganizerTeamController.updateRole
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_35
    delete:
      operationId: OrganizerTeamController.revoke
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_35
  /v2/organizer/staff-tasks:
    get:
      operationId: OrganizerStaffTasksController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_36
        - OrganizerStaffTasks
    post:
      operationId: OrganizerStaffTasksController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrganizerStaffTaskDto'
      responses:
        '201':
          description: ''
      tags: *ref_36
  /v2/organizer/staff-tasks/{taskId}/status:
    patch:
      operationId: OrganizerStaffTasksController.updateStatus
      parameters:
        - name: taskId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrganizerStaffTaskDto'
      responses:
        '200':
          description: ''
      tags: *ref_36
  /v2/me/organizer-memberships:
    get:
      operationId: MeOrganizerMembershipsController.listMine
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_37
        - 'Me: Organizer memberships'
  /v2/me/organizer-memberships/{id}/accept:
    post:
      operationId: MeOrganizerMembershipsController.accept
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_37
  /v2/organizers/me/kyc/bank-verification:
    get:
      operationId: OrganizerKycController.getBankVerification
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_38
        - bearer: []
      summary: Get the signed-in organizer's bank verification status.
      tags: &ref_39
        - 'Organizer: KYC workflow'
  /v2/organizers/me/kyc/verify-bank:
    post:
      operationId: OrganizerKycController.verifyBank
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyBankAccountDto'
      responses:
        '200':
          description: ''
      security: *ref_38
      summary: >-
        Verify the saved organizer payout account using the configured
        penny-drop provider.
      tags: *ref_39
  /v2/organizers/me/kyc:
    get:
      operationId: OrganizerKycController.getMyKyc
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_38
      summary: >-
        Owner read of the current organizer's KYC state. Returns null when no
        BusinessKyc has been created yet — the partner portal renders the 'not
        started' state.
      tags: *ref_39
  /v2/organizers/me/kyc/submit:
    post:
      operationId: OrganizerKycController.submit
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_38
      summary: >-
        Submit KYC for admin review. PENDING or RESUBMIT only. Requires
        businessRegistrationCertificate + panCard documents already uploaded via
        /v2/organizers/:id/business-kyc.
      tags: *ref_39
  /v2/organizers/me/kyc/resubmit:
    post:
      operationId: OrganizerKycController.resubmit
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_38
      summary: >-
        Resubmit KYC after rejection. REJECTED or RESUBMIT only. Clears prior
        rejection metadata.
      tags: *ref_39
  /v2/admin/organizer-kyc:
    get:
      operationId: AdminOrganizerKycController.list
      parameters:
        - name: state
          required: false
          in: query
          schema:
            enum:
              - PENDING
              - UNDER_REVIEW
              - APPROVED
              - REJECTED
              - RESUBMIT
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_40
        - bearer: []
      summary: >-
        List organizer KYC submissions awaiting admin review. Defaults to
        UNDER_REVIEW; supports ?state= and ?page=&limit=.
      tags: &ref_41
        - 'Admin: Organizer KYC'
  /v2/admin/organizer-kyc/{kycId}/approve:
    post:
      operationId: AdminOrganizerKycController.approve
      parameters:
        - name: kycId
          required: true
          in: path
          description: Business KYC id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_40
      summary: Approve an UNDER_REVIEW organizer KYC.
      tags: *ref_41
  /v2/admin/organizer-kyc/{kycId}/reject:
    post:
      operationId: AdminOrganizerKycController.reject
      parameters:
        - name: kycId
          required: true
          in: path
          description: Business KYC id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_40
      summary: >-
        Reject an UNDER_REVIEW organizer KYC. Reason required (10-500 chars),
        returned verbatim to the organizer.
      tags: *ref_41
  /v2/admin/organizers/{organizerId}:
    get:
      operationId: AdminOrganizersController.getOne
      parameters:
        - &ref_42
          name: Authorization
          in: header
          description: Bearer Token (Admin)
          schema:
            type: string
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get one organizer (admin detail incl. suspension)
      tags: &ref_43
        - Admin - Organizers Oversight
  /v2/admin/organizers/{organizerId}/suspend:
    post:
      operationId: AdminOrganizersController.suspend
      parameters:
        - *ref_42
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SuspendOrganizerDto'
      responses:
        '201':
          description: ''
      summary: Suspend an organizer (revokes access + active sessions)
      tags: *ref_43
  /v2/admin/organizers/{organizerId}/unsuspend:
    post:
      operationId: AdminOrganizersController.unsuspend
      parameters:
        - *ref_42
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UnsuspendOrganizerDto'
      responses:
        '201':
          description: ''
      summary: Unsuspend an organizer (restores APPROVED status)
      tags: *ref_43
  /v2/integrations/eazr/organizers/by-mobile:
    get:
      operationId: EazrOrganizerIntegrationController.organizerByMobile
      parameters:
        - &ref_44
          name: x-api-key
          in: header
          required: true
          schema:
            type: string
        - name: mobileNumber
          required: true
          in: query
          schema:
            type: string
        - name: x-api-key
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Find an organizer by mobile number
      tags: &ref_45
        - Eazr Organizer Integration
  /v2/integrations/eazr/organizers/{organizerId}/events:
    get:
      operationId: EazrOrganizerIntegrationController.organizerEvents
      parameters:
        - *ref_44
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: x-api-key
          required: true
          in: header
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: List events owned by an organizer
      tags: *ref_45
  /v2/integrations/eazr/organizers/{organizerId}/events/{eventId}:
    get:
      operationId: EazrOrganizerIntegrationController.organizerEvent
      parameters:
        - *ref_44
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: x-api-key
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get one event owned by an organizer
      tags: *ref_45
  /v2/organizers/{organizerId}/series-passes:
    get:
      operationId: OrganizerSeriesPassesController.list
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PUBLISHED
              - CLOSED
              - ARCHIVED
            type: string
      responses:
        '200':
          description: ''
      security: &ref_46
        - bearer: []
      summary: List series passes for this organizer.
      tags: &ref_47
        - 'Organizer: Series Passes'
    post:
      operationId: OrganizerSeriesPassesController.create
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_46
      summary: Create a new series pass (DRAFT status).
      tags: *ref_47
  /v2/organizers/{organizerId}/series-passes/{passId}:
    get:
      operationId: OrganizerSeriesPassesController.get
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: passId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_46
      summary: Get a single series pass by ID.
      tags: *ref_47
    patch:
      operationId: OrganizerSeriesPassesController.update
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: passId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_46
      summary: Update a series pass (non-archived only).
      tags: *ref_47
  /v2/organizers/{organizerId}/series-passes/{passId}/status:
    patch:
      operationId: OrganizerSeriesPassesController.transitionStatus
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: passId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_46
      summary: Transition pass status (DRAFT/PUBLISHED/CLOSED/ARCHIVED).
      tags: *ref_47
  /v2/organizers/{organizerId}/series-passes/{passId}/discount-stats:
    get:
      operationId: OrganizerSeriesPassesController.discountStats
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: passId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_46
      summary: >-
        Compute discount stats: bundle vs sum of cheapest event tickets +
        savings + savings %.
      tags: *ref_47
  /v2/organizers/{organizerId}/series-passes/{passId}/registrations:
    get:
      operationId: OrganizerSeriesPassesController.listRegistrations
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: passId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - PENDING
              - CONFIRMED
              - CANCELLED
            type: string
      responses:
        '200':
          description: ''
      security: *ref_46
      summary: List athlete registrations for this series pass.
      tags: *ref_47
  /v2/me/series-passes:
    get:
      operationId: MeSeriesPassesController.listMine
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_48
        - bearer: []
      summary: List the authenticated athlete's series-pass registrations.
      tags: &ref_49
        - 'Me: Series Passes'
  /v2/me/series-passes/entitlement:
    get:
      operationId: MeSeriesPassesController.entitlement
      parameters:
        - name: eventId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_48
      summary: >-
        Check whether the authenticated athlete holds a series-pass entitlement
        covering this event.
      tags: *ref_49
  /v2/me/series-passes/{passId}/register:
    post:
      operationId: MeSeriesPassesController.register
      parameters:
        - name: passId
          required: true
          in: path
          description: Series pass ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_48
      summary: >-
        Register the athlete for a published series pass (idempotent per
        (passId, athleteUserId)).
      tags: *ref_49
  /v2/me/series-passes/{passId}/registration:
    delete:
      operationId: MeSeriesPassesController.cancel
      parameters:
        - name: passId
          required: true
          in: path
          description: Series pass ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_48
      summary: Cancel the athlete's registration for this pass.
      tags: *ref_49
  /v2/organizers/{organizerId}/master-events/{eventId}:
    get:
      operationId: OrganizerMasterEventsController.detail
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_50
        - bearer: []
      summary: Master configuration, components and readiness.
      tags: &ref_51
        - 'Organizer: Master Events'
    patch:
      operationId: OrganizerMasterEventsController.update
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMasterEventConfigDto'
      responses:
        '200':
          description: ''
      security: *ref_50
      summary: Create or update master-event rules.
      tags: *ref_51
  /v2/organizers/{organizerId}/master-events/{eventId}/components:
    put:
      operationId: OrganizerMasterEventsController.components
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReplaceMasterComponentsDto'
      responses:
        '200':
          description: ''
      security: *ref_50
      summary: Atomically replace ordered master components.
      tags: *ref_51
  /v2/organizers/{organizerId}/master-events/{eventId}/configure:
    put:
      operationId: OrganizerMasterEventsController.configure
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfigureMasterEventDto'
      responses:
        '200':
          description: ''
      security: *ref_50
      summary: Atomically save master rules and ordered components.
      tags: *ref_51
  /v2/organizers/{organizerId}/master-events/{eventId}/participants:
    get:
      operationId: OrganizerMasterEventsController.participants
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_50
      summary: Master participant progress roster.
      tags: *ref_51
  /v2/organizers/{organizerId}/master-events/{eventId}/rewards/finalize:
    post:
      operationId: OrganizerMasterEventsController.finalizeRewards
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_50
      summary: Finalize idempotent master reward grants.
      tags: *ref_51
  /v2/organizers/{organizerId}/master-events/{eventId}/rewards:
    get:
      operationId: OrganizerMasterEventsController.rewards
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_50
      summary: List master reward grants.
      tags: *ref_51
  /v2/organizers/{organizerId}/master-events/{eventId}/orders:
    get:
      operationId: OrganizerMasterEventsController.orders
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_50
      summary: List master bundle payment and enrollment orders.
      tags: *ref_51
  /v2/events/{eventId}/master:
    get:
      operationId: AthleteMasterEventsController.detail
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Viewer-aware master journey and eligibility.
      tags: &ref_52
        - 'Athlete: Master Events'
  /v2/events/{eventId}/master/join:
    post:
      operationId: AthleteMasterEventsController.join
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: Join the master journey independently.
      tags: *ref_52
    delete:
      operationId: AthleteMasterEventsController.leave
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Leave the master journey.
      tags: *ref_52
  /v2/events/{eventId}/master/quote:
    get:
      operationId: AthleteMasterEventsController.quote
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Master enrollment quote and compatibility.
      tags: *ref_52
  /v2/events/{eventId}/master/orders/{orderId}/verify:
    post:
      operationId: AthleteMasterEventsController.verify
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: orderId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: Verify bundle payment and atomically enroll children.
      tags: *ref_52
  /v2/events/{eventId}/master/leaderboard:
    get:
      operationId: AthleteMasterEventsController.leaderboard
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Conditional master points leaderboard.
      tags: *ref_52
  /v2/events/{eventId}/master/rewards/me:
    get:
      operationId: AthleteMasterEventsController.rewards
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: My finalized master reward grants.
      tags: *ref_52
  /v2/master-events/webhooks/cashfree:
    post:
      operationId: MasterEventsWebhookController.cashfree
      parameters:
        - name: x-webhook-signature
          required: true
          in: header
          schema:
            type: string
        - name: x-webhook-timestamp
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Master Events: Webhooks'
  /v2/admin/master-events:
    get:
      operationId: AdminMasterEventsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_53
        - bearer: []
      summary: List master events for governance.
      tags: &ref_54
        - 'Admin: Master Events'
  /v2/admin/master-events/{eventId}:
    get:
      operationId: AdminMasterEventsController.detail
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_53
      summary: Inspect one master event.
      tags: *ref_54
  /v2/admin/master-events/{eventId}/status:
    patch:
      operationId: AdminMasterEventsController.status
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMasterAdminStatusDto'
      responses:
        '200':
          description: ''
      security: *ref_53
      summary: Moderate master-event publication status.
      tags: *ref_54
  /v2/admin/master-events/{eventId}/participants:
    get:
      operationId: AdminMasterEventsController.participants
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_53
      tags: *ref_54
  /v2/admin/master-events/{eventId}/rewards:
    get:
      operationId: AdminMasterEventsController.rewards
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_53
      tags: *ref_54
  /v2/admin/master-events/{eventId}/orders:
    get:
      operationId: AdminMasterEventsController.orders
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_53
      tags: *ref_54
  /v2/admin/master-events/orders/{orderId}/reconcile-refund:
    post:
      operationId: AdminMasterEventsController.reconcileRefund
      parameters:
        - name: orderId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_53
      tags: *ref_54
  /v2/admin/master-events/orders/{orderId}/reconcile-settlement:
    post:
      operationId: AdminMasterEventsController.reconcileSettlement
      parameters:
        - name: orderId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_53
      tags: *ref_54
  /v2/admin/master-events/rewards/{grantId}:
    patch:
      operationId: AdminMasterEventsController.reward
      parameters:
        - name: grantId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FulfillMasterRewardDto'
      responses:
        '200':
          description: ''
      security: *ref_53
      tags: *ref_54
  /v2/organizer/marketing/drafts:
    get:
      operationId: OrganizerMarketingDraftsController.list
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_55
        - bearer: []
      tags: &ref_56
        - 'Organizer: Marketing Drafts'
    post:
      operationId: OrganizerMarketingDraftsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMarketingDraftDto'
      responses:
        '201':
          description: ''
      security: *ref_55
      tags: *ref_56
  /v2/organizer/marketing/drafts/{id}:
    get:
      operationId: OrganizerMarketingDraftsController.get
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_55
      tags: *ref_56
    patch:
      operationId: OrganizerMarketingDraftsController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMarketingDraftDto'
      responses:
        '200':
          description: ''
      security: *ref_55
      tags: *ref_56
    delete:
      operationId: OrganizerMarketingDraftsController.delete
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_55
      tags: *ref_56
  /v2/users/dms/upload-media:
    post:
      operationId: UserDirectMessagesController.uploadMedia
      parameters: []
      responses:
        '201':
          description: ''
      summary: Upload media file for a DM — returns GCS URL
      tags: &ref_57
        - 'User: Direct Messages'
  /v2/users/dms:
    post:
      operationId: UserDirectMessagesController.send
      parameters: []
      responses:
        '201':
          description: ''
      summary: Send a direct message to any user
      tags: *ref_57
    get:
      operationId: UserDirectMessagesController.threads
      parameters:
        - name: filter
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Unified chat inbox — user DMs + club entries (one per club, all channels
        grouped)
      tags: *ref_57
  /v2/users/dms/unread-count:
    get:
      operationId: UserDirectMessagesController.unreadCount
      parameters: []
      responses:
        '200':
          description: ''
      summary: Total unread DM count (badge indicator)
      tags: *ref_57
  /v2/users/dms/{peerUserId}:
    get:
      operationId: UserDirectMessagesController.thread
      parameters:
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get full conversation thread with a user
      tags: *ref_57
  /v2/users/dms/{peerUserId}/read:
    post:
      operationId: UserDirectMessagesController.markThreadRead
      parameters:
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Bulk mark entire thread as read
      tags: *ref_57
  /v2/users/dms/{messageId}/read:
    patch:
      operationId: UserDirectMessagesController.markRead
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Mark a single message as read
      tags: *ref_57
  /v2/users/dms/{peerUserId}/preferences:
    get:
      operationId: UserDirectMessagesController.getPreferences
      parameters:
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get mute preference for a thread
      tags: *ref_57
    patch:
      operationId: UserDirectMessagesController.setPreferences
      parameters:
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Set mute preference for a thread
      tags: *ref_57
  /v2/users/dms/{messageId}:
    patch:
      operationId: UserDirectMessagesController.editMessage
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EditMessageDto'
      responses:
        '200':
          description: ''
      summary: Edit your own sent message body (sender only)
      tags: *ref_57
    delete:
      operationId: UserDirectMessagesController.deleteMessage
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Delete your own sent message for everyone (sender only)
      tags: *ref_57
  /v2/users/dms/{messageId}/me:
    delete:
      operationId: UserDirectMessagesController.deleteForMe
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Delete a message for me only — other user still sees it
      tags: *ref_57
  /v2/users/dms/{peerUserId}/thread:
    delete:
      operationId: UserDirectMessagesController.deleteThread
      parameters:
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Delete the DM conversation from the caller's inbox — hides the thread
        tile and clears its messages for the caller; reappears if a new message
        arrives. The peer is unaffected.
      tags: *ref_57
  /v2/users/dms/messages/{messageId}/reactions/{emoji}:
    post:
      operationId: UserDirectMessagesController.addReaction
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
        - name: emoji
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Add an emoji reaction to a DM message
      tags: *ref_57
    delete:
      operationId: UserDirectMessagesController.removeReaction
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
        - name: emoji
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Remove an emoji reaction from a DM message
      tags: *ref_57
  /v2/users/dms/messages/{messageId}/reactions:
    get:
      operationId: UserDirectMessagesController.getReactions
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get all reaction counts for a DM message
      tags: *ref_57
  /v2/users/dms/{peerUserId}/typing:
    post:
      operationId: UserDirectMessagesController.typing
      parameters:
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Signal typing — stores Redis key with 5s TTL
      tags: *ref_57
  /v2/users/dms/{peerUserId}/typing-status:
    get:
      operationId: UserDirectMessagesController.typingStatus
      parameters:
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Check if peer is currently typing
      tags: *ref_57
  /v2/users/check-email:
    get:
      operationId: UsersController.checkEmailExists
      parameters:
        - &ref_58
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: email
          required: true
          in: query
          description: Email address to check
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Check if an email already exists
      tags: &ref_59
        - Users
  /v2/users/username-available:
    get:
      operationId: UsersController.usernameAvailable
      parameters:
        - *ref_58
        - name: username
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Check whether a username (Repeak ID) is available
      tags: *ref_59
  /v2/users/{id}/upload-profile-photo:
    patch:
      operationId: UsersController.uploadProfilePhoto
      parameters:
        - *ref_58
        - name: Content-Type
          in: header
          description: multipart/form-data
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                userId:
                  type: string
                  example: '12345'
                  description: The ID of the user
                file:
                  type: string
                  format: binary
                  description: The selfie file to upload
              required:
                - userId
                - file
      responses:
        '200':
          description: ''
      summary: Upload the user selfie
      tags: *ref_59
  /v2/users/bots:
    post:
      description: >-
        Admin-only multipart endpoint. Every profile field and at least one
        sport are required. Use GET /v2/users/username-available for the
        debounced username check.
      operationId: UsersController.createBotUser
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - username
                - gender
                - dateOfBirth
                - bio
                - sportIds
                - profilePhoto
              properties:
                name:
                  type: string
                  example: Repeak Pace Bot
                username:
                  type: string
                  example: pace_bot_01
                gender:
                  type: string
                  enum:
                    - male
                    - female
                    - other
                dateOfBirth:
                  type: string
                  format: date
                  example: '1998-06-15'
                bio:
                  type: string
                sportIds:
                  type: array
                  items:
                    type: string
                    format: uuid
                profilePhoto:
                  type: string
                  format: binary
      responses:
        '201':
          description: ''
      summary: Create a fully populated bot athlete account
      tags: *ref_59
  /v2/users/me/bot-onboarding:
    post:
      description: >-
        Bot-only authenticated multipart endpoint. Call after POST
        /v2/auth/verify-otp returns the new bot access token.
      operationId: UsersController.completeBotOnboarding
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - username
                - gender
                - dateOfBirth
                - bio
                - sportIds
                - profilePhoto
              properties:
                name:
                  type: string
                  example: Repeak Pace Bot
                username:
                  type: string
                  example: pace_bot_01
                gender:
                  type: string
                  enum:
                    - male
                    - female
                    - other
                dateOfBirth:
                  type: string
                  format: date
                  example: '1998-06-15'
                bio:
                  type: string
                sportIds:
                  type: array
                  items:
                    type: string
                    format: uuid
                profilePhoto:
                  type: string
                  format: binary
      responses:
        '201':
          description: ''
      summary: Complete the current bot athlete onboarding profile
      tags: *ref_59
  /v2/users:
    post:
      operationId: UsersController.createUser
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserDto'
      responses:
        '201':
          description: ''
      tags: *ref_59
    get:
      operationId: getManyBaseUsersControllerUser
      parameters:
        - *ref_58
        - name: fields
          description: >-
            Selects resource fields. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#select"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: csv
          schema:
            type: array
            items:
              type: string
        - name: s
          description: >-
            Adds search condition. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#search"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: string
        - name: filter
          description: >-
            Adds filter condition. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#filter"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: or
          description: >-
            Adds OR condition. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#or"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: sort
          description: >-
            Adds sort by field. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#sort"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: join
          description: >-
            Adds relational resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#join"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: limit
          description: >-
            Limit amount of resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#limit"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: integer
        - name: offset
          description: >-
            Offset amount of resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#offset"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: integer
        - name: page
          description: >-
            Page portion of resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#page"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            type: integer
        - name: cache
          description: >-
            Reset cache (if was enabled). <a
            href="https://github.com/nestjsx/crud/wiki/Requests#cache"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            minimum: 0
            maximum: 1
            type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetManyUserResponseDto'
      summary: Retrieve multiple Users
      tags: *ref_59
  /v2/users/me:
    get:
      operationId: UsersController.getMe
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}:
    get:
      operationId: getOneBaseUsersControllerUser
      parameters:
        - *ref_58
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: fields
          description: >-
            Selects resource fields. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#select"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: csv
          schema:
            type: array
            items:
              type: string
        - name: join
          description: >-
            Adds relational resources. <a
            href="https://github.com/nestjsx/crud/wiki/Requests#join"
            target="_blank">Docs</a>
          required: false
          in: query
          collectionFormat: multi
          schema:
            type: array
            items:
              type: string
        - name: cache
          description: >-
            Reset cache (if was enabled). <a
            href="https://github.com/nestjsx/crud/wiki/Requests#cache"
            target="_blank">Docs</a>
          required: false
          in: query
          schema:
            minimum: 0
            maximum: 1
            type: integer
      responses:
        '200':
          description: Get one base response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
      summary: Retrieve a single User
      tags: *ref_59
    patch:
      operationId: UsersController.updateUser
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserDto'
      responses:
        '200':
          description: ''
      tags: *ref_59
    delete:
      operationId: deleteOneBaseUsersControllerUser
      parameters:
        - *ref_58
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200': {}
      summary: Delete a single User
      tags: *ref_59
  /v2/users/{id}/phone:
    patch:
      operationId: UsersController.userChangePhone
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/email:
    patch:
      operationId: UsersController.userChangeEmail
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/admin:
    patch:
      operationId: UsersController.updateUserByAdmin
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserDto'
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/toggle:
    patch:
      operationId: UsersController.toggleUser
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/me/fcm-token:
    patch:
      description: >-
        Called by the mobile app on every launch. Deactivates all previous
        tokens for the user and saves the new one (one user → one active token).
        Send platform as "android" or "ios".
      operationId: UsersController.updateMobileFcmToken
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnablePushNotificationDto'
      responses:
        '200':
          description: ''
      summary: Register or update the mobile FCM token for the current user.
      tags: *ref_59
  /v2/users/{id}/notifications/enable:
    post:
      description: Use only first time when creating FCM token.
      operationId: UsersController.enablePushNotification
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnablePushNotificationDto'
      responses:
        '201':
          description: ''
      summary: Enable sending notification to a device.
      tags: *ref_59
  /v2/users/{id}/notifications/disable:
    patch:
      operationId: UsersController.disablePushNotification
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DisablePushNotificationDto'
      responses:
        '200':
          description: ''
      summary: Disable sending notification to a device.
      tags: *ref_59
  /v2/users/{id}/notifications:
    post:
      operationId: UsersController.sendPushNotificationToSingleUser
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendPushNotificationDto'
      responses:
        '201':
          description: ''
      summary: Send push notification to a single user
      tags: *ref_59
    get:
      description: Use this api in notifications screen
      operationId: UsersController.getPushNotificationsOfSingleUser
      parameters:
        - *ref_58
        - name: type
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get push notifications of a single user
      tags: *ref_59
  /v2/users/{id}/notifications/preferences:
    get:
      description: >-
        Returns notification preferences grouped by category (challenges,
        events, activity). Other notifications are always enabled.
      operationId: UsersController.getUserNotificationPreferences
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      summary: Get a user's notifications preferences
      tags: *ref_59
    patch:
      description: >-
        Enable or disable notification categories (challenges, events,
        activity). Other notifications cannot be disabled.
      operationId: UsersController.updateUserNotificationPreferences
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationCategoryPreferencesDto'
      responses:
        '200':
          description: ''
      summary: Update a user's notifications preferences
      tags: *ref_59
  /v2/users/{id}/gears:
    post:
      operationId: UsersController.userCreateGear
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreateGearDto'
      responses:
        '201':
          description: ''
      tags: *ref_59
    get:
      operationId: UsersController.userGetGears
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/gears/{gearId}:
    get:
      operationId: UsersController.userGetGear
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
    patch:
      operationId: UsersController.userUpdateGear
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdateGearDto'
      responses:
        '200':
          description: ''
      tags: *ref_59
    delete:
      operationId: UsersController.userDeleteGear
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/schedules:
    post:
      operationId: UsersController.userCreateSchedule
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreateScheduleDto'
      responses:
        '201':
          description: ''
      tags: *ref_59
    get:
      operationId: UsersController.userGetSchedules
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/schedules/{scheduleId}:
    get:
      operationId: UsersController.userGetSchedule
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
    patch:
      operationId: UsersController.userUpdateSchedule
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdateScheduleDto'
      responses:
        '200':
          description: ''
      tags: *ref_59
    delete:
      operationId: UsersController.userDeleteSchedule
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/activities:
    post:
      operationId: UsersController.userCreateActivity
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreateActivityDto'
      responses:
        '201':
          description: ''
      tags: *ref_59
    get:
      operationId: UsersController.userGetActivities
      parameters:
        - *ref_58
        - name: date
          required: true
          in: query
          schema:
            format: date-time
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/activities/manual:
    post:
      operationId: UsersController.userLogManualActivity
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ManualLogActivityDto'
      responses:
        '201':
          description: ''
      tags: *ref_59
  /v2/users/me/activity-summary:
    get:
      operationId: UsersController.userActivitySummary
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/me/activity-trends:
    get:
      operationId: UsersController.userActivityTrends
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/me/pending-activity-targets:
    get:
      operationId: UsersController.userPendingActivityTargets
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/me/activities:
    get:
      operationId: UsersController.userGetMyActivities
      parameters:
        - *ref_58
        - name: date
          required: false
          in: query
          description: Optional date to filter (ISO date)
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Get the authenticated user's activities
      tags: *ref_59
  /v2/users/{id}/completed-activities:
    get:
      operationId: UsersController.getUserCompletedActivities
      parameters:
        - *ref_58
        - name: type
          required: false
          in: query
          schema:
            enum:
              - manual
              - challenge
              - event
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: page
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Get another user's completed activities
      tags: *ref_59
  /v2/users/{id}/activities/tracking-preferences:
    get:
      operationId: UsersController.userGetActivityTrackingPreferences
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/activities/{activityId}:
    get:
      operationId: UsersController.userGetActivity
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
    patch:
      operationId: UsersController.userUpdateActivity
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdateActivityDto'
      responses:
        '200':
          description: ''
      tags: *ref_59
    delete:
      operationId: UsersController.userDeleteActivity
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/activities/{activityId}/track-metadata:
    get:
      operationId: UsersController.userGetActivityTrackMetadata
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/challenges/{challengeId}:
    post:
      operationId: UsersController.userParticipateInChallenge
      parameters:
        - *ref_58
      responses:
        '201':
          description: ''
      tags: *ref_59
    get:
      operationId: UsersController.userGetChallenge
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
    patch:
      operationId: UsersController.userUpdateChallenge
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdateChallengeParticipationDto'
      responses:
        '200':
          description: ''
      tags: *ref_59
    delete:
      operationId: UsersController.userLeaveChallenge
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/badges:
    get:
      operationId: UsersController.getAllBadges
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/challenges:
    get:
      operationId: UsersController.userGetChallenges
      parameters:
        - *ref_58
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: timeframe
          required: false
          in: query
          description: >-
            Challenge-window filter. OMITTED = live + upcoming only, i.e. every
            challenge still able to earn progress — ended challenges are NOT
            returned. Pass `past` for the history view.
          schema:
            enum:
              - past
              - live
              - upcoming
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/steps/summary:
    get:
      operationId: UsersController.userGetStepsSummary
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/steps:
    get:
      operationId: UsersController.userGetSteps
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
    patch:
      operationId: UsersController.userSaveOrUpdateSteps
      parameters:
        - *ref_58
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreateStepsDto'
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/wallets/{walletId}:
    get:
      operationId: UsersController.userGetWallet
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/wallet:
    get:
      operationId: UsersController.userGetPrimaryWallet
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/public:
    get:
      operationId: UsersController.userPublicProfile
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/by-username/{username}:
    get:
      operationId: UsersController.userByUsername
      parameters:
        - *ref_58
        - name: username
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/username:
    post:
      operationId: UsersController.claimUsername
      parameters:
        - *ref_58
      responses:
        '201':
          description: ''
      tags: *ref_59
  /v2/users/{id}/profile-view:
    get:
      operationId: UsersController.userProfileView
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/users/{id}/posts:
    get:
      operationId: UsersController.getUserPosts
      parameters:
        - *ref_58
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get another user's posts (privacy + block gated)
      tags: *ref_59
  /v2/users/{id}/data-export:
    post:
      operationId: UsersController.userDataExport
      parameters:
        - *ref_58
      responses:
        '201':
          description: ''
      tags: *ref_59
  /v2/users/{id}/account:
    delete:
      operationId: UsersController.userDeleteAccount
      parameters:
        - *ref_58
      responses:
        '200':
          description: ''
      tags: *ref_59
  /v2/user/me/dashboard:
    get:
      operationId: AthleteDashboardController.dashboard
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_60
        - 'User: Athlete Dashboard'
  /v2/user/me/metrics/dashboard:
    get:
      operationId: AthleteDashboardController.metricsDashboard
      parameters:
        - name: timeRange
          required: false
          in: query
          schema:
            enum:
              - 30D
              - 90D
              - YTD
              - ALL
            type: string
        - name: sport
          required: false
          in: query
          schema:
            type: array
            items: {}
      responses:
        '200':
          description: ''
      summary: >-
        Athlete-facing performance metrics dashboard. Owner-only. 18 fixed-order
        tiles + recent activities ≤5 + trend/paceSeries/sportSplit time-series;
        per-tile sourceStatus AVAILABLE / NOT_TRACKED_YET.
      tags: *ref_60
  /v2/user/me/race-history:
    get:
      operationId: AthleteDashboardController.raceHistory
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_60
  /v2/user/me/training-programs:
    get:
      operationId: AthleteDashboardController.trainingPrograms
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_60
  /v2/user/me/training-programs/by-id/{id}:
    get:
      operationId: AthleteDashboardController.trainingProgram
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_60
  /v2/me/locale:
    get:
      operationId: UserLocaleController.get
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_61
        - 'User: Locale preference'
    patch:
      operationId: UserLocaleController.set
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_61
  /v2/me/units:
    get:
      operationId: UserUnitsController.get
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_62
        - 'User: Unit-system preference'
    patch:
      operationId: UserUnitsController.set
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_62
  /v2/me/privacy:
    get:
      operationId: UserPrivacyController.get
      parameters: []
      responses:
        '200':
          description: ''
      summary: Get the athlete privacy settings + supported values.
      tags: &ref_63
        - 'User: Privacy settings'
    patch:
      operationId: UserPrivacyController.set
      parameters: []
      responses:
        '200':
          description: ''
      summary: Update the athlete privacy settings (partial).
      tags: *ref_63
  /v2/u/{userId}/share-card.svg:
    get:
      operationId: OgProfileCardController.shareCard
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: theme
          required: true
          in: query
          schema:
            type: string
        - name: hide
          required: true
          in: query
          schema:
            type: string
        - name: hero
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Story-format (1080×1920) share card with 5 theme presets. PRD §16.4 G-4.
        Caches by (userId, theme, profile-version).
      tags: &ref_64
        - 'OG: Profile card'
  /v2/u/{athleteId}/card.png:
    get:
      operationId: OgProfileCardController.cardPng
      parameters:
        - name: athleteId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Return a 1200×630 OG profile card for the given athlete. Stub for §16.4;
        serves SVG until the full PNG generator lands.
      tags: *ref_64
  /v2/admin/users/{userId}/verification-tier:
    get:
      operationId: AdminUserVerificationController.getTier
      parameters:
        - &ref_65
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a user's current verification tier (admin diagnostic).
      tags: &ref_66
        - Admin — User Verification Tiers
    post:
      operationId: AdminUserVerificationController.setTier
      parameters:
        - *ref_65
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Set a user's verification tier. Tier changes are audited and
        append-only.
      tags: *ref_66
  /v2/users/me/preferred-sports:
    get:
      operationId: PreferredSportsController.listMine
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - Athlete - Preferred Sports
  /v2/users/me/workspaces:
    get:
      operationId: MeWorkspacesController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_67
        - 'Partner Console: My Workspaces'
  /v2/users/me/workspaces/switch:
    post:
      operationId: MeWorkspacesController.switch
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkspaceSwitchDto'
      responses:
        '204':
          description: ''
      summary: >-
        Record a workspace switch in the append-only audit log. 403 if the
        caller does not belong to the target workspace.
      tags: *ref_67
  /v2/users/me/preferences:
    get:
      operationId: MeConsolePreferencesController.get
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_68
        - 'Partner Hub: My Preferences'
    put:
      operationId: MeConsolePreferencesController.put
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_68
  /v2/users/me/clubs:
    get:
      description: >-
        Returns every ACTIVE membership for the bearer token user. Each item
        includes club workspace/card fields (id, name, slug, logo/banner,
        location, status, visibility, memberCount, verified, deactivated,
        deactivatedAt) and the caller's role (OWNER | ADMIN | MODERATOR |
        MEMBER) so the client can gate admin UI on first paint without a
        separate members fetch. Deactivated clubs are returned with
        deactivated=true rather than omitted, so a member sees a badge instead
        of the club vanishing.
      operationId: MeClubsController.list
      parameters: []
      responses:
        '200':
          description: ''
      summary: List the calling athlete's club memberships
      tags:
        - Users
  /v2/users/temp-assign-username/missing:
    get:
      operationId: TempAssignUsernameController.listMissing
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: TEMP — list users missing a username
      tags: &ref_69
        - v2/users/temp-assign-username
  /v2/users/temp-assign-username/bulk:
    post:
      operationId: TempAssignUsernameController.assignBulk
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: TEMP — bulk-assign usernames to old users
      tags: *ref_69
    delete:
      operationId: TempAssignUsernameController.removeBulk
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: TEMP — remove username from all users
      tags: *ref_69
  /v2/users/temp-assign-username/{id}:
    post:
      operationId: TempAssignUsernameController.assign
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: username
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: TEMP — assign a username to one old user
      tags: *ref_69
    delete:
      operationId: TempAssignUsernameController.removeUsername
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: TEMP — remove a user's username (not the user)
      tags: *ref_69
  /v2/me/muted-keywords:
    get:
      operationId: MeMutedKeywordsController.list
      parameters: []
      responses:
        '200':
          description: ''
      summary: List all muted keywords for the caller.
      tags: &ref_70
        - 'User: Muted keywords'
    post:
      operationId: MeMutedKeywordsController.add
      parameters: []
      responses:
        '201':
          description: ''
      summary: Add a keyword to the muted list.
      tags: *ref_70
  /v2/me/muted-keywords/{keyword}:
    delete:
      operationId: MeMutedKeywordsController.remove
      parameters:
        - name: keyword
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Remove a keyword from the muted list.
      tags: *ref_70
  /v2/me/tag-approvals/pending:
    get:
      operationId: MeTagApprovalsController.listPending
      parameters: []
      responses:
        '200':
          description: ''
      summary: List pending tag / mention approvals.
      tags: &ref_71
        - 'User: Tag approvals'
  /v2/me/tag-approvals/{id}/approve:
    post:
      operationId: MeTagApprovalsController.approve
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Approve a pending tag.
      tags: *ref_71
  /v2/me/tag-approvals/{id}/deny:
    post:
      operationId: MeTagApprovalsController.deny
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Deny a pending tag.
      tags: *ref_71
  /v2/me/tag-approval-required:
    patch:
      operationId: MeTagApprovalsController.setRequired
      parameters: []
      responses:
        '200':
          description: ''
      summary: Toggle whether new tags require your approval.
      tags: *ref_71
  /v2/hub/activation-token:
    post:
      operationId: HubController.mintActivationToken
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MintActivationTokenDto'
      responses:
        '201':
          description: ''
      summary: >-
        Mint a short-lived (60s) activation token for a product+entity the
        caller has (or just created) a membership on.
      tags: &ref_72
        - Hub Portal
  /v2/hub/activation-token/exchange:
    post:
      operationId: HubController.exchangeActivationToken
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExchangeActivationTokenDto'
      responses:
        '200':
          description: ''
      summary: >-
        Exchange an activation token for a real session on the destination
        portal.
      tags: *ref_72
  /v2/me/social-blocks/block/{targetUserId}:
    post:
      operationId: UserSocialBlocksController.block
      parameters:
        - &ref_73
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Block a user (mutual hide; only blocker is informed).
      tags: &ref_74
        - User Privacy — Block / Mute
    delete:
      operationId: UserSocialBlocksController.unblock
      parameters:
        - *ref_73
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Unblock a user (idempotent).
      tags: *ref_74
  /v2/me/social-blocks/mute/{targetUserId}:
    post:
      operationId: UserSocialBlocksController.mute
      parameters:
        - *ref_73
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Mute a user (one-way feed/search hide).
      tags: *ref_74
    delete:
      operationId: UserSocialBlocksController.unmute
      parameters:
        - *ref_73
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Unmute a user (idempotent).
      tags: *ref_74
  /v2/me/social-blocks/restrict/{targetUserId}:
    post:
      operationId: UserSocialBlocksController.restrict
      parameters:
        - *ref_73
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Restrict a user (comments held; DMs go to requests).
      tags: *ref_74
    delete:
      operationId: UserSocialBlocksController.unrestrict
      parameters:
        - *ref_73
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Unrestrict a user (idempotent).
      tags: *ref_74
  /v2/me/social-blocks/verdict/{targetUserId}:
    get:
      operationId: UserSocialBlocksController.verdict
      parameters:
        - *ref_73
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Returns the social-hide verdict for a single user from the caller's
        perspective.
      tags: *ref_74
  /v2/me/social-blocks/blocks:
    get:
      operationId: UserSocialBlocksController.listBlocks
      parameters:
        - *ref_73
      responses:
        '200':
          description: ''
      summary: >-
        List users the caller has blocked, with name + avatar + city for
        settings rendering.
      tags: *ref_74
  /v2/me/social-blocks/mutes:
    get:
      operationId: UserSocialBlocksController.listMutes
      parameters:
        - *ref_73
      responses:
        '200':
          description: ''
      summary: >-
        List users the caller has muted, with name + avatar + city for settings
        rendering.
      tags: *ref_74
  /v2/me/social-blocks/restricts:
    get:
      operationId: UserSocialBlocksController.listRestricts
      parameters:
        - *ref_73
      responses:
        '200':
          description: ''
      summary: List users the caller has restricted.
      tags: *ref_74
  /v2/user/me/safety-center:
    get:
      operationId: SafetyCenterController.getSafetyCenter
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Athlete-facing Safety Center aggregator. Returns own report history,
        block/mute lists, anti-cheat appeals, and published community
        guidelines. Owner-only.
      tags:
        - User — Safety Center (§86)
  /v2/admin/growth-loops:
    get:
      operationId: GrowthLoopsController.listAll
      parameters:
        - &ref_75
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: timeRange
          required: false
          in: query
          schema:
            enum:
              - 7D
              - 30D
              - 90D
              - YTD
              - ALL
            type: string
        - name: loopType
          required: false
          in: query
          schema:
            type: string
        - name: sourceStatus
          required: false
          in: query
          schema:
            type: string
        - name: ownerSurface
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List the 8 Repeak growth loops with stage / conversion / indicator
        metrics and explicit sourceStatus per signal. Admin-only.
      tags: &ref_76
        - Admin — Growth Loops (§84)
  /v2/admin/growth-loops/{loopCode}:
    get:
      operationId: GrowthLoopsController.getOne
      parameters:
        - *ref_75
        - name: loopCode
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Detail view for a single growth loop. Same loop-row shape as the list
        endpoint. Admin-only.
      tags: *ref_76
  /v2/user/me/training-programs/summary:
    get:
      operationId: TrainingProgramsSummaryController.getSummary
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Athlete-facing Training Programs summary — active enrollments + progress
        + today's workout + library highlights + payment status. Owner-only.
      tags:
        - User — Training Programs Summary (§22)
  /v2/user/me/notifications:
    get:
      operationId: UserNotificationCenterController.list
      parameters:
        - &ref_77
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: cursor
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: string
        - name: type
          required: false
          in: query
          schema:
            type: string
        - name: readStatus
          required: false
          in: query
          schema:
            enum:
              - ALL
              - READ
              - UNREAD
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List athlete notifications with filters + cursor pagination + unread
        count + push-token registration status. Owner-only.
      tags: &ref_78
        - User — Notification Center (§29)
  /v2/user/me/notifications/unread-count:
    get:
      operationId: UserNotificationCenterController.unreadCount
      parameters:
        - *ref_77
      responses:
        '200':
          description: ''
      summary: Athlete unread notification count.
      tags: *ref_78
  /v2/user/me/notifications/{notificationId}/read:
    post:
      operationId: UserNotificationCenterController.markRead
      parameters:
        - *ref_77
        - name: notificationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Mark a single notification read.
      tags: *ref_78
  /v2/user/me/notifications/read-all:
    post:
      operationId: UserNotificationCenterController.markAllRead
      parameters:
        - *ref_77
      responses:
        '201':
          description: ''
      summary: Mark every unread notification read.
      tags: *ref_78
  /v2/user/me/notifications/{notificationId}:
    delete:
      operationId: UserNotificationCenterController.dismiss
      parameters:
        - *ref_77
        - name: notificationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Dismiss a single notification (soft delete). Persists so it does not
        resurface on the next GET — owner-only, 404's on cross-user id.
      tags: *ref_78
  /v2/user/me/notifications/{notificationId}/dismiss:
    post:
      operationId: UserNotificationCenterController.dismissPost
      parameters:
        - *ref_77
        - name: notificationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Dismiss a single notification — same as DELETE :notificationId, exposed
        under the POST .../dismiss convention already used by the organizer
        recommendations/suggested-actions dismiss routes and the mobile client.
      tags: *ref_78
  /v2/user/me/notification-preferences:
    get:
      operationId: UserNotificationPreferencesCenterController.get
      parameters:
        - &ref_79
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Get the athlete notification preferences (per-type isEnabled +
        per-channel toggles + quietHours + channelSupport). Owner-only.
      tags: &ref_80
        - User — Notification Preferences (§29)
    patch:
      operationId: UserNotificationPreferencesCenterController.patch
      parameters:
        - *ref_79
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationPreferencesBodyDto'
      responses:
        '200':
          description: ''
      summary: >-
        Patch the athlete notification preferences. Persists per-type +
        per-channel + quietHours; returns the refreshed shape.
      tags: *ref_80
  /v2/user/me/nutrition/logs/photo:
    post:
      operationId: UserNutritionCenterController.uploadLogPhoto
      parameters:
        - &ref_81
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Upload a meal photo for a scanned log. Owner-only.
      tags: &ref_82
        - User — Nutrition Center (§23)
  /v2/user/me/nutrition/dashboard:
    get:
      operationId: UserNutritionCenterController.dashboard
      parameters:
        - *ref_81
        - name: date
          required: false
          in: query
          schema:
            type: string
        - name: range
          required: false
          in: query
          schema:
            enum:
              - DAY
              - 7D
              - 30D
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Athlete nutrition dashboard — daily totals + weekly series + meals +
        goals + progress. Owner-only.
      tags: *ref_82
  /v2/user/me/nutrition/logs:
    get:
      operationId: UserNutritionCenterController.listLogs
      parameters:
        - *ref_81
        - name: date
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List own nutrition logs for a date.
      tags: *ref_82
    post:
      operationId: UserNutritionCenterController.createLog
      parameters:
        - *ref_81
      responses:
        '201':
          description: ''
      summary: Create a manual / quick-add nutrition log.
      tags: *ref_82
  /v2/user/me/nutrition/logs/{logId}:
    delete:
      operationId: UserNutritionCenterController.deleteLog
      parameters:
        - *ref_81
        - name: logId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Delete an own nutrition log (soft-remove).
      tags: *ref_82
  /v2/user/me/nutrition/goals:
    get:
      operationId: UserNutritionCenterController.getGoals
      parameters:
        - *ref_81
      responses:
        '200':
          description: ''
      summary: Get athlete nutrition goals.
      tags: *ref_82
    patch:
      operationId: UserNutritionCenterController.patchGoals
      parameters:
        - *ref_81
      responses:
        '200':
          description: ''
      summary: Patch athlete nutrition goals.
      tags: *ref_82
  /v2/user/me/nutrition/quick-add-items:
    get:
      operationId: UserNutritionCenterController.quickAddItems
      parameters:
        - *ref_81
      responses:
        '200':
          description: ''
      summary: Browse the platform quick-add catalog.
      tags: *ref_82
  /v2/notifications/preferences:
    get:
      operationId: NotificationsController.getMyPreferences
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Athlete's unified notification preferences (per-type, per-channel, quiet
        hours, channel support).
      tags: &ref_83
        - Notifications
    patch:
      operationId: NotificationsController.patchMyPreferences
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationPreferencesBodyDto'
      responses:
        '200':
          description: ''
      summary: >-
        Patch the caller athlete preferences. Body fields are independent — pass
        only what changes.
      tags: *ref_83
  /v2/notifications:
    get:
      description: Only admins can fetch all notifications from db.
      operationId: NotificationsController.getPushNotifications
      parameters: []
      responses:
        '200':
          description: ''
      summary: Fetch notification of all users.
      tags: *ref_83
    post:
      description: Only admins can send notifications to all users.
      operationId: NotificationsController.sendPushNotificationsToAllUsers
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendPushNotificationDto'
      responses:
        '201':
          description: ''
      summary: Send notification to all users.
      tags: *ref_83
  /v2/notifications/preferences-types:
    post:
      operationId: NotificationsController.createPreferencesType
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateNotificationPreferencesType'
      responses:
        '201':
          description: ''
      tags: *ref_83
    get:
      operationId: NotificationsController.getAllPreferencesTypes
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_83
    delete:
      operationId: NotificationsController.deletePreferencesType
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeleteNotificationPreferencesType'
      responses:
        '200':
          description: ''
      tags: *ref_83
  /v2/notifications/{id}:
    patch:
      operationId: NotificationsController.markPushNotificationAsSeen
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Mark notification as seen.
      tags: *ref_83
  /v2/notifications/users/{userId}/category-preferences:
    get:
      description: >-
        Returns the enabled/disabled status for each notification category
        (challenges, events, activity). Other notifications are always enabled.
      operationId: NotificationsController.getUserNotificationCategoryPreferences
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a user's notification category preferences
      tags: *ref_83
    patch:
      description: >-
        Enable or disable notification categories (challenges, events,
        activity). Other notifications cannot be disabled.
      operationId: NotificationsController.updateUserNotificationCategoryPreferences
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationCategoryPreferencesDto'
      responses:
        '200':
          description: ''
      summary: Update a user's notification category preferences
      tags: *ref_83
  /v2/notifications/users/{userId}/enable:
    post:
      description: >-
        Call after obtaining an FCM token on the client. Deactivates all prior
        tokens for the user and registers the new one.
      operationId: NotificationsController.enablePushNotification
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnablePushNotificationDto'
      responses:
        '201':
          description: ''
      summary: Enable sending notification to a device.
      tags: *ref_83
  /v2/notifications/users/{userId}/disable:
    patch:
      description: >-
        Marks the token as inactive. Use on sign-out to stop push delivery to
        this device.
      operationId: NotificationsController.disablePushNotification
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DisablePushNotificationDto'
      responses:
        '200':
          description: ''
      summary: Disable sending notification to a device.
      tags: *ref_83
  /v2/user/notifications/inbox:
    get:
      operationId: InboxNotificationsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List the viewer inbox (unread first, then chronological)
      tags: &ref_84
        - 'Viewer: Notification Inbox'
  /v2/user/notifications/inbox/unread-count:
    get:
      operationId: InboxNotificationsController.unreadCount
      parameters: []
      responses:
        '200':
          description: ''
      summary: Unread count badge (bell icon)
      tags: *ref_84
  /v2/user/notifications/inbox/{id}/read:
    post:
      operationId: InboxNotificationsController.markRead
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Mark a single notification read
      tags: *ref_84
  /v2/user/notifications/inbox/read-all:
    post:
      operationId: InboxNotificationsController.markAllRead
      parameters: []
      responses:
        '201':
          description: ''
      summary: Mark every unread notification read
      tags: *ref_84
  /v2/coupons:
    post:
      operationId: CouponsController.createCoupon
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCouponDto'
      responses:
        '201':
          description: ''
      tags: &ref_85
        - Coupons
    get:
      operationId: CouponsController.getCoupons
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_85
  /v2/coupons/{id}:
    get:
      operationId: CouponsController.getCoupon
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_85
    patch:
      operationId: CouponsController.updateCoupon
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCouponDto'
      responses:
        '200':
          description: ''
      tags: *ref_85
    delete:
      operationId: CouponsController.deleteCoupon
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_85
  /v2/coupons/{id}/usage:
    get:
      operationId: CouponsController.getCouponUsage
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_85
  /v2/coupons/{id}/review:
    patch:
      operationId: CouponsController.reviewCoupon
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      tags: *ref_85
  /v2/coupons/{id}/toggle:
    patch:
      operationId: CouponsController.toggleCouponStatus
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_85
  /v2/admin/payment-providers:
    get:
      operationId: PaymentProvidersController.status
      parameters: []
      responses:
        '200':
          description: ''
      tags:
        - 'Admin: Payment Providers'
  /v2/payments/webhooks/razorpay:
    post:
      operationId: SubscriptionWebhooksController.razorpay
      parameters:
        - name: x-razorpay-signature
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_86
        - 'Public: Payment Webhooks'
  /v2/payments/webhooks/stripe:
    post:
      operationId: SubscriptionWebhooksController.stripe
      parameters:
        - name: stripe-signature
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_86
  /v2/payments/webhooks/manual:
    post:
      operationId: SubscriptionWebhooksController.manual
      parameters:
        - name: x-manual-signature
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_86
  /v2/payments/webhooks/cashfree:
    post:
      operationId: SubscriptionWebhooksController.cashfree
      parameters:
        - name: x-webhook-signature
          required: true
          in: header
          schema:
            type: string
        - name: x-webhook-timestamp
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_86
  /v2/admin/payout-requests:
    get:
      operationId: AdminPayoutWorkflowController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - REQUESTED
              - UNDER_REVIEW
              - APPROVED
              - REJECTED
              - PAID
              - CANCELLED
            type: string
        - name: payeeType
          required: false
          in: query
          schema:
            enum:
              - ORGANIZER
              - CLUB
            type: string
        - name: clubId
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_87
        - bearer: []
      summary: >-
        List payout requests, optionally by status / payee type / club.
        `payeeType=CLUB` (or any `clubId`) narrows to the club payout queue.
      tags: &ref_88
        - 'Admin: Payout Requests'
  /v2/admin/payout-requests/{id}/review:
    post:
      operationId: AdminPayoutWorkflowController.review
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_87
      summary: Start review (REQUESTED → UNDER_REVIEW).
      tags: *ref_88
  /v2/admin/payout-requests/{id}/approve:
    post:
      operationId: AdminPayoutWorkflowController.approve
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_87
      summary: Approve (UNDER_REVIEW → APPROVED).
      tags: *ref_88
  /v2/admin/payout-requests/{id}/reject:
    post:
      operationId: AdminPayoutWorkflowController.reject
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_87
      summary: Reject (UNDER_REVIEW → REJECTED). Reason required.
      tags: *ref_88
  /v2/admin/payout-requests/{id}/mark-paid:
    post:
      operationId: AdminPayoutWorkflowController.markPaid
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_87
      summary: Mark paid (APPROVED → PAID). Payment reference required.
      tags: *ref_88
  /v2/admin/refunds:
    get:
      operationId: RefundsController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_89
        - 'Admin: Refunds'
  /v2/admin/refunds/{id}/mark-manual-refunded:
    post:
      operationId: RefundsController.markManualRefunded
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_89
  /v2/admin/refunds/{id}/cancel:
    post:
      operationId: RefundsController.cancel
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_89
  /v2/support-tickets:
    post:
      operationId: SupportTicketsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSupportTicketDto'
      responses:
        '201':
          description: Support ticket created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportTicket'
      security: &ref_90
        - bearer: []
      summary: Create a new support ticket
      tags: &ref_91
        - Support Tickets
    get:
      operationId: SupportTicketsController.findAll
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - OPEN
              - IN_PROGRESS
              - WAITING_FOR_USER
              - RESOLVED
              - CLOSED
              - CANCELLED
            type: string
        - name: category
          required: false
          in: query
          schema:
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: userId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: List of support tickets
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Get all support tickets (user sees only their tickets)
      tags: *ref_91
  /v2/support-tickets/public-contact:
    post:
      operationId: SupportTicketsController.createPublicContact
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePublicContactDto'
      responses:
        '201':
          description: Ticket created and queued for the support inbox
      security: *ref_90
      summary: Submit a contact-form enquiry from the marketing site
      tags: *ref_91
  /v2/support-tickets/suggest-articles:
    post:
      operationId: SupportTicketsController.suggestArticles
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_90
      summary: >-
        Return KB articles relevant to the draft subject + description. No
        ticket created.
      tags: *ref_91
  /v2/support-tickets/my-tickets:
    get:
      operationId: SupportTicketsController.getMyTickets
      parameters: []
      responses:
        '200':
          description: List of user support tickets
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Get current user tickets
      tags: *ref_91
  /v2/support-tickets/my-tickets/stats:
    get:
      operationId: SupportTicketsController.getMyTicketStats
      parameters: []
      responses:
        '200':
          description: User ticket statistics
      security: *ref_90
      summary: Get current user ticket statistics
      tags: *ref_91
  /v2/support-tickets/by-ticket-number/{ticketNumber}:
    get:
      operationId: SupportTicketsController.findByTicketNumber
      parameters:
        - name: ticketNumber
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Support ticket details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Get support ticket by ticket number
      tags: *ref_91
  /v2/support-tickets/{id}/sla:
    get:
      operationId: SupportTicketsController.getSla
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_90
      summary: Compute SLA breach status for a ticket (admin-visible UI hint).
      tags: *ref_91
  /v2/support-tickets/{id}:
    get:
      operationId: SupportTicketsController.findOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Support ticket details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Get support ticket by ID
      tags: *ref_91
    patch:
      operationId: SupportTicketsController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSupportTicketDto'
      responses:
        '200':
          description: Support ticket updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Update support ticket
      tags: *ref_91
  /v2/support-tickets/{id}/messages:
    post:
      operationId: SupportTicketsController.addMessage
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSupportTicketMessageDto'
      responses:
        '201':
          description: Message added successfully
      security: *ref_90
      summary: Add message to support ticket
      tags: *ref_91
  /v2/support-tickets/{id}/rating:
    post:
      operationId: SupportTicketsController.addRating
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddUserRatingDto'
      responses:
        '200':
          description: Rating added successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Add user rating to resolved/closed ticket
      tags: *ref_91
  /v2/support-tickets/event-participation/{eventParticipationId}:
    get:
      operationId: SupportTicketsController.getByEventParticipation
      parameters:
        - name: eventParticipationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: List of support tickets for the event participation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Get support tickets for an event participation
      tags: *ref_91
  /v2/support-tickets/challenge-participation/{challengeParticipationId}:
    get:
      operationId: SupportTicketsController.getByChallengeParticipation
      parameters:
        - name: challengeParticipationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: List of support tickets for the challenge participation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicket'
      security: *ref_90
      summary: Get support tickets for a challenge participation
      tags: *ref_91
  /v2/support-tickets/{id}/attachments:
    post:
      operationId: SupportTicketsController.uploadTicketAttachments
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: Attachments uploaded successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicketAttachment'
      security: *ref_90
      summary: Upload attachments to a support ticket
      tags: *ref_91
    get:
      operationId: SupportTicketsController.getTicketAttachments
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: List of ticket attachments
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicketAttachment'
      security: *ref_90
      summary: Get all attachments for a support ticket
      tags: *ref_91
  /v2/support-tickets/{id}/messages/{messageId}/attachments:
    post:
      operationId: SupportTicketsController.uploadMessageAttachments
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: Attachments uploaded successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicketAttachment'
      security: *ref_90
      summary: Upload attachments to a message
      tags: *ref_91
    get:
      operationId: SupportTicketsController.getMessageAttachments
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: List of message attachments
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SupportTicketAttachment'
      security: *ref_90
      summary: Get all attachments for a message
      tags: *ref_91
  /v2/webhooks/postmark/inbound:
    post:
      operationId: PostmarkInboundController.inbound
      parameters:
        - name: authorization
          required: true
          in: header
          schema:
            type: string
        - name: token
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Postmark Inbound Parse receiver. Auth via HTTP Basic Auth (recommended)
        or ?token= query.
      tags:
        - 'Public: Email Webhooks'
  /v2/users/{userId}/nutrition-logs:
    post:
      operationId: NutritionController.saveLog
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SaveNutritionLogDto'
      responses:
        '201':
          description: ''
      tags: &ref_92
        - 'User: Nutrition'
    get:
      operationId: NutritionController.listLogs
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: date
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/nutrition-logs/{logId}:
    delete:
      operationId: NutritionController.deleteLog
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: logId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/nutrition/quick-add-items:
    get:
      operationId: NutritionController.listQuickAdd
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/nutrition-logs/quick-add:
    post:
      operationId: NutritionController.quickAdd
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QuickAddNutritionLogDto'
      responses:
        '201':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/health-stats:
    get:
      operationId: NutritionController.getStats
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
    put:
      operationId: NutritionController.updateStats
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateHealthStatsDto'
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/nutrition/profile/me:
    get:
      operationId: NutritionController.getAthleteNutritionProfile
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_92
    put:
      operationId: NutritionController.upsertAthleteNutritionProfile
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/nutrition/fueling-context:
    get:
      operationId: NutritionController.getFuelingContext
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/nutrition-logs/daily-report:
    post:
      operationId: NutritionController.dailyReport
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DailyReportDto'
      responses:
        '201':
          description: ''
      tags: *ref_92
  /v2/nutrition/scan:
    post:
      operationId: NutritionController.scan
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/nutrition/scan/voice:
    post:
      operationId: NutritionController.scanVoice
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/nutrition/tdee:
    get:
      operationId: NutritionController.getTdee
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/hydration-logs:
    post:
      operationId: NutritionController.logHydration
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_92
    get:
      operationId: NutritionController.listHydration
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: date
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/hydration-logs/daily:
    get:
      operationId: NutritionController.hydrationDaily
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: date
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/hydration-logs/range:
    get:
      operationId: NutritionController.hydrationRange
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: startDate
          required: true
          in: query
          schema:
            type: string
        - name: endDate
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/users/{userId}/hydration-logs/{logId}:
    delete:
      operationId: NutritionController.deleteHydration
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: logId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_92
  /v2/admin/nutrition/sources:
    get:
      operationId: AdminNutritionSourcesController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_93
        - 'Admin: Nutrition sources'
    post:
      operationId: AdminNutritionSourcesController.upsert
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_93
  /v2/admin/nutrition/sources/{key}:
    patch:
      operationId: AdminNutritionSourcesController.upsertByKey
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_93
  /v2/admin/nutrition/sources/{key}/enable:
    post:
      operationId: AdminNutritionSourcesController.enable
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Toggle source enabled flag.
      tags: *ref_93
  /v2/admin/nutrition/sources/seed/ifct:
    post:
      operationId: AdminNutritionSourcesController.seedIfct
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Idempotently seed the IFCT 2017 dataset (~40 staples). Repeatable;
        subsequent calls update existing rows.
      tags: *ref_93
  /v2/nutrition/foods:
    get:
      operationId: UserNutritionFoodsController.search
      parameters:
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: barcode
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - Nutrition foods (user)
  /v2/nutrition/fueling-templates:
    get:
      operationId: FuelingTemplatesController.list
      parameters:
        - name: category
          required: true
          in: query
          schema:
            type: string
        - name: tag
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_94
        - 'Nutrition: Fueling Templates'
  /v2/nutrition/fueling-templates/categories:
    get:
      operationId: FuelingTemplatesController.categories
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_94
  /v2/nutrition/fueling-templates/{id}:
    get:
      operationId: FuelingTemplatesController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_94
  /v2/admin/nutrition/fueling-templates:
    get:
      operationId: AdminFuelingTemplatesController.list
      parameters:
        - &ref_95
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: category
          required: true
          in: query
          schema:
            type: string
        - name: tag
          required: true
          in: query
          schema:
            type: string
        - name: activeOnly
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_96
        - 'Admin: Nutrition Fueling Templates'
    post:
      operationId: AdminFuelingTemplatesController.create
      parameters:
        - *ref_95
      responses:
        '201':
          description: ''
      tags: *ref_96
  /v2/admin/nutrition/fueling-templates/{id}:
    get:
      operationId: AdminFuelingTemplatesController.byId
      parameters:
        - *ref_95
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_96
    patch:
      operationId: AdminFuelingTemplatesController.update
      parameters:
        - *ref_95
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_96
    delete:
      operationId: AdminFuelingTemplatesController.archive
      parameters:
        - *ref_95
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_96
  /v2/admin/nutrition/fueling-templates/{id}/restore:
    post:
      operationId: AdminFuelingTemplatesController.restore
      parameters:
        - *ref_95
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_96
  /v2/analytics/admin/dashboard:
    get:
      description: |2-

              Returns platform-wide analytics for admin dashboard including:
              - Platform overview (users, organizers, events, challenges, revenue)
              - User analytics (growth trends, demographics, active users)
              - Event analytics (by status, category, type, ticket sales)
              - Challenge analytics (by type, participation, completion rates)
              - Financial analytics (revenue, commissions, refunds, payment methods)
              - Coin economy analytics (circulation, transactions, top holders)
              - Fitness analytics (activities, steps, calories)
              - Organizer analytics (top performers, approval status)
              - Support analytics (tickets by status, category, resolution time)
            
      operationId: AnalyticsController.getAdminDashboard
      parameters:
        - name: dateRange
          required: false
          in: query
          description: Predefined date range filter
          schema:
            default: last_30_days
            type: string
            enum:
              - today
              - last_7_days
              - last_30_days
              - last_90_days
              - last_year
              - all_time
              - custom
        - name: period
          required: false
          in: query
          description: Short-hand period alias (7d, 30d, 90d, 1y, today, all)
          schema:
            example: 90d
            type: string
        - name: startDate
          required: false
          in: query
          description: Start date for custom date range (ISO 8601 format)
          schema:
            example: '2024-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: End date for custom date range (ISO 8601 format)
          schema:
            example: '2024-12-31'
            type: string
      responses:
        '200':
          description: ''
      security: &ref_97
        - bearer: []
      summary: Get comprehensive admin dashboard analytics
      tags: &ref_98
        - Analytics
  /v2/analytics/admin/finance:
    get:
      description: |2-

              Returns comprehensive financial analytics for admin including:
              - Revenue overview (total revenue, platform commission, net revenue, growth metrics)
              - Payment analytics (by method, success/failure rates, average transaction value)
              - Refund analytics (total refunds, by status, refund rate)
              - Commission analytics (total commission, average rate, breakdown by organizer)
              - Organizer financials (top earners, revenue distribution)
              - Event financials (top revenue events, average ticket price)
              - Transaction trends (daily/weekly/monthly patterns)
              - Coin financials (total coins in circulation, purchase/redemption stats)
            
      operationId: AnalyticsController.getAdminFinanceAnalytics
      parameters:
        - name: dateRange
          required: false
          in: query
          description: Predefined date range filter
          schema:
            default: last_30_days
            type: string
            enum:
              - today
              - last_7_days
              - last_30_days
              - last_90_days
              - last_year
              - all_time
              - custom
        - name: period
          required: false
          in: query
          description: Short-hand period alias (7d, 30d, 90d, 1y, today, all)
          schema:
            example: 90d
            type: string
        - name: startDate
          required: false
          in: query
          description: Start date for custom date range (ISO 8601 format)
          schema:
            example: '2024-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: End date for custom date range (ISO 8601 format)
          schema:
            example: '2024-12-31'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_97
      summary: Get detailed admin finance analytics
      tags: *ref_98
  /v2/analytics/organizer/dashboard:
    get:
      description: |2-

              Returns organizer-specific analytics including:
              - Overview (events, challenges, products, coupons, revenue, ratings)
              - Event performance (per-event details, capacity, revenue, bookings)
              - Challenge performance (participation, completion rates, coins rewarded)
              - Financial summary (gross/net revenue, commissions, refunds)
              - Customer insights (unique customers, booking trends)
              - Coupon analytics (usage, top coupons, discount given)
              - Product analytics (by category, active products)
            
      operationId: AnalyticsController.getOrganizerDashboard
      parameters:
        - name: dateRange
          required: false
          in: query
          description: Predefined date range filter
          schema:
            default: last_30_days
            type: string
            enum:
              - today
              - last_7_days
              - last_30_days
              - last_90_days
              - last_year
              - all_time
              - custom
        - name: period
          required: false
          in: query
          description: Short-hand period alias (7d, 30d, 90d, 1y, today, all)
          schema:
            example: 90d
            type: string
        - name: startDate
          required: false
          in: query
          description: Start date for custom date range (ISO 8601 format)
          schema:
            example: '2024-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: End date for custom date range (ISO 8601 format)
          schema:
            example: '2024-12-31'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_97
      summary: Get comprehensive organizer dashboard analytics
      tags: *ref_98
  /v2/analytics/organizer/finance:
    get:
      description: |2-

              Returns comprehensive financial analytics for organizer including:
              - Revenue overview (gross revenue, platform commission, net revenue, growth metrics)
              - Payment analytics (by method, success/failure rates)
              - Refund analytics (total refunds, by status, refund rate)
              - Event revenue breakdown (revenue per event, top performing events)
              - Settlement info (pending settlement, next settlement date)
              - Transaction history (recent transactions with details)
              - Coupon impact (total discount given, usage stats, top coupons)
            
      operationId: AnalyticsController.getOrganizerFinanceAnalytics
      parameters:
        - name: dateRange
          required: false
          in: query
          description: Predefined date range filter
          schema:
            default: last_30_days
            type: string
            enum:
              - today
              - last_7_days
              - last_30_days
              - last_90_days
              - last_year
              - all_time
              - custom
        - name: period
          required: false
          in: query
          description: Short-hand period alias (7d, 30d, 90d, 1y, today, all)
          schema:
            example: 90d
            type: string
        - name: startDate
          required: false
          in: query
          description: Start date for custom date range (ISO 8601 format)
          schema:
            example: '2024-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: End date for custom date range (ISO 8601 format)
          schema:
            example: '2024-12-31'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_97
      summary: Get detailed organizer finance analytics
      tags: *ref_98
  /v2/analytics/organizer/events/{eventId}/finance:
    get:
      description: |2-

              Per-event equivalent of GET /analytics/organizer/finance —
              grossRevenue, netRevenue, platformFee, totalRefunded,
              refundedPercent, averageOrderValue, totalBookings,
              paymentsByMethod[], registrationsByDay[], couponUsage[], all
              scoped to a single eventId instead of the org-wide response.
            
      operationId: AnalyticsController.getOrganizerEventFinanceAnalytics
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: dateRange
          required: false
          in: query
          description: Predefined date range filter
          schema:
            default: last_30_days
            type: string
            enum:
              - today
              - last_7_days
              - last_30_days
              - last_90_days
              - last_year
              - all_time
              - custom
        - name: period
          required: false
          in: query
          description: Short-hand period alias (7d, 30d, 90d, 1y, today, all)
          schema:
            example: 90d
            type: string
        - name: startDate
          required: false
          in: query
          description: Start date for custom date range (ISO 8601 format)
          schema:
            example: '2024-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: End date for custom date range (ISO 8601 format)
          schema:
            example: '2024-12-31'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_97
      summary: >-
        Get finance analytics scoped to a single event (Missing-API P2,
        BACKEND_API_SPEC.md §2.1).
      tags: *ref_98
  /v2/analytics:
    get:
      description: >-
        Legacy endpoint for backward compatibility. Use GET
        /analytics/admin/dashboard for new implementations.
      operationId: AnalyticsController.getAnalyticsForAdmin
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_97
      summary: Get legacy analytics (deprecated - use admin/dashboard instead)
      tags: *ref_98
  /v2/organizer/reports:
    get:
      operationId: StandardReportsController.list
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_99
        - bearer: []
      summary: >-
        List the 5 PRD §42.7 standard report types + their shipped status. Use
        the `key` to call the per-report endpoints below.
      tags: &ref_100
        - 'Organizer: Reports'
  /v2/organizer/reports/income-statement:
    get:
      operationId: StandardReportsController.incomeStatement
      parameters:
        - name: from
          required: true
          in: query
          schema:
            example: '2026-04-01'
            type: string
        - name: to
          required: true
          in: query
          schema:
            example: '2026-04-30'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_99
      summary: >-
        Income Statement (PRD §42.7) — gross / commission / gateway / GST / net
        + reconciliation flag. Settlement-ledger aggregation.
      tags: *ref_100
  /v2/organizer/reports/payment-method-breakdown:
    get:
      operationId: StandardReportsController.paymentMethods
      parameters:
        - name: from
          required: true
          in: query
          schema:
            example: '2026-04-01'
            type: string
        - name: to
          required: true
          in: query
          schema:
            example: '2026-04-30'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_99
      summary: >-
        Payment Method Breakdown (PRD §42.7) — per-method volume + count + share
        %. Cross-org leak guard via EventParticipation→Event→Organizer chain.
        SUCCESS payments only.
      tags: *ref_100
  /v2/organizer/reports/cash-flow:
    get:
      operationId: StandardReportsController.cashFlow
      parameters:
        - name: from
          required: true
          in: query
          schema:
            example: '2026-04-01'
            type: string
        - name: to
          required: true
          in: query
          schema:
            example: '2026-04-30'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_99
      summary: >-
        Cash Flow (PRD §42.7) — money in (settlement payouts received) vs money
        out (refunds disbursed). Both COMPLETED-status only. Net cash position +
        inflow/outflow counts.
      tags: *ref_100
  /v2/organizer/reports/tax-liability:
    get:
      operationId: StandardReportsController.taxLiability
      parameters:
        - name: from
          required: true
          in: query
          schema:
            example: '2026-04-01'
            type: string
        - name: to
          required: true
          in: query
          schema:
            example: '2026-04-30'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_99
      summary: >-
        Tax Liability (PRD §42.7) — GST collected (ISSUED TaxInvoice rows) + TDS
        deducted (TdsDeduction rows scoped to deducteeType=ORGANIZER). Per-FY
        rollup + per-section TDS breakdown.
      tags: *ref_100
  /v2/organizer/reports/refund-analysis:
    get:
      operationId: StandardReportsController.refundAnalysis
      parameters:
        - name: from
          required: true
          in: query
          schema:
            example: '2026-04-01'
            type: string
        - name: to
          required: true
          in: query
          schema:
            example: '2026-04-30'
            type: string
      responses:
        '200':
          description: ''
      security: *ref_99
      summary: >-
        Refund Analysis (PRD §42.7) — refund volume + per-reason mix +
        per-status breakdown + refundRate (refunds ÷ SUCCESS payments).
        Cross-org via Refund.participation.event.organizer.
      tags: *ref_100
  /v2/cloud-storage/plans:
    post:
      operationId: StoragePlansController.create
      parameters:
        - &ref_101
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateStoragePlanDto'
      responses:
        '201':
          description: ''
      tags: &ref_102
        - Cloud Storage - Storage Plans
    get:
      operationId: StoragePlansController.findAll
      parameters:
        - *ref_101
        - name: activeOnly
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_102
  /v2/cloud-storage/plans/{id}:
    get:
      operationId: StoragePlansController.findOne
      parameters:
        - *ref_101
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_102
    patch:
      operationId: StoragePlansController.update
      parameters:
        - *ref_101
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateStoragePlanDto'
      responses:
        '200':
          description: ''
      tags: *ref_102
    delete:
      operationId: StoragePlansController.remove
      parameters:
        - *ref_101
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_102
  /v2/cloud-storage/plans/{id}/toggle-status:
    patch:
      operationId: StoragePlansController.toggleStatus
      parameters:
        - *ref_101
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_102
  /v2/cloud-storage/subscriptions:
    post:
      operationId: SubscriptionsController.purchase
      parameters:
        - &ref_103
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PurchaseSubscriptionDto'
      responses:
        '201':
          description: ''
      tags: &ref_104
        - Cloud Storage - Subscriptions
    get:
      operationId: SubscriptionsController.getMySubscriptions
      parameters:
        - *ref_103
      responses:
        '200':
          description: ''
      tags: *ref_104
  /v2/cloud-storage/subscriptions/payment-link:
    post:
      operationId: SubscriptionsController.purchaseWithLink
      parameters:
        - *ref_103
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PurchaseSubscriptionDto'
      responses:
        '201':
          description: ''
      tags: *ref_104
  /v2/cloud-storage/subscriptions/{subscriptionId}/verify-payment:
    post:
      operationId: SubscriptionsController.verifyPayment
      parameters:
        - *ref_103
        - name: subscriptionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_104
  /v2/cloud-storage/subscriptions/active:
    get:
      operationId: SubscriptionsController.getActiveSubscription
      parameters:
        - *ref_103
      responses:
        '200':
          description: ''
      tags: *ref_104
  /v2/cloud-storage/subscriptions/overview:
    get:
      operationId: SubscriptionsController.getSubscriptionOverview
      parameters:
        - *ref_103
      responses:
        '200':
          description: ''
      tags: *ref_104
  /v2/cloud-storage/subscriptions/repair-galleries:
    post:
      operationId: GalleryRepairController.repairGalleries
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags:
        - Cloud Storage - Subscriptions
  /v2/cloud-storage/event-settings/{eventId}/subscription:
    patch:
      operationId: GallerySubscriptionController.assignSubscription
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssignGallerySubscriptionDto'
      responses:
        '200':
          description: ''
      tags:
        - Cloud Storage - Event Settings
  /v2/cloud-storage/event-settings:
    post:
      operationId: CloudEventSettingsController.create
      parameters:
        - &ref_105
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        description: Create event settings with optional watermark logo image
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                eventId:
                  type: string
                  example: uuid-of-event
                watermarkEnabled:
                  type: boolean
                  example: false
                watermarkValue:
                  type: string
                  example: Marathon 2026 Official
                watermarkImage:
                  type: string
                  format: binary
                  description: >-
                    Watermark logo image (required when watermarkEnabled is
                    true)
                isFullyFree:
                  type: boolean
                  example: true
                freeImageCount:
                  type: number
                  example: 5
                pricingType:
                  type: string
                  enum:
                    - per_image
                    - bundle
                pricePerImage:
                  type: number
                  example: 49
                bundlePrice:
                  type: number
                  example: 299
              required:
                - eventId
      responses:
        '201':
          description: ''
      tags: &ref_106
        - Cloud Storage - Event Settings
    get:
      operationId: CloudEventSettingsController.getAllSettings
      parameters:
        - *ref_105
      responses:
        '200':
          description: ''
      tags: *ref_106
  /v2/cloud-storage/event-settings/{eventId}:
    patch:
      operationId: CloudEventSettingsController.update
      parameters:
        - *ref_105
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        description: Update event settings with optional watermark logo image
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                watermarkEnabled:
                  type: boolean
                  example: false
                watermarkValue:
                  type: string
                  example: Marathon 2026 Official
                watermarkImage:
                  type: string
                  format: binary
                  description: New watermark logo image
                isFullyFree:
                  type: boolean
                  example: true
                freeImageCount:
                  type: number
                  example: 5
                pricingType:
                  type: string
                  enum:
                    - per_image
                    - bundle
                pricePerImage:
                  type: number
                  example: 49
                bundlePrice:
                  type: number
                  example: 299
      responses:
        '200':
          description: ''
      tags: *ref_106
    get:
      operationId: CloudEventSettingsController.getSettings
      parameters:
        - *ref_105
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_106
    delete:
      operationId: CloudEventSettingsController.delete
      parameters:
        - *ref_105
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_106
  /v2/cloud-storage/event-settings/events/without-settings:
    get:
      operationId: CloudEventSettingsController.getEventsWithoutSettings
      parameters:
        - *ref_105
      responses:
        '200':
          description: ''
      tags: *ref_106
  /v2/cloud-storage/event-settings/{eventId}/toggle-live:
    patch:
      operationId: CloudEventSettingsController.toggleLive
      parameters:
        - *ref_105
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_106
  /v2/cloud-storage/media/check-limits:
    post:
      operationId: EventMediaController.checkLimits
      parameters:
        - &ref_107
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CheckUploadLimitsDto'
      responses:
        '201':
          description: ''
      tags: &ref_108
        - Cloud Storage - Event Media
  /v2/cloud-storage/media:
    post:
      operationId: EventMediaController.registerMedia
      parameters:
        - *ref_107
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterMediaDto'
      responses:
        '201':
          description: ''
      tags: *ref_108
  /v2/cloud-storage/media/bulk:
    post:
      operationId: EventMediaController.registerMediaBulk
      parameters:
        - *ref_107
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                type: string
      responses:
        '201':
          description: ''
      tags: *ref_108
  /v2/cloud-storage/media/{eventId}:
    get:
      operationId: EventMediaController.listMedia
      parameters:
        - *ref_107
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_108
  /v2/cloud-storage/media/{mediaId}:
    delete:
      operationId: EventMediaController.deleteMedia
      parameters:
        - *ref_107
        - name: mediaId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_108
  /v2/cloud-storage/user-images/galleries:
    get:
      operationId: UserImagesController.getMyGalleries
      parameters:
        - &ref_109
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_110
        - Cloud Storage - User Images
  /v2/cloud-storage/user-images/purchase:
    post:
      operationId: UserImagesController.purchase
      parameters:
        - *ref_109
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PurchaseImagesDto'
      responses:
        '201':
          description: ''
      tags: *ref_110
  /v2/cloud-storage/user-images/verify-payment/{orderId}:
    post:
      operationId: UserImagesController.verifyPayment
      parameters:
        - *ref_109
        - name: orderId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_110
  /v2/cloud-storage/user-images/event/{eventId}/status:
    get:
      operationId: UserImagesController.getEventCloudStatus
      parameters:
        - *ref_109
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_110
  /v2/cloud-storage/user-images/{eventId}:
    get:
      operationId: UserImagesController.getMyImages
      parameters:
        - *ref_109
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_110
  /v2/cloud-storage/webhooks/cashfree:
    post:
      operationId: WebhookController.handleCashfreeWebhook
      parameters:
        - name: x-webhook-signature
          required: true
          in: header
          schema:
            type: string
        - name: x-webhook-timestamp
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Cashfree payment webhook for cloud-storage (photo purchases / storage
        subscriptions). HMAC-SHA256 signature required.
      tags:
        - Cloud Storage - Webhooks
  /v2/cloud-storage/earnings/summary:
    get:
      operationId: EarningsController.getSummary
      parameters:
        - &ref_111
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_112
        - Cloud Storage - Earnings
  /v2/cloud-storage/earnings/by-event:
    get:
      operationId: EarningsController.getByEvent
      parameters:
        - *ref_111
      responses:
        '200':
          description: ''
      tags: *ref_112
  /v2/cloud-storage/earnings:
    get:
      operationId: EarningsController.getList
      parameters:
        - *ref_111
        - name: page
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_112
  /v2/cloud-storage/event-details:
    post:
      operationId: CloudEventDetailsController.create
      parameters:
        - &ref_113
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        description: >-
          Create event display details with optional cover image. All fields
          except eventId are auto-populated from the event if not provided.
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                eventId:
                  type: string
                  example: uuid-of-event
                title:
                  type: string
                  example: Marathon 2026
                description:
                  type: string
                  example: Annual city marathon event
                startDateTime:
                  type: string
                  format: date-time
                  example: '2026-03-15T09:00:00.000Z'
                endDateTime:
                  type: string
                  format: date-time
                  example: '2026-03-15T17:00:00.000Z'
                city:
                  type: string
                  example: Mumbai
                state:
                  type: string
                  example: Maharashtra
                address:
                  type: string
                  example: Marine Drive, Mumbai 400001
                coverImage:
                  type: string
                  format: binary
                  description: >-
                    Cover image file. If not provided, the event's existing
                    cover image will be used.
              required:
                - eventId
      responses:
        '201':
          description: ''
      tags: &ref_114
        - Cloud Storage - Event Details
  /v2/cloud-storage/event-details/{eventId}:
    patch:
      operationId: CloudEventDetailsController.update
      parameters:
        - *ref_113
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        description: Update event display details with optional cover image
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                title:
                  type: string
                  example: Marathon 2026 - Updated
                description:
                  type: string
                  example: Updated description
                startDateTime:
                  type: string
                  format: date-time
                  example: '2026-03-15T09:00:00.000Z'
                endDateTime:
                  type: string
                  format: date-time
                  example: '2026-03-15T17:00:00.000Z'
                city:
                  type: string
                  example: Mumbai
                state:
                  type: string
                  example: Maharashtra
                address:
                  type: string
                  example: Marine Drive, Mumbai 400001
                coverImage:
                  type: string
                  format: binary
                  description: New cover image file
      responses:
        '200':
          description: ''
      tags: *ref_114
    get:
      operationId: CloudEventDetailsController.getDetail
      parameters:
        - *ref_113
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_114
  /v2/cloud-storage/face-api/ingest:
    post:
      description: >-
        Upload images to detect faces, store in S3, and index embeddings for an
        event.
      operationId: FaceApiController.ingestImages
      parameters:
        - &ref_115
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/IngestImagesDto'
      responses:
        '201':
          description: ''
      summary: Ingest images for face detection
      tags: &ref_116
        - Cloud Storage - Face API (Organizer)
  /v2/cloud-storage/face-api/images:
    get:
      description: List all images with pagination for the organizer.
      operationId: FaceApiController.listImages
      parameters:
        - *ref_115
        - name: eventId
          required: false
          in: query
          description: Filter by event ID
          schema:
            type: string
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: string
        - name: pageSize
          required: false
          in: query
          description: 'Items per page (default: 20, max: 100)'
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List all images
      tags: *ref_116
    delete:
      description: >-
        Delete one or more images from cloud storage and the face index by asset
        URL. Accepts `assetUrls` (preferred) or the legacy `s3ImageUrls`.
      operationId: FaceApiController.deleteImages
      parameters:
        - *ref_115
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeleteImagesDto'
      responses:
        '200':
          description: ''
      summary: Delete images
      tags: *ref_116
  /v2/cloud-storage/face-api/events/{eventId}:
    delete:
      description: >-
        Delete all images and embeddings for an event. This action cannot be
        undone.
      operationId: FaceApiController.deleteEvent
      parameters:
        - *ref_115
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Delete all event images
      tags: *ref_116
  /v2/cloud-storage/face-api/storage:
    get:
      description: >-
        Get storage statistics by event for the organizer, including total
        storage, images, and faces.
      operationId: FaceApiController.getStorage
      parameters:
        - *ref_115
      responses:
        '200':
          description: ''
      summary: Get storage statistics
      tags: *ref_116
  /v2/cloud-storage/face-api/storage/all:
    get:
      description: >-
        Admin-only: Get storage statistics across all organizers with per-event
        breakdown.
      operationId: FaceApiController.getAllStorage
      parameters:
        - *ref_115
      responses:
        '200':
          description: ''
      summary: Get all organizers storage statistics
      tags: *ref_116
  /v2/cloud-storage/face-search:
    post:
      description: >-
        Upload 3 selfies (front, left, right) to search for matching faces in
        event photos. Returns free image URLs immediately. Paid images require
        purchase.
      operationId: FaceSearchController.faceSearch
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/FaceSearchDto'
      responses:
        '201':
          description: ''
      summary: Search for matching faces
      tags:
        - Cloud Storage - Face Search (User)
  /v2/organizer/declaration/{organizerId}:
    get:
      description: Get current declaration status and available actions
      operationId: OrganizerDeclarationController.getDeclaration
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer UUID
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get declaration status
      tags: &ref_117
        - Organizer - GST Declaration
  /v2/organizer/declaration/{organizerId}/fill:
    post:
      description: >-
        Submit template variables to generate the declaration PDF. Still
        requires a valid organizer Bearer token — OrganizerRoleGuard resolves
        `:organizerId` from the path and rejects (403) unless the caller is an
        OWNER/ADMIN team member of THAT specific organizer, so one organizer
        cannot fill another organizer's declaration just by changing the URL.
      operationId: OrganizerDeclarationController.fillVariables
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer UUID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FillDeclarationVariablesDto'
      responses:
        '201':
          description: ''
      summary: Fill declaration variables
      tags: *ref_117
  /v2/organizer/declaration/{organizerId}/upload-signed:
    post:
      description: >-
        Upload the physically signed declaration document (PDF, JPG, PNG, max
        5MB). Requires a valid organizer Bearer token — OrganizerRoleGuard
        verifies the caller is an OWNER/ADMIN team member of THIS :organizerId.
      operationId: OrganizerDeclarationController.uploadSigned
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer UUID
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
      responses:
        '201':
          description: ''
      summary: Upload signed declaration
      tags: *ref_117
  /v2/organizer/declaration/{organizerId}/download-pdf:
    get:
      description: >-
        Get a presigned URL to download the generated declaration PDF. Requires
        a valid organizer Bearer token — OrganizerRoleGuard verifies the caller
        is an OWNER/ADMIN team member of THIS :organizerId.
      operationId: OrganizerDeclarationController.downloadPdf
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer UUID
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Download generated PDF
      tags: *ref_117
  /v2/organizer/declaration/restart:
    put:
      description: Restart the declaration process after rejection
      operationId: OrganizerDeclarationController.restart
      parameters: []
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Restart rejected declaration
      tags: *ref_117
  /v2/organizer/declaration/test-delete:
    delete:
      operationId: OrganizerDeclarationController.deleteDeclaration
      parameters: []
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Delete declaration (TESTING ONLY — blocked in production)
      tags: *ref_117
  /v2/admin/gst-declaration/all:
    get:
      description: List all declarations with pagination and optional status filtering
      operationId: AdminDeclarationController.getAllDeclarations
      parameters:
        - name: page
          required: false
          in: query
          schema:
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          schema:
            example: 20
            type: number
        - name: status
          required: false
          in: query
          schema:
            enum:
              - PENDING_VARIABLES
              - VARIABLES_FILLED
              - PDF_GENERATED
              - SIGNED_UPLOADED
              - VERIFIED
              - REJECTED
            type: string
      responses:
        '200':
          description: ''
      security: &ref_118
        - bearer: []
      summary: Get all declarations
      tags: &ref_119
        - Admin - GST Declaration
  /v2/admin/gst-declaration/pending:
    get:
      description: List all declarations waiting for admin review with pagination
      operationId: AdminDeclarationController.getPendingDeclarations
      parameters:
        - name: page
          required: false
          in: query
          schema:
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          schema:
            example: 20
            type: number
        - name: status
          required: false
          in: query
          schema:
            enum:
              - SIGNED_UPLOADED
              - PDF_GENERATED
            type: string
      responses:
        '200':
          description: ''
      security: *ref_118
      summary: Get pending declarations
      tags: *ref_119
  /v2/admin/gst-declaration/statistics:
    get:
      description: Get summary statistics about GST declarations
      operationId: AdminDeclarationController.getStatistics
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_118
      summary: Get declaration statistics
      tags: *ref_119
  /v2/admin/gst-declaration/backfill-template-version:
    post:
      description: >-
        Re-points PENDING_VARIABLES declarations still pinned to an old template
        onto the current active template. Doesn't touch declarations that
        already have filled variables.
      operationId: AdminDeclarationController.backfillTemplateVersion
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_118
      summary: Backfill stale template versions
      tags: *ref_119
  /v2/admin/gst-declaration/{id}:
    get:
      description: Get detailed information about a specific declaration
      operationId: AdminDeclarationController.getDeclaration
      parameters:
        - name: id
          required: true
          in: path
          description: Declaration ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_118
      summary: Get declaration details
      tags: *ref_119
  /v2/admin/gst-declaration/{id}/verify:
    post:
      description: >-
        Verify and approve a GST declaration. This completes the organizer
        onboarding.
      operationId: AdminDeclarationController.verifyDeclaration
      parameters:
        - name: id
          required: true
          in: path
          description: Declaration ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_118
      summary: Verify declaration
      tags: *ref_119
  /v2/admin/gst-declaration/{id}/reject:
    post:
      description: >-
        Reject a GST declaration with a reason. The organizer will need to
        restart.
      operationId: AdminDeclarationController.rejectDeclaration
      parameters:
        - name: id
          required: true
          in: path
          description: Declaration ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_118
      summary: Reject declaration
      tags: *ref_119
  /v2/admin/gst-declaration/{id}/reset-template:
    post:
      description: >-
        Re-points one PENDING_VARIABLES declaration onto the current active
        template.
      operationId: AdminDeclarationController.resetTemplate
      parameters:
        - name: id
          required: true
          in: path
          description: Declaration ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_118
      summary: Reset a declaration to the latest active template
      tags: *ref_119
  /v2/admin/gst-declaration/{id}/audit-logs:
    get:
      description: Get the complete audit trail for a declaration
      operationId: AdminDeclarationController.getAuditLogs
      parameters:
        - name: id
          required: true
          in: path
          description: Declaration ID
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          schema:
            example: 50
            type: number
      responses:
        '200':
          description: ''
      security: *ref_118
      summary: Get declaration audit logs
      tags: *ref_119
  /v2/admin/gst-declaration/{id}/pdf:
    get:
      description: Generate a presigned URL to download the declaration PDF
      operationId: AdminDeclarationController.getPdfUrl
      parameters:
        - name: id
          required: true
          in: path
          description: Declaration ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_118
      summary: Get declaration PDF URL
      tags: *ref_119
  /v2/admin/gst-declaration/{id}/signed-document:
    get:
      description: Generate a presigned URL to download the uploaded signed document
      operationId: AdminDeclarationController.getSignedDocumentUrl
      parameters:
        - name: id
          required: true
          in: path
          description: Declaration ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_118
      summary: Get signed document URL
      tags: *ref_119
  /v2/admin/gst-template:
    get:
      description: Get all declaration templates with optional filtering
      operationId: AdminTemplateController.listTemplates
      parameters:
        - name: isActive
          required: false
          in: query
          schema:
            type: boolean
      responses:
        '200':
          description: ''
      security: &ref_120
        - bearer: []
      summary: List templates
      tags: &ref_121
        - Admin - GST Template
    post:
      description: Create a new declaration template (creates new version)
      operationId: AdminTemplateController.createTemplate
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateGstDeclarationTemplateDto'
      responses:
        '201':
          description: ''
      security: *ref_120
      summary: Create new template
      tags: *ref_121
  /v2/admin/gst-template/active:
    get:
      description: Get the currently active template used for new declarations
      operationId: AdminTemplateController.getActiveTemplate
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_120
      summary: Get active template
      tags: *ref_121
  /v2/admin/gst-template/{id}:
    get:
      description: Get detailed information about a specific template
      operationId: AdminTemplateController.getTemplate
      parameters:
        - name: id
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_120
      summary: Get template by ID
      tags: *ref_121
    put:
      description: Update an existing template (creates new version)
      operationId: AdminTemplateController.updateTemplate
      parameters:
        - name: id
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateGstDeclarationTemplateDto'
      responses:
        '200':
          description: ''
      security: *ref_120
      summary: Update template
      tags: *ref_121
    delete:
      description: Soft delete a template (cannot delete active templates)
      operationId: AdminTemplateController.deleteTemplate
      parameters:
        - name: id
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_120
      summary: Delete template
      tags: *ref_121
  /v2/admin/gst-template/versions/{name}:
    get:
      description: Get all versions of a template by name
      operationId: AdminTemplateController.getTemplateVersions
      parameters:
        - name: name
          required: true
          in: path
          description: Template name
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_120
      summary: Get template versions
      tags: *ref_121
  /v2/admin/gst-template/{id}/activate:
    post:
      description: Activate a template (deactivates all others)
      operationId: AdminTemplateController.activateTemplate
      parameters:
        - name: id
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_120
      summary: Activate template
      tags: *ref_121
  /v2/admin/gst-template/{id}/deactivate:
    post:
      description: Deactivate a template
      operationId: AdminTemplateController.deactivateTemplate
      parameters:
        - name: id
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_120
      summary: Deactivate template
      tags: *ref_121
  /v2/admin/notification-categories:
    post:
      operationId: AdminCategoriesController.create
      parameters:
        - &ref_122
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateNotificationCategoryDto'
      responses:
        '201':
          description: ''
      tags: &ref_123
        - Admin - Notification Categories
    get:
      operationId: AdminCategoriesController.findAll
      parameters:
        - *ref_122
      responses:
        '200':
          description: ''
      tags: *ref_123
  /v2/admin/notification-categories/{id}:
    patch:
      operationId: AdminCategoriesController.update
      parameters:
        - *ref_122
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationCategoryDto'
      responses:
        '200':
          description: ''
      tags: *ref_123
    delete:
      operationId: AdminCategoriesController.remove
      parameters:
        - *ref_122
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_123
  /v2/admin/notification-templates/sms:
    get:
      operationId: AdminTemplatesController.findAllSms
      parameters:
        - &ref_124
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_125
        - Admin - Notification Templates
    post:
      operationId: AdminTemplatesController.createSms
      parameters:
        - *ref_124
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSmsTemplateDto'
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/msg91-logs:
    get:
      operationId: AdminTemplatesController.getSmsLogs
      parameters:
        - *ref_124
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/msg91-analytics:
    get:
      operationId: AdminTemplatesController.getSmsAnalytics
      parameters:
        - *ref_124
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/{id}:
    get:
      operationId: AdminTemplatesController.findOneSms
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
    patch:
      operationId: AdminTemplatesController.updateSms
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSmsTemplateDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
    delete:
      operationId: AdminTemplatesController.removeSms
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/create-via-msg91:
    post:
      operationId: AdminTemplatesController.createSmsViaMsg91
      parameters:
        - *ref_124
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSmsViaMsg91Dto'
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/{id}/add-version:
    post:
      operationId: AdminTemplatesController.addSmsVersion
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddSmsTemplateVersionDto'
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/{id}/mark-default:
    get:
      operationId: AdminTemplatesController.markSmsVersionDefault
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: versionId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/sync:
    post:
      operationId: AdminTemplatesController.syncSms
      parameters:
        - *ref_124
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/{id}/pricing:
    patch:
      operationId: AdminTemplatesController.updateSmsPricing
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTemplatePricingDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/sms/{id}/visibility:
    patch:
      operationId: AdminTemplatesController.updateSmsVisibility
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email:
    get:
      operationId: AdminTemplatesController.findAllEmail
      parameters:
        - *ref_124
      responses:
        '200':
          description: ''
      tags: *ref_125
    post:
      operationId: AdminTemplatesController.createEmail
      parameters:
        - *ref_124
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEmailTemplateDto'
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/validate:
    get:
      operationId: AdminTemplatesController.validateEmail
      parameters:
        - *ref_124
        - name: email
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/{id}:
    get:
      operationId: AdminTemplatesController.findOneEmail
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
    patch:
      operationId: AdminTemplatesController.updateEmail
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEmailTemplateDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
    delete:
      operationId: AdminTemplatesController.removeEmail
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/css-inline:
    post:
      operationId: AdminTemplatesController.inlineEmailCss
      parameters:
        - *ref_124
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/create-via-msg91:
    post:
      operationId: AdminTemplatesController.createEmailViaMsg91
      parameters:
        - *ref_124
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEmailViaMsg91Dto'
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/sync:
    post:
      operationId: AdminTemplatesController.syncEmail
      parameters:
        - *ref_124
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/{id}/version-details:
    get:
      operationId: AdminTemplatesController.getEmailVersionDetails
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/{id}/pricing:
    patch:
      operationId: AdminTemplatesController.updateEmailPricing
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTemplatePricingDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/email/{id}/visibility:
    patch:
      operationId: AdminTemplatesController.updateEmailVisibility
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp:
    get:
      operationId: AdminTemplatesController.findAllWhatsapp
      parameters:
        - *ref_124
      responses:
        '200':
          description: ''
      tags: *ref_125
    post:
      operationId: AdminTemplatesController.createWhatsapp
      parameters:
        - *ref_124
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWhatsappTemplateDto'
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp/{id}:
    get:
      operationId: AdminTemplatesController.findOneWhatsapp
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
    patch:
      operationId: AdminTemplatesController.updateWhatsapp
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWhatsappTemplateDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
    delete:
      operationId: AdminTemplatesController.removeWhatsapp
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp/{id}/provider-mapping:
    patch:
      operationId: AdminTemplatesController.updateWhatsappProviderMapping
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp/{id}/rollback-mapping:
    post:
      operationId: AdminTemplatesController.rollbackWhatsappMapping
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp/{id}/verify-gupshup:
    post:
      operationId: AdminTemplatesController.verifyGupshupTemplate
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp/sync:
    post:
      operationId: AdminTemplatesController.syncWhatsapp
      parameters:
        - *ref_124
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp/{id}/pricing:
    patch:
      operationId: AdminTemplatesController.updateWhatsappPricing
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTemplatePricingDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/whatsapp/{id}/visibility:
    patch:
      operationId: AdminTemplatesController.updateWhatsappVisibility
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/push:
    get:
      operationId: AdminTemplatesController.findAllPush
      parameters:
        - *ref_124
      responses:
        '200':
          description: ''
      tags: *ref_125
    post:
      operationId: AdminTemplatesController.createPush
      parameters:
        - *ref_124
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePushTemplateDto'
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/push/{id}:
    get:
      operationId: AdminTemplatesController.findOnePush
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
    patch:
      operationId: AdminTemplatesController.updatePush
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePushTemplateDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
    delete:
      operationId: AdminTemplatesController.removePush
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/push/{id}/preview:
    post:
      operationId: AdminTemplatesController.previewPush
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/push/{id}/visibility:
    patch:
      operationId: AdminTemplatesController.updatePushVisibility
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-templates/push/{id}/pricing:
    patch:
      operationId: AdminTemplatesController.updatePushPricing
      parameters:
        - *ref_124
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTemplatePricingDto'
      responses:
        '200':
          description: ''
      tags: *ref_125
  /v2/admin/notification-logs/batches:
    get:
      operationId: AdminLogsController.findAllBatches
      parameters:
        - &ref_126
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_127
        - Admin - Notification Logs
  /v2/admin/notification-logs/batches/{id}:
    get:
      operationId: AdminLogsController.findBatch
      parameters:
        - *ref_126
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_127
  /v2/admin/notification-wallets:
    get:
      operationId: AdminWalletController.findAll
      parameters:
        - &ref_128
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_129
        - Admin - Notification Wallets
  /v2/admin/notification-wallets/{organizerId}:
    get:
      operationId: AdminWalletController.findOne
      parameters:
        - *ref_128
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_129
  /v2/admin/notification-wallets/{organizerId}/adjust:
    post:
      operationId: AdminWalletController.adjust
      parameters:
        - *ref_128
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdjustOrganizerWalletDto'
      responses:
        '201':
          description: ''
      tags: *ref_129
  /v2/admin/notifications/send:
    post:
      operationId: AdminNotificationsController.send
      parameters:
        - &ref_130
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendNotificationDto'
      responses:
        '201':
          description: ''
      tags: &ref_131
        - Admin - Notifications
  /v2/admin/notifications/provider-health:
    get:
      operationId: AdminNotificationsController.providerHealth
      parameters:
        - *ref_130
      responses:
        '200':
          description: ''
      tags: *ref_131
  /v2/admin/notifications/pipeline-readiness:
    get:
      operationId: AdminNotificationsController.pipelineReadinessSnapshot
      parameters:
        - *ref_130
      responses:
        '200':
          description: ''
      tags: *ref_131
  /v2/admin/notification-settlements:
    get:
      operationId: AdminSettlementController.findAll
      parameters:
        - &ref_132
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_133
        - Admin - Notification Settlements
  /v2/admin/notification-settlements/calculate:
    post:
      operationId: AdminSettlementController.calculate
      parameters:
        - *ref_132
      responses:
        '201':
          description: ''
      tags: *ref_133
  /v2/admin/notification-settlements/{id}/process:
    post:
      operationId: AdminSettlementController.process
      parameters:
        - *ref_132
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_133
  /v2/admin/system-notifications:
    post:
      operationId: AdminSystemNotificationsController.create
      parameters:
        - &ref_134
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSystemNotificationMappingDto'
      responses:
        '201':
          description: ''
      tags: &ref_135
        - Admin - System Notifications
    get:
      operationId: AdminSystemNotificationsController.findAll
      parameters:
        - *ref_134
        - name: event
          required: false
          in: query
          schema:
            enum:
              - event_approved
              - event_rejected
              - event_registered
              - event_cancelled
              - event_announcement
              - event_reminder
              - challenge_approved
              - challenge_rejected
              - challenge_announcement
              - challenge_completed
              - challenge_reward
              - payment_success
              - payment_failed
              - refund_initiated
              - refund_completed
              - welcome
              - new_follower
              - kyc_pending_admin
              - kyc_approved
              - kyc_rejected
              - organizer_registration_confirmation
              - subscription_renewal
              - team_invite
              - event_assignment_invited
              - assignment_responded
              - crew_role_changed
              - shift_reminder
              - attendance_approval_needed
              - attendance_decided
            type: string
        - name: channel
          required: false
          in: query
          schema:
            enum:
              - sms
              - email
              - whatsapp
              - push
            type: string
        - name: enabled
          required: false
          in: query
          schema:
            type: boolean
      responses:
        '200':
          description: ''
      tags: *ref_135
  /v2/admin/system-notifications/events:
    get:
      operationId: AdminSystemNotificationsController.getAllEvents
      parameters:
        - *ref_134
      responses:
        '200':
          description: ''
      tags: *ref_135
  /v2/admin/system-notifications/{id}:
    get:
      operationId: AdminSystemNotificationsController.findOne
      parameters:
        - *ref_134
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_135
    patch:
      operationId: AdminSystemNotificationsController.update
      parameters:
        - *ref_134
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSystemNotificationMappingDto'
      responses:
        '200':
          description: ''
      tags: *ref_135
    delete:
      operationId: AdminSystemNotificationsController.remove
      parameters:
        - *ref_134
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_135
  /v2/organizer/notifications/send:
    post:
      operationId: OrganizerNotificationsController.send
      parameters:
        - &ref_136
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendNotificationDto'
      responses:
        '201':
          description: ''
      tags: &ref_137
        - Organizer - Notifications
  /v2/organizer/notifications/batches:
    get:
      operationId: OrganizerNotificationsController.getBatches
      parameters:
        - *ref_136
      responses:
        '200':
          description: ''
      tags: *ref_137
  /v2/organizer/notifications/batches/{id}:
    get:
      operationId: OrganizerNotificationsController.getBatch
      parameters:
        - *ref_136
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_137
  /v2/organizer/notifications/upload-recipients:
    post:
      operationId: OrganizerNotificationsController.uploadRecipients
      parameters:
        - *ref_136
      responses:
        '201':
          description: ''
      tags: *ref_137
  /v2/organizer/notifications/templates:
    get:
      operationId: OrganizerNotificationsController.getTemplates
      parameters:
        - *ref_136
        - name: channel
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_137
  /v2/organizer/notifications/promotion-templates:
    get:
      operationId: OrganizerNotificationsController.getPromotionTemplates
      parameters:
        - *ref_136
      responses:
        '200':
          description: ''
      tags: *ref_137
  /v2/organizer/notifications/promotion-send:
    post:
      operationId: OrganizerNotificationsController.sendPromotion
      parameters:
        - *ref_136
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendPromotionDto'
      responses:
        '201':
          description: ''
      tags: *ref_137
  /v2/organizer/notifications/batches/{id}/cancel:
    post:
      operationId: OrganizerNotificationsController.cancelBatch
      parameters:
        - *ref_136
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Cancel a scheduled batch. Only valid for batches in SCHEDULED status.
      tags: *ref_137
  /v2/organizer/notifications/quota:
    get:
      operationId: OrganizerNotificationsController.getQuota
      parameters:
        - *ref_136
      responses:
        '200':
          description: ''
      summary: >-
        Organizer marketing send quota — hourly + daily usage and reset
        timestamps. For the composer UI to surface remaining quota before
        submit.
      tags: *ref_137
  /v2/organizer/notifications/audience/preview:
    post:
      operationId: OrganizerNotificationsController.previewAudience
      parameters:
        - *ref_136
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AudiencePreviewDto'
      responses:
        '201':
          description: ''
      summary: >-
        Preview recipient count for an audienceSpec. Runs the same unsubscribe +
        marketing-preference filters the real send applies, so the composer
        shows the filtered count — never a pre-filter estimate.
      tags: *ref_137
  /v2/organizer/notification-wallet:
    get:
      operationId: OrganizerWalletController.getWallet
      parameters:
        - &ref_138
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_139
        - Organizer - Notification Wallet
  /v2/organizer/notification-wallet/top-up:
    post:
      operationId: OrganizerWalletController.topUp
      parameters:
        - *ref_138
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TopUpWalletDto'
      responses:
        '201':
          description: ''
      tags: *ref_139
  /v2/organizer/notification-settlements:
    get:
      operationId: OrganizerSettlementController.findOwn
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - Organizer - Notification Settlements
  /v2/notification-webhooks/msg91:
    post:
      operationId: WebhookController.handleMsg91
      parameters:
        - name: x-msg91-signature
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_140
        - Notification System - Webhooks
  /v2/notification-webhooks/whatsapp:
    post:
      operationId: WebhookController.handleWhatsapp
      parameters:
        - name: x-hub-signature-256
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_140
  /v2/notification-webhooks/wallet-topup:
    post:
      operationId: WebhookController.handleWalletTopUp
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_140
  /v2/unsubscribe/{token}:
    post:
      operationId: UnsubscribeController.redeem
      parameters:
        - name: token
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Confirm a recipient's unsubscribe from an organizer's marketing sends.
      tags:
        - 'Public: Unsubscribe'
  /v2/admin/notifications/outbox/summary:
    get:
      operationId: AdminNotificationOutboxController.summary
      parameters:
        - &ref_141
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Outbox summary: counts by status + channel, oldest-pending age, dead
        count, last 10 failures.
      tags: &ref_142
        - Admin - Notification Outbox
  /v2/admin/notifications/outbox:
    get:
      operationId: AdminNotificationOutboxController.list
      parameters:
        - *ref_141
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: channel
          required: true
          in: query
          schema:
            type: string
        - name: userId
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Outbox list (paginated). Body NEVER returned — only a fixed-shape
        preview for triage.
      tags: *ref_142
  /v2/admin/notifications/outbox/{id}/retry:
    post:
      operationId: AdminNotificationOutboxController.retryOne
      parameters:
        - *ref_141
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Manually re-drive a DEAD or FAILED outbox row. Resets attempts, clears
        last error, sets status=PENDING — the next processor tick picks it up.
        SENT and PROCESSING rows return 409.
      tags: *ref_142
  /v2/admin/notifications/outbox/retry:
    post:
      operationId: AdminNotificationOutboxController.retryBulk
      parameters:
        - *ref_141
      responses:
        '200':
          description: ''
      summary: >-
        Bulk re-drive a list of outbox row ids (cap 100). Returns per-id outcome
        — partial success is allowed.
      tags: *ref_142
  /v2/admin/notifications/outbox/bulk-redrive:
    post:
      operationId: AdminNotificationOutboxController.bulkRedrive
      parameters:
        - *ref_141
      responses:
        '200':
          description: ''
      summary: >-
        Filter-based bulk re-drive of FAILED/DEAD outbox rows. Default
        dryRun=true.
      tags: *ref_142
  /v2/webhooks/msg91/dlr:
    post:
      operationId: ProviderDlrWebhookController.msg91
      parameters:
        - name: x-msg91-signature
          required: true
          in: header
          description: HMAC-SHA256 of the raw request body using MSG91_DLR_SIGNATURE_SECRET
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_143
        - 'Webhooks: Notification DLR'
  /v2/webhooks/gupshup/dlr:
    post:
      operationId: ProviderDlrWebhookController.gupshup
      parameters:
        - name: x-gupshup-signature
          required: true
          in: header
          description: >-
            HMAC-SHA256 of the raw request body using
            GUPSHUP_DLR_SIGNATURE_SECRET
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_143
  /v2/webhooks/msg91/email/dlr:
    post:
      operationId: ProviderDlrWebhookController.msg91Email
      parameters:
        - name: x-msg91-email-signature
          required: true
          in: header
          description: >-
            HMAC-SHA256 of the raw request body using
            MSG91_EMAIL_DLR_SIGNATURE_SECRET
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_143
  /v2/admin/notifications/retry-policies:
    get:
      operationId: AdminNotificationRetryPolicyController.list
      parameters:
        - &ref_144
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_145
        - 'Admin: Notification Retry Policies'
    post:
      operationId: AdminNotificationRetryPolicyController.create
      parameters:
        - *ref_144
      responses:
        '201':
          description: ''
      tags: *ref_145
  /v2/admin/notifications/retry-policies/{id}:
    get:
      operationId: AdminNotificationRetryPolicyController.byId
      parameters:
        - *ref_144
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_145
    patch:
      operationId: AdminNotificationRetryPolicyController.update
      parameters:
        - *ref_144
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_145
  /v2/admin/promotion-templates:
    get:
      operationId: AdminPromotionTemplatesController.findAll
      parameters:
        - &ref_146
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: partnerType
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_147
        - Admin - Promotion Templates
    post:
      operationId: AdminPromotionTemplatesController.create
      parameters:
        - *ref_146
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePromotionTemplateDto'
      responses:
        '201':
          description: ''
      tags: *ref_147
  /v2/admin/promotion-templates/{id}:
    get:
      operationId: AdminPromotionTemplatesController.findOne
      parameters:
        - *ref_146
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_147
    patch:
      operationId: AdminPromotionTemplatesController.update
      parameters:
        - *ref_146
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePromotionTemplateDto'
      responses:
        '200':
          description: ''
      tags: *ref_147
  /v2/admin/promotion-templates/{id}/enabled:
    patch:
      operationId: AdminPromotionTemplatesController.setEnabled
      parameters:
        - *ref_146
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_147
  /v2/promotion-studio/{workspaceType}/{workspaceId}/templates:
    get:
      operationId: PromotionStudioController.templates
      parameters:
        - name: workspaceType
          required: true
          in: path
          schema:
            type: string
        - name: workspaceId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_148
        - bearer: []
      tags: &ref_149
        - Notification Studio - Promotions
  /v2/promotion-studio/{workspaceType}/{workspaceId}/estimate:
    post:
      operationId: PromotionStudioController.estimate
      parameters:
        - name: workspaceType
          required: true
          in: path
          schema:
            type: string
        - name: workspaceId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PromotionStudioSendDto'
      responses:
        '201':
          description: ''
      security: *ref_148
      tags: *ref_149
  /v2/promotion-studio/{workspaceType}/{workspaceId}/send:
    post:
      operationId: PromotionStudioController.send
      parameters:
        - name: workspaceType
          required: true
          in: path
          schema:
            type: string
        - name: workspaceId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PromotionStudioSendDto'
      responses:
        '201':
          description: ''
      security: *ref_148
      tags: *ref_149
  /v2/promotion-studio/{workspaceType}/{workspaceId}/history:
    get:
      operationId: PromotionStudioController.history
      parameters:
        - name: workspaceType
          required: true
          in: path
          schema:
            type: string
        - name: workspaceId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_148
      tags: *ref_149
  /v2/admin/notification-steps/summary:
    get:
      operationId: AdminNotificationStepsController.getSummary
      parameters:
        - &ref_150
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_151
        - Admin - Notification Steps
  /v2/admin/notification-steps:
    get:
      operationId: AdminNotificationStepsController.findAll
      parameters:
        - *ref_150
        - name: role
          required: false
          in: query
          schema:
            type: string
            enum:
              - admin
              - organizer
              - brand
              - club
              - user
              - volunteer
        - name: category
          required: false
          in: query
          schema:
            example: kyc
            type: string
        - name: search
          required: false
          in: query
          schema:
            example: KYC
            type: string
        - name: page
          required: false
          in: query
          schema:
            default: 1
            type: string
        - name: limit
          required: false
          in: query
          schema:
            default: 20
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_151
  /v2/admin/notification-steps/{stepId}:
    get:
      operationId: AdminNotificationStepsController.findOne
      parameters:
        - *ref_150
        - name: stepId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_151
  /v2/admin/notification-template-records:
    post:
      operationId: AdminNotificationTemplatesController.create
      parameters:
        - &ref_152
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTemplateDto'
      responses:
        '201':
          description: ''
      tags: &ref_153
        - Admin - Notification Templates
    get:
      operationId: AdminNotificationTemplatesController.findAll
      parameters:
        - *ref_152
        - name: channel
          required: false
          in: query
          schema:
            enum:
              - push
              - email
              - sms
              - whatsapp
            type: string
        - name: provider
          required: false
          in: query
          schema:
            enum:
              - fcm
              - msg91
              - meta
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_153
  /v2/admin/notification-template-records/{id}:
    get:
      operationId: AdminNotificationTemplatesController.findOne
      parameters:
        - *ref_152
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_153
    put:
      operationId: AdminNotificationTemplatesController.update
      parameters:
        - *ref_152
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTemplateDto'
      responses:
        '200':
          description: ''
      tags: *ref_153
    delete:
      operationId: AdminNotificationTemplatesController.remove
      parameters:
        - *ref_152
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_153
  /v2/admin/notification-mappings:
    post:
      operationId: AdminNotificationMappingsController.create
      parameters:
        - &ref_154
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMappingDto'
      responses:
        '201':
          description: ''
      tags: &ref_155
        - Admin - Notification Mappings
    get:
      operationId: AdminNotificationMappingsController.findAll
      parameters:
        - *ref_154
        - name: stepId
          required: false
          in: query
          schema:
            type: string
        - name: channel
          required: false
          in: query
          schema:
            enum:
              - push
              - email
              - sms
              - whatsapp
            type: string
        - name: role
          required: false
          in: query
          schema:
            enum:
              - admin
              - organizer
              - brand
              - club
              - user
              - volunteer
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_155
  /v2/admin/notification-mappings/bulk:
    post:
      operationId: AdminNotificationMappingsController.bulkCreate
      parameters:
        - *ref_154
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkCreateMappingDto'
      responses:
        '201':
          description: ''
      tags: *ref_155
  /v2/admin/notification-mappings/template-candidates:
    get:
      operationId: AdminNotificationMappingsController.listTemplateCandidates
      parameters:
        - *ref_154
        - name: channel
          required: true
          in: query
          schema:
            enum:
              - push
              - email
              - sms
              - whatsapp
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_155
  /v2/admin/notification-mappings/{id}:
    put:
      operationId: AdminNotificationMappingsController.update
      parameters:
        - *ref_154
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMappingDto'
      responses:
        '200':
          description: ''
      tags: *ref_155
    delete:
      operationId: AdminNotificationMappingsController.remove
      parameters:
        - *ref_154
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_155
  /v2/admin/notification-logs/stats:
    get:
      operationId: AdminNotificationLogsController.getStats
      parameters:
        - &ref_156
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: startDate
          required: false
          in: query
          schema:
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_157
        - Admin - Notification Logs
  /v2/admin/notification-logs:
    get:
      operationId: AdminNotificationLogsController.findAll
      parameters:
        - *ref_156
        - name: stepId
          required: false
          in: query
          schema:
            example: ADMIN_KYC_SUBMITTED
            type: string
        - name: channel
          required: false
          in: query
          schema:
            type: string
            enum:
              - push
              - email
              - sms
              - whatsapp
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - queued
              - sent
              - delivered
              - failed
              - skipped
        - name: recipientId
          required: false
          in: query
          schema:
            type: string
        - name: startDate
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2026-12-31'
            type: string
        - name: page
          required: false
          in: query
          schema:
            default: 1
            type: string
        - name: limit
          required: false
          in: query
          schema:
            default: 20
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_157
  /v2/admin/notification-logs/{id}:
    get:
      operationId: AdminNotificationLogsController.findOne
      parameters:
        - *ref_156
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_157
  /v2/admin/notification-logs/{id}/resend:
    post:
      operationId: AdminNotificationLogsController.resend
      parameters:
        - *ref_156
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Re-send a previously-FAILED dispatch log using the same step + channel +
        recipient + variables. Writes a NEW log row (append-only audit). PUSH
        channel is not supported because the push payload is not persisted on
        the log row.
      tags: *ref_157
  /v2/admin/notification-journeys/summary:
    get:
      operationId: AdminNotificationJourneysController.getSummary
      parameters:
        - &ref_158
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_159
        - Admin - Notification Journeys
  /v2/admin/notification-journeys/{role}:
    get:
      operationId: AdminNotificationJourneysController.findJourney
      parameters:
        - *ref_158
        - name: role
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_159
  /v2/admin/notification-journeys/{role}/steps/{stepId}:
    patch:
      operationId: AdminNotificationJourneysController.updateStep
      parameters:
        - *ref_158
        - name: role
          required: true
          in: path
          schema:
            type: string
        - name: stepId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateJourneyStepDto'
      responses:
        '200':
          description: ''
      tags: *ref_159
  /v2/clubs/{id}/readiness:
    get:
      operationId: ClubsController.getClubReadiness
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_160
        - Clubs
  /v2/clubs/{id}/monetization-eligibility:
    get:
      operationId: ClubsController.getMonetizationEligibility
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/creation-eligibility:
    get:
      operationId: ClubsController.getCreationEligibility
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs:
    get:
      operationId: ClubsController.list
      parameters:
        - name: city
          required: true
          in: query
          schema:
            type: string
        - name: sport
          required: true
          in: query
          schema:
            type: string
        - name: featured
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
    post:
      operationId: ClubsController.createClub
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubDto'
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{idOrSlug}:
    get:
      operationId: ClubsController.getOne
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/join:
    post:
      operationId: ClubsController.join
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/tiers/{tierId}/checkout:
    post:
      operationId: ClubsController.tierCheckout
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/tiers/{tierId}/payments/{paymentId}/verify:
    post:
      operationId: ClubsController.verifyTierPayment
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
        - name: paymentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/leave:
    post:
      operationId: ClubsController.leave
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/tier/cancel:
    post:
      operationId: ClubsController.cancelTier
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/tier/resume:
    post:
      operationId: ClubsController.resumeTier
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/mute:
    post:
      operationId: ClubsController.muteClub
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
    delete:
      operationId: ClubsController.unmuteClub
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/block:
    post:
      operationId: ClubsController.blockClub
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
    delete:
      operationId: ClubsController.unblockClub
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/social-verdict:
    get:
      operationId: ClubsController.clubSocialVerdict
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/membership/me:
    get:
      operationId: ClubsController.myMembership
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/summary:
    get:
      operationId: ClubsController.summary
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/members:
    get:
      operationId: ClubsController.members
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/posts:
    get:
      operationId: ClubsController.posts
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/messages:
    get:
      operationId: ClubsController.messages
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: channelId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/announcements:
    get:
      operationId: ClubsController.announcements
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/challenges:
    get:
      operationId: ClubsController.clubChallenges
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/runs:
    get:
      operationId: ClubsController.runs
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: upcoming
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/runs/calendar:
    get:
      operationId: ClubsController.runsCalendar
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/runs/{runId}:
    get:
      operationId: ClubsController.runDetail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
        - name: occurrenceStart
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/runs/{runId}/rsvp:
    post:
      operationId: ClubsController.rsvp
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RsvpClubRunDto'
      responses:
        '201':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/tiers:
    get:
      operationId: ClubsController.tiers
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/follow:
    post:
      operationId: ClubsController.followClub
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_160
    delete:
      operationId: ClubsController.unfollowClub
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/follow/status:
    get:
      operationId: ClubsController.clubFollowStatus
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/follow/count:
    get:
      operationId: ClubsController.clubFollowCount
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{clubId}/sports:
    get:
      operationId: ClubsController.listClubSports
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/{id}/featured-members:
    get:
      operationId: ClubsController.listFeaturedMembers
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: placement
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/clubs/by-sport/{sportId}:
    get:
      operationId: ClubsController.listClubsBySport
      parameters:
        - name: sportId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_160
  /v2/organizer/clubs:
    get:
      operationId: OrganizerClubsController.listMine
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_161
        - 'Organizer: Clubs'
    post:
      operationId: OrganizerClubsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubDto'
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/setup-status:
    get:
      operationId: OrganizerClubsController.getSetupStatus
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/submit-setup:
    post:
      operationId: OrganizerClubsController.submitSetup
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitOrganizerClubSetupDto'
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/my-role:
    get:
      operationId: OrganizerClubsController.myRole
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/admins:
    get:
      operationId: OrganizerClubsController.listAdmins
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/active-members-roster:
    get:
      operationId: OrganizerClubsController.listActiveMembersRoster
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/activity:
    get:
      operationId: OrganizerClubsController.listActivity
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/verification-eligibility:
    get:
      operationId: OrganizerClubsController.verificationEligibility
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/verify-request:
    post:
      operationId: OrganizerClubsController.verifyRequest
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}:
    patch:
      operationId: OrganizerClubsController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateClubDto'
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/logo:
    post:
      operationId: OrganizerClubsController.uploadLogo
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/banner:
    post:
      operationId: OrganizerClubsController.uploadBanner
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/announcements:
    post:
      operationId: OrganizerClubsController.createAnnouncement
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubAnnouncementDto'
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/runs:
    post:
      operationId: OrganizerClubsController.createRun
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubRunDto'
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/runs/{runId}:
    patch:
      operationId: OrganizerClubsController.updateRun
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateClubRunDto'
      responses:
        '200':
          description: ''
      tags: *ref_161
    delete:
      operationId: OrganizerClubsController.deleteRun
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/memberships:
    get:
      operationId: OrganizerClubsController.listMemberships
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/memberships/{membershipId}/approve:
    post:
      operationId: OrganizerClubsController.approveMembership
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/memberships/{membershipId}/reject:
    post:
      operationId: OrganizerClubsController.rejectMembership
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/members/{userId}:
    get:
      operationId: OrganizerClubsController.getMember
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
    delete:
      operationId: OrganizerClubsController.removeMember
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/memberships/{membershipId}/notes:
    patch:
      operationId: OrganizerClubsController.updateNotes
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/memberships/{membershipId}/transfer-ownership:
    post:
      operationId: OrganizerClubsController.transferOwnership
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestClubOwnershipTransferDto'
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/ownership-transfer:
    get:
      operationId: OrganizerClubsController.outgoingOwnershipTransfer
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/ownership-transfer/{requestId}/cancel:
    post:
      operationId: OrganizerClubsController.cancelOwnershipTransfer
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: requestId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/metrics:
    get:
      operationId: OrganizerClubsController.metrics
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/tiers:
    get:
      operationId: OrganizerClubsController.listTiers
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/tiers:
    post:
      operationId: OrganizerClubsController.createTier
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubTierDto'
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{id}/tiers/{tierId}:
    patch:
      operationId: OrganizerClubsController.updateTier
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateClubTierDto'
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/sports:
    post:
      operationId: OrganizerClubsController.addClubSport
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/sports/{sportId}:
    delete:
      operationId: OrganizerClubsController.removeClubSport
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: sportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/organizer/clubs/{clubId}/sports/{sportId}/primary:
    patch:
      operationId: OrganizerClubsController.setPrimaryClubSport
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: sportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_161
  /v2/admin/clubs/verification-queue:
    get:
      operationId: AdminClubsController.verificationQueue
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_162
        - 'Admin: Clubs'
  /v2/admin/clubs/{id}/verify-approve:
    post:
      operationId: AdminClubsController.verifyApprove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}/verify-reject:
    post:
      operationId: AdminClubsController.verifyReject
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_162
  /v2/admin/clubs:
    get:
      operationId: AdminClubsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/runs:
    get:
      operationId: AdminClubsController.listRuns
      parameters:
        - name: clubId
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/announcements/{annId}:
    delete:
      operationId: AdminClubsController.deleteAnnouncement
      parameters:
        - name: annId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}:
    get:
      operationId: AdminClubsController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
    patch:
      operationId: AdminClubsController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateClubDto'
      responses:
        '200':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}/deactivate:
    post:
      operationId: AdminClubsController.deactivate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminDeactivateClubDto'
      responses:
        '201':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}/reactivate:
    post:
      operationId: AdminClubsController.reactivate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}/members:
    get:
      operationId: AdminClubsController.listMembers
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
    post:
      operationId: AdminClubsController.createMember
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminCreateClubMembershipDto'
      responses:
        '201':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}/members/{userId}:
    patch:
      operationId: AdminClubsController.updateMember
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminUpdateClubMembershipDto'
      responses:
        '200':
          description: ''
      tags: *ref_162
    delete:
      operationId: AdminClubsController.removeMember
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}/announcements:
    get:
      operationId: AdminClubsController.listAnnouncements
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
    post:
      operationId: AdminClubsController.createAnnouncement
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminCreateClubAnnouncementDto'
      responses:
        '201':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/{id}/moderation-reports:
    get:
      operationId: AdminClubsController.listModerationReports
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_162
  /v2/admin/clubs/chat/recent-activity:
    get:
      operationId: AdminClubChatController.recentActivity
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_163
        - bearer: []
      tags: &ref_164
        - 'Admin: Club chat moderation'
  /v2/admin/clubs/{clubId}/chat/messages:
    get:
      operationId: AdminClubChatController.listMessages
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: includeInactive
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_163
      tags: *ref_164
  /v2/admin/clubs/{clubId}/chat/messages/{msgId}:
    delete:
      operationId: AdminClubChatController.softDelete
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: msgId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_163
      tags: *ref_164
  /v2/clubs/{clubId}/posts:
    post:
      operationId: ClubDepthController.createPost
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_165
        - 'User: Clubs Depth'
    get:
      operationId: ClubDepthController.listPosts
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/posts/{postId}:
    delete:
      operationId: ClubDepthController.deletePost
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/posts/{postId}/comments:
    post:
      operationId: ClubDepthController.addComment
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_165
    get:
      operationId: ClubDepthController.listComments
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/posts/{postId}/comments/{commentId}:
    delete:
      operationId: ClubDepthController.deleteComment
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/chat/upload-media:
    post:
      operationId: ClubDepthController.uploadChatMedia
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/chat:
    post:
      operationId: ClubDepthController.sendChat
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_165
    get:
      operationId: ClubDepthController.listChat
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: before
          required: true
          in: query
          schema:
            type: string
        - name: channelId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/chat/{messageId}:
    delete:
      operationId: ClubDepthController.deleteChatForEveryone
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/chat/{messageId}/me:
    delete:
      operationId: ClubDepthController.deleteChatForMe
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/runs/{runId}/attendance:
    get:
      operationId: ClubDepthController.attendanceForRun
      parameters:
        - name: runId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/clubs/{clubId}/streak/me:
    get:
      operationId: ClubDepthController.myStreak
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_165
  /v2/admin/clubs/attendance/infer:
    post:
      operationId: AdminClubDepthController.inferForActivity
      parameters: []
      responses:
        '201':
          description: ''
      tags: &ref_166
        - 'Admin: Clubs Depth'
  /v2/admin/clubs/runs/{runId}/attendance/manual:
    post:
      operationId: AdminClubDepthController.manualAttendance
      parameters:
        - name: runId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_166
  /v2/admin/clubs/runs/{runId}/attendance:
    get:
      operationId: AdminClubDepthController.listAttendance
      parameters:
        - name: runId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_166
  /v2/organizer/clubs/{clubId}/moderation/posts:
    get:
      operationId: OrganizerClubModerationController.listPosts
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: hidden
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_167
        - 'Organizer: Club Moderation'
  /v2/organizer/clubs/{clubId}/moderation/posts/{postId}/comments:
    get:
      operationId: OrganizerClubModerationController.listComments
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: hidden
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_167
  /v2/organizer/clubs/{clubId}/moderation/posts/{postId}/hide:
    post:
      operationId: OrganizerClubModerationController.hidePost
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '201':
          description: ''
      tags: *ref_167
  /v2/organizer/clubs/{clubId}/moderation/posts/{postId}:
    delete:
      operationId: OrganizerClubModerationController.hidePostLegacy
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '200':
          description: ''
      tags: *ref_167
  /v2/organizer/clubs/{clubId}/moderation/posts/{postId}/comments/{commentId}/hide:
    post:
      operationId: OrganizerClubModerationController.hideComment
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '201':
          description: ''
      tags: *ref_167
  /v2/organizer/clubs/{clubId}/moderation/posts/{postId}/comments/{commentId}:
    delete:
      operationId: OrganizerClubModerationController.hideCommentLegacy
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '200':
          description: ''
      tags: *ref_167
  /v2/organizer/clubs/{clubId}/moderation/posts/{postId}/unhide:
    post:
      operationId: OrganizerClubModerationController.unhidePost
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_167
  /v2/organizer/clubs/{clubId}/moderation/posts/{postId}/comments/{commentId}/unhide:
    post:
      operationId: OrganizerClubModerationController.unhideComment
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_167
  /v2/organizer/clubs/{clubId}/analytics/mrr:
    get:
      operationId: OrganizerClubAnalyticsController.mrr
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Monthly recurring revenue (MRR).
      tags: &ref_168
        - 'Organizer: Club Creator Analytics'
  /v2/organizer/clubs/{clubId}/analytics/churn:
    get:
      operationId: OrganizerClubAnalyticsController.churn
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Churn over a sliding window.
      tags: *ref_168
  /v2/organizer/clubs/{clubId}/analytics/ltv:
    get:
      operationId: OrganizerClubAnalyticsController.ltv
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Lifetime value (ARPU ÷ monthly churn).
      tags: *ref_168
  /v2/organizer/clubs/{clubId}/analytics/cohort-retention:
    get:
      operationId: OrganizerClubAnalyticsController.cohort
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: months
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Cohort retention by month-joined.
      tags: *ref_168
  /v2/organizer/clubs/{clubId}/analytics/dashboard:
    get:
      operationId: OrganizerClubAnalyticsController.dashboard
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: window
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Combined analytics dashboard.
      tags: *ref_168
  /v2/organizer/clubs/{clubId}/featured-members:
    get:
      operationId: OrganizerClubFeaturedController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_169
        - bearer: []
      summary: List all featured-member slots for the club.
      tags: &ref_170
        - 'Organizer: Club Featured Members'
    post:
      operationId: OrganizerClubFeaturedController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_169
      summary: Feature a member.
      tags: *ref_170
  /v2/organizer/clubs/{clubId}/featured-members/active:
    get:
      operationId: OrganizerClubFeaturedController.active
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: placement
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_169
      summary: Live rotation for a placement (deterministic order).
      tags: *ref_170
  /v2/organizer/clubs/{clubId}/featured-members/{id}:
    patch:
      operationId: OrganizerClubFeaturedController.update
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_169
      summary: Update a featured slot.
      tags: *ref_170
  /v2/organizer/clubs/{clubId}/featured-members/{id}/activate:
    post:
      operationId: OrganizerClubFeaturedController.activate
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_169
      summary: Activate a featured slot.
      tags: *ref_170
  /v2/organizer/clubs/{clubId}/featured-members/{id}/deactivate:
    post:
      operationId: OrganizerClubFeaturedController.deactivate
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_169
      summary: Deactivate a featured slot.
      tags: *ref_170
  /v2/organizer/clubs/{clubId}/featured-members/reorder:
    post:
      operationId: OrganizerClubFeaturedController.reorder
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_169
      summary: Reorder featured slots by id sequence.
      tags: *ref_170
  /v2/clubs/{clubId}/admin/recognition-rules:
    get:
      operationId: ClubAdminRecognitionController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_171
        - bearer: []
      summary: List recognition rules.
      tags: &ref_172
        - 'Club Admin: Auto-Recognition'
    post:
      operationId: ClubAdminRecognitionController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_171
      summary: Create a recognition rule (DISABLED by default).
      tags: *ref_172
  /v2/clubs/{clubId}/admin/recognition-rules/{id}:
    get:
      operationId: ClubAdminRecognitionController.getOne
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_171
      summary: Get a recognition rule.
      tags: *ref_172
    patch:
      operationId: ClubAdminRecognitionController.update
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_171
      summary: Update a recognition rule.
      tags: *ref_172
  /v2/clubs/{clubId}/admin/recognition-rules/{id}/evaluate:
    get:
      operationId: ClubAdminRecognitionController.evaluate
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_171
      summary: Preview who the rule would recognise (no award).
      tags: *ref_172
  /v2/clubs/{clubId}/admin/recognition-rules/{id}/enable:
    post:
      operationId: ClubAdminRecognitionController.enable
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_171
      summary: Enable a recognition rule.
      tags: *ref_172
  /v2/clubs/{clubId}/admin/recognition-rules/{id}/disable:
    post:
      operationId: ClubAdminRecognitionController.disable
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_171
      summary: Disable a recognition rule.
      tags: *ref_172
  /v2/clubs/{clubId}/admin/audience-segments:
    get:
      operationId: ClubAdminAudienceController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_173
        - bearer: []
      summary: List audience segments.
      tags: &ref_174
        - 'Club Admin: Audience Segments'
    post:
      operationId: ClubAdminAudienceController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_173
      summary: Create an audience segment.
      tags: *ref_174
  /v2/clubs/{clubId}/admin/audience-segments/{id}:
    patch:
      operationId: ClubAdminAudienceController.update
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_173
      summary: Update an audience segment.
      tags: *ref_174
  /v2/clubs/{clubId}/admin/audience-segments/{id}/archive:
    post:
      operationId: ClubAdminAudienceController.archive
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_173
      summary: Archive an audience segment.
      tags: *ref_174
  /v2/clubs/{clubId}/admin/audience-segments/{id}/preview:
    get:
      operationId: ClubAdminAudienceController.preview
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_173
      summary: Preview matching member count (count only).
      tags: *ref_174
  /v2/clubs/{clubId}/admin/audience-segments/challenges/{challengeId}/attach/{segmentId}:
    post:
      operationId: ClubAdminAudienceController.attach
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
        - name: segmentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_173
      summary: Attach a segment to a challenge.
      tags: *ref_174
  /v2/clubs/{clubId}/admin/audience-segments/challenge-audiences/{id}:
    delete:
      operationId: ClubAdminAudienceController.detach
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_173
      summary: Detach a segment from a challenge.
      tags: *ref_174
  /v2/clubs/{clubId}/admin/audience-segments/challenges/{challengeId}/audiences:
    get:
      operationId: ClubAdminAudienceController.listAudiences
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_173
      summary: List segments attached to a challenge.
      tags: *ref_174
  /v2/clubs/{clubId}/admin/announcements/{id}/email-blast:
    get:
      operationId: ClubAdminAnnouncementBlastController.status
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_175
        - bearer: []
      summary: Get the email-blast status for an announcement.
      tags: &ref_176
        - 'Club Admin: Announcement Email Blast'
    post:
      operationId: ClubAdminAnnouncementBlastController.blast
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_175
      summary: Send an email blast for a published announcement.
      tags: *ref_176
  /v2/clubs/{clubId}/admin/memberships/{id}/change-tier/preview:
    post:
      operationId: ClubAdminTierChangeController.preview
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: &ref_177
        - bearer: []
      summary: Preview the refund for a proposed tier change.
      tags: &ref_178
        - 'Club Admin: Membership Tier Change'
  /v2/clubs/{clubId}/admin/memberships/{id}/change-tier:
    post:
      operationId: ClubAdminTierChangeController.changeTier
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_177
      summary: Change a membership tier (refund-last-billing).
      tags: *ref_178
  /v2/clubs/{clubId}/channels:
    get:
      operationId: ClubChannelsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List the caller-visible channels for a club. Default #general is
        auto-provisioned if missing.
      tags: &ref_179
        - 'Clubs: Channels'
    post:
      operationId: ClubChannelsController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Create a channel. Admin-only.
      tags: *ref_179
  /v2/clubs/{clubId}/channels/{channelId}:
    patch:
      operationId: ClubChannelsController.update
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: channelId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Update a channel. Admin-only.
      tags: *ref_179
    delete:
      operationId: ClubChannelsController.archive
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: channelId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Archive (soft-delete) a channel. Admin-only. The #general default
        channel cannot be archived.
      tags: *ref_179
  /v2/clubs/{clubId}/leaderboard:
    get:
      operationId: ClubPointsController.allTime
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: sportId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        All-time club leaderboard. Pass `sportId` query for per-sport scoping
        (§18.7 G-15 Phase 2). Omit for combined.
      tags: &ref_180
        - 'Clubs: Gamification'
  /v2/clubs/{clubId}/leaderboard/weekly:
    get:
      operationId: ClubPointsController.weekly
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: weekKey
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: sportId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Weekly club leaderboard. `weekKey` defaults to the current ISO week
        (format YYYY-WW). Pass `sportId` for per-sport scoping (§18.7 G-15 Phase
        2).
      tags: *ref_180
  /v2/clubs/{clubId}/leaderboard/monthly:
    get:
      operationId: ClubPointsController.monthly
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: monthKey
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: sportId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Monthly club leaderboard (§55.2). `monthKey` defaults to the current UTC
        month (format YYYY-MM). Banned/removed/left memberships are excluded.
      tags: *ref_180
  /v2/clubs/{clubId}/member-of-the-month/detect:
    post:
      operationId: ClubPointsController.detectMom
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Member-of-the-Month detection (§55.3). Idempotent per (clubId,
        monthKey). Returns the winner + tie status; emits
        CLUB_MEMBER_OF_THE_MONTH the first time.
      tags: *ref_180
  /v2/clubs/{clubId}/points/grants:
    get:
      operationId: ClubPointsController.listGrants
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Admin-only: list manual grant/debit history for the club. Paginated;
        most-recent first.
      tags: *ref_180
    post:
      operationId: ClubPointsController.grant
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: 'Admin-only: grant/debit points to a member. Negative `points` = debit.'
      tags: *ref_180
  /v2/clubs/{clubId}/points/reverse/{entryId}:
    post:
      operationId: ClubPointsController.reverse
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: entryId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Admin-only: reverse a prior ledger entry. Writes a compensating negative
        row.
      tags: *ref_180
  /v2/clubs/{clubId}/tiers/{tierId}/promos:
    get:
      operationId: ClubTierPromosController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List promo codes for a tier. Admin-only.
      tags: &ref_181
        - 'Clubs: Tier promos'
    post:
      operationId: ClubTierPromosController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Create a promo code for a tier. Admin-only.
      tags: *ref_181
  /v2/clubs/{clubId}/tiers/{tierId}/promos/{promoId}:
    delete:
      operationId: ClubTierPromosController.archive
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
        - name: promoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Archive a promo code. Admin-only.
      tags: *ref_181
  /v2/clubs/{clubId}/tiers/{tierId}/promos/quote:
    get:
      operationId: ClubTierPromosController.quote
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
        - name: code
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Quote a promo code against a tier. Returns {ok, reason,
        effectiveAmount?, effectivePct?}.
      tags: *ref_181
  /v2/clubs/{clubId}/admin/members/{userId}/mute:
    post:
      operationId: ClubAdminMembersController.mute
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_182
        - 'User: Club Admin — Member Management'
    delete:
      operationId: ClubAdminMembersController.unmute
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/{userId}/ban:
    post:
      operationId: ClubAdminMembersController.ban
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
    delete:
      operationId: ClubAdminMembersController.unban
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/{userId}/warn:
    post:
      operationId: ClubAdminMembersController.warn
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/{userId}/remove:
    post:
      operationId: ClubAdminMembersController.remove
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/{userId}/suspend:
    post:
      operationId: ClubAdminMembersController.suspend
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/{userId}/restore:
    post:
      operationId: ClubAdminMembersController.restore
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/{userId}/promote:
    post:
      operationId: ClubAdminMembersController.promote
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
    delete:
      operationId: ClubAdminMembersController.demote
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/bulk-approve:
    post:
      operationId: ClubAdminMembersController.bulkApprove
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/bulk-message:
    post:
      operationId: ClubAdminMembersController.bulkMessage
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/members/export.csv:
    get:
      operationId: ClubAdminMembersController.exportCsv
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_182
  /v2/clubs/{clubId}/admin/announcements/{announcementId}/pin:
    post:
      operationId: ClubAdminAnnouncementsController.pin
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: announcementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_183
        - 'User: Club Admin — Announcements'
    delete:
      operationId: ClubAdminAnnouncementsController.unpin
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: announcementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_183
  /v2/clubs/{clubId}/admin/announcements:
    get:
      operationId: ClubAdminAnnouncementsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_183
    post:
      operationId: ClubAdminAnnouncementsController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubAnnouncementDto'
      responses:
        '201':
          description: ''
      tags: *ref_183
  /v2/clubs/{clubId}/admin/announcements/{announcementId}:
    delete:
      operationId: ClubAdminAnnouncementsController.remove
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: announcementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_183
  /v2/clubs/{clubId}/admin/announcements/scheduled:
    post:
      operationId: ClubAdminAnnouncementsController.schedule
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_183
    get:
      operationId: ClubAdminAnnouncementsController.listScheduled
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_183
  /v2/clubs/{clubId}/admin/announcements/scheduled/{announcementId}:
    delete:
      operationId: ClubAdminAnnouncementsController.cancelSchedule
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: announcementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_183
  /v2/clubs/{clubId}/admin/announcements/{announcementId}/metrics:
    get:
      operationId: ClubAdminAnnouncementsController.metrics
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: announcementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_183
  /v2/clubs/{clubId}/admin/runs:
    post:
      operationId: ClubAdminRunsController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubRunDto'
      responses:
        '201':
          description: ''
      tags: &ref_184
        - 'User: Club Admin — Runs'
  /v2/clubs/{clubId}/admin/runs/{runId}:
    patch:
      operationId: ClubAdminRunsController.update
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateClubRunDto'
      responses:
        '200':
          description: ''
      tags: *ref_184
    delete:
      operationId: ClubAdminRunsController.cancel
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_184
  /v2/clubs/{clubId}/admin/runs/{runId}/rsvps:
    get:
      operationId: ClubAdminRunsController.listRsvps
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
        - name: occurrenceStart
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_184
  /v2/clubs/{clubId}/admin/runs/{runId}/attendance:
    get:
      operationId: ClubAdminRunsController.listAttendance
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_184
  /v2/clubs/{clubId}/admin/runs/{runId}/attendance/manual:
    post:
      operationId: ClubAdminRunsController.markAttendance
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_184
  /v2/clubs/{clubId}/admin/runs/{runId}/occurrence-cohorts:
    get:
      operationId: ClubAdminRunsController.listOccurrenceCohorts
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: runId
          required: true
          in: path
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_184
  /v2/clubs/{clubId}/admin/setup-wizard:
    post:
      operationId: ClubAdminSettingsController.apply
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClubSetupWizardDto'
      responses:
        '201':
          description: ''
      tags:
        - 'User: Club Admin — Setup Wizard'
  /v2/clubs/{clubId}/dms:
    post:
      operationId: ClubDirectMessagesController.send
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_185
        - 'User: Club Direct Messages'
    get:
      operationId: ClubDirectMessagesController.threads
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/messages/{messageId}/reactions/{emoji}:
    post:
      operationId: ClubDirectMessagesController.addReaction
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
        - name: emoji
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_185
    delete:
      operationId: ClubDirectMessagesController.removeReaction
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
        - name: emoji
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/messages/{messageId}/reactions:
    get:
      operationId: ClubDirectMessagesController.getReactions
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{peerUserId}:
    get:
      operationId: ClubDirectMessagesController.thread
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{messageId}/read:
    patch:
      operationId: ClubDirectMessagesController.markRead
      parameters:
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{peerUserId}/read:
    post:
      operationId: ClubDirectMessagesController.markThreadRead
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{peerUserId}/messages/{messageId}/report:
    post:
      operationId: ClubDirectMessagesController.reportMessage
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{peerUserId}/preferences:
    get:
      operationId: ClubDirectMessagesController.getThreadPreferences
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
    patch:
      operationId: ClubDirectMessagesController.setThreadPreferences
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{peerUserId}/typing:
    post:
      operationId: ClubDirectMessagesController.emitTyping
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '204':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{peerUserId}/typing-status:
    get:
      operationId: ClubDirectMessagesController.getTypingStatus
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{messageId}:
    delete:
      operationId: ClubDirectMessagesController.deleteForEveryone
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{messageId}/me:
    delete:
      operationId: ClubDirectMessagesController.deleteForMe
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/dms/{peerUserId}/thread:
    delete:
      operationId: ClubDirectMessagesController.deleteThread
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: peerUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_185
  /v2/clubs/{clubId}/admin/awards:
    get:
      operationId: ClubAdminAwardsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_186
        - 'Club: Custom Awards'
    post:
      operationId: ClubAdminAwardsController.grant
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_186
  /v2/clubs/{clubId}/admin/awards/{awardId}:
    patch:
      operationId: ClubAdminAwardsController.update
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: awardId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_186
    delete:
      operationId: ClubAdminAwardsController.deactivate
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: awardId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_186
  /v2/clubs/{clubId}/awards:
    get:
      operationId: PublicClubAwardsController.listPublic
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Club Awards'
  /v2/organizer/clubs/{clubId}/members/invite:
    post:
      operationId: ClubAdminInvitesController.invite
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubInviteDto'
      responses:
        '201':
          description: ''
      security: &ref_187
        - bearer: []
      summary: >-
        Create an admin-issued club invite by email OR phone (or neither, for a
        shareable link). Optionally grants ADMIN or MODERATOR on acceptance —
        ADMIN requires the caller to be OWNER, mirroring the promote endpoint,
        and a link invite may never carry a role.
      tags: &ref_188
        - 'User: Club Admin — Invites'
  /v2/organizer/clubs/{clubId}/members/invites:
    get:
      operationId: ClubAdminInvitesController.list
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - PENDING
              - ACCEPTED
              - REVOKED
              - EXPIRED
            type: string
      responses:
        '200':
          description: ''
      security: *ref_187
      summary: List club invites (PENDING by default; filter by status).
      tags: *ref_188
  /v2/organizer/clubs/{clubId}/members/invites/{inviteId}:
    delete:
      operationId: ClubAdminInvitesController.revoke
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: inviteId
          required: true
          in: path
          description: Invite id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_187
      summary: Revoke a pending invite. Cross-club returns same-shape 404.
      tags: *ref_188
  /v2/clubs/invites/by-token/{token}:
    get:
      operationId: ClubInviteRedemptionController.preview
      parameters:
        - name: token
          required: true
          in: path
          description: Invite share token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Preview a club invite from its share token. Public — the recipient may
        not have an account yet. Returns a verdict object (valid + reason)
        rather than 404ing, so each rejection can be shown differently.
      tags: &ref_189
        - Club invites — redemption
  /v2/clubs/invites/{token}/accept:
    post:
      operationId: ClubInviteRedemptionController.accept
      parameters:
        - name: token
          required: true
          in: path
          description: Invite share token
          schema:
            type: string
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: >-
        Accept a club invite. Creates the membership via the normal join path so
        every guard (suspension, club-active, banned, tier) still applies. A
        targeted invite auto-approves into a gated club; a shareable link does
        NOT — it still faces club.requiresApproval, since a link can be
        forwarded to anyone.
      tags: *ref_189
  /v2/clubs/{clubId}/admin/run-templates:
    get:
      operationId: ClubAdminRunTemplatesController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_190
        - 'User: Club Admin — Run Templates'
    post:
      operationId: ClubAdminRunTemplatesController.create
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_190
  /v2/clubs/{clubId}/admin/run-templates/{templateId}:
    patch:
      operationId: ClubAdminRunTemplatesController.update
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_190
    delete:
      operationId: ClubAdminRunTemplatesController.remove
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_190
  /v2/clubs/{clubId}/admin/run-templates/{templateId}/apply:
    post:
      operationId: ClubAdminRunTemplatesController.apply
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_190
  /v2/clubs/{clubId}/admin/awards/nominations:
    get:
      operationId: ClubAdminAwardNominationsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_191
        - 'User: Club Admin — Award Nominations'
    post:
      operationId: ClubAdminAwardNominationsController.nominate
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_191
  /v2/clubs/{clubId}/admin/awards/nominations/{nominationId}/approve:
    post:
      operationId: ClubAdminAwardNominationsController.approve
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: nominationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_191
  /v2/clubs/{clubId}/admin/awards/nominations/{nominationId}/reject:
    post:
      operationId: ClubAdminAwardNominationsController.reject
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: nominationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_191
  /v2/clubs/{clubId}/admin/post-reports:
    get:
      operationId: ClubAdminPostReportsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_192
        - 'User: Club Admin — Post Reports'
  /v2/clubs/{clubId}/admin/post-reports/{reportId}:
    get:
      operationId: ClubAdminPostReportsController.detail
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_192
  /v2/clubs/{clubId}/admin/post-reports/{reportId}/resolve:
    post:
      operationId: ClubAdminPostReportsController.resolve
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_192
  /v2/clubs/{clubId}/admin/post-reports/{reportId}/reject:
    post:
      operationId: ClubAdminPostReportsController.reject
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_192
  /v2/clubs/{clubId}/admin/post-reports/{reportId}/escalate:
    post:
      operationId: ClubAdminPostReportsController.escalate
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_192
  /v2/clubs/{clubId}/admin/post-reports/{reportId}/archive:
    post:
      operationId: ClubAdminPostReportsController.archive
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_192
  /v2/clubs/{clubId}/admin/post-reports/{reportId}/restore:
    post:
      operationId: ClubAdminPostReportsController.restore
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_192
  /v2/clubs/onboarding/me:
    get:
      operationId: ClubOnboardingController.getMyClub
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_193
        - bearer: []
      summary: >-
        Primary Club lifecycle state. Prefers an owned Club, then a retained
        Admin workspace after ownership transfer; returns null when neither
        exists.
      tags: &ref_194
        - 'Club: Onboarding workflow'
  /v2/clubs/onboarding/me/{clubId}/submit:
    post:
      operationId: ClubOnboardingController.submit
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_193
      summary: >-
        Submit a DRAFT club for admin review. Required: club name + slug already
        saved.
      tags: *ref_194
  /v2/clubs/onboarding/me/{clubId}/resubmit:
    post:
      operationId: ClubOnboardingController.resubmit
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_193
      summary: >-
        Resubmit a SUSPENDED (rejected) club for admin re-review. Clears prior
        rejection reason.
      tags: *ref_194
  /v2/admin/club-onboarding:
    get:
      operationId: AdminClubOnboardingController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PENDING_APPROVAL
              - ACTIVE
              - SUSPENDED
              - ARCHIVED
              - UNDER_REVIEW
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_195
        - bearer: []
      summary: >-
        Paginated admin queue. Default status = PENDING_APPROVAL. Other
        accepted: ACTIVE, SUSPENDED.
      tags: &ref_196
        - 'Admin: Club onboarding queue'
  /v2/admin/club-onboarding/{clubId}/approve:
    post:
      operationId: AdminClubOnboardingController.approve
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_195
      summary: Approve a PENDING_APPROVAL club. PENDING_APPROVAL → ACTIVE.
      tags: *ref_196
  /v2/admin/club-onboarding/{clubId}/reject:
    post:
      operationId: AdminClubOnboardingController.reject
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RejectClubDto'
      responses:
        '201':
          description: ''
      security: *ref_195
      summary: >-
        Reject a PENDING_APPROVAL club. PENDING_APPROVAL → SUSPENDED. Reason
        required (10-500 chars), returned verbatim to the organizer.
      tags: *ref_196
  /v2/organizer/clubs/{clubId}/monetization/summary:
    get:
      operationId: OrganizerClubMonetizationController.getSummary
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_197
        - bearer: []
      summary: >-
        Per-tier revenue rows + club totals + sourceStatus map (NOT_TRACKED_YET
        for mrr / churnRate / lifetimeValue — no fabricated numbers).
      tags: &ref_198
        - 'Organizer: Club monetization'
  /v2/organizer/clubs/{clubId}/monetization/payments:
    get:
      operationId: OrganizerClubMonetizationController.listPayments
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: status
          required: false
          in: query
          schema: {}
      responses:
        '200':
          description: ''
      security: *ref_197
      summary: >-
        Paginated payment history. Optional status filter (CAPTURED / REFUNDED /
        PENDING / FAILED / CANCELLED).
      tags: *ref_198
  /v2/clubs/{clubId}/admin/discoverable-events:
    get:
      operationId: ClubW2FeaturesController.discoverEvents
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: city
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_199
        - bearer: []
      summary: Discover organizer events (city-scoped) the club may attach to.
      tags: &ref_200
        - 'Club Admin: Wave 2'
  /v2/clubs/{clubId}/admin/events/{eventId}/attach:
    post:
      operationId: ClubW2FeaturesController.requestAttach
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_199
      summary: >-
        Club requests to attach / co-host an organizer event. Emits
        club.event_attach.requested.
      tags: *ref_200
  /v2/clubs/{clubId}/admin/event-attachments:
    get:
      operationId: ClubW2FeaturesController.listAttachments
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_199
      summary: List the club's attach requests (any status).
      tags: *ref_200
  /v2/clubs/{clubId}/admin/event-attachments/{attachmentId}/detach:
    post:
      operationId: ClubW2FeaturesController.detach
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: attachmentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_199
      summary: Club withdraws (detaches) its own active attachment.
      tags: *ref_200
  /v2/clubs/{clubId}/admin/brand-challenges/{challengeId}/join:
    post:
      operationId: ClubW2FeaturesController.joinBrandChallenge
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_199
      summary: >-
        Club joins (as a club) an APPROVED brand challenge. Emits
        club.brand_challenge.joined.
      tags: *ref_200
  /v2/clubs/{clubId}/admin/brand-challenges/{challengeId}/withdraw:
    post:
      operationId: ClubW2FeaturesController.withdrawBrandChallenge
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_199
      summary: Club withdraws from a brand challenge it joined.
      tags: *ref_200
  /v2/clubs/{clubId}/admin/brand-challenges/participations:
    get:
      operationId: ClubW2FeaturesController.listBrandParticipations
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_199
      summary: List brand challenges this club has joined.
      tags: *ref_200
  /v2/clubs/{clubId}/admin/member-segments:
    get:
      operationId: ClubW2FeaturesController.listSegments
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_199
      summary: List club member segments.
      tags: *ref_200
    post:
      operationId: ClubW2FeaturesController.createSegment
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_199
      summary: Create a saved member segment.
      tags: *ref_200
  /v2/organizer/events/attachment-requests:
    get:
      operationId: OrganizerEventAttachmentsController.listForOrganizer
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_201
        - bearer: []
      summary: 'OM: list attach requests for events the organizer owns.'
      tags: &ref_202
        - 'Organizer: Event attachments'
  /v2/organizer/events/attachment-requests/{attachmentId}/approve:
    post:
      operationId: OrganizerEventAttachmentsController.approve
      parameters:
        - name: attachmentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_201
      summary: 'OM: approve a club attach request. Emits club.event_attach.approved.'
      tags: *ref_202
  /v2/organizer/events/attachment-requests/{attachmentId}/reject:
    post:
      operationId: OrganizerEventAttachmentsController.reject
      parameters:
        - name: attachmentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_201
      summary: 'OM: reject a club attach request. Emits club.event_attach.rejected.'
      tags: *ref_202
  /v2/clubs/{clubId}/admin/settings:
    get:
      operationId: ClubUserAdminController.getSettings[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_203
        - 'User: Club Admin'
    patch:
      operationId: ClubUserAdminController.updateSettings[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClubSetupWizardDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin:
    get:
      operationId: ClubUserAdminController.getSettings[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}:
    patch:
      operationId: ClubUserAdminController.updateSettings[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClubSetupWizardDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/shipping/pickup-address:
    get:
      operationId: ClubUserAdminController.clubPickupAddress
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
    post:
      operationId: ClubUserAdminController.saveClubPickupAddress
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/logo:
    post:
      operationId: ClubUserAdminController.uploadLogo
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/banner:
    post:
      operationId: ClubUserAdminController.uploadBanner
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/deactivate:
    post:
      operationId: ClubUserAdminController.deactivateClub
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeactivateClubDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/reactivate:
    post:
      operationId: ClubUserAdminController.reactivateClub
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/status:
    get:
      operationId: ClubUserAdminController.getDeactivationStatus
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/metrics:
    get:
      operationId: ClubUserAdminController.getMetrics[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/metrics:
    get:
      operationId: ClubUserAdminController.getMetrics[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/my-role:
    get:
      operationId: ClubUserAdminController.myRole[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/my-role:
    get:
      operationId: ClubUserAdminController.myRole[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/admins:
    get:
      operationId: ClubUserAdminController.listAdmins[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admins:
    get:
      operationId: ClubUserAdminController.listAdmins[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/members/roles:
    get:
      operationId: ClubUserAdminController.listAdmins[2]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/analytics/dashboard:
    get:
      operationId: ClubUserAdminController.analyticsDashboard[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: window
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/analytics/dashboard:
    get:
      operationId: ClubUserAdminController.analyticsDashboard[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: window
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/tiers:
    get:
      operationId: ClubUserAdminController.listTiers[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: includeInactive
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
    post:
      operationId: ClubUserAdminController.createTier[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubTierDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/tiers:
    get:
      operationId: ClubUserAdminController.listTiers[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: includeInactive
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
    post:
      operationId: ClubUserAdminController.createTier[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubTierDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/tiers/{tierId}:
    patch:
      operationId: ClubUserAdminController.updateTier[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateClubTierDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/tiers/{tierId}:
    patch:
      operationId: ClubUserAdminController.updateTier[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateClubTierDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/tiers/preview-breakdown:
    post:
      operationId: ClubUserAdminController.previewTierBreakdown[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewClubTierBreakdownDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/tiers/preview-breakdown:
    post:
      operationId: ClubUserAdminController.previewTierBreakdown[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewClubTierBreakdownDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/tiers/{tierId}/breakdown:
    get:
      operationId: ClubUserAdminController.getTierBreakdown[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/tiers/{tierId}/breakdown:
    get:
      operationId: ClubUserAdminController.getTierBreakdown[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/verification/eligibility:
    get:
      operationId: ClubUserAdminController.verificationEligibility[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/verification-eligibility:
    get:
      operationId: ClubUserAdminController.verificationEligibility[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/verification/request:
    post:
      operationId: ClubUserAdminController.requestVerification[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/verify-request:
    post:
      operationId: ClubUserAdminController.requestVerification[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/featured-members:
    get:
      operationId: ClubUserAdminController.listFeaturedMembers
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
    post:
      operationId: ClubUserAdminController.createFeaturedMember[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/featured-members:
    post:
      operationId: ClubUserAdminController.createFeaturedMember[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/featured-members/{id}:
    patch:
      operationId: ClubUserAdminController.updateFeaturedMember[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/featured-members/{id}:
    patch:
      operationId: ClubUserAdminController.updateFeaturedMember[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/featured-members/reorder:
    post:
      operationId: ClubUserAdminController.reorderFeaturedMembers[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/featured-members/reorder:
    post:
      operationId: ClubUserAdminController.reorderFeaturedMembers[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/featured-members/{id}/activate:
    post:
      operationId: ClubUserAdminController.activateFeaturedMember[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/featured-members/{id}/activate:
    post:
      operationId: ClubUserAdminController.activateFeaturedMember[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/featured-members/{id}/deactivate:
    post:
      operationId: ClubUserAdminController.deactivateFeaturedMember[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/featured-members/{id}/deactivate:
    post:
      operationId: ClubUserAdminController.deactivateFeaturedMember[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/invites:
    get:
      operationId: ClubUserAdminController.listInvites[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
    post:
      operationId: ClubUserAdminController.createInvite[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/members/invites:
    get:
      operationId: ClubUserAdminController.listInvites[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/members/invite:
    post:
      operationId: ClubUserAdminController.createInvite[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/invites/{inviteId}:
    delete:
      operationId: ClubUserAdminController.revokeInvite[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: inviteId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/members/invites/{inviteId}:
    delete:
      operationId: ClubUserAdminController.revokeInvite[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: inviteId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/memberships/{membershipId}/notes:
    patch:
      operationId: ClubUserAdminController.updateMembershipNotes[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/memberships/{membershipId}/notes:
    patch:
      operationId: ClubUserAdminController.updateMembershipNotes[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/members/{membershipId}/notes:
    patch:
      operationId: ClubUserAdminController.updateMembershipNotes[2]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/members:
    get:
      operationId: ClubUserAdminController.listMembersByStatus[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/members-by-status:
    get:
      operationId: ClubUserAdminController.listMembersByStatus[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/members/{targetUserId}:
    get:
      operationId: ClubUserAdminController.getMemberDetail[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
    delete:
      operationId: ClubUserAdminController.removeMemberByUser[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/members/{targetUserId}:
    get:
      operationId: ClubUserAdminController.getMemberDetail[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
    delete:
      operationId: ClubUserAdminController.removeMemberByUser[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/members/{membershipId}/approve:
    post:
      operationId: ClubUserAdminController.approveMember[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/memberships/{membershipId}/approve:
    post:
      operationId: ClubUserAdminController.approveMember[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/members/{membershipId}/reject:
    post:
      operationId: ClubUserAdminController.rejectMember[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/memberships/{membershipId}/reject:
    post:
      operationId: ClubUserAdminController.rejectMember[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/active-members-roster:
    get:
      operationId: ClubUserAdminController.activeRoster[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/active-members-roster:
    get:
      operationId: ClubUserAdminController.activeRoster[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/activity:
    get:
      operationId: ClubUserAdminController.activityFeed[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/activity:
    get:
      operationId: ClubUserAdminController.activityFeed[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/monetization/summary:
    get:
      operationId: ClubUserAdminController.monetizationSummary[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/monetization/summary:
    get:
      operationId: ClubUserAdminController.monetizationSummary[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/monetization/payments:
    get:
      operationId: ClubUserAdminController.monetizationPayments[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/monetization/payments:
    get:
      operationId: ClubUserAdminController.monetizationPayments[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/memberships/{membershipId}/transfer-ownership:
    post:
      operationId: ClubUserAdminController.transferOwnership[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestClubOwnershipTransferDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/memberships/{membershipId}/transfer-ownership:
    post:
      operationId: ClubUserAdminController.transferOwnership[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestClubOwnershipTransferDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/members/{membershipId}/transfer-ownership:
    post:
      operationId: ClubUserAdminController.transferOwnership[2]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestClubOwnershipTransferDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/ownership-transfers/incoming:
    get:
      operationId: ClubUserAdminController.incomingOwnershipTransfers
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/ownership-transfer:
    get:
      operationId: ClubUserAdminController.outgoingOwnershipTransfer
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/ownership-transfers/{requestId}/accept:
    post:
      operationId: ClubUserAdminController.acceptOwnershipTransfer
      parameters:
        - name: requestId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AcceptClubOwnershipTransferDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/ownership-transfers/{requestId}/decline:
    post:
      operationId: ClubUserAdminController.declineOwnershipTransfer
      parameters:
        - name: requestId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/ownership-transfer/{requestId}/cancel:
    post:
      operationId: ClubUserAdminController.cancelOwnershipTransfer
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: requestId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts:
    get:
      operationId: ClubUserAdminController.listModerationPosts[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: hidden
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts:
    get:
      operationId: ClubUserAdminController.listModerationPosts[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: hidden
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts/{postId}/comments:
    get:
      operationId: ClubUserAdminController.listModerationComments[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: hidden
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts/{postId}/comments:
    get:
      operationId: ClubUserAdminController.listModerationComments[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: hidden
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts/{postId}/hide:
    post:
      operationId: ClubUserAdminController.hideModerationPost[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts/{postId}/hide:
    post:
      operationId: ClubUserAdminController.hideModerationPost[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts/{postId}:
    delete:
      operationId: ClubUserAdminController.hideModerationPostLegacy[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts/{postId}:
    delete:
      operationId: ClubUserAdminController.hideModerationPostLegacy[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts/{postId}/comments/{commentId}/hide:
    post:
      operationId: ClubUserAdminController.hideModerationComment[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts/{postId}/comments/{commentId}/hide:
    post:
      operationId: ClubUserAdminController.hideModerationComment[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts/{postId}/comments/{commentId}:
    delete:
      operationId: ClubUserAdminController.hideModerationCommentLegacy[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts/{postId}/comments/{commentId}:
    delete:
      operationId: ClubUserAdminController.hideModerationCommentLegacy[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HideClubContentDto'
      responses:
        '200':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts/{postId}/unhide:
    post:
      operationId: ClubUserAdminController.unhideModerationPost[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts/{postId}/unhide:
    post:
      operationId: ClubUserAdminController.unhideModerationPost[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/admin/moderation/posts/{postId}/comments/{commentId}/unhide:
    post:
      operationId: ClubUserAdminController.unhideModerationComment[0]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/moderation/posts/{postId}/comments/{commentId}/unhide:
    post:
      operationId: ClubUserAdminController.unhideModerationComment[1]
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: postId
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_203
  /v2/clubs/{clubId}/tiers/{tierId}/commission:
    patch:
      operationId: ClubAdminCommissionController.setTierCommission
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminSetTierCommissionDto'
      responses:
        '200':
          description: ''
      summary: 'Platform admin: set/clear the per-tier club subscription commission.'
      tags: &ref_204
        - 'Admin: Club Commission'
  /v2/clubs/{clubId}/commission:
    patch:
      operationId: ClubAdminCommissionController.setClubCommission
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminSetClubCommissionDto'
      responses:
        '200':
          description: ''
      summary: >-
        Platform admin: set/clear the club-wide subscription commission
        override.
      tags: *ref_204
  /v2/clubs/{clubId}/tiers/{tierId}/commission/breakdown:
    get:
      operationId: ClubAdminCommissionController.getTierCommissionBreakdown
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Platform admin: resolved commission split for a saved tier, plus the raw
        tier/club overrides.
      tags: *ref_204
  /v2/clubs/{clubId}/kyc:
    get:
      operationId: ClubKycController.get
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_205
        - bearer: []
      summary: >-
        The club's KYC record, or null if it has never started one. Includes
        document URLs and bank details — the club owns this data.
      tags: &ref_206
        - 'Club: KYC'
    post:
      operationId: ClubKycController.upsert
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                identityProof:
                  type: string
                  format: binary
                  description: Authorised signatory's Aadhaar / identity document
                panCard:
                  type: string
                  format: binary
                  description: Club or owner PAN (required to submit)
                legalName:
                  type: string
                  description: Legal name exactly as it appears on PAN
                dateOfBirthOrIncorporation:
                  type: string
                  format: date
                panNumber:
                  type: string
                  description: 10-character PAN
                panConsent:
                  type: boolean
                  description: Consent to PAN verification
                addressProof:
                  type: string
                  format: binary
                  description: Club address proof
                cancelledCheque:
                  type: string
                  format: binary
                  description: Cancelled cheque (bank proof — shown under Settlement)
                bankAccountDetails:
                  type: string
                  description: >-
                    JSON string: { "accountHolderName", "accountNumber",
                    "ifscCode", "bankName", "branchName"? }. Bracket-notation
                    fields (bankAccountDetails[ifscCode]) are also accepted.
                contactEmail:
                  type: string
                  description: Authorised signatory contact email
                contactPhone:
                  type: string
                  description: Authorised signatory contact phone
      responses:
        '201':
          description: ''
      security: *ref_205
      summary: >-
        Create or update the club KYC. Only documents actually attached to this
        request are overwritten. Locked while UNDER_REVIEW / APPROVED.
      tags: *ref_206
    patch:
      operationId: ClubKycController.patch
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                identityProof:
                  type: string
                  format: binary
                  description: Authorised signatory's Aadhaar / identity document
                panCard:
                  type: string
                  format: binary
                  description: Club or owner PAN (required to submit)
                legalName:
                  type: string
                  description: Legal name exactly as it appears on PAN
                dateOfBirthOrIncorporation:
                  type: string
                  format: date
                panNumber:
                  type: string
                  description: 10-character PAN
                panConsent:
                  type: boolean
                  description: Consent to PAN verification
                addressProof:
                  type: string
                  format: binary
                  description: Club address proof
                cancelledCheque:
                  type: string
                  format: binary
                  description: Cancelled cheque (bank proof — shown under Settlement)
                bankAccountDetails:
                  type: string
                  description: >-
                    JSON string: { "accountHolderName", "accountNumber",
                    "ifscCode", "bankName", "branchName"? }. Bracket-notation
                    fields (bankAccountDetails[ifscCode]) are also accepted.
                contactEmail:
                  type: string
                  description: Authorised signatory contact email
                contactPhone:
                  type: string
                  description: Authorised signatory contact phone
      responses:
        '200':
          description: ''
      security: *ref_205
      summary: >-
        Partial update of the club KYC — identical semantics to POST (nothing is
        cleared unless a replacement is supplied).
      tags: *ref_206
  /v2/clubs/{clubId}/kyc/verify-pan:
    post:
      operationId: ClubKycController.verifyPan
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_205
      summary: >-
        Verify the saved club legal name, PAN and date through Sandbox and
        persist the evidence.
      tags: *ref_206
  /v2/clubs/{clubId}/kyc/verify-bank:
    post:
      operationId: ClubKycController.verifyBank
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyClubKycBankDto'
      responses:
        '200':
          description: ''
      security: *ref_205
      summary: >-
        Penny-drop verify the club settlement account and store the result on
        the KYC record. Returns 200 for BOTH outcomes: { verified: true,
        accountHolderName, bankVerification, kyc } or { verified: false, reason,
        message }. Locked while UNDER_REVIEW / APPROVED (CLUB_KYC_LOCKED). If a
        settlement account is already saved, the submitted account must be that
        same account (CLUB_KYC_BANK_ACCOUNT_MISMATCH) — otherwise a club could
        verify one account and settle to another.
      tags: *ref_206
  /v2/clubs/{clubId}/kyc/submit:
    post:
      operationId: ClubKycController.submit
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_205
      summary: >-
        Submit the club KYC for admin review. Requires panCard, a bank account
        (number + IFSC) and a successful penny-drop verification of that
        account.
      tags: *ref_206
  /v2/admin/club-kyc:
    get:
      operationId: AdminClubKycController.list
      parameters:
        - name: state
          required: false
          in: query
          schema:
            enum:
              - PENDING
              - UNDER_REVIEW
              - APPROVED
              - REJECTED
              - RESUBMIT
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_207
        - bearer: []
      summary: >-
        List club KYC submissions awaiting review. Defaults to UNDER_REVIEW;
        supports ?state= and ?page=&limit=.
      tags: &ref_208
        - 'Admin: Club KYC'
  /v2/admin/club-kyc/by-club/{clubId}:
    get:
      operationId: AdminClubKycController.detailByClub
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_207
      summary: >-
        Full club KYC detail for a given club, looked up by clubId rather than
        kycId. Returns null (not 404) when the club has never started a KYC
        submission — powers the combined onboarding+KYC review page.
      tags: *ref_208
  /v2/admin/club-kyc/{kycId}:
    get:
      operationId: AdminClubKycController.detail
      parameters:
        - name: kycId
          required: true
          in: path
          description: Club KYC id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_207
      summary: >-
        Full club KYC detail — includes the document URLs and full bank account
        details so the reviewer can actually inspect the submission.
      tags: *ref_208
  /v2/admin/club-kyc/{kycId}/approve:
    post:
      operationId: AdminClubKycController.approve
      parameters:
        - name: kycId
          required: true
          in: path
          description: Club KYC id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_207
      summary: Approve an UNDER_REVIEW club KYC.
      tags: *ref_208
  /v2/admin/club-kyc/{kycId}/reject:
    post:
      operationId: AdminClubKycController.reject
      parameters:
        - name: kycId
          required: true
          in: path
          description: Club KYC id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewClubKycDto'
      responses:
        '201':
          description: ''
      security: *ref_207
      summary: >-
        Reject an UNDER_REVIEW club KYC. Reason required (10-500 chars), shown
        verbatim to the club.
      tags: *ref_208
  /v2/admin/club-kyc/{kycId}/request-resubmission:
    post:
      operationId: AdminClubKycController.requestResubmission
      parameters:
        - name: kycId
          required: true
          in: path
          description: Club KYC id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewClubKycDto'
      responses:
        '201':
          description: ''
      security: *ref_207
      summary: >-
        Send an UNDER_REVIEW club KYC back for changes (RESUBMIT) without a hard
        rejection. Reason required (10-500 chars).
      tags: *ref_208
  /v2/clubs/{clubId}/rc-grants:
    post:
      operationId: ClubRcGrantsController.create
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubRcGrantRequestDto'
      responses:
        '201':
          description: ''
      security: &ref_209
        - bearer: []
      summary: >-
        Request an RC Coin grant. At most one request may be open at a time (409
        CLUB_RC_GRANT_REQUEST_ALREADY_OPEN). Granted RC is a DEBT measured in
        COINS: the club owes back the number of RC it took, and the cash is cut
        from a future payout at whatever the RC rate is AT THAT TIME.
      tags: &ref_210
        - 'Club: RC Grants'
    get:
      operationId: ClubRcGrantsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - REQUESTED
              - APPROVED
              - REJECTED
              - CANCELLED
        - name: challengeId
          required: false
          in: query
          description: Only the grant for this challenge
          schema:
            type: string
        - name: page
          required: false
          in: query
          description: Page (1-based)
          schema:
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Page size (max 100)
          schema:
            example: 25
            type: number
      responses:
        '200':
          description: ''
      security: *ref_209
      summary: >-
        This club's RC grant requests, newest first, plus the club's outstanding
        granted-RC debt in COINS (`outstandingRc`) and its rupee value at the
        CURRENT rate (`estimatedFiatAtCurrentRate` + `rateUsed`, both null when
        the platform rate is unreadable — never a guessed zero).
      tags: *ref_210
  /v2/clubs/{clubId}/rc-grants/{id}/cancel:
    post:
      operationId: ClubRcGrantsController.cancel
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: id
          required: true
          in: path
          description: RC grant request id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_209
      summary: >-
        Withdraw an RC grant request that is still awaiting review. An APPROVED
        grant cannot be cancelled — the coins are already in the wallet and the
        debt already exists.
      tags: *ref_210
  /v2/admin/club-rc-grants:
    get:
      operationId: AdminClubRcGrantsController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - REQUESTED
              - APPROVED
              - REJECTED
              - CANCELLED
        - name: challengeId
          required: false
          in: query
          description: Only the grant for this challenge
          schema:
            type: string
        - name: page
          required: false
          in: query
          description: Page (1-based)
          schema:
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Page size (max 100)
          schema:
            example: 25
            type: number
        - name: clubId
          required: false
          in: query
          description: Restrict the queue to one club.
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_211
        - bearer: []
      summary: >-
        RC grant queue, OLDEST FIRST (longest-waiting club at the top). Filter
        with ?status=REQUESTED|APPROVED|REJECTED|CANCELLED, ?clubId=, ?page=,
        ?limit=.
      tags: &ref_212
        - 'Admin: Club RC Grants'
  /v2/admin/club-rc-grants/{id}:
    get:
      operationId: AdminClubRcGrantsController.detail
      parameters:
        - name: id
          required: true
          in: path
          description: RC grant request id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_211
      summary: >-
        One RC grant request, plus the requesting club's total outstanding
        granted-RC debt in COINS (with a rupee estimate at today's rate) — the
        number a reviewer needs before handing over more.
      tags: *ref_212
  /v2/admin/club-rc-grants/{id}/approve:
    post:
      operationId: AdminClubRcGrantsController.approve
      parameters:
        - name: id
          required: true
          in: path
          description: RC grant request id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApproveClubRcGrantDto'
      responses:
        '200':
          description: ''
      security: *ref_211
      summary: >-
        Approve an RC grant. Omit approvedRc to grant the full ask; supply a
        smaller number to trim it (never larger). In one transaction this
        records the granted COINS as the debt, notes the current platform rate
        as history only, and credits the club creator wallet. The rupee amount
        is NOT fixed here — it is computed at payout time from the live rate.
        Idempotent — approving twice credits once.
      tags: *ref_212
  /v2/admin/club-rc-grants/{id}/reject:
    post:
      operationId: AdminClubRcGrantsController.reject
      parameters:
        - name: id
          required: true
          in: path
          description: RC grant request id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RejectClubRcGrantDto'
      responses:
        '200':
          description: ''
      security: *ref_211
      summary: >-
        Reject an RC grant request. Reason required (10-1000 chars), shown
        verbatim to the club. Credits nothing and creates no debt.
      tags: *ref_212
  /v2/clubs/{clubId}/settlements:
    get:
      operationId: ClubAdminSettlementsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_213
        - bearer: []
      summary: >-
        The club's own settlement history — only rows whose PAYEE is this club,
        never organizer-paid rows that merely carry the club as an attribution
        tag.
      tags: &ref_214
        - 'Club: Settlements & Payouts'
  /v2/clubs/{clubId}/settlements/payout-requests:
    get:
      operationId: ClubAdminSettlementsController.listPayoutRequests
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_213
      summary: The club's own payout requests.
      tags: *ref_214
  /v2/clubs/{clubId}/settlements/{settlementId}:
    get:
      operationId: ClubAdminSettlementsController.detail
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: settlementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_213
      summary: >-
        One of the club’s own settlements, including `payableAmount` and the
        itemised `grantRecovery` line (rupees withheld + RC extinguished + the
        LIVE rate used) that explains the gap between `netAmount` and what is
        paid. 404s (SETTLEMENT_NOT_FOUND) for another club’s or an
        organizer-paid settlement.
      tags: *ref_214
  /v2/clubs/{clubId}/settlements/{settlementId}/payout-request:
    post:
      operationId: ClubAdminSettlementsController.requestPayout
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: settlementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_213
      summary: >-
        Request payout of an ELIGIBLE club settlement. Coded conflicts:
        PAYOUT_ALREADY_REQUESTED, PAYOUT_ALREADY_PAID, SETTLEMENT_NOT_ELIGIBLE,
        CLUB_PAYOUT_FROZEN, SETTLEMENT_NOT_CLUB_PAYEE.
      tags: *ref_214
  /v2/clubs/{clubId}/settlements/payout-requests/{id}/cancel:
    post:
      operationId: ClubAdminSettlementsController.cancelPayoutRequest
      parameters:
        - name: clubId
          required: true
          in: path
          description: Club id
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_213
      summary: Cancel an open club payout request (reason required).
      tags: *ref_214
  /v2/wallets/creator/{ownerType}/{ownerId}:
    get:
      operationId: CreatorWalletsController.getBalance
      parameters:
        - &ref_215
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: ownerType
          required: true
          in: path
          schema:
            type: string
        - name: ownerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_216
        - Creator Wallets
  /v2/wallets/creator/{ownerType}/{ownerId}/transactions:
    get:
      operationId: CreatorWalletsController.getTransactions
      parameters:
        - *ref_215
        - name: ownerType
          required: true
          in: path
          schema:
            type: string
        - name: ownerId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          schema:
            example: 20
            type: number
        - name: type
          required: false
          in: query
          schema:
            example: credit
            type: string
        - name: source
          required: false
          in: query
          schema:
            example: prize_reservation
            type: string
        - name: search
          required: false
          in: query
          description: Search description, source, or source reference
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_216
  /v2/leaderboards:
    get:
      operationId: LeaderboardsController.listByContext
      parameters:
        - name: context
          required: true
          in: query
          schema:
            type: string
        - name: contextId
          required: true
          in: query
          schema:
            type: string
        - name: metric
          required: true
          in: query
          schema:
            type: string
        - name: scope
          required: true
          in: query
          schema:
            type: string
        - name: scopeKey
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_217
        - Leaderboards
  /v2/leaderboards/{id}/entries:
    get:
      operationId: LeaderboardsController.getEntries
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_217
  /v2/leaderboards/{id}/entries/for-me:
    get:
      operationId: LeaderboardsController.getEntriesForViewer
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_217
  /v2/leaderboards/{id}/user/{userId}:
    get:
      operationId: LeaderboardsController.userRank
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_217
  /v2/leaderboards/{id}/entries/filtered:
    get:
      operationId: LeaderboardsController.getFiltered
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: scope
          required: true
          in: query
          schema:
            type: string
        - name: scopeKey
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_217
  /v2/leaderboards/admin/ingest:
    post:
      operationId: LeaderboardsController.adminIngest
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_217
  /v2/live-leaderboards:
    get:
      operationId: LiveLeaderboardController.snapshot
      parameters:
        - name: context
          required: true
          in: query
          schema:
            type: string
        - name: contextId
          required: true
          in: query
          schema:
            type: string
        - name: metric
          required: true
          in: query
          schema:
            type: string
        - name: scope
          required: true
          in: query
          schema:
            type: string
        - name: scopeKey
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Live Leaderboard'
  /v2/admin/anti-cheat/governance:
    get:
      operationId: AdminAntiCheatController.governanceSnapshot
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_218
        - 'Admin: Anti-Cheat'
  /v2/admin/anti-cheat/governance/rules/{ruleKey}:
    patch:
      operationId: AdminAntiCheatController.updateRule
      parameters:
        - name: ruleKey
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/governance/mode:
    patch:
      operationId: AdminAntiCheatController.updateMode
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/queue:
    get:
      operationId: AdminAntiCheatController.queue
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: severity
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/flags/{flagId}:
    get:
      operationId: AdminAntiCheatController.getFlag
      parameters:
        - name: flagId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/flags/{flagId}/responses:
    get:
      operationId: AdminAntiCheatController.listFlagResponses
      parameters:
        - name: flagId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/flags/{flagId}/decision:
    post:
      operationId: AdminAntiCheatController.decide
      parameters:
        - name: flagId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDecisionDto'
      responses:
        '201':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/appeals:
    get:
      operationId: AdminAntiCheatController.appeals
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/appeals/{appealId}:
    get:
      operationId: AdminAntiCheatController.getAppeal
      parameters:
        - name: appealId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_218
  /v2/admin/anti-cheat/appeals/{appealId}/decision:
    post:
      operationId: AdminAntiCheatController.decideAppeal
      parameters:
        - name: appealId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppealDecisionDto'
      responses:
        '201':
          description: ''
      tags: *ref_218
  /v2/anti-cheat/live-signals:
    post:
      operationId: UserAntiCheatController.recordLiveSignals
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostLiveSignalsDto'
      responses:
        '201':
          description: ''
      tags: &ref_219
        - Anti-Cheat
  /v2/anti-cheat/my-flags:
    get:
      operationId: UserAntiCheatController.myFlags
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-appeals:
    get:
      operationId: UserAntiCheatController.myAppeals
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-flags/by-activity/{activityId}:
    get:
      operationId: UserAntiCheatController.getFlagByActivity
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-flags/{flagId}:
    get:
      operationId: UserAntiCheatController.getFlag
      parameters:
        - name: flagId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-flags/{flagId}/appeal:
    post:
      operationId: UserAntiCheatController.appeal
      parameters:
        - name: flagId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitAppealDto'
      responses:
        '201':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-appeals/{appealId}:
    get:
      operationId: UserAntiCheatController.getMyAppeal
      parameters:
        - name: appealId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-flags/{flagId}/respond:
    post:
      operationId: UserAntiCheatController.submitInfoResponse
      parameters:
        - name: flagId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitFlagInfoResponseDto'
      responses:
        '201':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-flags/{flagId}/responses:
    get:
      operationId: UserAntiCheatController.listMyResponses
      parameters:
        - name: flagId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/my-status:
    get:
      operationId: UserAntiCheatController.myStatus
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_219
  /v2/anti-cheat/dual-recording/{activityId}/submit:
    post:
      operationId: DualRecordingController.submit
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Upload the secondary-device samples that back the DTW match for a
        RANKED-policy activity.
      tags: &ref_220
        - 'User: Dual Recording'
  /v2/anti-cheat/dual-recording/{activityId}/evaluate:
    post:
      operationId: DualRecordingController.evaluate
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Run DTW on the uploaded secondary samples.
      tags: *ref_220
  /v2/anti-cheat/dual-recording/{activityId}/status:
    get:
      operationId: DualRecordingController.status
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Read the DTW verdict + score for the activity.
      tags: *ref_220
  /v2/organizer/events/{eventId}/check-in/scan:
    post:
      operationId: OrganizerCheckInController.scan
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScanQrDto'
      responses:
        '201':
          description: ''
      tags: &ref_221
        - 'Organizer: Check-in + Bib'
  /v2/organizer/events/{eventId}/check-in/scan-by-bib:
    post:
      operationId: OrganizerCheckInController.scanByBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/check-in/search:
    get:
      operationId: OrganizerCheckInController.search
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: bib
          required: true
          in: query
          schema:
            type: string
        - name: name
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/check-in/status:
    get:
      operationId: OrganizerCheckInController.status
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/check-in/summary:
    get:
      operationId: OrganizerCheckInController.summary
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/check-in/{checkinId}/undo:
    post:
      operationId: OrganizerCheckInController.undoCheckin
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: checkinId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/check-in/sync-batch:
    post:
      operationId: OrganizerCheckInController.syncBatch
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SyncBatchCheckInDto'
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/bibs/assign:
    post:
      operationId: OrganizerCheckInController.bulkAssignBibs
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkAssignBibsDto'
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/bibs/auto-assign:
    post:
      operationId: OrganizerCheckInController.autoAssignBibs
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AutoAssignBibsDto'
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/waves:
    get:
      operationId: OrganizerCheckInController.listWaves
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/waves/capacity:
    get:
      operationId: OrganizerCheckInController.waveCapacity
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/waves/{slotId}/open:
    post:
      operationId: OrganizerCheckInController.openWave
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/waves/{slotId}/start:
    post:
      operationId: OrganizerCheckInController.startWave
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/waves/{slotId}/close:
    post:
      operationId: OrganizerCheckInController.closeWave
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_221
  /v2/organizer/events/{eventId}/participants/{participantId}/bib:
    patch:
      operationId: OrganizerCheckInController.updateBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateBibDto'
      responses:
        '200':
          description: ''
      tags: *ref_221
  /v2/users/{userId}/event-participations/{participationId}/qr:
    get:
      operationId: UserCheckInController.issueQrs
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'User: Check-in QR'
  /v2/organizers/events/{eventId}/race-day-dashboard:
    get:
      operationId: RaceDayDashboardController.getDashboard
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: noMovementThresholdMin
          required: false
          in: query
          description: No-movement alert threshold in minutes. Defaults to 5 per PRD §36.1.
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_222
        - bearer: []
      summary: Get race-day dashboard snapshot (PRD §36.1 single pane of glass).
      tags: &ref_223
        - Race Day Dashboard
  /v2/organizers/events/{eventId}/race-day-dashboard/check-in-rate:
    get:
      operationId: RaceDayDashboardController.checkInRateOverTime
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: bucketMinutes
          required: false
          in: query
          description: Bucket size in minutes (1-60, default 5).
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_222
      summary: >-
        Check-in rate over time series — bucketed CHECKED_IN counts (PRD §43.5
        G-43-14).
      tags: *ref_223
  /v2/organizers/events/{eventId}/race-day-dashboard/progress-buckets:
    get:
      operationId: RaceDayDashboardController.progressBuckets
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: kmBucketSize
          required: false
          in: query
          description: Distance bucket size in km (1-20, default 5).
          schema:
            type: string
        - name: lateCutoffMinutes
          required: false
          in: query
          description: >-
            Minutes after wave start where a finisher is considered late
            (default 240 = 4h).
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_222
      summary: >-
        Race-day deeper analytics: per-wave progress, km histogram, late
        finishers (PRD §36.1 / §36.4 R8).
      tags: *ref_223
  /v2/organizers/events/{eventId}/race-day-dashboard/volunteer-performance:
    get:
      operationId: RaceDayDashboardController.volunteerPerformance
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_222
      summary: Per-volunteer scan performance rollup (PRD §43.5 G-43-16).
      tags: *ref_223
  /v2/organizers/{organizerId}/race-day-aggregate/today:
    get:
      operationId: RaceDayAggregateController.today
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: hoursBack
          required: false
          in: query
          description: Lookback window hours (1-72, default 24).
          schema:
            type: string
        - name: hoursForward
          required: false
          in: query
          description: Lookahead window hours (1-72, default 24).
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Per-event headline counts + organizer-wide totals for events within ±24h
        (PRD §44 R9).
      tags:
        - Race Day Aggregate
  /v2/organizer/events/{eventId}/race-day/mass-notify/segments:
    get:
      operationId: RaceDayMassNotifyController.segments
      parameters: []
      responses:
        '200':
          description: ''
      summary: List supported recipient segments
      tags: &ref_224
        - 'Organizer: Race-day mass notify'
  /v2/organizer/events/{eventId}/race-day/mass-notify/dry-run:
    get:
      operationId: RaceDayMassNotifyController.dryRun
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: segment
          required: true
          in: query
          schema:
            type: string
        - name: waveSlotId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Count recipients matching the segment without sending — used by OM
        confirm dialog before send.
      tags: *ref_224
  /v2/organizer/events/{eventId}/race-day/mass-notify/send:
    post:
      operationId: RaceDayMassNotifyController.send
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Record + dispatch a race-day mass notification. Returns dispatched=false
        + reason=PROVIDER_NOT_CONFIGURED when no provider is configured (audit
        row still written for forensic intent).
      tags: *ref_224
  /v2/organizer/race-day/validation-queue/counts:
    get:
      operationId: RaceDayValidationQueueController.counts
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Validation queue counts for the cockpit tile: open, underReview,
        recent24hResolved, recent24hDismissed.
      tags: &ref_225
        - 'Organizer: Race-day validation queue'
  /v2/organizer/race-day/validation-queue/recent:
    get:
      operationId: RaceDayValidationQueueController.recent
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Most recent OPEN/UNDER_REVIEW flags for the cockpit drawer (default 20,
        max 100).
      tags: *ref_225
  /v2/organizer/events/{eventId}/race-day/announcements/templates:
    get:
      operationId: RaceDayAnnouncementsController.templates
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        List the 8 canonical announcement templates (wave opening / starting /
        route change / weather / medical / sponsor / results / custom).
      tags: &ref_226
        - 'Organizer: Race-day announcements'
  /v2/organizer/events/{eventId}/race-day/announcements/preview:
    post:
      operationId: RaceDayAnnouncementsController.preview
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Persist an announcement as PREVIEWED (audited). Cockpit shows the
        operator the rendered body before they click Send.
      tags: *ref_226
  /v2/organizer/events/{eventId}/race-day/announcements/{id}/send:
    post:
      operationId: RaceDayAnnouncementsController.send
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Dispatch the announcement. Text broadcast unconditional; audio attempted
        only if SARVAM_API_KEY (or other audio provider) configured. Returns
        explicit `audioReason: AUDIO_PROVIDER_NOT_CONFIGURED` when audio is
        honest-degraded.
      tags: *ref_226
  /v2/organizer/events/{eventId}/race-day/announcements/{id}/mark-failed:
    post:
      operationId: RaceDayAnnouncementsController.markFailed
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Mark an announcement as FAILED with audited reason. Used by
        post-dispatch error handling.
      tags: *ref_226
  /v2/organizer/events/{eventId}/race-day/announcements:
    get:
      operationId: RaceDayAnnouncementsController.list
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List recent announcements for the cockpit history drawer.
      tags: *ref_226
  /v2/hybrid-race/{eventId}/start:
    post:
      operationId: HybridRaceController.start
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartHybridRaceDto'
      responses:
        '201':
          description: ''
      tags: &ref_227
        - Hybrid Race (User)
  /v2/hybrid-race/{eventId}/checkpoint:
    post:
      operationId: HybridRaceController.checkpoint
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitCheckpointsDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/live-position:
    post:
      operationId: HybridRaceController.livePosition
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PushLivePositionDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
    get:
      operationId: HybridRaceController.getLivePosition
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: resultId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/finish:
    post:
      operationId: HybridRaceController.finish
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FinishHybridRaceDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/near-pace:
    get:
      operationId: HybridRaceController.nearPace
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: window
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/leaderboard:
    get:
      operationId: HybridRaceController.leaderboard
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: eligibility
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/local-routes/suggest:
    post:
      operationId: HybridRaceController.suggestRoutes
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SuggestLocalRouteQueryDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/photo-check/init:
    post:
      operationId: HybridRaceController.initPhotoCheck
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InitPhotoCheckQueryDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/photo-check/{photoCheckId}/submit:
    post:
      operationId: HybridRaceController.submitPhotoCheck
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: photoCheckId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitPhotoCheckDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/photo-check/{photoCheckId}/skip:
    post:
      operationId: HybridRaceController.skipPhotoCheck
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: photoCheckId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SkipPhotoCheckDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/photo-check/{photoCheckId}/appeal:
    post:
      operationId: HybridRaceController.appealPhotoCheck
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: photoCheckId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppealPhotoCheckDto'
      responses:
        '201':
          description: ''
      tags: *ref_227
  /v2/hybrid-race/{eventId}/photo-check/state:
    get:
      operationId: HybridRaceController.photoCheckState
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_227
  /v2/organizer/events/{eventId}/hybrid-race/ensure:
    post:
      operationId: OrganizerHybridRaceController.ensure
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_228
        - 'Organizer: Hybrid Race Ops'
  /v2/organizer/events/{eventId}/hybrid-race/config:
    get:
      operationId: OrganizerHybridRaceController.getConfig
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_228
    patch:
      operationId: OrganizerHybridRaceController.updateConfig
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateHybridConfigDto'
      responses:
        '200':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/participants:
    get:
      operationId: OrganizerHybridRaceController.listParticipants
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: q
          required: false
          in: query
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - IN_PROGRESS
              - FINISHED
              - DNF
        - name: verificationState
          required: false
          in: query
          schema:
            type: string
            enum:
              - PROVISIONAL
              - VERIFIED
              - REJECTED
              - UNDER_REVIEW
        - name: validationTier
          required: false
          in: query
          schema:
            type: string
            enum:
              - STANDARD
              - STRICT
              - ELITE
        - name: page
          required: false
          in: query
          schema:
            minimum: 1
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          schema:
            minimum: 1
            maximum: 100
            default: 25
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/dashboard:
    get:
      operationId: OrganizerHybridRaceController.dashboard
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/cockpit:
    get:
      operationId: OrganizerHybridRaceController.getCockpit
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/results/{resultId}/flag-for-review:
    post:
      operationId: OrganizerHybridRaceController.flagForReview
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FlagResultForReviewDto'
      responses:
        '201':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/results/{resultId}/resolve-review:
    post:
      operationId: OrganizerHybridRaceController.resolveReview
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolveReviewDto'
      responses:
        '201':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/physical-results/upload:
    post:
      operationId: OrganizerHybridRaceController.uploadResults
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UploadPhysicalResultsDto'
      responses:
        '201':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/results/recompute-ranks:
    post:
      operationId: OrganizerHybridRaceController.recompute
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_228
  /v2/organizer/events/{eventId}/hybrid-race/results/{resultId}/merch-shipment:
    patch:
      operationId: OrganizerHybridRaceController.updateMerch
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMerchShipmentDto'
      responses:
        '200':
          description: ''
      tags: *ref_228
  /v2/race/results/{resultId}/public:
    get:
      operationId: PublicHybridRaceController.getPublic
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_229
        - Hybrid Race (Public)
  /v2/race/results/this-week/list:
    get:
      operationId: PublicHybridRaceController.listThisWeek
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_229
  /v2/race/results/{resultId}/certificate:
    get:
      operationId: PublicHybridRaceController.getCertificate
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_229
  /v2/race/results/{resultId}/certificate.pdf:
    get:
      operationId: PublicHybridRaceController.getCertificatePdf
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_229
  /v2/race/results/{resultId}/verify:
    get:
      operationId: PublicHybridRaceController.verifyCertificate
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
        - name: h
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_229
  /v2/race/results/{resultId}/finisher-card.svg:
    get:
      operationId: PublicHybridRaceController.getFinisherCard
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_229
  /v2/hybrid-race/results/{resultId}/cheer:
    post:
      operationId: RaceDayController.sendCheer
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_230
        - Race-day companion
  /v2/hybrid-race/results/{resultId}/cheers:
    get:
      operationId: RaceDayController.listCheers
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_230
  /v2/hybrid-race/races/{hybridRaceId}/chat:
    get:
      operationId: RaceDayController.listChat
      parameters:
        - name: hybridRaceId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_230
  /v2/events/{eventId}/certificate/me:
    get:
      operationId: EventCertificateController.myCertificate
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_231
        - 'Events: Certificate'
  /v2/events/{eventId}/finisher-card/{userId}.svg:
    get:
      operationId: EventCertificateController.finisherCardForUser
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_231
  /v2/admin/hybrid-race/edge-cases/flagged:
    get:
      operationId: AdminEdgeCaseController.listFlagged
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List edge-case verdicts flagged for admin review. Paginated. Cross-link
        §71 G-71-9 review queue.
      tags: &ref_232
        - 'Admin: Hybrid Race Edge Cases'
  /v2/admin/hybrid-race/edge-cases/result/{resultId}:
    get:
      operationId: AdminEdgeCaseController.recentForResult
      parameters:
        - name: resultId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Recent edge-case verdicts for a single hybrid-race result. Used by admin
        result-detail UI to show timeline of observations.
      tags: *ref_232
  /v2/security/race-signing/session:
    post:
      operationId: RaceSigningController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSigningSessionDto'
      responses:
        '201':
          description: ''
      tags: &ref_233
        - Race Signing
  /v2/security/race-signing/session/{signingSessionId}:
    delete:
      operationId: RaceSigningController.revoke
      parameters:
        - name: signingSessionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_233
  /v2/admin/reports:
    get:
      operationId: AdminOpsAdminController.listReports
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: targetType
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_234
        - 'Admin: Operations'
  /v2/admin/reports/appeals:
    get:
      operationId: AdminOpsAdminController.listAppeals
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: level
          required: true
          in: query
          schema:
            type: string
        - name: reportId
          required: true
          in: query
          schema:
            type: string
        - name: appellantUserId
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/reports/appeals/bulk-decide:
    post:
      operationId: AdminOpsAdminController.bulkDecideAppeals
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/reports/appeals/{appealId}:
    get:
      operationId: AdminOpsAdminController.getAppeal
      parameters:
        - name: appealId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/reports/appeals/{appealId}/decide:
    post:
      operationId: AdminOpsAdminController.decideAppeal
      parameters:
        - name: appealId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DecideReportAppealDto'
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/reports/{id}:
    get:
      operationId: AdminOpsAdminController.getReport
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/reports/{id}/resolve:
    post:
      operationId: AdminOpsAdminController.resolveReport
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/disputes:
    get:
      operationId: AdminOpsAdminController.listDisputes
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/disputes/{id}:
    get:
      operationId: AdminOpsAdminController.getDispute
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/disputes/{id}/resolve:
    post:
      operationId: AdminOpsAdminController.resolveDispute
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/disputes/{id}/evidence:
    post:
      operationId: AdminOpsAdminController.adminAttachDisputeEvidence
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
    get:
      operationId: AdminOpsAdminController.adminListDisputeEvidence
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/disputes/{id}/messages:
    post:
      operationId: AdminOpsAdminController.adminPostDisputeMessage
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
    get:
      operationId: AdminOpsAdminController.adminListDisputeMessages
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/chargebacks:
    get:
      operationId: AdminOpsAdminController.listChargebacks
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/chargebacks/{id}/resolve:
    post:
      operationId: AdminOpsAdminController.resolveChargeback
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/feature-flags:
    get:
      operationId: AdminOpsAdminController.listFlags
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/feature-flags/{key}:
    put:
      operationId: AdminOpsAdminController.upsertFlag
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/feature-flags/{key}/guarded:
    post:
      operationId: AdminOpsAdminController.upsertFlagGuarded
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/feature-flags/{key}/audience:
    put:
      operationId: AdminOpsAdminController.updateFlagAudience
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/feature-flags/{key}/audience/preview:
    post:
      operationId: AdminOpsAdminController.previewFlagAudience
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/ab-tests:
    get:
      operationId: AdminOpsAdminController.listAbTests
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/ab-tests/{key}:
    put:
      operationId: AdminOpsAdminController.upsertAbTest
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/suspend:
    post:
      operationId: AdminOpsAdminController.suspend
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/unsuspend:
    post:
      operationId: AdminOpsAdminController.unsuspend
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/password-reset:
    post:
      operationId: AdminOpsAdminController.passwordReset
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/rc-adjust:
    post:
      operationId: AdminOpsAdminController.rcAdjust
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/restrict:
    post:
      operationId: AdminOpsAdminController.restrict
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/restrictions:
    get:
      operationId: AdminOpsAdminController.listRestrictions
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/restrictions/history:
    get:
      operationId: AdminOpsAdminController.restrictionHistory
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/users/{id}/unrestrict:
    post:
      operationId: AdminOpsAdminController.unrestrict
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_234
  /v2/admin/moderation/warning-standings:
    get:
      operationId: AdminOpsAdminController.listWarningStandings
      parameters:
        - name: minTier
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/admin/moderation/report-strikes:
    get:
      operationId: AdminOpsAdminController.listReportStrikes
      parameters:
        - name: activeOnly
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_234
  /v2/ops/reports/mine:
    get:
      operationId: AdminOpsUserController.myReports
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_235
        - 'User: Report + Dispute + Flags'
  /v2/ops/reports/mine/check:
    get:
      operationId: AdminOpsUserController.myReportStatus
      parameters:
        - name: targetType
          required: true
          in: query
          schema:
            type: string
        - name: targetId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/reports/against-me:
    get:
      operationId: AdminOpsUserController.reportsAgainstMe
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/reports/mine/{reportId}/timeline:
    get:
      operationId: AdminOpsUserController.myReportTimeline
      parameters:
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/reports/against-me/{reportId}/timeline:
    get:
      operationId: AdminOpsUserController.affectedUserReportTimeline
      parameters:
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/reports/appeals/mine:
    get:
      operationId: AdminOpsUserController.myAppeals
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/reports:
    post:
      operationId: AdminOpsUserController.report
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateReportDto'
      responses:
        '201':
          description: ''
      tags: *ref_235
  /v2/ops/reports/{reportId}/appeal:
    post:
      operationId: AdminOpsUserController.submitAppeal
      parameters:
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitReportAppealDto'
      responses:
        '201':
          description: ''
      tags: *ref_235
  /v2/ops/reports/{reportId}/appeals/second-instance:
    post:
      operationId: AdminOpsUserController.submitSecondInstanceAppeal
      parameters:
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitReportAppealDto'
      responses:
        '201':
          description: ''
      tags: *ref_235
  /v2/ops/reports/appeals/{appealId}:
    get:
      operationId: AdminOpsUserController.getMyAppeal
      parameters:
        - name: appealId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/reports/{reportId}:
    get:
      operationId: AdminOpsUserController.getMyReport
      parameters:
        - name: reportId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/disputes:
    post:
      operationId: AdminOpsUserController.openDispute
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_235
  /v2/ops/disputes/{id}/evidence:
    post:
      operationId: AdminOpsUserController.attachDisputeEvidence
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_235
    get:
      operationId: AdminOpsUserController.listDisputeEvidence
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/disputes/{id}/messages:
    post:
      operationId: AdminOpsUserController.postDisputeMessage
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_235
    get:
      operationId: AdminOpsUserController.listDisputeMessages
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/feature-flags/{key}/evaluate:
    get:
      operationId: AdminOpsUserController.evaluateFlag
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/ops/ab-tests/{key}/assign:
    get:
      operationId: AdminOpsUserController.assignVariant
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_235
  /v2/admin/reward-pools:
    get:
      operationId: AdminRewardPoolsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_236
        - 'Admin: Reward Pools'
  /v2/admin/reward-pools/{id}/review:
    post:
      operationId: AdminRewardPoolsController.review
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_236
  /v2/admin/reward-pools/{id}/manually-fund:
    post:
      operationId: AdminRewardPoolsController.manuallyFund
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_236
  /v2/admin/reward-pools/{id}/refund:
    post:
      operationId: AdminRewardPoolsController.refund
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_236
  /v2/admin/verification/organizers:
    get:
      operationId: AdminVerificationController.listOrganizers
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: state
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_237
        - 'Admin: Verification'
  /v2/admin/verification/organizers/{id}:
    get:
      operationId: AdminVerificationController.organizerDetail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_237
  /v2/admin/verification/organizers/{id}/approve:
    post:
      operationId: AdminVerificationController.approveOrganizer
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_237
  /v2/admin/verification/organizers/{id}/reject:
    post:
      operationId: AdminVerificationController.rejectOrganizer
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DestructiveActionDto'
      responses:
        '201':
          description: ''
      tags: *ref_237
  /v2/admin/verification/organizers/{id}/eazr-tag:
    patch:
      operationId: AdminVerificationController.updateOrganizerEazrTag
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrganizerEazrTagDto'
      responses:
        '200':
          description: ''
      tags: *ref_237
  /v2/admin/verification/sponsors:
    get:
      operationId: AdminVerificationController.listSponsors
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: state
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_237
  /v2/admin/verification/sponsors/{brandId}:
    get:
      operationId: AdminVerificationController.sponsorDetail
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_237
  /v2/admin/verification/sponsors/{brandId}/vendor-results:
    get:
      operationId: AdminVerificationController.sponsorVendorResults
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_237
  /v2/admin/verification/sponsors/{brandId}/approve:
    post:
      operationId: AdminVerificationController.approveSponsor
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_237
  /v2/admin/verification/sponsors/{brandId}/reject:
    post:
      operationId: AdminVerificationController.rejectSponsor
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DestructiveActionDto'
      responses:
        '201':
          description: ''
      tags: *ref_237
  /v2/admin/verification/clubs:
    get:
      operationId: AdminVerificationController.listClubs
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: state
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_237
  /v2/admin/verification/clubs/{clubId}:
    get:
      operationId: AdminVerificationController.clubDetail
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_237
  /v2/admin/verification/clubs/{clubId}/approve:
    post:
      operationId: AdminVerificationController.approveClub
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_237
  /v2/admin/verification/clubs/{clubId}/reject:
    post:
      operationId: AdminVerificationController.rejectClub
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DestructiveActionDto'
      responses:
        '201':
          description: ''
      tags: *ref_237
  /v2/admin/chargebacks/defend:
    get:
      operationId: AdminChargebackDefendController.list
      parameters:
        - name: defendStatus
          required: false
          in: query
          schema:
            enum:
              - NEW
              - NEEDS_EVIDENCE
              - EVIDENCE_READY
              - SUBMITTED
              - WON
              - LOST
              - EXPIRED
              - CANCELLED
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
        - name: fromDate
          required: false
          in: query
          schema:
            type: string
        - name: toDate
          required: false
          in: query
          schema:
            type: string
        - name: eventId
          required: false
          in: query
          schema:
            type: string
        - name: organizerId
          required: false
          in: query
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_238
        - bearer: []
      summary: >-
        List chargebacks with defend-flow projection. Filters: defendStatus /
        search (gatewayCaseId) / fromDate / toDate. Paginated.
      tags: &ref_239
        - 'Admin: Chargeback defend flow'
  /v2/admin/chargebacks/defend/{chargebackId}:
    get:
      operationId: AdminChargebackDefendController.getDetail
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_238
      summary: >-
        Detail projection: includes evidence list + defense draft + reviewer
        fields. paymentId is unmasked here (admin scope).
      tags: *ref_239
  /v2/admin/chargebacks/defend/{chargebackId}/evidence:
    post:
      operationId: AdminChargebackDefendController.addEvidence
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddEvidenceDto'
      responses:
        '201':
          description: ''
      security: *ref_238
      summary: >-
        Add an evidence item. kind enum + (fileUrl absolute http(s) OR
        description) required.
      tags: *ref_239
  /v2/admin/chargebacks/defend/{chargebackId}/defense-draft:
    patch:
      operationId: AdminChargebackDefendController.saveDefenseDraft
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SaveDefenseDraftDto'
      responses:
        '200':
          description: ''
      security: *ref_238
      summary: >-
        Save defense draft (autosave-friendly). Caps at 4000 chars. Recomputes
        derived defendStatus.
      tags: *ref_239
  /v2/admin/chargebacks/defend/{chargebackId}/submit-defense:
    post:
      operationId: AdminChargebackDefendController.submitDefense
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_238
      summary: >-
        Submit defense packet. Requires ≥2 evidence items + ≥40-char draft.
        Honesty: gatewaySubmissionStatus is set to
        MANUAL_GATEWAY_UPLOAD_REQUIRED — no real Cashfree/Razorpay dispute API
        integrated yet.
      tags: *ref_239
  /v2/admin/chargebacks/defend/{chargebackId}/mark-won:
    post:
      operationId: AdminChargebackDefendController.markWon
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TerminalReasonDto'
      responses:
        '201':
          description: ''
      security: *ref_238
      summary: >-
        Mark a SUBMITTED chargeback as WON. Records resolvedByUserId +
        resolvedAt + resolutionReason.
      tags: *ref_239
  /v2/admin/chargebacks/defend/{chargebackId}/mark-lost:
    post:
      operationId: AdminChargebackDefendController.markLost
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TerminalReasonDto'
      responses:
        '201':
          description: ''
      security: *ref_238
      summary: >-
        Mark a SUBMITTED chargeback as LOST. Records resolvedByUserId +
        resolvedAt + resolutionReason.
      tags: *ref_239
  /v2/admin/chargebacks/defend/{chargebackId}/mark-expired:
    post:
      operationId: AdminChargebackDefendController.markExpired
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TerminalReasonDto'
      responses:
        '201':
          description: ''
      security: *ref_238
      summary: >-
        Mark a non-SUBMITTED chargeback as EXPIRED. Allowed when the gateway
        deadline has passed without submission.
      tags: *ref_239
  /v2/admin/chargebacks/defend/{chargebackId}/cancel:
    post:
      operationId: AdminChargebackDefendController.cancel
      parameters:
        - name: chargebackId
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TerminalReasonDto'
      responses:
        '201':
          description: ''
      security: *ref_238
      summary: >-
        Cancel a non-terminal chargeback (e.g. duplicate webhook, gateway
        dropped the case).
      tags: *ref_239
  /v2/admin/provider-readiness:
    get:
      operationId: ProviderReadinessController.snapshot
      parameters: []
      responses:
        '200':
          description: ''
      tags:
        - 'Admin: Provider Readiness'
  /v2/admin/enrichment/organizers/{id}/risk:
    get:
      operationId: AdminEnrichmentController.organizerRisk
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_240
        - 'Admin: Enrichment (Wave 6)'
  /v2/admin/enrichment/organizers/{id}/feedback:
    get:
      operationId: AdminEnrichmentController.organizerFeedback
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_240
  /v2/admin/enrichment/anti-cheat/peer-comparison/{activityId}:
    get:
      operationId: AdminEnrichmentController.peerComparison
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_240
  /v2/admin/enrichment/active-alerts:
    get:
      operationId: AdminEnrichmentController.activeAlerts
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_240
  /v2/admin/csat/summary:
    get:
      operationId: AdminCsatController.summary
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_241
        - 'Admin: CSAT (Wave 6 §63.4)'
  /v2/admin/csat/recent:
    get:
      operationId: AdminCsatController.recent
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_241
  /v2/admin/csat/by-ticket/{ticketId}:
    get:
      operationId: AdminCsatController.byTicket
      parameters:
        - name: ticketId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_241
  /v2/admin/csat:
    post:
      operationId: AdminCsatController.create
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_241
  /v2/admin/experiments:
    get:
      operationId: AdminExperimentsController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_242
        - 'Admin: Experiments (Wave 6 §64.2/§64.3)'
    post:
      operationId: AdminExperimentsController.create
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_242
  /v2/admin/experiments/{key}:
    get:
      operationId: AdminExperimentsController.getByKey
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_242
    patch:
      operationId: AdminExperimentsController.update
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_242
    delete:
      operationId: AdminExperimentsController.archive
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_242
  /v2/admin/experiments/{key}/results:
    get:
      operationId: AdminExperimentsController.results
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_242
  /v2/admin/experiments/significance:
    post:
      operationId: AdminExperimentsController.significance
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_242
  /v2/admin/kb-articles:
    get:
      operationId: AdminKbController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_243
        - bearer: []
      summary: List KB articles, optionally by status.
      tags: &ref_244
        - 'Admin: Knowledge Base'
    post:
      operationId: AdminKbController.create
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_243
      summary: Create a KB article (DRAFT).
      tags: *ref_244
  /v2/admin/kb-articles/{id}:
    get:
      operationId: AdminKbController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_243
      summary: Get a KB article by id.
      tags: *ref_244
    put:
      operationId: AdminKbController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_243
      summary: Update a KB article (bumps version).
      tags: *ref_244
  /v2/admin/kb-articles/{id}/publish:
    post:
      operationId: AdminKbController.publish
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_243
      summary: Publish a KB article.
      tags: *ref_244
  /v2/admin/kb-articles/{id}/archive:
    post:
      operationId: AdminKbController.archive
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_243
      summary: Archive a KB article.
      tags: *ref_244
  /v2/admin/rate-limits/blocked:
    get:
      operationId: AdminRateLimitsController.listBlockedIps
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_245
        - 'Admin: Rate limits'
  /v2/admin/rate-limits/unblock:
    post:
      operationId: AdminRateLimitsController.unblockIp
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UnblockIpDto'
      responses:
        '201':
          description: ''
      tags: *ref_245
  /v2/ops/community-guidelines:
    get:
      operationId: CommunityGuidelinesPublicController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_246
        - Community Guidelines (Public)
  /v2/ops/community-guidelines/{slug}:
    get:
      operationId: CommunityGuidelinesPublicController.getBySlug
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_246
  /v2/admin/community-guidelines:
    get:
      operationId: CommunityGuidelinesAdminController.list
      parameters:
        - name: isPublished
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_247
        - 'Admin: Community Guidelines'
    post:
      operationId: CommunityGuidelinesAdminController.create
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_247
  /v2/admin/community-guidelines/{id}:
    get:
      operationId: CommunityGuidelinesAdminController.getById
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_247
    patch:
      operationId: CommunityGuidelinesAdminController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_247
  /v2/admin/trust-export/dry-run:
    get:
      operationId: TrustExportAdminController.dryRun
      parameters:
        - name: since
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_248
        - 'Admin: Trust Export'
  /v2/admin/trust-export:
    post:
      operationId: TrustExportAdminController.runExport
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_248
  /v2/admin/trust-export/jsonl:
    post:
      operationId: TrustExportAdminController.runExportJsonl
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_248
  /v2/admin/rc/rules:
    get:
      operationId: AdminRcRulesController.listRules
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_249
        - 'Admin: RC Rules & Store'
  /v2/admin/rc/rules/{ruleKey}:
    put:
      operationId: AdminRcRulesController.upsertRule
      parameters:
        - name: ruleKey
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_249
  /v2/admin/rc/store-items:
    get:
      operationId: AdminRcRulesController.listStore
      parameters:
        - name: all
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_249
  /v2/admin/rc/store-items/{sku}:
    put:
      operationId: AdminRcRulesController.upsertStore
      parameters:
        - name: sku
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_249
  /v2/admin/rc/redemptions:
    get:
      operationId: AdminRcRulesController.listRedemptions
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_249
  /v2/admin/rc/redemptions/{id}/fulfill:
    post:
      operationId: AdminRcRulesController.fulfill
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_249
  /v2/admin/rc/redemptions/{id}/ship:
    post:
      operationId: AdminRcRulesController.ship
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_249
  /v2/admin/rc/redemptions/{id}/deliver:
    post:
      operationId: AdminRcRulesController.deliver
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_249
  /v2/admin/rc/redemptions/{id}/cancel:
    post:
      operationId: AdminRcRulesController.cancelRedemption
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_249
  /v2/admin/rc/redemptions/{id}/ship-via-shiprocket:
    post:
      operationId: AdminRcRulesController.shipViaShiprocket
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_249
  /v2/rc/store:
    get:
      operationId: UserRcStoreController.store
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_250
        - 'User: RC Store'
  /v2/rc/redemptions:
    get:
      operationId: UserRcStoreController.redemptions
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_250
  /v2/rc/daily-cap-state:
    get:
      operationId: UserRcStoreController.dailyCapState
      parameters:
        - name: eventId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_250
  /v2/rc/rules:
    get:
      operationId: UserRcStoreController.listRules
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_250
  /v2/rc/redeem/{sku}:
    post:
      operationId: UserRcStoreController.redeem
      parameters:
        - name: sku
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_250
  /v2/rc/redemptions/{id}/address:
    put:
      operationId: UserRcStoreController.captureRedemptionAddress
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_250
  /v2/rc/transactions:
    get:
      operationId: UserRcStoreController.transactions
      parameters:
        - name: type
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_250
  /v2/admin/metrics/north-star:
    get:
      operationId: AdminMetricsController.northStar
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_251
        - 'Admin: North-Star Metrics'
  /v2/admin/metrics/revenue-series:
    get:
      operationId: AdminMetricsController.revenue
      parameters:
        - name: days
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_251
  /v2/admin/payments:
    get:
      operationId: AdminPaymentsController.list
      parameters:
        - name: ledger
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: provider
          required: true
          in: query
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Admin: Payment Reconciliation'
  /v2/admin/webhook-events:
    get:
      operationId: AdminWebhookEventsController.list
      parameters:
        - name: provider
          required: true
          in: query
          schema:
            type: string
        - name: outcome
          required: true
          in: query
          schema:
            type: string
        - name: endpoint
          required: true
          in: query
          schema:
            type: string
        - name: externalOrderId
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_252
        - 'Admin: Payment Webhook Events'
  /v2/admin/webhook-events/{id}:
    get:
      operationId: AdminWebhookEventsController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_252
  /v2/admin/webhook-events/{id}/acknowledge:
    post:
      operationId: AdminWebhookEventsController.acknowledge
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Acknowledge a webhook event log row (manual reconciliation). Emits
        webhook_event.acknowledged.
      tags: *ref_252
  /v2/admin/webhook-events/{id}/cancel:
    post:
      operationId: AdminWebhookEventsController.cancel
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Cancel a poisoned webhook event log row. Emits webhook_event.cancelled.
      tags: *ref_252
  /v2/admin/webhook-events/{id}/replay:
    post:
      operationId: AdminWebhookEventsController.replay
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Mark a webhook event for replay. Emits webhook_event.replayed.
      tags: *ref_252
  /v2/client-errors:
    post:
      operationId: ClientErrorsController.ingest
      parameters: []
      responses:
        '204':
          description: ''
      tags:
        - 'Public: Client Error Ingress'
  /v2/client-events:
    post:
      operationId: ClientEventsController.ingest
      parameters: []
      responses:
        '204':
          description: ''
      tags:
        - 'Public: Client Event Ingress'
  /v2/admin/scheduler/jobs:
    get:
      operationId: AdminSchedulerController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_253
        - 'Admin: Scheduler Observability'
  /v2/admin/scheduler/jobs/{name}:
    get:
      operationId: AdminSchedulerController.detail
      parameters:
        - name: name
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_253
  /v2/admin/scheduler/jobs/{name}/run:
    post:
      operationId: AdminSchedulerController.runNow
      parameters:
        - name: name
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_253
  /v2/integrations:
    get:
      operationId: UserIntegrationsController.my
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_254
        - 'User: Integrations'
  /v2/integrations/available:
    get:
      operationId: UserIntegrationsController.available
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_254
  /v2/integrations/status:
    get:
      operationId: UserIntegrationsController.status
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_254
  /v2/integrations/apple-health/upload:
    post:
      operationId: UserIntegrationsController.appleHealthUpload
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_254
  /v2/integrations/google-fit/upload:
    post:
      operationId: UserIntegrationsController.googleFitUpload
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_254
  /v2/integrations/health/activities:
    post:
      operationId: UserIntegrationsController.ingestHealthActivities
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_254
  /v2/integrations/health/deletions:
    post:
      operationId: UserIntegrationsController.deleteHealthActivities
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HealthActivityDeletionsDto'
      responses:
        '201':
          description: ''
      tags: *ref_254
  /v2/integrations/{provider}:
    delete:
      operationId: UserIntegrationsController.disconnect
      parameters:
        - name: provider
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_254
  /v2/admin/integrations/apple-health/upload:
    post:
      operationId: AdminIntegrationsController.ingestAppleHealth
      parameters: []
      responses:
        '201':
          description: ''
      tags: &ref_255
        - 'Admin: Integrations'
  /v2/admin/integrations/logs:
    get:
      operationId: AdminIntegrationsController.listLogs
      parameters:
        - name: provider
          required: true
          in: query
          schema:
            type: string
        - name: userId
          required: true
          in: query
          schema:
            type: string
        - name: kind
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_255
  /v2/admin/integrations/health:
    get:
      operationId: AdminIntegrationsController.health
      parameters:
        - name: windowHours
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_255
  /v2/admin/wearables:
    get:
      operationId: AdminWearablesController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_256
        - 'Admin: Wearables'
  /v2/admin/wearables/{provider}/credentials:
    put:
      operationId: AdminWearablesController.upsert
      parameters:
        - name: provider
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_256
  /v2/admin/wearables/{provider}/test-connection:
    post:
      operationId: AdminWearablesController.testConnection
      parameters:
        - name: provider
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_256
  /v2/integrations/wearables:
    get:
      operationId: UserWearablesController.availability
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_257
        - 'User: Wearables'
  /v2/integrations/wearables/{provider}/authorize:
    get:
      operationId: UserWearablesController.authorize
      parameters:
        - name: provider
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_257
  /v2/integrations/wearables/{provider}/callback:
    get:
      operationId: UserWearablesController.callback
      parameters:
        - name: provider
          required: true
          in: path
          schema:
            type: string
        - name: code
          required: true
          in: query
          schema:
            type: string
        - name: state
          required: true
          in: query
          schema:
            type: string
        - name: oauth_token
          required: true
          in: query
          schema:
            type: string
        - name: oauth_verifier
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_257
  /v2/integrations/wearables/{provider}/sync:
    post:
      operationId: UserWearablesController.sync
      parameters:
        - name: provider
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_257
  /v2/integrations/wearables/terra/webhook:
    post:
      operationId: TerraWebhookController.webhook
      parameters:
        - name: terra-signature
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Terra webhook receiver. Verified with terra-signature HMAC; unsigned
        requests fail.
      tags:
        - 'Public: Wearable Webhooks'
  /v2/tracking/sessions/{id}/live-activity:
    get:
      operationId: TrackingController.liveActivityFor
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_258
        - 'User: Native Tracking'
  /v2/tracking/sessions:
    post:
      operationId: TrackingController.start
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartTrackingSessionDto'
      responses:
        '201':
          description: ''
      tags: *ref_258
  /v2/tracking/sessions/{id}:
    get:
      operationId: TrackingController.get
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_258
  /v2/tracking/sessions/{id}/points:
    get:
      operationId: TrackingController.points
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_258
    post:
      operationId: TrackingController.append
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppendTrackingPointsDto'
      responses:
        '201':
          description: ''
      tags: *ref_258
  /v2/tracking/sessions/{id}/finish:
    post:
      operationId: TrackingController.finish
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FinishTrackingSessionDto'
      responses:
        '201':
          description: ''
      tags: *ref_258
  /v2/tracking/sessions/{id}/abandon:
    post:
      operationId: TrackingController.abandon
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AbandonTrackingSessionDto'
      responses:
        '201':
          description: ''
      tags: *ref_258
  /v2/me/live-tracking-shares:
    post:
      operationId: LiveTrackingShareController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateLiveTrackingShareDto'
      responses:
        '201':
          description: ''
      summary: >-
        Create a live-tracking share. Up to 5 recipients per share, max 3 active
        per athlete, max 20 invites/24h.
      tags: &ref_259
        - 'Me: Live tracking sharing'
  /v2/me/live-tracking-shares/active:
    get:
      operationId: LiveTrackingShareController.listActive
      parameters: []
      responses:
        '200':
          description: ''
      summary: List the caller athlete's ACTIVE live-tracking shares.
      tags: *ref_259
  /v2/me/live-tracking-shares/{shareId}/cancel:
    post:
      operationId: LiveTrackingShareController.cancel
      parameters:
        - name: shareId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelLiveTrackingShareDto'
      responses:
        '200':
          description: ''
      summary: >-
        Cancel a live-tracking share. ACTIVE → CANCELLED. Recipients see
        "sharing stopped" within ~5 seconds.
      tags: *ref_259
  /v2/me/live-tracking-shares/{shareId}/recipients:
    get:
      operationId: LiveTrackingShareController.listRecipients
      parameters:
        - name: shareId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List recipients of a share for the athlete's "who's watching" view.
        Excludes access-token hashes.
      tags: *ref_259
  /v2/track/{token}:
    get:
      operationId: LiveTrackingSharePublicController.fetchState
      parameters:
        - name: token
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Fetch state for a live-tracking share. Token is HMAC-signed; recipient
        does NOT need a Repeak account.
      tags: &ref_260
        - 'Public: Live tracking share recipient'
  /v2/track/{token}/opt-out:
    post:
      operationId: LiveTrackingSharePublicController.optOut
      parameters:
        - name: token
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Recipient opts out of the share. Idempotent — already-opted-out is
        treated as success.
      tags: *ref_260
  /v2/social/suggestions:
    get:
      operationId: SocialController.listSuggestions
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: city
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_261
        - 'User: Social'
  /v2/social/contact-matches:
    post:
      operationId: SocialController.matchContacts
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_261
  /v2/social/users/{userId}/follow:
    post:
      operationId: SocialController.follow
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_261
    delete:
      operationId: SocialController.unfollow
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/social/me/follow-requests:
    get:
      operationId: SocialController.listIncomingFollowRequests
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: order
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/social/me/follow-requests/sent:
    get:
      operationId: SocialController.listSentFollowRequests
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: order
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/social/follow-requests/{edgeId}/approve:
    post:
      operationId: SocialController.approveFollowRequest
      parameters:
        - name: edgeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_261
  /v2/social/follow-requests/{edgeId}/reject:
    post:
      operationId: SocialController.rejectFollowRequest
      parameters:
        - name: edgeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_261
  /v2/social/me/followers/{followerId}:
    delete:
      operationId: SocialController.removeFollower
      parameters:
        - name: followerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/social/users/{userId}/following:
    get:
      operationId: SocialController.isFollowing
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/social/users/{userId}/counts:
    get:
      operationId: SocialController.counts
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/social/users/{userId}/followers:
    get:
      operationId: SocialController.followers
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: cursor
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/social/users/{userId}/followings:
    get:
      operationId: SocialController.followings
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: cursor
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_261
  /v2/feed/stories:
    get:
      operationId: StoriesController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_262
        - 'User: Stories'
    post:
      operationId: StoriesController.create
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_262
  /v2/feed/stories/text:
    post:
      operationId: StoriesController.createText
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/public:
    get:
      operationId: StoriesController.getPublic
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/view:
    post:
      operationId: StoriesController.view
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/react:
    post:
      operationId: StoriesController.react
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/reply:
    post:
      operationId: StoriesController.reply
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/sticker/{stickerId}/respond:
    post:
      operationId: StoriesController.stickerRespond
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: stickerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/viewers:
    get:
      operationId: StoriesController.viewers
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/insights:
    get:
      operationId: StoriesController.insights
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}/status:
    get:
      operationId: StoriesController.status
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_262
  /v2/feed/stories/{id}:
    delete:
      operationId: StoriesController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_262
  /v2/feed/stories/video:
    post:
      operationId: StoriesController.createVideo
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_262
  /v2/feed/stories/close-friends/picker:
    get:
      operationId: StoriesSettingsController.getCloseFriendsPicker
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_263
        - 'User: Story settings'
  /v2/feed/stories/close-friends:
    get:
      operationId: StoriesSettingsController.listCloseFriends
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_263
    post:
      operationId: StoriesSettingsController.addCloseFriends
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_263
  /v2/feed/stories/close-friends/{userId}:
    delete:
      operationId: StoriesSettingsController.removeCloseFriend
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_263
  /v2/feed/stories/highlights:
    get:
      operationId: StoriesSettingsController.listHighlights
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_263
    post:
      operationId: StoriesSettingsController.createHighlight
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_263
  /v2/feed/stories/highlights/{id}:
    delete:
      operationId: StoriesSettingsController.deleteHighlight
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_263
  /v2/feed/stories/highlights/by-user/{userId}:
    get:
      operationId: StoriesSettingsController.listByUser
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_263
  /v2/feed/stories/highlights/{id}/stories:
    get:
      operationId: StoriesSettingsController.stories
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_263
  /v2/feed:
    get:
      operationId: FeedController.myFeed
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: type
          required: true
          in: query
          schema:
            type: string
        - name: sort
          required: true
          in: query
          schema:
            type: string
        - name: seed
          required: true
          in: query
          schema:
            type: string
        - name: tag
          required: true
          in: query
          schema:
            type: string
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_264
        - 'User: Feed'
  /v2/feed/tags/trending:
    get:
      operationId: FeedController.trendingTags
      parameters:
        - name: window
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/me/insights:
    get:
      operationId: FeedController.creatorAnalytics
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/posts/{id}/insights:
    get:
      operationId: FeedController.postInsights
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/posts/{id}/public:
    get:
      operationId: FeedController.getPostPublic
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/posts/{id}:
    get:
      operationId: FeedController.getPost
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
    patch:
      operationId: FeedController.updateMyPost
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
    delete:
      operationId: FeedController.deleteMyPost
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/me/posts:
    get:
      operationId: FeedController.myPosts
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/users/{userId}/posts:
    get:
      operationId: FeedController.getUserPosts
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/{id}:
    get:
      operationId: FeedController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/posts:
    post:
      operationId: FeedController.createPost
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_264
  /v2/feed/posts/upload-image:
    post:
      operationId: FeedController.uploadPostImage
      parameters:
        - name: surface
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_264
  /v2/feed/{id}/kudos:
    post:
      operationId: FeedController.toggleKudos
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_264
    get:
      operationId: FeedController.listKudos
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/{id}/comments:
    post:
      operationId: FeedController.addComment
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_264
    get:
      operationId: FeedController.listComments
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: rootCommentId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/{id}/comments/{commentId}:
    delete:
      operationId: FeedController.deleteComment
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: commentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/{id}/repost:
    post:
      operationId: FeedController.repost
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_264
  /v2/feed/{id}/bookmark:
    post:
      operationId: FeedController.toggleBookmark
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_264
  /v2/feed/bookmarks/me:
    get:
      operationId: FeedController.myBookmarks
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/activities/{activityId}/comments:
    get:
      operationId: FeedController.commentsByActivity
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: rootCommentId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/feed/posts/{id}/hide-from/{targetUserId}:
    post:
      operationId: FeedController.hideFromPost
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_264
    delete:
      operationId: FeedController.unhideFromPost
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: targetUserId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_264
  /v2/user-feed:
    get:
      operationId: UserFeedController.dualFeed
      parameters:
        - name: tab
          required: true
          in: query
          schema:
            type: string
        - name: cursor
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Athlete App: Feed'
  /v2/admin/feed:
    get:
      operationId: AdminFeedController.list
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: type
          required: true
          in: query
          schema:
            type: string
        - name: trustStatus
          required: true
          in: query
          schema:
            type: string
        - name: hiddenReason
          required: true
          in: query
          schema:
            type: string
        - name: actorId
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: includeInactive
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_265
        - bearer: []
      tags: &ref_266
        - 'Admin: Feed moderation'
  /v2/admin/feed/comments:
    get:
      operationId: AdminFeedController.listComments
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: postId
          required: true
          in: query
          schema:
            type: string
        - name: authorId
          required: true
          in: query
          schema:
            type: string
        - name: isHidden
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/comments/{id}/hide:
    patch:
      operationId: AdminFeedController.hideComment
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/comments/{id}/unhide:
    patch:
      operationId: AdminFeedController.unhideComment
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/hashtags:
    get:
      operationId: AdminFeedController.listHashtags
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: sort
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/hashtags/{tag}/ban:
    patch:
      operationId: AdminFeedController.banHashtag
      parameters:
        - name: tag
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/hashtags/{tag}/unban:
    patch:
      operationId: AdminFeedController.unbanHashtag
      parameters:
        - name: tag
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/hashtags/{tag}/posts:
    get:
      operationId: AdminFeedController.listHashtagPosts
      parameters:
        - name: tag
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/{id}:
    get:
      operationId: AdminFeedController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
    delete:
      operationId: AdminFeedController.softDelete
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/{id}/trust:
    patch:
      operationId: AdminFeedController.setTrust
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/{id}/hide:
    post:
      operationId: AdminFeedController.hide
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/admin/feed/{id}/unhide:
    post:
      operationId: AdminFeedController.unhide
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_265
      tags: *ref_266
  /v2/dm/threads:
    post:
      operationId: DmController.openThread
      parameters: []
      responses:
        '201':
          description: ''
      tags: &ref_267
        - 'User: DMs'
    get:
      operationId: DmController.listThreads
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/unread-count:
    get:
      operationId: DmController.getUnreadCount
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/inbox/sse:
    get:
      operationId: DmController.inboxSse
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/sse:
    get:
      operationId: DmController.threadSse
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/messages:
    get:
      operationId: DmController.listMessages
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
    post:
      operationId: DmController.send
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendMessageDto'
      responses:
        '201':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/read:
    post:
      operationId: DmController.markRead
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/messages/{msgId}:
    patch:
      operationId: DmController.editMessage
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: msgId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EditMessageDto'
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/messages/{msgId}/reactions/{emoji}:
    post:
      operationId: DmController.addReaction
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: msgId
          required: true
          in: path
          schema:
            type: string
        - name: emoji
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_267
    delete:
      operationId: DmController.removeReaction
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: msgId
          required: true
          in: path
          schema:
            type: string
        - name: emoji
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/typing:
    post:
      operationId: DmController.typing
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/search:
    get:
      operationId: DmController.searchMessages
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/mute:
    patch:
      operationId: DmController.setMuted
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/messages/{msgId}/me:
    delete:
      operationId: DmController.deleteForMe
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: msgId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/requests:
    get:
      operationId: DmController.listRequests
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_267
  /v2/dm/requests/{threadId}/accept:
    post:
      operationId: DmController.acceptRequest
      parameters:
        - name: threadId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_267
  /v2/dm/requests/{threadId}/decline:
    post:
      operationId: DmController.declineRequest
      parameters:
        - name: threadId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_267
  /v2/dm/threads/{id}/archive:
    post:
      operationId: DmController.archiveThread
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_267
  /v2/dm/media:
    post:
      operationId: DmController.getMediaUploadUrl
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MediaUploadDto'
      responses:
        '201':
          description: ''
      tags: *ref_267
  /v2/admin/dm/threads:
    get:
      operationId: AdminDmController.listThreads
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: participantUserId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_268
        - bearer: []
      tags: &ref_269
        - 'Admin: DM compliance'
  /v2/admin/dm/threads/{id}/messages:
    get:
      operationId: AdminDmController.listMessages
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_268
      tags: *ref_269
  /v2/organizer/events/{eventId}/photos:
    post:
      operationId: OrganizerEventPhotosController.upload
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_270
        - 'Organizer: Event Photos'
    get:
      operationId: OrganizerEventPhotosController.list
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_270
  /v2/organizer/events/{eventId}/photos/{photoId}/bib:
    patch:
      operationId: OrganizerEventPhotosController.setBib
      parameters:
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_270
  /v2/organizer/events/{eventId}/photos/{photoId}:
    delete:
      operationId: OrganizerEventPhotosController.remove
      parameters:
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_270
  /v2/organizer/events/{eventId}/photos/bulk:
    post:
      operationId: OrganizerEventPhotosController.uploadBulk
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_270
  /v2/organizer/events/{eventId}/photos/sales-analytics:
    get:
      operationId: OrganizerEventPhotosController.salesAnalytics
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_270
  /v2/events/{eventId}/photos:
    get:
      operationId: PublicEventPhotosController.listPublic
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Event Photos'
  /v2/user/photos:
    get:
      operationId: UserPhotosController.mine
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_271
        - 'User: Photos'
  /v2/user/photos/matches:
    get:
      operationId: UserPhotosController.matches
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_271
  /v2/user/photos/matches/{matchId}/confirm:
    post:
      operationId: UserPhotosController.confirmMatch
      parameters:
        - name: matchId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_271
  /v2/user/photos/matches/{matchId}/withdraw:
    post:
      operationId: UserPhotosController.withdrawMatch
      parameters:
        - name: matchId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_271
  /v2/user/photos/{photoId}/purchase/initiate:
    post:
      operationId: UserPhotosController.initiatePurchase
      parameters:
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_271
  /v2/user/photos/face-consent/status:
    get:
      operationId: UserPhotosController.consentStatus
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_271
  /v2/user/photos/face-consent/grant:
    post:
      operationId: UserPhotosController.grantConsent
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_271
  /v2/user/photos/face-consent/revoke:
    delete:
      operationId: UserPhotosController.revokeConsent
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_271
  /v2/user/photos/{photoId}:
    get:
      operationId: UserPhotosController.detail
      parameters:
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_271
  /v2/admin/photos:
    get:
      operationId: AdminPhotosController.list
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: processingStatus
          required: true
          in: query
          schema:
            type: string
        - name: visibility
          required: true
          in: query
          schema:
            type: string
        - name: uploaderType
          required: true
          in: query
          schema:
            type: string
        - name: eventId
          required: true
          in: query
          schema:
            type: string
        - name: hasMatches
          required: true
          in: query
          schema:
            type: string
        - name: hasOcr
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_272
        - 'Admin: Photos'
  /v2/admin/photos/stats:
    get:
      operationId: AdminPhotosController.stats
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_272
  /v2/admin/photos/matches/{matchId}:
    delete:
      operationId: AdminPhotosController.removeMatch
      parameters:
        - name: matchId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_272
  /v2/admin/photos/{photoId}/matches/manual:
    post:
      operationId: AdminPhotosController.addManualMatch
      parameters:
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_272
  /v2/admin/photos/{id}/visibility:
    patch:
      operationId: AdminPhotosController.setVisibility
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_272
  /v2/admin/photos/{id}/moderate:
    post:
      operationId: AdminPhotosController.moderate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_272
  /v2/admin/photos/{id}:
    get:
      operationId: AdminPhotosController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_272
  /v2/user/photos/face-profile:
    get:
      operationId: FaceProfileController.get
      parameters: []
      responses:
        '200':
          description: ''
      summary: Get the caller's current face profile.
      tags: &ref_273
        - 'User: Photo face profile'
    post:
      operationId: FaceProfileController.upload
      parameters: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
      responses:
        '201':
          description: ''
      summary: Upload a selfie for face-match indexing.
      tags: *ref_273
    delete:
      operationId: FaceProfileController.revoke
      parameters: []
      responses:
        '200':
          description: ''
      summary: Revoke the active face profile.
      tags: *ref_273
  /v2/user/photos/face-profile/engine:
    get:
      operationId: FaceProfileController.engine
      parameters: []
      responses:
        '200':
          description: ''
      summary: Report whether the face-match engine is wired in this environment.
      tags: *ref_273
  /v2/events/{eventId}/photo-packages:
    get:
      operationId: PhotoPackagesController.list
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_274
        - Photo Packages
  /v2/events/{eventId}/photo-packages/{packageId}:
    get:
      operationId: PhotoPackagesController.detail
      parameters:
        - name: packageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_274
  /v2/user/referrals/me:
    get:
      operationId: UserReferralsController.me
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_275
        - 'User: Referrals'
  /v2/user/referrals/me/summary:
    get:
      operationId: UserReferralsController.mySummary
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_275
  /v2/user/referrals/me/claim:
    get:
      operationId: UserReferralsController.myClaim
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_275
  /v2/user/referrals/me/referrals:
    get:
      operationId: UserReferralsController.myReferrals
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_275
  /v2/user/referrals/claim:
    post:
      operationId: UserReferralsController.claim
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_275
  /v2/user/referrals/me/attribution:
    get:
      operationId: UserReferralsController.myAttribution
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_275
  /v2/user/referrals/me/rotate-code:
    post:
      operationId: UserReferralsController.rotateCode
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_275
  /v2/admin/referrals/by-referrer/{userId}:
    get:
      operationId: AdminReferralsController.byReferrer
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_276
        - 'Admin: Referrals'
  /v2/admin/referrals/settlements:
    get:
      operationId: AdminReferralsController.settlements
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: kind
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_276
  /v2/admin/referrals/summary:
    get:
      operationId: AdminReferralsController.summary
      parameters:
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_276
  /v2/admin/referrals/trends:
    get:
      operationId: AdminReferralsController.trends
      parameters:
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_276
  /v2/admin/referrals/replay/dry-run:
    post:
      operationId: AdminReferralsController.replayDryRun
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_276
  /v2/admin/referrals/replay/execute:
    post:
      operationId: AdminReferralsController.replayExecute
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_276
  /v2/referrals/by-code/{code}:
    get:
      operationId: PublicReferralsController.byCode
      parameters:
        - name: code
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_277
        - 'Public: Referrals'
  /v2/referrals/leaderboard:
    get:
      operationId: PublicReferralsController.leaderboard
      parameters:
        - name: window
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_277
  /v2/links:
    post:
      operationId: LinksController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateLinkDto'
      responses:
        '201':
          description: ''
      tags:
        - Links
  /v2/links/{code}:
    get:
      operationId: PublicLinksController.resolve
      parameters:
        - name: code
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Links'
  /l/{code}:
    get:
      operationId: ShortLinkRedirectController.redirect
      parameters:
        - name: code
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Links'
  /v2/user/premium/status:
    get:
      operationId: UserPremiumController.status
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_278
        - 'User: Athlete Premium'
  /v2/user/premium/purchase/initiate:
    post:
      operationId: UserPremiumController.initiate
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_278
  /v2/pricing/tiers:
    get:
      operationId: PublicPricingController.listActive
      parameters:
        - name: audience
          required: false
          in: query
          schema:
            enum:
              - ATHLETE
              - BRAND
              - CLUB
              - ORGANIZER
            type: string
      responses:
        '200':
          description: ''
      summary: List ACTIVE pricing tiers, optionally filtered by audience.
      tags:
        - 'Public: Pricing'
  /v2/sponsor/brands/{brandId}/pricing:
    get:
      operationId: SponsorBrandPricingController.getBrandPricing
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_279
        - bearer: []
      summary: Brand's current pricing tier + available ACTIVE BRAND tiers in one call.
      tags: &ref_280
        - 'Sponsor: Brand pricing'
  /v2/sponsor/brands/{brandId}/pricing/select:
    post:
      operationId: SponsorBrandPricingController.select
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SelectTierBody'
      responses:
        '201':
          description: ''
      security: *ref_279
      summary: >-
        Select / request a pricing tier. HONESTY: no real payment integration
        for brand subscriptions today; result.status flips to
        PAYMENT_REQUIRED_NOT_WIRED for fixed-price tiers and
        CONTACT_SALES_REQUIRED for CUSTOM. Frontend never claims a capture
        happened.
      tags: *ref_280
  /v2/admin/pricing/tiers:
    get:
      operationId: AdminPricingController.list
      parameters:
        - name: audience
          required: false
          in: query
          schema:
            enum:
              - ATHLETE
              - BRAND
              - CLUB
              - ORGANIZER
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - ACTIVE
              - INACTIVE
              - DRAFT
              - ARCHIVED
            type: string
      responses:
        '200':
          description: ''
      security: &ref_281
        - bearer: []
      summary: List pricing tiers (DRAFT/INACTIVE/ARCHIVED included).
      tags: &ref_282
        - 'Admin: Pricing matrix'
    post:
      operationId: AdminPricingController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePricingTierBody'
      responses:
        '201':
          description: ''
      security: *ref_281
      summary: Create pricing tier (admin)
      tags: *ref_282
  /v2/admin/pricing/tiers/{tierId}:
    patch:
      operationId: AdminPricingController.update
      parameters:
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePricingTierBody'
      responses:
        '200':
          description: ''
      security: *ref_281
      summary: Update pricing tier (admin)
      tags: *ref_282
  /v2/admin/pricing/tiers/{tierId}/archive:
    post:
      operationId: AdminPricingController.archive
      parameters:
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_281
      summary: Archive pricing tier (admin)
      tags: *ref_282
  /v2/admin/pricing/tiers/{tierId}/activate:
    post:
      operationId: AdminPricingController.activate
      parameters:
        - name: tierId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_281
      summary: Activate pricing tier (admin)
      tags: *ref_282
  /v2/admin/revenue-streams:
    get:
      operationId: AdminRevenueStreamsController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            type: string
        - name: sourceStatus
          required: false
          in: query
          schema:
            type: string
        - name: ownerSurface
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_283
        - bearer: []
      summary: List all 8 revenue stream rows. Filters apply post-aggregation.
      tags: &ref_284
        - 'Admin: Revenue streams'
  /v2/admin/revenue-streams/{streamCode}:
    get:
      operationId: AdminRevenueStreamsController.getOne
      parameters:
        - name: streamCode
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_283
      summary: Single stream detail. 404 on unknown streamCode.
      tags: *ref_284
  /v2/sponsor/brands/{brandId}/revenue-streams:
    get:
      operationId: SponsorBrandRevenueStreamsController.listBrand
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Brand-scoped revenue streams (BRAND_CHALLENGE + BRAND_PRICING_TIER
        only). Cross-brand callers get 403.
      tags:
        - 'Sponsor: Brand revenue streams'
  /v2/clubs/{clubId}/revenue-streams:
    get:
      operationId: ClubRevenueStreamsController.listClub
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Club-scoped revenue streams (CLUB_MEMBERSHIP only). Cross-club callers
        get 403.
      tags:
        - 'Club: Revenue streams'
  /v2/admin/marketplace/economics:
    get:
      operationId: AdminMarketplaceEconomicsController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - ACTIVE
              - INACTIVE
              - ARCHIVED
            type: string
      responses:
        '200':
          description: ''
      security: &ref_285
        - bearer: []
      summary: >-
        List marketplace economics configs with optional status filter
        (DRAFT/ACTIVE/INACTIVE/ARCHIVED).
      tags: &ref_286
        - 'Admin: Marketplace economics'
    post:
      operationId: AdminMarketplaceEconomicsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMarketplaceEconomicsBody'
      responses:
        '201':
          description: ''
      security: *ref_285
      summary: Create marketplace economics config (admin)
      tags: *ref_286
  /v2/admin/marketplace/economics/projections:
    get:
      operationId: AdminMarketplaceEconomicsController.projections
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_285
      summary: >-
        Honest revenue projection —
        gross/platformFee/sellerPayout/tax/net/orderCount/refundAmount. ALWAYS
        null with sourceStatus today; no marketplace order/payment source table
        exists yet.
      tags: *ref_286
  /v2/admin/marketplace/economics/{configId}:
    get:
      operationId: AdminMarketplaceEconomicsController.getOne
      parameters:
        - name: configId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_285
      summary: Single config detail
      tags: *ref_286
    patch:
      operationId: AdminMarketplaceEconomicsController.update
      parameters:
        - name: configId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMarketplaceEconomicsBody'
      responses:
        '200':
          description: ''
      security: *ref_285
      summary: Update marketplace economics config (admin)
      tags: *ref_286
  /v2/admin/marketplace/economics/{configId}/activate:
    post:
      operationId: AdminMarketplaceEconomicsController.activate
      parameters:
        - name: configId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_285
      summary: >-
        Activate config. Auto-deactivates the prior ACTIVE row to INACTIVE.
        Refuses ARCHIVED → ACTIVE.
      tags: *ref_286
  /v2/admin/marketplace/economics/{configId}/archive:
    post:
      operationId: AdminMarketplaceEconomicsController.archive
      parameters:
        - name: configId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_285
      summary: Archive config (permanent retire — audit trail)
      tags: *ref_286
  /v2/marketplace/economics:
    get:
      operationId: PublicMarketplaceEconomicsController.getPublic
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Public-safe active marketplace economics. Returns null fields + honest
        availability note when no ACTIVE config exists.
      tags:
        - 'Public: Marketplace economics'
  /v2/share/year-in-sport/{userId}/{year}:
    get:
      operationId: ShareController.getYearInSport
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: year
          required: true
          in: path
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: &ref_287
        - Share + Year-in-Sport
  /v2/share/initiated:
    post:
      operationId: ShareController.shareInitiated
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ShareEventDto'
      responses:
        '202':
          description: ''
      tags: *ref_287
  /v2/share/completed:
    post:
      operationId: ShareController.shareCompleted
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ShareEventDto'
      responses:
        '202':
          description: ''
      tags: *ref_287
  /v2/share/link-opened:
    post:
      operationId: ShareController.linkOpened
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ShareLinkOpenedDto'
      responses:
        '202':
          description: ''
      tags: *ref_287
  /v2/share/install-attributed:
    post:
      operationId: ShareController.installAttributed
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InstallAttributedDto'
      responses:
        '202':
          description: ''
      tags: *ref_287
  /v2/user/adaptive-training/plans:
    post:
      operationId: AdaptiveTrainingController.createPlan
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAdaptivePlanDto'
      responses:
        '201':
          description: ''
      tags: &ref_288
        - 'User: Adaptive Training (B21/B23)'
  /v2/user/adaptive-training/plans/active:
    get:
      operationId: AdaptiveTrainingController.activePlan
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_288
  /v2/user/adaptive-training/plans/{id}:
    get:
      operationId: AdaptiveTrainingController.getPlan
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_288
    delete:
      operationId: AdaptiveTrainingController.cancel
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_288
  /v2/user/adaptive-training/plans/{id}/activate:
    post:
      operationId: AdaptiveTrainingController.activate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_288
  /v2/user/adaptive-training/today:
    get:
      operationId: AdaptiveTrainingController.today
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_288
  /v2/user/adaptive-training/sessions/{id}/launch:
    post:
      operationId: AdaptiveTrainingController.launchSession
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LaunchSessionDto'
      responses:
        '201':
          description: ''
      tags: *ref_288
  /v2/user/adaptive-training/sessions/{id}/complete:
    post:
      operationId: AdaptiveTrainingController.completeSession
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CompleteSessionDto'
      responses:
        '201':
          description: ''
      tags: *ref_288
  /v2/user/adaptive-training/sessions/{id}/abandon:
    post:
      operationId: AdaptiveTrainingController.abandonSession
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AbandonSessionDto'
      responses:
        '201':
          description: ''
      tags: *ref_288
  /v2/user/adaptive-training/plans/{id}/realign:
    post:
      operationId: AdaptiveTrainingController.realign
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_288
  /v2/routes:
    get:
      operationId: RoutesController.list
      parameters:
        - name: city
          required: false
          in: query
          schema:
            type: string
        - name: distance
          required: false
          in: query
          schema:
            type: string
            enum:
              - 5K
              - 10K
              - 15K
              - HALF
        - name: sport
          required: false
          in: query
          description: Filter by sport type.
          schema:
            type: string
            enum:
              - RUN
              - CYCLE
              - WALK
              - HIKE
        - name: difficulty
          required: false
          in: query
          description: 'Filter by difficulty (maps to terrain: FLAT/ROLLING/HILLY).'
          schema:
            type: string
            enum:
              - EASY
              - MODERATE
              - HARD
        - name: surface
          required: false
          in: query
          description: Filter by surface type.
          schema:
            type: string
        - name: minDistanceKm
          required: false
          in: query
          description: Min route distance in km.
          schema:
            type: number
        - name: maxDistanceKm
          required: false
          in: query
          description: Max route distance in km.
          schema:
            type: number
        - name: minElevation
          required: false
          in: query
          description: Min elevation gain in metres.
          schema:
            type: number
        - name: maxElevation
          required: false
          in: query
          description: Max elevation gain in metres.
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 1-based results page.
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: &ref_289
        - Routes (B22)
  /v2/routes/nearby:
    get:
      operationId: RoutesController.nearby
      parameters:
        - name: lat
          required: true
          in: query
          description: Viewer's latitude (WGS-84)
          schema:
            example: 12.9763
            type: number
        - name: lng
          required: true
          in: query
          description: Viewer's longitude (WGS-84)
          schema:
            example: 77.5929
            type: number
        - name: radiusKm
          required: false
          in: query
          description: Search radius in kilometres. Default 10. Max 100.
          schema:
            default: 10
            type: number
        - name: sport
          required: false
          in: query
          description: Filter by sport type.
          schema:
            type: string
            enum:
              - RUN
              - CYCLE
              - WALK
              - HIKE
        - name: difficulty
          required: false
          in: query
          description: 'Filter by difficulty (maps to terrain: FLAT/ROLLING/HILLY).'
          schema:
            type: string
            enum:
              - EASY
              - MODERATE
              - HARD
        - name: surface
          required: false
          in: query
          description: Filter by surface type.
          schema:
            type: string
        - name: minDistanceKm
          required: false
          in: query
          description: Min route distance in km.
          schema:
            type: number
        - name: maxDistanceKm
          required: false
          in: query
          description: Max route distance in km.
          schema:
            type: number
        - name: minElevation
          required: false
          in: query
          description: Min elevation gain in metres.
          schema:
            type: number
        - name: maxElevation
          required: false
          in: query
          description: Max elevation gain in metres.
          schema:
            type: number
        - name: limit
          required: false
          in: query
          description: Max results. Default 10. Hard cap 50.
          schema:
            default: 10
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_289
  /v2/routes/saved:
    get:
      operationId: RoutesController.getSaved
      parameters:
        - name: limit
          required: false
          in: query
          description: Max results. Default 20. Hard cap 50.
          schema:
            default: 20
            type: number
        - name: offset
          required: false
          in: query
          description: Offset for pagination. Default 0.
          schema:
            default: 0
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_289
  /v2/routes/{id}:
    get:
      operationId: RoutesController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_289
  /v2/routes/{id}/mark-started:
    post:
      operationId: RoutesController.markStarted
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_289
  /v2/routes/{id}/save:
    post:
      operationId: RoutesController.save
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_289
    delete:
      operationId: RoutesController.unsave
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_289
  /v2/admin/routes:
    get:
      operationId: AdminRoutesController.list
      parameters:
        - &ref_290
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: city
          required: false
          in: query
          schema:
            type: string
        - name: distance
          required: false
          in: query
          schema:
            type: string
            enum:
              - 5K
              - 10K
              - 15K
              - HALF
        - name: sport
          required: false
          in: query
          description: Filter by sport type.
          schema:
            type: string
            enum:
              - RUN
              - CYCLE
              - WALK
              - HIKE
        - name: difficulty
          required: false
          in: query
          description: 'Filter by difficulty (maps to terrain: FLAT/ROLLING/HILLY).'
          schema:
            type: string
            enum:
              - EASY
              - MODERATE
              - HARD
        - name: surface
          required: false
          in: query
          description: Filter by surface type.
          schema:
            type: string
        - name: minDistanceKm
          required: false
          in: query
          description: Min route distance in km.
          schema:
            type: number
        - name: maxDistanceKm
          required: false
          in: query
          description: Max route distance in km.
          schema:
            type: number
        - name: minElevation
          required: false
          in: query
          description: Min elevation gain in metres.
          schema:
            type: number
        - name: maxElevation
          required: false
          in: query
          description: Max elevation gain in metres.
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 1-based results page.
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: List all routes (incl. inactive) for admin management.
      tags: &ref_291
        - 'Admin: Routes'
    post:
      operationId: AdminRoutesController.create
      parameters:
        - *ref_290
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateRouteDto'
      responses:
        '201':
          description: ''
      summary: Create a curated route.
      tags: *ref_291
  /v2/admin/routes/{id}:
    patch:
      operationId: AdminRoutesController.update
      parameters:
        - *ref_290
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateRouteDto'
      responses:
        '200':
          description: ''
      summary: Update a route (partial).
      tags: *ref_291
    delete:
      operationId: AdminRoutesController.remove
      parameters:
        - *ref_290
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Soft-delete a route.
      tags: *ref_291
  /v2/admin/routes/{id}/active:
    patch:
      operationId: AdminRoutesController.setActive
      parameters:
        - *ref_290
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Show/hide a route from the athlete list.
      tags: *ref_291
  /v2/user/form-score:
    get:
      operationId: FormController.getScore
      parameters:
        - name: historyLimit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_292
        - 'User: Form Score + Strictness Floor (B25)'
  /v2/user/strictness-floor:
    get:
      operationId: FormController.getFloor
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_292
  /v2/user/form-score/recompute:
    post:
      operationId: FormController.recompute
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_292
  /v2/admin/audit-logs:
    get:
      operationId: AuditLogController.list
      parameters:
        - name: organizerId
          required: false
          in: query
          schema:
            format: uuid
            type: string
        - name: subjectType
          required: false
          in: query
          schema:
            type: string
        - name: subjectId
          required: false
          in: query
          schema:
            type: string
        - name: actorId
          required: false
          in: query
          schema:
            format: uuid
            type: string
        - name: action
          required: false
          in: query
          schema:
            type: string
        - name: startDate
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2026-04-18'
            type: string
        - name: limit
          required: false
          in: query
          schema:
            maximum: 500
            default: 50
            type: number
        - name: cursor
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        DEPRECATED — use /v2/admin/audit-log (singular) instead. Retained for
        back-compat; metadata is now defense-in-depth redacted to match the
        canonical viewer.
      tags:
        - 'Admin: Audit logs'
  /v2/admin/audit-log:
    get:
      operationId: AdminAuditLogController.list
      parameters:
        - name: organizerId
          required: false
          in: query
          schema:
            format: uuid
            type: string
        - name: subjectType
          required: false
          in: query
          schema:
            type: string
        - name: subjectId
          required: false
          in: query
          schema:
            type: string
        - name: actorId
          required: false
          in: query
          schema:
            format: uuid
            type: string
        - name: action
          required: false
          in: query
          schema:
            type: string
        - name: startDate
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2026-04-18'
            type: string
        - name: limit
          required: false
          in: query
          schema:
            maximum: 500
            default: 50
            type: number
        - name: cursor
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_293
        - bearer: []
      summary: >-
        Admin audit-log viewer — closed-allowlist projection + redacted
        metadata. Filter by actor / subjectType+subjectId / action / date range.
        Cursor-paginated.
      tags: &ref_294
        - 'Admin: Audit log (viewer)'
  /v2/admin/audit-log/export:
    post:
      operationId: AdminAuditLogController.export
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_293
      summary: >-
        Admin audit-log CSV export. Body carries the same filters as the viewer
        plus a 10–500 char reason; backend emits `admin.audit_log.exported`
        audit with `{ filterDigest, rowCount, reasonLen }`. Hard cap 5000 rows.
      tags: *ref_294
  /v2/admin/audit-log/chain-health:
    get:
      operationId: AdminAuditLogController.chainHealth
      parameters:
        - name: window
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_293
      summary: >-
        Audit-log chain health — recomputes SHA-256 entry_hash for the latest N
        rows and walks prev_hash linkage. Returns brokenLinkCount,
        firstBrokenSequence, and up to 10 broken-link diagnostics. Window param
        defaults to 10000 (capped at 100000).
      tags: *ref_294
  /v2/users/me/medals:
    get:
      operationId: MedalsController.myMedals
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_295
        - 'Events: Medals'
  /v2/users/{userId}/medals:
    get:
      operationId: MedalsController.userMedals
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_295
  /v2/events/{eventId}/medals/top:
    get:
      operationId: MedalsController.topForEvent
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_295
  /v2/events/{eventId}/bibs/me:
    get:
      operationId: BibsController.myBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_296
        - 'Events: Digital Bibs'
    patch:
      operationId: BibsController.updateMyBibName
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_296
  /v2/organizer/events/{eventId}/bibs/issue:
    post:
      operationId: BibsController.issueForEvent
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_296
  /v2/organizer/events/{eventId}/bibs/roster:
    get:
      operationId: BibsController.bibRoster
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_296
  /v2/organizer/events/{eventId}/participants/{participantId}/bib/revoke:
    post:
      operationId: BibsController.revokeOneBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_296
  /v2/organizer/events/{eventId}/participants/{participantId}/bib/reissue:
    post:
      operationId: BibsController.reissueOneBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_296
  /v2/b/{slug}:
    get:
      operationId: BibsController.shareBySlug
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_296
  /v2/bib-templates:
    get:
      operationId: BibTemplatesController.list
      parameters:
        - name: includeDrafts
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: 'Gallery: global templates + the caller organization''s own templates.'
      tags: &ref_297
        - Bib Templates
    post:
      operationId: BibTemplatesController.create
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Create a bib template. Admins create GLOBAL templates; organizers create
        ORGANIZER-scope templates owned by themselves.
      tags: *ref_297
  /v2/bib-templates/{id}:
    get:
      operationId: BibTemplatesController.one
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_297
    patch:
      operationId: BibTemplatesController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_297
    delete:
      operationId: BibTemplatesController.archive
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_297
  /v2/bib-templates/{id}/preview:
    post:
      operationId: BibTemplatesController.preview
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Re-render the sample preview PNG (gallery thumbnail).
      tags: *ref_297
  /v2/organizer/events/{eventId}/bib-config:
    get:
      operationId: OrganizerBibConfigController.getConfig
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Read the current bib config for an event.
      tags: &ref_298
        - 'Organizer: Bib Config'
    patch:
      operationId: OrganizerBibConfigController.patchConfig
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Patch the bib config. Any omitted field is left untouched.
      tags: *ref_298
  /v2/time/now:
    get:
      operationId: TimeController.now
      parameters: []
      responses:
        '200':
          description: ''
      tags:
        - Server time
  /v2/virtual-run/open:
    get:
      operationId: VirtualRunController.openEvents
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Open-window virtual-run catalogue — every event currently accepting
        virtual submissions. Public.
      tags: &ref_299
        - Virtual Run
  /v2/virtual-run/{eventId}/window:
    get:
      operationId: VirtualRunController.window
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Window-state snapshot for an event. Public so mobile can show "opens in
        3d" shell before sign-in.
      tags: *ref_299
  /v2/virtual-run/{eventId}/leaderboard:
    get:
      operationId: VirtualRunController.leaderboard
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Public leaderboard — ASC by durationSeconds.
      tags: *ref_299
  /v2/virtual-run/{eventId}/me:
    get:
      operationId: VirtualRunController.me
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_299
  /v2/virtual-run/{eventId}/submit:
    post:
      operationId: VirtualRunController.submit
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitVirtualRunDto'
      responses:
        '201':
          description: ''
      summary: >-
        Submit an Activity against a virtual event. PB-replace: only a faster
        submission overwrites.
      tags: *ref_299
  /v2/media/video/uploads:
    post:
      operationId: MediaAssetsController.createVideoUpload
      parameters: []
      responses:
        '201':
          description: ''
      tags: &ref_300
        - 'User: Moderated media'
  /v2/media/assets/{assetId}/upload-complete:
    post:
      operationId: MediaAssetsController.completeUpload
      parameters:
        - name: assetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_300
  /v2/media/assets/{assetId}/moderation-status:
    get:
      operationId: MediaAssetsController.status
      parameters:
        - name: assetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_300
  /v2/media/assets/{assetId}/preview:
    get:
      operationId: MediaAssetsController.preview
      parameters:
        - name: assetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_300
  /v2/media/assets/{assetId}/appeals:
    post:
      operationId: MediaAssetsController.appeal
      parameters:
        - name: assetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_300
  /v2/admin/moderation/media:
    get:
      operationId: AdminMediaModerationController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_301
        - 'Admin: Media moderation'
  /v2/admin/moderation/media/{assetId}:
    get:
      operationId: AdminMediaModerationController.detail
      parameters:
        - name: assetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_301
  /v2/admin/moderation/media/{assetId}/approve:
    post:
      operationId: AdminMediaModerationController.approve
      parameters:
        - name: assetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_301
  /v2/admin/moderation/media/{assetId}/reject:
    post:
      operationId: AdminMediaModerationController.reject
      parameters:
        - name: assetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_301
  /v2/internal/media/moderation/process:
    post:
      operationId: InternalMediaModerationController.process
      parameters:
        - name: authorization
          required: true
          in: header
          schema:
            type: string
        - name: x-repeak-internal-token
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_302
        - InternalMediaModeration
  /v2/internal/media/moderation/storage-finalized:
    post:
      operationId: InternalMediaModerationController.storageFinalized
      parameters:
        - name: authorization
          required: true
          in: header
          schema:
            type: string
        - name: x-repeak-internal-token
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_302
  /v2/ocr/checkpoint:
    post:
      operationId: OcrController.extract
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Extract bib/checkpoint-code from a race-day photo. Returns { bibNumber,
        checkpointCode, confidence }.
      tags:
        - OCR
  /v2/search:
    get:
      operationId: SearchController.search
      parameters:
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: collections
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Global search across users + clubs + events + challenges. Typo-tolerant
        when Typesense is on; Postgres ILIKE fallback otherwise.
      tags: &ref_303
        - Search
  /v2/search/autocomplete:
    get:
      operationId: SearchController.autocomplete
      parameters:
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: perGroup
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §28 — autocomplete suggestions grouped by collection (events, clubs,
        athletes, challenges, brand challenges, programs).
      tags: *ref_303
  /v2/search/client-token:
    get:
      operationId: SearchController.clientToken
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Mint a Typesense search-only key for the mobile/web SDK. 503 when search
        isn't configured on this instance.
      tags: *ref_303
  /v2/search/status:
    get:
      operationId: SearchController.status
      parameters: []
      responses:
        '200':
          description: ''
      summary: Search engine health + collection list.
      tags: *ref_303
  /v2/search/athletes:
    get:
      operationId: SearchController.athletes
      parameters:
        - name: city
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §28.2 — paginated list of athlete-discoverable users (PUBLIC +
        ATHLETES_ONLY profiles).
      tags: *ref_303
  /v2/search/brands:
    get:
      operationId: SearchController.brands
      parameters:
        - name: featuredOnly
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §28.2 — paginated list of active sponsor brands.
      tags: *ref_303
  /v2/search/content:
    get:
      operationId: SearchController.content
      parameters:
        - name: sport
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §28.2 — paginated list of published content items.
      tags: *ref_303
  /v2/admin/search/ensure:
    post:
      operationId: AdminSearchController.ensure
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Force-create every collection (idempotent) and return the current
        catalog.
      tags: &ref_304
        - 'Admin: Search'
  /v2/admin/search/reindex/{collection}:
    post:
      operationId: AdminSearchController.queueReindex
      parameters:
        - name: collection
          required: true
          in: path
          schema:
            type: string
      responses:
        '202':
          description: ''
      summary: >-
        Queue a bulk reindex for the named collection. Non-blocking: returns
        immediately. Actual walk happens inside SearchReindexScheduler.
      tags: *ref_304
  /v2/admin/search/health:
    get:
      operationId: AdminSearchController.healthOverview
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Search engine + per-collection health overview (Typesense doc counts
        joined with Postgres row counts for drift detection).
      tags: *ref_304
  /v2/explore:
    get:
      operationId: ExploreController.getExplore
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Authenticated explore surface — trending hashtags, suggested athletes,
        upcoming events, trending clubs, open virtual runs.
      tags: &ref_305
        - Explore
  /v2/explore/public:
    get:
      operationId: ExploreController.getPublicExplore
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Public explore surface. Same carousels minus the per-user
        suggestedAthletes lane.
      tags: *ref_305
  /v2/explore/trending:
    get:
      operationId: ExploreController.getTrending
      parameters:
        - name: city
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §28 — events + clubs trending in the supplied city (or city-agnostic
        when omitted).
      tags: *ref_305
  /v2/explore/marquee:
    get:
      operationId: ExploreController.getMarquee
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §28 — upcoming marquee events (featured flag).
      tags: *ref_305
  /v2/coach/ask:
    post:
      operationId: AiCoachController.ask
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Ask the AI coach. Returns Claude Sonnet reply + any structured tool
        calls. 503 when ANTHROPIC_API_KEY is unset.
      tags: &ref_306
        - AI Coach
  /v2/coach/history:
    get:
      operationId: AiCoachController.listHistory
      parameters: []
      responses:
        '200':
          description: ''
      summary: §24 — list this athlete's coach conversation history (default thread).
      tags: *ref_306
  /v2/coach/context:
    get:
      operationId: AiCoachController.contextPreview
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        §24.3 — preview the 8 context streams the coach assembles for this
        athlete.
      tags: *ref_306
  /v2/coach/status:
    get:
      operationId: AiCoachController.status
      parameters: []
      responses:
        '200':
          description: ''
      summary: Coach health probe — enabled flag + active model. Never 503s.
      tags: *ref_306
  /v2/coach/voice/ask:
    post:
      operationId: AiCoachController.voiceAsk
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Sprint 8 — voice-assisted coach ask. Accepts base64 audio, runs Sarvam
        STT in the requested locale, and forwards the transcription to the text
        `ask` endpoint. 503 `SARVAM_NOT_CONFIGURED` when the backend has no
        Sarvam key.
      tags: *ref_306
  /v2/coach/voice/speak:
    post:
      operationId: AiCoachController.voiceSpeak
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Sprint 8 — text-to-speech for the coach reply. Returns a base64 audio
        blob in the requested locale. 503 `SARVAM_NOT_CONFIGURED` when the
        backend has no Sarvam key.
      tags: *ref_306
  /v2/admin/ai-cost-budget/snapshot:
    get:
      operationId: AdminAiCostBudgetController.snapshot
      parameters:
        - name: budgetUsd
          required: true
          in: query
          schema:
            type: string
        - name: periodDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Read-only snapshot of current period AI cost vs budget. Returns alert
        level + projection + top-5 burners. Does NOT emit events.
      tags: &ref_307
        - 'Admin: AI Cost Budget'
  /v2/admin/ai-cost-budget/run:
    post:
      operationId: AdminAiCostBudgetController.run
      parameters:
        - name: budgetUsd
          required: true
          in: query
          schema:
            type: string
        - name: periodDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Run dispatcher: aggregates usage logs + emits ai_cost_budget.<level>
        event. Returns the same verdict shape as snapshot.
      tags: *ref_307
  /v2/admin/training-templates:
    get:
      operationId: AdminTrainingTemplatesController.list
      parameters:
        - name: sportKey
          required: true
          in: query
          schema:
            type: string
        - name: targetDistance
          required: true
          in: query
          schema:
            type: string
        - name: publishedOnly
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_308
        - 'Admin: Training templates'
    post:
      operationId: AdminTrainingTemplatesController.create
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_308
  /v2/admin/training-templates/{id}:
    get:
      operationId: AdminTrainingTemplatesController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_308
    patch:
      operationId: AdminTrainingTemplatesController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_308
    delete:
      operationId: AdminTrainingTemplatesController.archive
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_308
  /v2/admin/training-templates/{id}/publish:
    post:
      operationId: AdminTrainingTemplatesController.publish
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: 'Flip published flag. `{ published: true|false }`.'
      tags: *ref_308
  /v2/training-templates:
    get:
      operationId: UserTrainingTemplatesController.list
      parameters:
        - name: sportKey
          required: true
          in: query
          schema:
            type: string
        - name: targetDistance
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_309
        - Training templates
  /v2/training-templates/{id}:
    get:
      operationId: UserTrainingTemplatesController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_309
  /v2/me/consent:
    get:
      operationId: MeComplianceController.listConsent
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Return current consent state for every tracked purpose + the policy
        version the client should show.
      tags: &ref_310
        - 'Me: DPDP data rights'
    post:
      operationId: MeComplianceController.setConsent
      parameters:
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetSingleConsentDto'
      responses:
        '201':
          description: ''
      summary: >-
        Grant or withdraw a single consent. Idempotent (no-op when current state
        already matches).
      tags: *ref_310
  /v2/me/consent/history:
    get:
      operationId: MeComplianceController.historyConsent
      parameters:
        - name: purpose
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Append-only history for one or all purposes. Filter with
        ?purpose=MARKETING_EMAIL.
      tags: *ref_310
  /v2/me/consent/bulk:
    post:
      operationId: MeComplianceController.setConsentBulk
      parameters:
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetBulkConsentDto'
      responses:
        '201':
          description: ''
      summary: >-
        Bulk set consent (e.g. for initial signup defaults or a mass-toggle in
        settings).
      tags: *ref_310
  /v2/me/data-export:
    post:
      operationId: MeComplianceController.dataExport
      parameters:
        - name: format
          required: true
          in: query
          schema:
            type: string
        - name: delivery
          required: true
          in: query
          schema:
            type: string
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Export all PII + activity data for the authenticated principal.
        Audit-logged. Returns JSON by default; ?format=csv returns a CSV blob
        (RFC 4180); ?delivery=email sends a Postmark email with a 24-hour
        signed-URL download link (G-30-13b) — the response shrinks to a small
        JSON envelope `{ delivery: "email", expiresAt }` on success or `{
        delivery: "fallback", reason }` when email is honest-disabled (response
        body still contains the inline JSON/CSV).
      tags: *ref_310
  /v2/me/data-erasure/active:
    get:
      operationId: MeComplianceController.getActiveErasure
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Active erasure request for the caller (REQUESTED or CONFIRMED). Returns
        null when none in flight. Backend-backed alternative to the per-tab
        sessionStorage workaround the clients used to use.
      tags: *ref_310
  /v2/me/data-erasure:
    post:
      operationId: MeComplianceController.requestErasure
      parameters:
        - name: x-correlation-id
          required: true
          in: header
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DataErasureRequestDto'
      responses:
        '201':
          description: ''
      summary: >-
        Create a DPDP §12 erasure request. PII is scrambled immediately;
        hard-delete runs after the cool-off window elapses + legal-hold review.
      tags: *ref_310
  /v2/me/data-erasure/cancel/{requestId}:
    post:
      operationId: MeComplianceController.cancelErasure
      parameters:
        - name: requestId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DataErasureCancelDto'
      responses:
        '201':
          description: ''
      summary: Cancel an erasure request that is still within its cool-off window.
      tags: *ref_310
  /v2/me/medical-info/erase:
    post:
      operationId: MeComplianceController.eraseMedicalInfo
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Erase medical-info fields (emergency contact, etc.) for the calling
        athlete. Preserves consent records.
      tags: *ref_310
  /v2/admin/compliance/erasure-requests:
    get:
      operationId: AdminComplianceController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List erasure requests filtered by status.
      tags: &ref_311
        - 'Admin: Compliance'
  /v2/admin/compliance/erasure-requests/{id}/reject:
    post:
      operationId: AdminComplianceController.reject
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminErasureRejectDto'
      responses:
        '201':
          description: ''
      summary: >-
        Reject an erasure request because a legal hold blocks it. Statute +
        retention date mandatory.
      tags: *ref_311
  /v2/admin/compliance/erasure-requests/tick:
    post:
      operationId: AdminComplianceController.tick
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Advance cool-off-eligible requests to CONFIRMED. Scheduled worker calls
        this too.
      tags: *ref_311
  /v2/admin/compliance/users/{userId}/consent/history:
    get:
      operationId: AdminComplianceController.userConsentHistory
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: View a principal's full consent history (admin support).
      tags: *ref_311
  /v2/admin/compliance/consent-manager/status:
    get:
      operationId: AdminComplianceController.cmStatus
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Consent-Manager vendor wiring status. Reports whether credentials are
        configured; never leaks the creds.
      tags: *ref_311
  /v2/organizer/tax/documents:
    get:
      operationId: OrganizerTaxController.listDocs
      parameters: []
      responses:
        '200':
          description: ''
      summary: List the organizer-uploaded tax documents.
      tags: &ref_312
        - 'Organizer: Tax'
    post:
      operationId: OrganizerTaxController.createDoc
      parameters: []
      responses:
        '201':
          description: ''
      summary: Register a tax document (metadata + file ref).
      tags: *ref_312
  /v2/organizer/tax/documents/{id}:
    patch:
      operationId: OrganizerTaxController.updateDoc
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Update a tax document status (or archive).
      tags: *ref_312
  /v2/organizer/tax/invoices:
    get:
      operationId: OrganizerTaxController.list
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: eventId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List GST invoices for the caller organizer. Optional FY + status +
        eventId filter.
      tags: *ref_312
  /v2/organizer/tax/invoices/export.csv:
    get:
      operationId: OrganizerTaxController.exportInvoices
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        CSV export of the caller organizer's tax invoices for a FY. Optional
        status filter.
      tags: *ref_312
  /v2/organizer/tax/invoices/{id}/pdf:
    get:
      operationId: OrganizerTaxController.invoicePdf
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Generate / fetch the GST tax invoice PDF for the caller organizer (PRD
        §42.5 D-116). Lazy + cached on TaxInvoice.pdfS3Key. Returns S3 key +
        signed URL.
      tags: *ref_312
  /v2/organizer/tax/invoices/{id}:
    get:
      operationId: OrganizerTaxController.get
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a single invoice by id.
      tags: *ref_312
  /v2/organizer/tax/events/{eventId}/rollup:
    get:
      operationId: OrganizerTaxController.rollupForEvent
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Per-event tax report rollup (PRD §42.5 G-42-13) — totals + filing-ready
        (ISSUED-only) + per-status breakdown + FY list.
      tags: *ref_312
  /v2/organizer/tax/invoices/{id}/issue:
    post:
      operationId: OrganizerTaxController.issue
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Attempt to issue a DRAFT invoice via ClearTax. Returns 503 when the
        vendor wiring is absent.
      tags: *ref_312
  /v2/organizer/tax/tds/194o:
    get:
      operationId: OrganizerTaxController.tdsList
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: quarter
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: 194-O deductions against the caller organizer. Filter by FY + quarter.
      tags: *ref_312
  /v2/organizer/tax/tds/194o/export.csv:
    get:
      operationId: OrganizerTaxController.exportTds
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: quarter
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        CSV export of the caller organizer's 194-O TDS rows for a FY. Optional
        quarter filter.
      tags: *ref_312
  /v2/organizer/tax/form-16a:
    get:
      operationId: OrganizerTaxController.form16aList
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Form 16A certificates for this organizer. 194-O section only.
      tags: *ref_312
  /v2/organizer/tax/form-16a/{id}/pdf:
    get:
      operationId: OrganizerTaxController.form16aPdf
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Form 16A PDF descriptor (PRD §42.5). Ownership-guarded. 404 on cross-org
        access; 409 when status is DRAFT / CANCELLED or pdfUrl is missing.
      tags: *ref_312
  /v2/me/prize-tax:
    get:
      operationId: UserPrizeTaxController.list
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List prize-tax rows for the caller.
      tags: &ref_313
        - 'Me: Prize tax'
  /v2/me/prize-tax/{id}:
    get:
      operationId: UserPrizeTaxController.get
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Fetch a single prize-tax row by id.
      tags: *ref_313
  /v2/me/prize-tax/{id}/acknowledge:
    post:
      operationId: UserPrizeTaxController.acknowledge
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Winner acknowledgement — moves a CALCULATED row to TDS_DEDUCTED.
      tags: *ref_313
  /v2/me/form-16a:
    get:
      operationId: UserPrizeTaxController.form16aList
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Form 16A certificates for the caller (194-B section). Filter by FY.
      tags: *ref_313
  /v2/admin/compliance/cleartax/status:
    get:
      operationId: AdminTaxController.cleartaxStatus
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        ClearTax vendor wiring status. Never leaks secrets; reports presence
        only.
      tags: &ref_314
        - 'Admin: Tax'
  /v2/admin/compliance/tax-invoices:
    get:
      operationId: AdminTaxController.listInvoices
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List tax invoices; filter by FY + status.
      tags: *ref_314
  /v2/admin/compliance/tax-invoices/export.csv:
    get:
      operationId: AdminTaxController.exportInvoices
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        CSV export of tax invoices for an FY. Returns a CSV payload as string;
        caller wraps in download.
      tags: *ref_314
  /v2/admin/compliance/tax-invoices/{id}/issue:
    post:
      operationId: AdminTaxController.issueInvoice
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Issue a DRAFT invoice via ClearTax (may 503).
      tags: *ref_314
  /v2/admin/compliance/tds:
    get:
      operationId: AdminTaxController.listTds
      parameters:
        - name: section
          required: true
          in: query
          schema:
            type: string
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: quarter
          required: true
          in: query
          schema:
            type: string
        - name: deducteeId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List TDS rows; filter by section + FY + quarter.
      tags: *ref_314
  /v2/admin/compliance/tds/export.csv:
    get:
      operationId: AdminTaxController.exportTds
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: section
          required: true
          in: query
          schema:
            type: string
        - name: quarter
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: CSV export of TDS rows for an FY + section.
      tags: *ref_314
  /v2/admin/compliance/prize-tax:
    post:
      operationId: AdminTaxController.createPrizeTax
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePrizeTaxDto'
      responses:
        '201':
          description: ''
      summary: Create a prize-tax settlement. Idempotent on resultId when supplied.
      tags: *ref_314
    get:
      operationId: AdminTaxController.listPrizeTax
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List prize-tax rows.
      tags: *ref_314
  /v2/admin/compliance/prize-tax/{id}/calculate:
    post:
      operationId: AdminTaxController.calculatePrizeTax
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Run 194-B math on a prize-tax row + advance to CALCULATED.
      tags: *ref_314
  /v2/admin/compliance/prize-tax/export.csv:
    get:
      operationId: AdminTaxController.exportPrizeTax
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: CSV export of prize-tax rows for an FY. Optional status filter.
      tags: *ref_314
  /v2/admin/compliance/prize-tax/{id}/tds-deducted:
    post:
      operationId: AdminTaxController.markTdsDeducted
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Advance CALCULATED → TDS_DEDUCTED.
      tags: *ref_314
  /v2/admin/compliance/prize-tax/{id}/disburse:
    post:
      operationId: AdminTaxController.disburse
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Advance TDS_DEDUCTED → DISBURSED.
      tags: *ref_314
  /v2/admin/compliance/form-16a/aggregate:
    post:
      operationId: AdminTaxController.aggregate
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AggregateForm16ADto'
      responses:
        '201':
          description: ''
      summary: >-
        Aggregate one quarter into a Form 16A DRAFT. Idempotent; re-runs refresh
        DRAFT sums.
      tags: *ref_314
  /v2/admin/compliance/form-16a/{id}/generate:
    post:
      operationId: AdminTaxController.generate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenerateForm16ADto'
      responses:
        '201':
          description: ''
      summary: >-
        Generate a Form 16A PDF via ClearTax. 503s cleanly when vendor is not
        wired.
      tags: *ref_314
  /v2/admin/compliance/form-16a:
    get:
      operationId: AdminTaxController.listForm16a
      parameters:
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: quarter
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List all Form 16A rows for FY + quarter.
      tags: *ref_314
  /v2/admin/compliance/tax/backfill/run:
    post:
      operationId: AdminTaxController.runBackfill
      parameters: []
      responses:
        '201':
          description: ''
      summary: Manually run the backfill worker that drafts invoices + 194-O rows.
      tags: *ref_314
  /v2/admin/compliance/account-merge/preview:
    post:
      operationId: AdminAccountMergeController.preview
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewMergeDto'
      responses:
        '201':
          description: ''
      summary: >-
        Compute the dependent-row preview without persisting anything. Safe to
        call repeatedly.
      tags: &ref_315
        - 'Admin: Account merge'
  /v2/admin/compliance/account-merge/propose:
    post:
      operationId: AdminAccountMergeController.propose
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProposeMergeDto'
      responses:
        '201':
          description: ''
      summary: >-
        Persist a merge proposal. Reason ≥ 8 chars; conflict if either user has
        an open proposal.
      tags: *ref_315
  /v2/admin/compliance/account-merge:
    get:
      operationId: AdminAccountMergeController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List merge proposals; filter by status.
      tags: *ref_315
  /v2/admin/compliance/account-merge/{id}:
    get:
      operationId: AdminAccountMergeController.get
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_315
  /v2/admin/compliance/account-merge/{id}/cancel:
    post:
      operationId: AdminAccountMergeController.cancel
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelMergeDto'
      responses:
        '201':
          description: ''
      tags: *ref_315
  /v2/admin/compliance/account-merge/{id}/execute:
    post:
      operationId: AdminAccountMergeController.execute
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Execute a PROPOSED merge. Feature-flag gated — returns 503 with code
        ACCOUNT_MERGE_EXECUTE_DISABLED until Sprint 10.
      tags: *ref_315
  /v2/sponsor/brands/{brandId}/prize-tax:
    get:
      operationId: SponsorPrizeTaxController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: financialYear
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List prize-tax rows for events sponsored by this brand. Optional FY +
        status filter.
      tags: &ref_316
        - 'Sponsor: Prize tax'
  /v2/sponsor/brands/{brandId}/prize-tax/{id}:
    get:
      operationId: SponsorPrizeTaxController.get
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Fetch one prize-tax row.
      tags: *ref_316
  /v2/sponsor/brands/{brandId}/prize-tax/{id}/notify-winner:
    post:
      operationId: SponsorPrizeTaxController.notifyWinner
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NotifyWinnerDto'
      responses:
        '201':
          description: ''
      summary: >-
        Notify the winner. Writes an inbox row + advances state to TDS_DEDUCTED.
        Email/SMS fan-out is ops-configurable.
      tags: *ref_316
  /v2/organizer/events/{eventId}/medical/participants/search:
    get:
      operationId: OrganizerMedicalTentController.searchParticipants
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: bib
          required: true
          in: query
          schema:
            type: string
        - name: name
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_317
        - bearer: []
      summary: >-
        Search participants for medical-tent operations. Returns name, bib,
        check-in status, open-incident count. NEVER returns medical info.
      tags: &ref_318
        - 'Organizer: Medical tent'
  /v2/organizer/events/{eventId}/medical/participants/{participantId}/reveal:
    post:
      operationId: OrganizerMedicalTentController.revealSafetyProfile
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RevealSafetyProfileDto'
      responses:
        '201':
          description: ''
      security: *ref_317
      summary: >-
        Reveal a participant safety profile. Required: justification (10–500
        chars). Writes a medical_info_access_logs row + a hash-chained audit-log
        entry.
      tags: *ref_318
  /v2/organizer/events/{eventId}/medical/incidents:
    get:
      operationId: OrganizerMedicalTentController.listIncidents
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: excludeStatus
          required: true
          in: query
          schema:
            type: string
        - name: severity
          required: true
          in: query
          schema:
            type: string
        - name: participantId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_317
      tags: *ref_318
  /v2/organizer/events/{eventId}/medical/incidents/{incidentId}:
    get:
      operationId: OrganizerMedicalTentController.getIncident
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: incidentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_317
      tags: *ref_318
    patch:
      operationId: OrganizerMedicalTentController.updateIncident
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: incidentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateMedicalIncidentDto'
      responses:
        '200':
          description: ''
      security: *ref_317
      tags: *ref_318
  /v2/organizer/events/{eventId}/medical/participants/{participantId}/incidents:
    post:
      operationId: OrganizerMedicalTentController.createIncident
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMedicalIncidentDto'
      responses:
        '201':
          description: ''
      security: *ref_317
      tags: *ref_318
  /v2/organizer/events/{eventId}/medical/incidents/{incidentId}/close:
    post:
      operationId: OrganizerMedicalTentController.closeIncident
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: incidentId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CloseMedicalIncidentDto'
      responses:
        '201':
          description: ''
      security: *ref_317
      tags: *ref_318
  /v2/admin/risk-register:
    get:
      operationId: AdminRiskRegisterController.snapshot
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_319
        - bearer: []
      summary: >-
        Risk register snapshot — 13 launch-blocking domain probes with current
        health, signal, last-checked, recommended action, and runbook anchor.
      tags: &ref_320
        - 'Admin: Risk register'
  /v2/admin/risk-register/{riskId}:
    get:
      operationId: AdminRiskRegisterController.getRisk
      parameters:
        - name: riskId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_319
      summary: Drill-down for a specific risk id.
      tags: *ref_320
  /v2/admin/risk-register/{riskId}/acknowledge:
    post:
      operationId: AdminRiskRegisterController.acknowledge
      parameters:
        - name: riskId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RiskActionDto'
      responses:
        '201':
          description: ''
      security: *ref_319
      summary: >-
        Admin acknowledges current risk state. Writes a hash-chained audit row
        "risk.acknowledged".
      tags: *ref_320
  /v2/admin/risk-register/{riskId}/escalate:
    post:
      operationId: AdminRiskRegisterController.escalate
      parameters:
        - name: riskId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RiskActionDto'
      responses:
        '201':
          description: ''
      security: *ref_319
      summary: >-
        Admin escalates a risk. Writes a hash-chained audit row
        "risk.escalated". Use for SEV1 invocation per crisis runbook.
      tags: *ref_320
  /v2/admin/ext-readiness:
    get:
      operationId: AdminExtReadinessController.snapshot
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Read-only snapshot of all 8 EXT adapter readiness flags + blockers +
        NOT_CONFIGURED error codes.
      tags:
        - 'Admin: External Readiness'
  /v2/admin/brand-challenge-approvals/pending:
    get:
      operationId: AdminBrandReadinessController.listPending
      parameters: []
      responses:
        '200':
          description: ''
      summary: List brand challenges awaiting admin approval
      tags: &ref_321
        - 'Admin: Brand readiness'
  /v2/admin/brand-challenge-approvals/{challengeId}/approve:
    post:
      operationId: AdminBrandReadinessController.approve
      parameters:
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Approve a brand-sponsored challenge
      tags: *ref_321
  /v2/admin/brand-challenge-approvals/{challengeId}/reject:
    post:
      operationId: AdminBrandReadinessController.reject
      parameters:
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Reject a brand-sponsored challenge
      tags: *ref_321
  /v2/admin/fulfillment-tasks:
    get:
      operationId: AdminBrandReadinessController.listTasks
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: brandId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List fulfillment queue (admin)
      tags: *ref_321
    post:
      operationId: AdminBrandReadinessController.create
      parameters: []
      responses:
        '201':
          description: ''
      summary: Create a fulfillment task (admin or auto-flow)
      tags: *ref_321
  /v2/admin/fulfillment-tasks/aging:
    get:
      operationId: AdminBrandReadinessController.listAging
      parameters: []
      responses:
        '200':
          description: ''
      summary: List fulfillment tasks with SLA aging class
      tags: *ref_321
  /v2/admin/fulfillment-tasks/{id}/assign:
    post:
      operationId: AdminBrandReadinessController.assign
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Assign a PENDING fulfillment task to an ops user
      tags: *ref_321
  /v2/admin/fulfillment-tasks/{id}/transition:
    post:
      operationId: AdminBrandReadinessController.transition
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Transition a fulfillment task
      tags: *ref_321
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/submit-for-approval:
    post:
      operationId: SponsorBrandReadinessController.submit
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Submit a brand-sponsored challenge for admin approval
      tags: &ref_322
        - 'Sponsor: Brand readiness'
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/approval-status:
    get:
      operationId: SponsorBrandReadinessController.approvalStatus
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get current approval status
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/coupons/autogen:
    post:
      operationId: SponsorBrandReadinessController.autogen
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Auto-generate a coupon batch for a brand challenge
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/coupons/upload:
    post:
      operationId: SponsorBrandReadinessController.upload
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Upload pre-existing partner coupon codes (CSV-style array)
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/coupons:
    get:
      operationId: SponsorBrandReadinessController.listBatches
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List coupon batches for this brand, each enriched with live assigned /
        redeemed / available code counts
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/coupons/{batchId}/export:
    get:
      operationId: SponsorBrandReadinessController.exportBatch
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: batchId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Export a coupon batch as CSV
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/fulfillment-tasks:
    get:
      operationId: SponsorBrandReadinessController.listFulfillment
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List fulfillment tasks for this brand
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/metrics/live:
    get:
      operationId: SponsorBrandReadinessController.metricsLive
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        V3-P1-002 — live engagement metrics for one brand challenge
        (participants / completions / rewards / CPE).
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/metrics/compare:
    get:
      operationId: SponsorBrandReadinessController.metricsCompare
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        V3-P1-003 — comparative metrics across all challenges for this brand
        (CPE benchmark + ROI).
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/reward-distribution:
    get:
      operationId: SponsorBrandReadinessController.getRewardDistribution
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Get the reward distribution config (Top-N / all-completers / tiered) for
        a brand challenge
      tags: *ref_322
    put:
      operationId: SponsorBrandReadinessController.upsertRewardDistribution
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Create or update the reward distribution config (tier rules) for a brand
        challenge
      tags: *ref_322
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/reward-distribution/activate:
    post:
      operationId: SponsorBrandReadinessController.activateRewardDistribution
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Activate (lock in) the reward distribution config for a challenge
      tags: *ref_322
  /v2/me/coupons:
    get:
      operationId: UserBrandReadinessController.myCoupons
      parameters: []
      responses:
        '200':
          description: ''
      summary: List my assigned coupon codes
      tags: &ref_323
        - 'Me: Brand-reward read surfaces'
  /v2/me/fulfillment-tasks:
    get:
      operationId: UserBrandReadinessController.myFulfillment
      parameters: []
      responses:
        '200':
          description: ''
      summary: List my fulfillment tasks (merch / concierge rewards)
      tags: *ref_323
  /v2/users/me/coupons:
    get:
      operationId: AthleteCouponsController.list
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_324
        - bearer: []
      summary: >-
        Coupon codes assigned to me, newest first. Includes the code itself,
        what it is for, and whether it is redeemed or expired.
      tags: &ref_325
        - 'Athlete: Coupons'
  /v2/users/me/coupons/{codeId}/redeem:
    post:
      operationId: AthleteCouponsController.redeem
      parameters:
        - name: codeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_324
      summary: >-
        Mark one of my coupons used. Idempotent — a second call returns the
        original redemption time rather than moving it.
      tags: *ref_325
  /v2/subscriptions/plans:
    get:
      operationId: SubscriptionsReadinessController.listPlans
      parameters:
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List subscription plans (catalog, read-only). Optionally filter by
        audience.
      tags: &ref_326
        - 'Subscriptions: Plans + entitlements'
  /v2/me/subscription:
    get:
      operationId: SubscriptionsReadinessController.getMySubscription
      parameters:
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Resolve my effective plan + entitlements (legacy shape — prefer GET
        /v2/me/entitlements).
      tags: *ref_326
  /v2/me/subscription/upgrade-intent:
    get:
      operationId: SubscriptionsReadinessController.upgradeIntent
      parameters:
        - name: targetPlan
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Record upgrade intent. If the target plan has no provider plan ID
        configured, returns 503 + caller must surface waitlist UX.
      tags: *ref_326
  /v2/subscriptions/webhooks/cashfree:
    post:
      operationId: SubscriptionsWebhooksController.cashfree
      parameters:
        - name: x-webhook-signature
          required: true
          in: header
          schema:
            type: string
        - name: x-webhook-timestamp
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Cashfree subscription webhook. HMAC-SHA256 signature required. Returns
        503 SUBSCRIPTION_WEBHOOK_NOT_CONFIGURED when secret unset (no silent
        acceptance).
      tags:
        - 'Public: Subscription Webhooks'
  /v2/me/entitlements:
    get:
      operationId: MeEntitlementsController.myEntitlements
      parameters:
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Resolved plan + features + limits + usage for the caller. The single
        contract clients render from.
      tags: &ref_327
        - 'Subscriptions: Me'
  /v2/subscriptions/catalog:
    get:
      operationId: MeEntitlementsController.catalogForAudience
      parameters:
        - name: audience
          required: true
          in: query
          schema:
            type: string
        - name: countryCode
          required: true
          in: query
          schema:
            type: string
        - name: currency
          required: true
          in: query
          schema:
            type: string
        - name: platform
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Purchasable plans for an audience, priced for a country. Replaces
        client-side price tables.
      tags: *ref_327
  /v2/subscriptions/quote:
    post:
      operationId: SubscriptionQuoteController.quote
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QuoteSubscriptionDto'
      responses:
        '201':
          description: ''
      summary: >-
        Price a plan for the caller, optionally applying a coupon. Returns line
        items: base → discount → tax → payable.
      tags:
        - 'Subscriptions: Quote'
  /v2/admin/subscriptions/plans:
    get:
      operationId: AdminSubscriptionPlansController.listPlans
      parameters:
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List all plans, optionally filtered by audience
      tags: &ref_328
        - 'Admin: Subscription Plans'
    post:
      operationId: AdminSubscriptionPlansController.createPlan
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePlanDto'
      responses:
        '201':
          description: ''
      summary: Create a plan (starts as DRAFT with an empty v1 draft version)
      tags: *ref_328
  /v2/admin/subscriptions/plan-prices:
    get:
      operationId: AdminSubscriptionPlansController.listPlanPrices
      parameters:
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Flat list of mappable plan prices (plan × version × cycle × currency).
        Feeds the store-product mapping picker — `plans` returns bare rows with
        no nested versions or prices to walk.
      tags: *ref_328
  /v2/admin/subscriptions/plans/{id}:
    patch:
      operationId: AdminSubscriptionPlansController.updatePlan
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePlanDto'
      responses:
        '200':
          description: ''
      summary: Edit plan presentation. Safe at any time — no effect on live mandates.
      tags: *ref_328
  /v2/admin/subscriptions/plans/{id}/impact:
    get:
      operationId: AdminSubscriptionPlansController.impact
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Live subscriber count per version — read before publish or retire
      tags: *ref_328
  /v2/admin/subscriptions/plans/{id}/diff:
    get:
      operationId: AdminSubscriptionPlansController.diff
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Field-level diff between two versions
      tags: *ref_328
  /v2/admin/subscriptions/plans/{id}/versions:
    post:
      operationId: AdminSubscriptionPlansController.mintVersion
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MintVersionDto'
      responses:
        '201':
          description: ''
      summary: >-
        Mint a DRAFT version copied from the current PUBLISHED one. This is how
        a price change happens.
      tags: *ref_328
  /v2/admin/subscriptions/versions/{id}:
    patch:
      operationId: AdminSubscriptionPlansController.updateVersion
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateVersionDto'
      responses:
        '200':
          description: ''
      summary: Edit DRAFT version terms (trial, tax, renewal)
      tags: *ref_328
  /v2/admin/subscriptions/versions/{id}/prices:
    post:
      operationId: AdminSubscriptionPlansController.upsertPrice
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertPriceDto'
      responses:
        '201':
          description: ''
      summary: Add or update a price on a DRAFT version
      tags: *ref_328
  /v2/admin/subscriptions/versions/{id}/validate:
    post:
      operationId: AdminSubscriptionPlansController.validate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Publish checklist without publishing. Empty array = ready to publish.
      tags: *ref_328
  /v2/admin/subscriptions/versions/{id}/publish:
    post:
      operationId: AdminSubscriptionPlansController.publish
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublishVersionDto'
      responses:
        '201':
          description: ''
      summary: >-
        Freeze commercial terms and make the version sellable. Fails with a
        field-level error list.
      tags: *ref_328
  /v2/admin/subscriptions/versions/{id}/retire:
    post:
      operationId: AdminSubscriptionPlansController.retire
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Stop new sales. Existing subscribers keep resolving through this
        version.
      tags: *ref_328
  /v2/admin/subscriptions/features:
    post:
      operationId: AdminSubscriptionPlansController.createFeature
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFeatureDto'
      responses:
        '201':
          description: ''
      summary: Create a gateable feature
      tags: *ref_328
  /v2/admin/subscriptions/versions/{id}/features:
    post:
      operationId: AdminSubscriptionPlansController.setPlanFeature
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetPlanFeatureDto'
      responses:
        '201':
          description: ''
      summary: >-
        Map a feature onto a version. On a PUBLISHED version only
        non-restrictive edits are accepted (409 REQUIRES_NEW_VERSION otherwise).
      tags: *ref_328
  /v2/admin/subscriptions/simulate:
    post:
      operationId: AdminSubscriptionPlansController.simulate
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimulateEntitlementsDto'
      responses:
        '201':
          description: ''
      summary: >-
        Dry-run the resolver and (optionally) the quote for a user / plan /
        country / coupon
      tags: *ref_328
  /v2/admin/subscriptions/seed-from-catalog:
    post:
      operationId: AdminSubscriptionPlansController.seed
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Transcribe the static plan catalog into the DB. Idempotent; the cutover
        step from architecture doc §7.
      tags: *ref_328
  /v2/admin/subscriptions/engine-status:
    get:
      operationId: AdminSubscriptionPlansController.engineStatus
      parameters: []
      responses:
        '200':
          description: ''
      summary: Which source the resolver is reading and how many plans exist in the DB
      tags: *ref_328
  /v2/admin/subscriptions/coupons:
    get:
      operationId: AdminSubscriptionCouponsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: batchTag
          required: true
          in: query
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List coupons with claim counts
      tags: &ref_329
        - 'Admin: Subscription Coupons'
    post:
      operationId: AdminSubscriptionCouponsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCouponDto'
      responses:
        '201':
          description: ''
      summary: Create a coupon (money fields are minor units)
      tags: *ref_329
  /v2/admin/subscriptions/coupons/{id}:
    get:
      operationId: AdminSubscriptionCouponsController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Coupon detail + scopes + committed/pending/remaining
      tags: *ref_329
    patch:
      operationId: AdminSubscriptionCouponsController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCouponDto'
      responses:
        '200':
          description: ''
      summary: >-
        Edit a coupon. Discount value fields return 409 COUPON_VALUE_FROZEN once
        claimed.
      tags: *ref_329
  /v2/admin/subscriptions/coupons/{id}/toggle:
    post:
      operationId: AdminSubscriptionCouponsController.toggle
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Pause / resume instantly — the promo kill switch
      tags: *ref_329
  /v2/admin/subscriptions/coupons/{id}/scopes:
    post:
      operationId: AdminSubscriptionCouponsController.replaceScopes
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Replace eligibility scopes. OR within a scope type, AND across types.
      tags: *ref_329
  /v2/admin/subscriptions/coupons/bulk-generate:
    post:
      operationId: AdminSubscriptionCouponsController.bulkGenerate
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkGenerateCouponsDto'
      responses:
        '201':
          description: ''
      summary: Generate N unique codes from a prefix, sharing one config via batchTag
      tags: *ref_329
  /v2/admin/subscriptions/coupons/{id}/preview:
    post:
      operationId: AdminSubscriptionCouponsController.preview
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewCouponDto'
      responses:
        '201':
          description: ''
      summary: >-
        Preview the exact line items and rejection reason a user would get for
        this coupon
      tags: *ref_329
  /v2/admin/subscriptions/coupons/{id}/analytics:
    get:
      operationId: AdminSubscriptionCouponsController.analytics
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Redemption counts and total discount given, in minor units
      tags: *ref_329
  /v2/admin/subscriptions/coupons/release-expired-reservations:
    post:
      operationId: AdminSubscriptionCouponsController.releaseExpired
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Release PENDING reservations past their TTL so abandoned checkouts stop
        holding slots
      tags: *ref_329
  /v2/admin/subscriptions/config/regions:
    get:
      operationId: AdminSubscriptionConfigController.listRegions
      parameters: []
      responses:
        '200':
          description: ''
      summary: List pricing regions
      tags: &ref_330
        - 'Admin: Subscription Config'
    post:
      operationId: AdminSubscriptionConfigController.upsertRegion
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertRegionDto'
      responses:
        '201':
          description: ''
      summary: >-
        Create or update a pricing region. A country may belong to only one
        region.
      tags: *ref_330
  /v2/admin/subscriptions/config/tax-categories:
    get:
      operationId: AdminSubscriptionConfigController.listTax
      parameters: []
      responses:
        '200':
          description: ''
      summary: Tax categories with their effective-dated rates
      tags: *ref_330
    post:
      operationId: AdminSubscriptionConfigController.upsertTaxCategory
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertTaxCategoryDto'
      responses:
        '201':
          description: ''
      summary: Create or rename a tax category
      tags: *ref_330
  /v2/admin/subscriptions/config/tax-rates:
    post:
      operationId: AdminSubscriptionConfigController.addTaxRate
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddTaxRateDto'
      responses:
        '201':
          description: ''
      summary: >-
        Add an effective-dated rate. Supersedes the open rate for the same scope
        rather than editing it — historic invoices must stay reconstructable.
      tags: *ref_330
  /v2/admin/subscriptions/config/providers:
    get:
      operationId: AdminSubscriptionConfigController.listProviders
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Payment providers with `adapterDeployed` — a false value means the row
        is inert and must not be offered as a choice.
      tags: *ref_330
    post:
      operationId: AdminSubscriptionConfigController.upsertProvider
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertProviderDto'
      responses:
        '201':
          description: ''
      summary: >-
        Create or update a provider. Enabling one with no compiled adapter is
        rejected.
      tags: *ref_330
  /v2/admin/subscriptions/config/provider-refs:
    post:
      operationId: AdminSubscriptionConfigController.upsertProviderRef
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertProviderRefDto'
      responses:
        '201':
          description: ''
      summary: >-
        Map a plan price to its provider-side plan id. Required before a paid
        price can be published.
      tags: *ref_330
  /v2/admin/subscriptions/config/feature-dependencies:
    get:
      operationId: AdminSubscriptionConfigController.listDependencies
      parameters: []
      responses:
        '200':
          description: ''
      summary: List feature dependencies, by code
      tags: *ref_330
    post:
      operationId: AdminSubscriptionConfigController.addDependency
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddFeatureDependencyDto'
      responses:
        '201':
          description: ''
      summary: >-
        Declare that one feature requires another. Cycles are rejected — they
        would make publish validation unsatisfiable for both.
      tags: *ref_330
  /v2/admin/subscriptions/config/feature-dependencies/{id}:
    delete:
      operationId: AdminSubscriptionConfigController.removeDependency
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Remove a feature dependency
      tags: *ref_330
  /v2/admin/subscriptions/config/feature-categories:
    get:
      operationId: AdminSubscriptionConfigController.listCategories
      parameters: []
      responses:
        '200':
          description: ''
      summary: List feature categories
      tags: *ref_330
  /v2/admin/subscriptions/config/feature-inventory:
    get:
      operationId: AdminSubscriptionConfigController.featureInventory
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Reconcile feature codes gated in CODE against feature rows in CONFIG.
        Reports gates with no row (unconfigurable) and rows with no gate
        (unenforced).
      tags: *ref_330
  /v2/me/iap/config:
    get:
      operationId: SubscriptionsIapController.iapConfig
      parameters: []
      responses:
        '200':
          description: ''
      summary: Native IAP bootstrap. `enabled:false` means no store query or paywall.
      tags: &ref_331
        - 'Subscriptions: IAP'
  /v2/me/iap/sync:
    post:
      operationId: SubscriptionsIapController.syncFromStore
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Re-read the caller’s subscriptions from the stores and apply what
        changed. Backs Restore Purchases.
      tags: *ref_331
  /v2/me/iap/purchase:
    post:
      operationId: SubscriptionsIapController.submitPurchase
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitPurchaseDto'
      responses:
        '201':
          description: ''
      summary: >-
        Report a completed store purchase. The token is VERIFIED against the
        store; the client body never grants entitlement.
      tags: *ref_331
  /v2/iap/apple/notifications:
    post:
      operationId: SubscriptionsIapController.appleNotification
      parameters:
        - name: token
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        App Store Server Notifications v2. Authenticated by Apple JWS signature
        (x5c chain to a pinned root). Idempotent on notificationUUID.
      tags: *ref_331
  /v2/iap/google/notifications:
    post:
      operationId: SubscriptionsIapController.googleNotification
      parameters:
        - name: authorization
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_331
  /v2/iap/ops/lifecycle-sweep:
    post:
      operationId: SubscriptionsIapController.opsLifecycleSweep
      parameters:
        - name: authorization
          required: true
          in: header
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Run the lifecycle sweep. Bearer-authenticated with
        SUBSCRIPTION_OPS_TOKEN, for Cloud Scheduler. Idempotent. 503 when the
        token is unset.
      tags: *ref_331
  /v2/admin/subscriptions/settings:
    get:
      operationId: AdminSubscriptionIapController.getSettings
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Subscription master switch, plus launch-readiness signals (store
        mappings, unmapped events, engine source).
      tags: &ref_332
        - 'Admin: Subscription IAP + Settings'
    patch:
      operationId: AdminSubscriptionIapController.updateSettings
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSubscriptionSettingsDto'
      responses:
        '200':
          description: ''
      summary: >-
        Update the master switch. Partial — only supplied fields change. Turning
        the master off also stands down enforcement.
      tags: *ref_332
  /v2/admin/subscriptions/lifecycle/sweep:
    post:
      operationId: AdminSubscriptionIapController.sweepLifecycle
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Expire lapsed subscriptions now. Idempotent. Intended for Cloud
        Scheduler, since Cloud Run scale-to-zero can starve the in-process cron.
      tags: *ref_332
  /v2/admin/subscriptions/subscribers:
    get:
      operationId: AdminSubscriptionIapController.searchSubscribers
      parameters:
        - name: query
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: planKey
          required: true
          in: query
          schema:
            type: string
        - name: source
          required: true
          in: query
          schema:
            type: string
        - name: audience
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Search subscribers by user id, store transaction id or product.
        Filterable by status/plan/source.
      tags: *ref_332
  /v2/admin/subscriptions/subscribers/{id}:
    get:
      operationId: AdminSubscriptionIapController.subscriberDetail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Full record for one subscription: state, resolved entitlements, and the
        last 50 store events.
      tags: *ref_332
  /v2/admin/subscriptions/subscribers/{id}/extend:
    post:
      operationId: AdminSubscriptionIapController.extendSubscriber
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExtendSubscriptionDto'
      responses:
        '201':
          description: ''
      summary: Extend a subscription by N days. Additive, audited, reason required.
      tags: *ref_332
  /v2/admin/subscriptions/subscribers/{id}/revoke:
    post:
      operationId: AdminSubscriptionIapController.revokeSubscriber
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RevokeSubscriptionDto'
      responses:
        '201':
          description: ''
      summary: >-
        Revoke a subscription immediately. Does not refund. Audited, reason
        required.
      tags: *ref_332
  /v2/admin/subscriptions/organizer-drift:
    get:
      operationId: AdminSubscriptionIapController.organizerDrift
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Read-only comparison of the engine against the legacy organizer
        subscriptions. Migration gate: drifted must be 0.
      tags: *ref_332
  /v2/admin/subscriptions/analytics/summary:
    get:
      operationId: AdminSubscriptionIapController.analyticsSummary
      parameters:
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        MRR (normalised monthly), active/trial/past-due counts, ARPU, plan and
        store breakdown.
      tags: *ref_332
  /v2/admin/subscriptions/analytics/churn:
    get:
      operationId: AdminSubscriptionIapController.analyticsChurn
      parameters:
        - name: days
          required: true
          in: query
          schema:
            type: string
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Churn rate and counts over N days (default 30), broken down by
        cancellation reason.
      tags: *ref_332
  /v2/admin/subscriptions/analytics/trial-conversion:
    get:
      operationId: AdminSubscriptionIapController.analyticsTrialConversion
      parameters:
        - name: days
          required: true
          in: query
          schema:
            type: string
        - name: audience
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Trial-to-paid conversion for trials STARTED in the window, so the cohort
        is fixed.
      tags: *ref_332
  /v2/admin/subscriptions/seed-athlete-tiers:
    post:
      operationId: AdminSubscriptionIapController.seedAthleteTiers
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Seed the Athlete / Passport / Champion tiers, prices and feature
        mappings. Idempotent — existing rows are skipped, never overwritten.
      tags: *ref_332
  /v2/admin/subscriptions/store-products:
    get:
      operationId: AdminSubscriptionIapController.listStoreProducts
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Store product mappings joined to plan + price. `priceMatchesStore:false`
        means the paywall shows a price the store will not charge.
      tags: *ref_332
    post:
      operationId: AdminSubscriptionIapController.upsertStoreProduct
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertStoreProductRefDto'
      responses:
        '201':
          description: ''
      summary: >-
        Map a plan price to a store product. `markSynced` asserts the product is
        live in the store console — it is what makes the price purchasable on
        mobile.
      tags: *ref_332
  /v2/admin/subscriptions/store-products/{id}:
    delete:
      operationId: AdminSubscriptionIapController.removeStoreProduct
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Remove a mapping. The price stops being purchasable on that store
        immediately; existing subscribers are unaffected.
      tags: *ref_332
  /v2/admin/subscriptions/iap-events:
    get:
      operationId: AdminSubscriptionIapController.listEvents
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: userId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Store event ledger. Filter `status=UNMAPPED` for purchases that landed
        with no matching plan mapping — those are real customers waiting on
        config.
      tags: *ref_332
  /v2/admin/subscriptions/iap-events/{id}/replay:
    post:
      operationId: AdminSubscriptionIapController.replayEvent
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Re-run a stored event through ingest. Re-normalises from the raw
        payload, so it picks up mapping and code fixes.
      tags: *ref_332
  /v2/admin/analytics/onboarding-funnel:
    get:
      operationId: AdminAnalyticsReadinessController.onboardingFunnel
      parameters: []
      responses:
        '200':
          description: ''
      summary: V3-P1-023 — onboarding funnel drop-off counts
      tags: &ref_333
        - 'Admin: Analytics readiness'
  /v2/admin/analytics/five-funnels:
    get:
      operationId: AdminAnalyticsReadinessController.fiveFunnels
      parameters: []
      responses:
        '200':
          description: ''
      summary: V3-P1-024 — 5-funnel attribution counts
      tags: *ref_333
  /v2/admin/analytics/waa:
    get:
      operationId: AdminAnalyticsReadinessController.waa
      parameters: []
      responses:
        '200':
          description: ''
      summary: V3-P1-025 — weekly active athletes (last 7d)
      tags: *ref_333
  /v2/admin/analytics/engagement-retention:
    get:
      operationId: AdminAnalyticsReadinessController.engagementRetention
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        V3-P1-026 — DAU/WAU/MAU + D1/D7/D30 retention. Retention buckets return
        null (NOT_INSTRUMENTED) until cohort signup-day audit access ships.
      tags: *ref_333
  /v2/admin/analytics/performance:
    get:
      operationId: AdminAnalyticsReadinessController.performance
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        V3-P1-041 — performance monitoring (p50/p95/p99). Honestly
        NOT_INSTRUMENTED until OpenTelemetry/Datadog wired; runbook returned.
      tags: *ref_333
  /v2/p1-final/series-leaderboard/{seriesKey}:
    get:
      operationId: P1FinalClosureController.series
      parameters:
        - name: seriesKey
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: V3-P1-021 series leaderboard top entries
      tags: &ref_334
        - 'V3-P1-FINAL: Consolidated launch-grade closures'
  /v2/p1-final/self-service-requests:
    post:
      operationId: P1FinalClosureController.createSelfService
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P1-034 self-service bib transfer / distance / defer
      tags: *ref_334
  /v2/p1-final/fundraising-teams:
    post:
      operationId: P1FinalClosureController.createTeam
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P1-035 group fundraising team
      tags: *ref_334
  /v2/p1-final/campaigns:
    post:
      operationId: P1FinalClosureController.createCampaign
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P1-009 + V3-P1-018 engagement campaign create
      tags: *ref_334
    get:
      operationId: P1FinalClosureController.listCampaigns
      parameters: []
      responses:
        '200':
          description: ''
      summary: V3-P1-009 list campaigns
      tags: *ref_334
  /v2/p1-final/cheers:
    post:
      operationId: P1FinalClosureController.sendCheer
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P1-011 / V3-P1-029 live cheer send
      tags: *ref_334
  /v2/p1-final/cheers/me:
    get:
      operationId: P1FinalClosureController.myCheers
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: V3-P1-011 list cheers I received
      tags: *ref_334
  /v2/p1-final/training-programs:
    post:
      operationId: P1FinalClosureController.createTrainingProgram
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P1-022 custom training program create
      tags: *ref_334
  /v2/p1-final/training-programs/me:
    get:
      operationId: P1FinalClosureController.myTrainingPrograms
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_334
  /v2/p1-final/churn-risk/compute:
    post:
      operationId: P1FinalClosureController.computeChurn
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P1-038 rules-based churn risk compute
      tags: *ref_334
  /v2/p1-final/churn-risk/me:
    get:
      operationId: P1FinalClosureController.myChurnRisk
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_334
  /v2/p1-final/churn-risk/bucket/{bucket}:
    get:
      operationId: P1FinalClosureController.churnByBucket
      parameters:
        - name: bucket
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_334
  /v2/p2-final/compromised-accounts:
    post:
      operationId: P2FinalClosureController.submitCompromised
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-007 compromised account intake
      tags: &ref_335
        - 'V3-P2-FINAL: Consolidated P2 launch-grade closures'
    get:
      operationId: P2FinalClosureController.listCompromised
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: V3-P2-007 list compromised account reports
      tags: *ref_335
  /v2/p2-final/clubs/{clubId}/sports:
    post:
      operationId: P2FinalClosureController.setClubSports
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: V3-P2-012 set club sports
      tags: *ref_335
    get:
      operationId: P2FinalClosureController.listClubSports
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/memories:
    post:
      operationId: P2FinalClosureController.createMemory
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-019 generate athlete memory (system)
      tags: *ref_335
  /v2/p2-final/memories/me:
    get:
      operationId: P2FinalClosureController.myMemories
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/photographer-listings:
    post:
      operationId: P2FinalClosureController.createListing
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-020 create photographer listing
      tags: *ref_335
    get:
      operationId: P2FinalClosureController.listListings
      parameters:
        - name: city
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/tags:
    post:
      operationId: P2FinalClosureController.tag
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-021 tag athlete in photo/activity
      tags: *ref_335
  /v2/p2-final/tags/{tagId}/remove:
    post:
      operationId: P2FinalClosureController.removeTag
      parameters:
        - name: tagId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: V3-P2-021 remove tag (tagged user only)
      tags: *ref_335
  /v2/p2-final/tags/{subjectType}/{subjectId}:
    get:
      operationId: P2FinalClosureController.listTags
      parameters:
        - name: subjectType
          required: true
          in: path
          schema:
            type: string
        - name: subjectId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/events/{eventId}/version-snapshot:
    post:
      operationId: P2FinalClosureController.snapshot
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: V3-P2-028 capture event version snapshot
      tags: *ref_335
  /v2/p2-final/events/{eventId}/versions:
    get:
      operationId: P2FinalClosureController.listVersions
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/referrals/code:
    post:
      operationId: P2FinalClosureController.genCode
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-034 generate referral code
      tags: *ref_335
  /v2/p2-final/referrals/redeem:
    post:
      operationId: P2FinalClosureController.redeem
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-034 redeem referral code
      tags: *ref_335
  /v2/p2-final/referrals/me:
    get:
      operationId: P2FinalClosureController.myReferrals
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/clubs/{clubId}/awards:
    post:
      operationId: P2FinalClosureController.grantAward
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: V3-P2-040 grant club award
      tags: *ref_335
    get:
      operationId: P2FinalClosureController.listAwards
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: periodKey
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/experiments:
    post:
      operationId: P2FinalClosureController.upsertVariant
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-049/050 upsert experiment variant
      tags: *ref_335
  /v2/p2-final/experiments/{experimentKey}:
    get:
      operationId: P2FinalClosureController.listVariants
      parameters:
        - name: experimentKey
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/experiments/event:
    post:
      operationId: P2FinalClosureController.experimentEvent
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-049/050 record exposure / conversion
      tags: *ref_335
  /v2/p2-final/retention/hook:
    post:
      operationId: P2FinalClosureController.recordRetention
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-057/058 record retention hook execution
      tags: *ref_335
  /v2/p2-final/retention/me:
    get:
      operationId: P2FinalClosureController.myRetention
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/kb-metrics/event:
    post:
      operationId: P2FinalClosureController.kbEvent
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-042 record KB article metric
      tags: *ref_335
  /v2/p2-final/kb-metrics:
    get:
      operationId: P2FinalClosureController.listKb
      parameters:
        - name: periodKey
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/p2-final/dashboards:
    post:
      operationId: P2FinalClosureController.createDash
      parameters: []
      responses:
        '201':
          description: ''
      summary: V3-P2-037 create custom dashboard
      tags: *ref_335
  /v2/p2-final/dashboards/me:
    get:
      operationId: P2FinalClosureController.myDashboards
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_335
  /v2/organizers/{organizerId}/audience:
    get:
      operationId: OrganizerAudienceController.list
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: sportId
          required: false
          in: query
          schema:
            type: string
        - name: minLifetimeSpend
          required: false
          in: query
          schema:
            type: string
        - name: maxLifetimeSpend
          required: false
          in: query
          schema:
            type: string
        - name: minEventCount
          required: false
          in: query
          schema:
            type: string
        - name: lastEventAfter
          required: false
          in: query
          description: ISO-8601
          schema:
            type: string
        - name: lastEventBefore
          required: false
          in: query
          description: ISO-8601
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_336
        - bearer: []
      summary: List master cross-event audience for an organizer.
      tags: &ref_337
        - Organizer Audience
  /v2/organizers/{organizerId}/audience/export.csv:
    get:
      operationId: OrganizerAudienceController.exportCsv
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: sportId
          required: true
          in: query
          schema:
            type: string
        - name: minLifetimeSpend
          required: true
          in: query
          schema:
            type: string
        - name: minEventCount
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_336
      summary: Export the audience to CSV (capped at 50k rows for memory safety).
      tags: *ref_337
  /v2/organizers/{organizerId}/audience/backfill:
    post:
      operationId: OrganizerAudienceController.backfill
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_336
      summary: >-
        Trigger a full audience rebuild from event_participations history. Cheap
        for organizers <50k participations.
      tags: *ref_337
  /v2/organizers/{organizerId}/audience/{athleteUserId}/lifetime-value:
    get:
      operationId: OrganizerAudienceController.lifetimeValue
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: athleteUserId
          required: true
          in: path
          description: Athlete user ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_336
      summary: Read lifetime-value snapshot for a single athlete under this organizer.
      tags: *ref_337
  /v2/organizers/{organizerId}/analytics/cohort:
    get:
      operationId: OrganizerAnalyticsController.cohort
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_338
        - bearer: []
      summary: >-
        Cohort retention — YoY repeat-participation metrics derived from the
        master audience (PRD §43.2 G-43-7).
      tags: &ref_339
        - Organizer Analytics
  /v2/organizers/{organizerId}/analytics/attribution:
    get:
      operationId: OrganizerAnalyticsController.attribution
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Marketing attribution mix — first-touch source breakdown (PRD §43.1
        G-43-8).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/demographics:
    get:
      operationId: OrganizerAnalyticsController.demographics
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Audience demographics — gender split + age buckets + top-25 city
        distribution (PRD §43.1 G-43-3).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/repeat-participants:
    get:
      operationId: OrganizerAnalyticsController.repeatParticipants
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Repeat-participation analytics — lifetime + repeat counts, average
        events/athlete, top-N (PRD §43.2 G-43-9).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/lifetime-value:
    get:
      operationId: OrganizerAnalyticsController.lifetimeValueAggregate
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Lifetime-value analytics — aggregate distribution + cohorts + anonymized
        top-N (PRD §43.4 G-43-10).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/hybrid:
    get:
      operationId: OrganizerAnalyticsController.hybrid
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Hybrid race analytics — adoption mix (PHYSICAL/HYBRID/VIRTUAL) +
        validation rate (PRD §43.3 G-43-9 + G-43-11).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/events/{eventId}/first-timer-split:
    get:
      operationId: OrganizerAnalyticsController.firstTimerSplit
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: Per-event repeat-vs-first-timer split (PRD §43.1 G-43-3).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/hybrid-geo:
    get:
      operationId: OrganizerAnalyticsController.hybridGeo
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Geographic distribution of hybrid participants — top-25 city aggregation
        (PRD §43.3 G-43-10).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/aggregate:
    get:
      operationId: OrganizerAnalyticsController.organizationAggregate
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Organization-wide aggregate metrics — total events, lifetime athletes,
        total spend, avg events/athlete (PRD §44.1 G-44-1).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/club-affiliations:
    get:
      operationId: OrganizerAnalyticsController.clubAffiliations
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Top-25 clubs ranked by distinct athletes in this organizer's audience
        (PRD §43.1 G-43-4).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics/demographics-deep-dive:
    get:
      operationId: OrganizerAnalyticsController.demographicsDeepDive
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Top-N cohort cap (1-500, default 100).
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_338
      summary: >-
        Audience demographics cross-tabulation — gender × age × city cohorts,
        top-N (PRD §43.1 G-43-2 deep-dive).
      tags: *ref_339
  /v2/organizers/{organizerId}/analytics-identified/lifetime-value:
    get:
      operationId: OrganizerIdentifiedLtvController.lifetimeValueIdentified
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Identified lifetime-value — top-N athletes WITH userId (PRD §43.4
        G-43-10; OWNER+ADMIN only — PII-adjacent).
      tags:
        - Organizer Audience — Identified LTV
  /v2/organizer/audience:
    get:
      operationId: OrganizerAudiencePortalController.list
      parameters:
        - name: q
          required: false
          in: query
          description: Name substring
          schema:
            type: string
        - name: repeatOnly
          required: false
          in: query
          schema:
            type: boolean
        - name: minEvents
          required: false
          in: query
          schema:
            type: number
        - name: from
          required: false
          in: query
          description: lastEventAt ISO-8601 lower bound
          schema:
            type: string
        - name: to
          required: false
          in: query
          description: lastEventAt ISO-8601 upper bound
          schema:
            type: string
        - name: dormantOnly
          required: false
          in: query
          description: >-
            Sprint 04P — server-resolved dormant cohort filter (shared 180-day
            threshold).
          schema:
            type: boolean
        - name: cohortTag
          required: false
          in: query
          description: >-
            Sprint 04X — first-class tag filter (single-select). Mirrors the
            per-row tag enum so list + tag agree on what each tag means.
          schema:
            enum:
              - DORMANT
              - REPEAT
              - FIRST_TIME
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_340
        - bearer: []
      summary: >-
        Projected cross-event audience list for the partner portal. OWNER +
        ADMIN only (PRD §44.3).
      tags: &ref_341
        - 'Organizer: Audience (portal)'
  /v2/organizer/audience/summary:
    get:
      operationId: OrganizerAudiencePortalController.summary
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_340
      summary: >-
        Audience summary aggregates (totalAudience / repeatParticipants /
        averageEventsPerParticipant / totalRegistrations / totalLifetimeSpendInr
        / dormantParticipants).
      tags: *ref_341
  /v2/organizer/audience/{athleteUserId}:
    get:
      operationId: OrganizerAudiencePortalController.athleteLifetimeValue
      parameters:
        - name: athleteUserId
          required: true
          in: path
          description: Athlete user UUID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_340
      summary: >-
        Projected single-athlete LTV snapshot (PRD §44.3). Owner+Admin only.
        NotFound when the athlete is not in this organizer audience.
      tags: *ref_341
  /v2/organizer/audience/{athleteUserId}/timeline:
    get:
      operationId: OrganizerAudiencePortalController.athleteTimeline
      parameters:
        - name: athleteUserId
          required: true
          in: path
          description: Athlete user UUID
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: *ref_340
      summary: >-
        Per-athlete chronological event timeline (PRD §44.3). Owner+Admin only.
        404 if the athlete is not in this organizer audience; otherwise
        paginated rows (may be empty).
      tags: *ref_341
  /v2/organizer/audience/cohort-link:
    post:
      operationId: OrganizerAudiencePortalController.mintCohortLink
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MintCohortLinkDto'
      responses:
        '201':
          description: ''
      security: *ref_340
      summary: >-
        Mint an HMAC-signed v2 cohort link (PRD §44.3 / §40). Returns the URL +
        expiration ISO.
      tags: *ref_341
  /v2/organizer/audience/cohort-link/verify:
    post:
      operationId: OrganizerAudiencePortalController.verifyCohortLink
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyCohortLinkDto'
      responses:
        '201':
          description: ''
      security: *ref_340
      summary: >-
        Verify a v2 cohort link token; returns the safe criteria when the
        signature, expiration, and organizer-match all pass.
      tags: *ref_341
  /v2/organizer/activity:
    get:
      operationId: OrganizerActivityController.list
      parameters:
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: actorId
          required: false
          in: query
          schema:
            type: string
        - name: action
          required: false
          in: query
          schema:
            type: string
        - name: from
          required: false
          in: query
          schema:
            example: '2026-04-01'
            type: string
        - name: to
          required: false
          in: query
          schema:
            example: '2026-04-30'
            type: string
        - name: subjectType
          required: false
          in: query
          schema:
            example: Event
            type: string
        - name: subjectId
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Paginated organizer team activity log (PRD §44.4). Filter by actorId /
        action / date range. OWNER + ADMIN + VIEWER.
      tags:
        - 'Organizer: Activity'
  /v2/organizer/events/{eventId}/sponsorship-packages:
    get:
      operationId: EventSponsorshipsController.list
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event id
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - ACTIVE
              - ARCHIVED
            type: string
      responses:
        '200':
          description: ''
      security: &ref_342
        - bearer: []
      summary: >-
        List sponsorship packages for an event (PRD §38 / §41). OWNER + ADMIN +
        VIEWER.
      tags: &ref_343
        - 'Organizer: Event sponsorship packages'
    post:
      operationId: EventSponsorshipsController.create
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_342
      summary: Create a sponsorship package (DRAFT). OWNER + ADMIN only.
      tags: *ref_343
  /v2/organizer/events/{eventId}/sponsorship-packages/{packageId}:
    get:
      operationId: EventSponsorshipsController.getOne
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event id
          schema:
            type: string
        - name: packageId
          required: true
          in: path
          description: Package id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_342
      summary: Get a single sponsorship package by id (cross-org guard returns 404).
      tags: *ref_343
    patch:
      operationId: EventSponsorshipsController.update
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event id
          schema:
            type: string
        - name: packageId
          required: true
          in: path
          description: Package id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_342
      summary: Update a sponsorship package (non-archived only). OWNER + ADMIN only.
      tags: *ref_343
    delete:
      operationId: EventSponsorshipsController.archive
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event id
          schema:
            type: string
        - name: packageId
          required: true
          in: path
          description: Package id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_342
      summary: Archive a sponsorship package (terminal). OWNER + ADMIN only.
      tags: *ref_343
  /v2/organizer/events/{eventId}/sponsorship-packages/{packageId}/status:
    patch:
      operationId: EventSponsorshipsController.transitionStatus
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event id
          schema:
            type: string
        - name: packageId
          required: true
          in: path
          description: Package id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_342
      summary: Transition status (DRAFT ⇄ ACTIVE → ARCHIVED). OWNER + ADMIN only.
      tags: *ref_343
  /v2/me/challenge-participations/{id}/tax-receipt:
    get:
      operationId: CharityTaxReceiptController.taxReceipt
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: format
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Download the 80G tax receipt for the athlete's charity-challenge
        participation. Currently returns text/plain; PDF wrapper carry-forward.
      tags:
        - Charity — 80G Tax Receipt
  /v2/admin/charities:
    post:
      operationId: AdminCharitiesController.create
      parameters:
        - &ref_344
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Register a new charity. Defaults to UNVERIFIED.
      tags: &ref_345
        - Admin — Charity Verification
    get:
      operationId: AdminCharitiesController.list
      parameters:
        - *ref_344
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: country
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List charities, optionally filtered by status (e.g. ?status=verified or
        ?status=pending).
      tags: *ref_345
  /v2/admin/charities/{id}:
    get:
      operationId: AdminCharitiesController.findOne
      parameters:
        - *ref_344
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a charity by ID.
      tags: *ref_345
  /v2/admin/charities/{id}/status:
    patch:
      operationId: AdminCharitiesController.transition
      parameters:
        - *ref_344
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Transition a charity to a new verification status. Only legal
        transitions accepted; audit-logged.
      tags: *ref_345
  /v2/organizers/{organizerId}/training-programs/library:
    get:
      operationId: TrainingProgramController.getLibrary
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema: {}
      responses:
        '200':
          description: ''
      security: &ref_346
        - bearer: []
      summary: Read-only canonical workout library — one example per WorkoutType.
      tags: &ref_347
        - Organizer Training Programs
  /v2/organizers/{organizerId}/training-programs:
    get:
      operationId: TrainingProgramController.list
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PUBLISHED
              - ARCHIVED
            type: string
        - name: sport
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_346
      summary: List training-program templates for an organizer.
      tags: *ref_347
    post:
      operationId: TrainingProgramController.create
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTrainingProgramDto'
      responses:
        '201':
          description: ''
      security: *ref_346
      summary: Create a new training-program template.
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/{templateId}:
    get:
      operationId: TrainingProgramController.getOne
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_346
      summary: Get a single template (with all workouts in week/day order).
      tags: *ref_347
    patch:
      operationId: TrainingProgramController.update
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTrainingProgramDto'
      responses:
        '200':
          description: ''
      security: *ref_346
      summary: Update a template (name / description / sport / status / etc.).
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/{templateId}/workouts:
    post:
      operationId: TrainingProgramController.addWorkout
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddWorkoutDto'
      responses:
        '201':
          description: ''
      security: *ref_346
      summary: Add a workout to the template schedule.
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/{templateId}/workouts/{workoutId}:
    patch:
      operationId: TrainingProgramController.updateWorkout
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
        - name: workoutId
          required: true
          in: path
          description: Workout ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkoutDto'
      responses:
        '200':
          description: ''
      security: *ref_346
      summary: Update an existing workout slot.
      tags: *ref_347
    delete:
      operationId: TrainingProgramController.removeWorkout
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
        - name: workoutId
          required: true
          in: path
          description: Workout ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_346
      summary: Soft-delete a workout slot.
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/{templateId}/workouts/from-library:
    post:
      operationId: TrainingProgramController.customizeFromLibrary
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomizeFromLibraryDto'
      responses:
        '201':
          description: ''
      security: *ref_346
      summary: Clone a library workout into the template (preserves source linkage).
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/{templateId}/assignments:
    post:
      operationId: TrainingProgramController.assignToAthlete
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssignProgramDto'
      responses:
        '201':
          description: ''
      security: *ref_346
      summary: >-
        Assign this template to a single athlete for an event (PRD §38.2
        G-38-3).
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/{templateId}/assignments/bulk:
    post:
      operationId: TrainingProgramController.bulkAssign
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkAssignProgramDto'
      responses:
        '201':
          description: ''
      security: *ref_346
      summary: >-
        Bulk-assign this template to multiple athletes for an event (PRD §38.2
        G-38-3, max 1000 athletes/call).
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/assignments/{assignmentId}:
    delete:
      operationId: TrainingProgramController.unassign
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: assignmentId
          required: true
          in: path
          description: Assignment ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_346
      summary: Unassign a previously-assigned program (soft-deletes the row).
      tags: *ref_347
  /v2/organizers/{organizerId}/training-programs/events/{eventId}/assignments:
    get:
      operationId: TrainingProgramController.listForEvent
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_346
      summary: List active program assignments for an event.
      tags: *ref_347
  /v2/me/programs/library:
    get:
      operationId: AthleteProgramsController.library
      parameters:
        - &ref_348
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: sport
          required: false
          in: query
          schema:
            type: string
        - name: durationWeeksMin
          required: false
          in: query
          schema:
            type: number
        - name: durationWeeksMax
          required: false
          in: query
          schema:
            type: number
        - name: distanceMetersMin
          required: false
          in: query
          schema:
            type: number
        - name: distanceMetersMax
          required: false
          in: query
          schema:
            type: number
        - name: eventId
          required: false
          in: query
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Browse the published training-program library with filters.
      tags: &ref_349
        - Athlete Programs
  /v2/me/programs/{id}/preview:
    get:
      operationId: AthleteProgramsController.preview
      parameters:
        - *ref_348
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Week-by-week schedule preview for a published template.
      tags: *ref_349
  /v2/me/programs/admin-library:
    get:
      operationId: AthleteProgramsController.adminLibrary
      parameters:
        - *ref_348
        - name: sport
          required: false
          in: query
          schema:
            type: string
        - name: targetDistance
          required: false
          in: query
          description: 5K / 10K / 21K / 42K / ULTRA / GENERAL
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: >-
        Browse the admin-authored Phase-1 launch library (platform-curated
        programs).
      tags: *ref_349
  /v2/me/programs/workouts/{workoutId}/feedback:
    get:
      operationId: AthleteProgramsController.workoutFeedback
      parameters:
        - *ref_348
        - name: workoutId
          required: true
          in: path
          schema:
            type: string
        - name: currentPaceSecondsPerKm
          required: false
          in: query
          schema:
            type: number
        - name: tolerancePct
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Mid-workout feedback verdict given the athlete's current pace.
      tags: *ref_349
  /v2/me/programs/{id}/enroll:
    post:
      operationId: AthleteProgramsController.enroll
      parameters:
        - *ref_348
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Enrol the authenticated athlete in a published training-program
        template.
      tags: *ref_349
  /v2/me/programs/enrollments:
    get:
      operationId: AthleteProgramsController.listEnrollments
      parameters:
        - *ref_348
      responses:
        '200':
          description: ''
      summary: List the athlete's training-program enrollments.
      tags: *ref_349
  /v2/me/programs/enrollments/{enrollmentId}:
    delete:
      operationId: AthleteProgramsController.cancelEnrollment
      parameters:
        - *ref_348
        - name: enrollmentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Cancel an enrollment.
      tags: *ref_349
  /v2/me/programs/today-workout:
    get:
      operationId: AthleteProgramsController.todayWorkout
      parameters:
        - *ref_348
      responses:
        '200':
          description: ''
      summary: >-
        Today's workout for the athlete's active enrollment (rest day →
        workout=null with reason).
      tags: *ref_349
  /v2/me/programs/enrollments/{enrollmentId}/adherence:
    get:
      operationId: AthleteProgramsController.enrollmentAdherence
      parameters:
        - *ref_348
        - name: enrollmentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Adherence + schedule progress for one of the athlete's enrollments.
      tags: *ref_349
  /v2/me/programs/{templateId}/reviews:
    post:
      operationId: AthleteProgramsController.submitReview
      parameters:
        - *ref_348
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Submit (or update) a program review. Requires a COMPLETED enrollment for
        this template.
      tags: *ref_349
  /v2/me/programs/reviews/{reviewId}/helpful:
    post:
      operationId: AthleteProgramsController.markReviewHelpful
      parameters:
        - *ref_348
        - name: reviewId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Mark a review helpful (athlete-only).
      tags: *ref_349
  /v2/me/programs/reviews/{reviewId}/flag:
    post:
      operationId: AthleteProgramsController.flagReview
      parameters:
        - *ref_348
        - name: reviewId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Flag a review for moderation.
      tags: *ref_349
  /v2/programs/{templateId}/reviews:
    get:
      operationId: ProgramReviewsPublicController.list
      parameters:
        - name: templateId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: >-
        List published reviews for a program. Public — anonymous browsers can
        see.
      tags:
        - Programs — Reviews (Public)
  /v2/training/plans:
    get:
      operationId: UnifiedTrainingController.listPlans
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        §22 — list every training plan owned by the caller across all source
        systems.
      tags: &ref_350
        - Training (unified)
  /v2/training/plans/active:
    get:
      operationId: UnifiedTrainingController.activePlan
      parameters: []
      responses:
        '200':
          description: ''
      summary: §22 — return the single active plan across all source systems, or null.
      tags: *ref_350
  /v2/training/upcoming-workouts:
    get:
      operationId: UnifiedTrainingController.upcomingWorkouts
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §22 — upcoming workouts merged across the caller's active plans (all
        source systems).
      tags: *ref_350
  /v2/training/plans/{templateId}/enroll:
    post:
      operationId: UnifiedTrainingController.enrollInPlan
      parameters:
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        §22 — enrol the caller in an athlete-program template (delegates to
        ProgramEnrollmentService).
      tags: *ref_350
  /v2/training/workouts/{workoutId}/complete:
    post:
      operationId: UnifiedTrainingController.completeWorkout
      parameters:
        - name: workoutId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        §22 — mark a workout/session complete. Adaptive supports direct
        complete; legacy and program enrollments require activity submission.
      tags: *ref_350
  /v2/training/plans/generate:
    post:
      operationId: UnifiedTrainingController.generatePlan
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        §22 — generate a new plan. Routes to adaptive or legacy AI chat plan
        generators based on sourceSystem.
      tags: *ref_350
  /v2/discover/map:
    get:
      operationId: DiscoverMapController.search
      parameters:
        - name: lat
          required: true
          in: query
          description: Latitude (WGS84)
          schema:
            example: 12.9716
            type: number
        - name: lng
          required: true
          in: query
          description: Longitude (WGS84)
          schema:
            example: 77.5946
            type: number
        - name: radiusKm
          required: false
          in: query
          description: Search radius in km (default 50, max 500).
          schema:
            example: 50
            type: number
        - name: sportIds
          required: false
          in: query
          description: Comma-separated sportId list to filter by.
          schema:
            type: array
            items:
              type: string
        - name: from
          required: false
          in: query
          description: >-
            Lower bound on startDateTime (ISO). Defaults to "now" so past events
            are filtered out.
          schema:
            type: string
        - name: to
          required: false
          in: query
          description: >-
            Upper bound on startDateTime (ISO). When omitted, results are
            unbounded forward.
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Result limit (default 100, max 500).
          schema:
            example: 100
            type: number
      responses:
        '200':
          description: ''
      summary: §28 — geo-pinned event pins for the Discover Map surface
      tags:
        - v2/discover/map
  /v2/content-feed:
    get:
      operationId: ContentFeedController.forYou
      parameters:
        - name: sports
          required: true
          in: query
          schema:
            type: string
        - name: levels
          required: true
          in: query
          schema:
            type: string
        - name: tag
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_351
        - 'Content: Feed'
  /v2/content-feed/{id}:
    get:
      operationId: ContentFeedController.byId
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_351
  /v2/admin/content-feed/cover-images:
    post:
      operationId: AdminContentFeedController.uploadCoverImage
      parameters:
        - &ref_352
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: Content-Type
          in: header
          description: multipart/form-data
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                coverImage:
                  type: string
                  format: binary
      responses:
        '201':
          description: ''
      tags: &ref_353
        - 'Admin: Content Feed'
  /v2/admin/content-feed:
    get:
      operationId: AdminContentFeedController.list
      parameters:
        - *ref_352
        - name: publishStatus
          required: true
          in: query
          schema:
            type: string
        - name: contentType
          required: true
          in: query
          schema:
            type: string
        - name: sport
          required: true
          in: query
          schema:
            type: string
        - name: level
          required: true
          in: query
          schema:
            type: string
        - name: tag
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_353
    post:
      operationId: AdminContentFeedController.create
      parameters:
        - *ref_352
      responses:
        '201':
          description: ''
      tags: *ref_353
  /v2/admin/content-feed/{id}:
    get:
      operationId: AdminContentFeedController.byId
      parameters:
        - *ref_352
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_353
    patch:
      operationId: AdminContentFeedController.update
      parameters:
        - *ref_352
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_353
    delete:
      operationId: AdminContentFeedController.archive
      parameters:
        - *ref_352
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_353
  /v2/admin/content-feed/{id}/publish:
    patch:
      operationId: AdminContentFeedController.publish
      parameters:
        - *ref_352
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_353
  /v2/admin/content-feed/{id}/unpublish:
    patch:
      operationId: AdminContentFeedController.unpublish
      parameters:
        - *ref_352
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_353
  /v2/admin/content-feed/{id}/restore:
    post:
      operationId: AdminContentFeedController.restore
      parameters:
        - *ref_352
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_353
  /v2/users/me/onboarding/athlete-follows/suggestions:
    post:
      operationId: OnboardingController.previewAthleteFollows
      parameters: []
      responses:
        '201':
          description: ''
      summary: Preview athlete follow suggestions from unsaved sport interests.
      tags: &ref_354
        - v2/users/onboarding
  /v2/users/me/onboarding/sport-topics/catalog:
    post:
      operationId: OnboardingController.getSportTopicCatalog
      parameters: []
      responses:
        '201':
          description: ''
      summary: List active admin-managed topics grouped by selected sports.
      tags: *ref_354
  /v2/users/me/onboarding/interests:
    put:
      operationId: OnboardingController.saveSportInterests
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SaveOnboardingInterestsDto'
      responses:
        '200':
          description: ''
      summary: >-
        Persist selected sports, topics and sub-topics before follow
        suggestions.
      tags: *ref_354
  /v2/users/me/onboarding/athlete-follows:
    post:
      operationId: OnboardingController.createAthleteFollowSelection
      parameters: []
      responses:
        '201':
          description: ''
      summary: Persist the initial onboarding sports and athlete-follow selection.
      tags: *ref_354
    put:
      operationId: OnboardingController.replaceAthleteFollowSelection
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Replace all onboarding sports and athlete-follow selections before
        completion.
      tags: *ref_354
  /v2/users/me/onboarding/find-community:
    get:
      operationId: OnboardingController.findCommunity
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §14 — clubs near the athlete for the onboarding find-community screen.
      tags: *ref_354
  /v2/users/me/onboarding/first-event-suggestion:
    get:
      operationId: OnboardingController.firstEventSuggestion
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §14 — events near the athlete for the onboarding first-event screen.
      tags: *ref_354
  /v2/users/{id}/onboarding:
    get:
      operationId: OnboardingController.getOnboardingState
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §14 — onboarding wizard state for the given user (self-only access).
      tags: *ref_354
  /v2/users/{id}/onboarding/optional:
    patch:
      operationId: OnboardingController.recordOptionalStep
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §14.4 — record a skippable onboarding step visit/adoption signal.
      tags: *ref_354
  /v2/users/{id}/onboarding/sports:
    put:
      operationId: OnboardingController.setSportPreferences
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §14.1 Screen 7 — set the user's active multi-sport preferences
        (self-only).
      tags: *ref_354
  /v2/user/me/onboarding/state:
    get:
      operationId: UserOnboardingStateController.getState
      parameters:
        - &ref_355
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Get the athlete onboarding wizard state — 18 steps with per-step status,
        current step, lastActiveStep, completion timestamps. Owner-only.
      tags: &ref_356
        - User — Onboarding State (§14)
    patch:
      operationId: UserOnboardingStateController.patchState
      parameters:
        - *ref_355
      responses:
        '200':
          description: ''
      summary: >-
        Patch the wizard state — mark an optional step as COMPLETED/SKIPPED, or
        update lastActiveStep for resume. Required-step status is derived from
        User columns and cannot be patched here.
      tags: *ref_356
  /v2/user/me/onboarding/complete:
    post:
      operationId: UserOnboardingStateController.complete
      parameters:
        - *ref_355
      responses:
        '201':
          description: ''
      summary: >-
        Mark onboarding complete. Refuses when required steps are still pending;
        persists wizardCompletedAt timestamp.
      tags: *ref_356
  /v2/users/{id}/repeak-id:
    get:
      operationId: RepeakIdController.getRepeakId
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §16 — Repeak ID aggregate (header + stats + PRs + recent + race + badges
        + clubs + challenges)
      tags:
        - v2/users/repeak-id
  /v2/users/{userId}/albums:
    post:
      operationId: UserAlbumsController.createAlbum
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserAlbumDto'
      responses:
        '201':
          description: ''
      summary: §26.6 — create user album
      tags: &ref_357
        - v2/users/albums
    get:
      operationId: UserAlbumsController.listAlbums
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: type
          required: false
          in: query
          schema:
            type: string
            enum:
              - RACE_DAY
              - TRAINING
              - CLUB
              - CUSTOM
        - name: page
          required: false
          in: query
          description: Page (1-based, default 1)
          schema:
            type: number
        - name: limit
          required: false
          in: query
          description: Page size (default 20, max 100)
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: §26.6 — list user albums (paginated)
      tags: *ref_357
  /v2/users/{userId}/albums/{albumId}:
    get:
      operationId: UserAlbumsController.getAlbum
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: albumId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §26.6 — get one album
      tags: *ref_357
    patch:
      operationId: UserAlbumsController.updateAlbum
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: albumId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserAlbumDto'
      responses:
        '200':
          description: ''
      summary: §26.6 — update album (rename / cover)
      tags: *ref_357
    delete:
      operationId: UserAlbumsController.deleteAlbum
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: albumId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §26.6 — delete album (photos move to unfiled, not deleted)
      tags: *ref_357
  /v2/users/{userId}/photos:
    post:
      operationId: UserAlbumsController.createPhoto
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserPhotoDto'
      responses:
        '201':
          description: ''
      summary: §26.2 — create user photo (post-upload)
      tags: *ref_357
    get:
      operationId: UserAlbumsController.listPhotos
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: albumId
          required: false
          in: query
          schema:
            type: string
        - name: activityId
          required: false
          in: query
          schema:
            type: string
        - name: eventId
          required: false
          in: query
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: §26.2 — list user photos (paginated)
      tags: *ref_357
  /v2/users/{userId}/photos/{photoId}:
    get:
      operationId: UserAlbumsController.getPhoto
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §26.2 — get one photo
      tags: *ref_357
    patch:
      operationId: UserAlbumsController.updatePhoto
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserPhotoDto'
      responses:
        '200':
          description: ''
      summary: §26.2 — update photo (caption / album / privacy)
      tags: *ref_357
    delete:
      operationId: UserAlbumsController.deletePhoto
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: photoId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §26.2 — delete photo (soft-removal)
      tags: *ref_357
  /v2/brands/discover:
    get:
      operationId: PublicAthleteBrandController.discover
      parameters:
        - name: category
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: number
        - name: limit
          required: true
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: >-
        §47 — public catalogue of active sponsor brands for the mobile Discover
        screen
      tags: &ref_358
        - 'Public: Brand Discover'
  /v2/brands/challenges/discover:
    get:
      operationId: PublicAthleteBrandController.discoverBrandChallenges
      parameters:
        - name: sport
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: number
        - name: limit
          required: true
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: §28 — public list of brand-sponsored challenges currently joinable.
      tags: *ref_358
  /v2/brands/profile/{slug}:
    get:
      operationId: PublicAthleteBrandController.profile
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §47 — brand profile (logo, story, categories, kyc) for the mobile
        brand-detail screen
      tags: *ref_358
  /v2/users/me/sponsors:
    get:
      operationId: MyAthleteBrandController.mySponsors
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        §16.2 / §47 — brands the athlete has received goodies from OR follows;
        powers the Repeak ID brand-card
      tags: &ref_359
        - 'User: My Sponsors'
  /v2/users/me/organizations/following:
    get:
      operationId: MyAthleteBrandController.myFollowedOrgs
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Organizations the athlete explicitly follows. Powers the "Organizations
        I Follow" section on the athlete profile.
      tags: *ref_359
  /v2/admin/platform-health/services:
    get:
      operationId: PlatformHealthController.services
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_360
        - 'Admin: Platform Health (services / jobs)'
  /v2/admin/platform-health/jobs:
    get:
      operationId: PlatformHealthController.jobs
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_360
  /v2/admin/platform-health/slow-queries:
    get:
      operationId: PlatformHealthController.slowQueries
      parameters:
        - name: limit
          required: false
          in: query
          description: Max rows to return (default 25, max 100).
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_360
  /v2/admin/retention/cohorts/summary:
    get:
      operationId: RetentionController.summary
      parameters:
        - name: date
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_361
        - 'Admin: Retention'
  /v2/admin/retention/users/{userId}/cohort:
    get:
      operationId: RetentionController.forUser
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_361
  /v2/admin/retention/cohorts/snapshot:
    post:
      operationId: RetentionController.snapshot
      parameters:
        - name: date
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_361
  /v2/admin/retention/trends:
    get:
      operationId: RetentionController.trends
      parameters:
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_361
  /v2/admin/retention/dashboard:
    get:
      operationId: RetentionController.getDashboard
      parameters:
        - name: date
          required: true
          in: query
          schema:
            type: string
        - name: referralFrom
          required: true
          in: query
          schema:
            type: string
        - name: referralTo
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_361
  /v2/admin/lifecycle/triggers/summary:
    get:
      operationId: LifecycleController.summary
      parameters:
        - name: date
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_362
        - 'Admin: Lifecycle Triggers'
  /v2/admin/lifecycle/triggers/run:
    post:
      operationId: LifecycleController.run
      parameters:
        - name: date
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_362
  /v2/admin/lifecycle/users/{userId}/history:
    get:
      operationId: LifecycleController.history
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_362
  /v2/admin/lifecycle/triggers/trends:
    get:
      operationId: LifecycleController.trends
      parameters:
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_362
  /v2/public/stats:
    get:
      operationId: PublicWebController.getStats
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_363
        - Public Web
  /v2/public/og/events/{idOrSlug}.svg:
    get:
      operationId: PublicWebController.eventCard
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_363
  /v2/public/og/challenges/{idOrSlug}.svg:
    get:
      operationId: PublicWebController.challengeCard
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_363
  /v2/public/og/clubs/{idOrSlug}.svg:
    get:
      operationId: PublicWebController.clubCard
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_363
  /v2/editions/{idOrSlug}:
    get:
      operationId: EditionsController.detail
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Edition detail (first-class; viewer-aware when authed).
      tags: &ref_364
        - Editions
  /v2/editions/{idOrSlug}/leaderboard:
    get:
      operationId: EditionsController.leaderboard
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Edition leaderboard (separate per edition).
      tags: *ref_364
  /v2/editions/{idOrSlug}/leaderboard/me:
    get:
      operationId: EditionsController.myLeaderboardPlacing
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: The authenticated athlete's own rank in an edition leaderboard.
      tags: *ref_364
  /v2/editions/{idOrSlug}/register:
    post:
      operationId: EditionsController.register
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: Register the authenticated athlete for an Edition.
      tags: *ref_364
  /v2/editions/registrations/{registrationId}/verify:
    post:
      operationId: EditionsController.verify
      parameters:
        - name: registrationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: Verify (server-side) and confirm a paid edition registration.
      tags: *ref_364
  /v2/me/registrations:
    get:
      operationId: EditionsController.myRegistrations
      parameters: []
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: The authenticated athlete's Edition registrations (feeds Join).
      tags: *ref_364
  /v2/editions/webhooks/cashfree:
    post:
      operationId: EditionsController.cashfreeWebhook
      parameters:
        - name: x-webhook-signature
          required: true
          in: header
          schema:
            type: string
        - name: x-webhook-timestamp
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_364
  /v2/events/{idOrSlug}/editions:
    get:
      operationId: EditionsController.forEvent
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List the Editions of an Event.
      tags: *ref_364
  /v2/organizers/events/{eventId}/editions/{editionId}:
    patch:
      operationId: EditionsController.updateAsOrganizer
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: editionId
          required: true
          in: path
          description: Edition ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEditionDto'
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Update an edition (organizer). Distance + certificate today.
      tags: *ref_364
  /v2/organizers/events/{eventId}/edition:
    patch:
      operationId: EditionsController.updateDefaultEdition
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                minimumDistanceKm:
                  type: number
                  description: Minimum GPS distance (km) for a finisher certificate.
                certificateTemplateFile:
                  type: string
                  format: binary
                  description: Finisher certificate template artwork.
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Update (create-on-demand) the event's default Edition — distance +
        certificate template upload.
      tags: *ref_364
  /v2/organizations/{id}:
    get:
      operationId: OrganizationController.detail
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Organization social profile (athlete-facing).
      tags: &ref_365
        - Organizations
  /v2/organizations/{id}/events:
    get:
      description: >-
        Returns only live/upcoming events (published, open, closing_soon,
        in_progress). Cancelled, completed, and deleted events are excluded. Use
        ?page=1&limit=10. Each item carries can_view_detail=true. Detail page:
        GET /v2/events/:idOrSlug/public
      operationId: OrganizationController.events
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Organization's live + upcoming events (paginated).
      tags: *ref_365
  /v2/organizations/{id}/challenges:
    get:
      description: >-
        Returns only approved + active challenges. Cancelled and deleted
        challenges are excluded. Use ?page=1&limit=10. can_view_detail=true when
        the challenge has not ended. Detail page: GET
        /v2/challenges/:idOrSlug/public
      operationId: OrganizationController.challenges
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Organization's active challenges (paginated).
      tags: *ref_365
  /v2/organizations/{id}/announcements:
    get:
      operationId: OrganizationController.announcements
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Organization's announcements (broadcasts).
      tags: *ref_365
  /v2/organizations/{id}/follow:
    post:
      operationId: OrganizationController.follow
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: Follow an Organization.
      tags: *ref_365
    delete:
      operationId: OrganizationController.unfollow
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Unfollow an Organization (idempotent).
      tags: *ref_365
  /v2/participation-feed:
    get:
      operationId: ParticipationFeedController.feed
      parameters:
        - name: tab
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Following (graph) + For You (discovery) participation feed.
      tags:
        - Participation Feed
  /v2/discover/graph:
    get:
      operationId: DiscoverGraphController.graph
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Public Organizations + open Editions for Discover.
      tags:
        - Discover
  /v2/events/templates:
    post:
      operationId: EventTemplatesController.save
      parameters: []
      responses:
        '201':
          description: ''
      tags: &ref_366
        - 'Organizer: Event Templates'
    get:
      operationId: EventTemplatesController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_366
  /v2/events/templates/from-event/{eventId}:
    post:
      operationId: EventTemplatesController.saveFromEvent
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_366
  /v2/events/templates/{templateId}:
    get:
      operationId: EventTemplatesController.getOne
      parameters:
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_366
    delete:
      operationId: EventTemplatesController.remove
      parameters:
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_366
  /v2/events/templates/{templateId}/clone:
    post:
      operationId: EventTemplatesController.clone
      parameters:
        - name: templateId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_366
  /v2/events/standard-templates:
    get:
      operationId: StandardEventTemplatesController.list
      parameters: []
      responses:
        '200':
          description: ''
      summary: List the 8 platform-provided templates
      tags: &ref_367
        - 'Organizer: Standard event templates'
  /v2/events/standard-templates/{key}:
    get:
      operationId: StandardEventTemplatesController.get
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a single template by key
      tags: *ref_367
  /v2/events/standard-templates/{key}/instantiate:
    post:
      operationId: StandardEventTemplatesController.instantiate
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Hydrate a draft event-create payload from a template. Organizer reviews
        + edits before persisting.
      tags: *ref_367
  /v2/events/{eventId}/clone:
    post:
      operationId: EventCloneController.clone
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Clone the event SHELL (metadata + tickets) into a new DRAFT row. Does
        NOT copy registrations, payments, results, check-ins, or incidents.
      tags:
        - 'Organizer: Event clone'
  /v2/organizer/events/bulk:
    post:
      description: >-
        Run unpublish / cancel / clone on up to 100 event IDs. Returns per-id
        success/failure so the UI can surface partial successes.
      operationId: EventBulkController.runBulk
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkEventActionDto'
      responses:
        '200':
          description: Per-id results returned.
      summary: Bulk action on events
      tags:
        - Organizer Events — Bulk
  /v2/organizer/events/{eventId}/waitlist:
    get:
      operationId: EventWaitlistOrganizerController.listWaitlist
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Waitlist entries.
      summary: List waitlist entries for an event
      tags: &ref_368
        - Organizer Events — Waitlist
  /v2/organizer/events/{eventId}/waitlist/{entryId}/promote:
    post:
      operationId: EventWaitlistOrganizerController.promoteEntry
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: entryId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Promote a waitlist entry to OFFERED (out-of-order)
      tags: *ref_368
  /v2/organizer/events/{eventId}/waitlist/{entryId}/notify:
    post:
      operationId: EventWaitlistOrganizerController.resendNotify
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: entryId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Re-send the OFFERED notification
      tags: *ref_368
  /v2/organizer/events/{eventId}/waitlist/{entryId}:
    delete:
      operationId: EventWaitlistOrganizerController.removeEntry
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: entryId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Remove a waitlist entry (soft delete)
      tags: *ref_368
  /v2/organizer/events/{eventId}/anti-cheat:
    get:
      description: >-
        Resolves Event → HybridRace → HybridRaceResult.activityIds →
        AntiCheatFlag. Returns counts by severity/status + the most recent flags
        with athlete + rule.
      operationId: EventAntiCheatOrganizerController.listFlags
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Per-event anti-cheat snapshot.
      summary: List anti-cheat flags scoped to this event
      tags:
        - Organizer Events — Anti-Cheat
  /v2/organizer/events/{eventId}/wave-roster:
    get:
      operationId: EventWavesOrganizerController.listWaves
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Waves with roster.
      summary: List waves (slots) with per-wave participant counts + roster
      tags: &ref_369
        - Organizer Events — Waves
  /v2/organizer/events/{eventId}/participations/{participationId}/wave:
    patch:
      operationId: EventWavesOrganizerController.moveToWave
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MoveParticipationToWaveDto'
      responses:
        '200':
          description: ''
      summary: Move a participation to a different wave (slot)
      tags: *ref_369
  /v2/organizer/events/{eventId}/waves/seed:
    post:
      operationId: EventWavesOrganizerController.seedWaves
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SeedWavesDto'
      responses:
        '201':
          description: ''
      summary: >-
        Bulk auto-assign participants across waves (PRD §35.3). Capacity-aware;
        supports dryRun preview.
      tags: *ref_369
  /v2/organizer/events/{eventId}/self-service-config:
    get:
      operationId: EventSelfServiceConfigController.get
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Read the per-event participant self-service policy (PRD §35.4).
      tags: &ref_370
        - Organizer Events — Self-service
    patch:
      operationId: EventSelfServiceConfigController.update
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSelfServiceConfigDto'
      responses:
        '200':
          description: ''
      summary: Update the per-event participant self-service policy (PRD §35.4).
      tags: *ref_370
  /v2/organizers/events/{eventId}/sponsors:
    get:
      operationId: EventSponsorsController.sponsors
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: An event's sponsoring brands (committed deals).
      tags:
        - Event Sponsors
  /v2/events/{eventId}/prizes:
    get:
      operationId: EventPublicPrizesController.getPublicPrizes
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Prize leaderboards retrieved
      summary: An event's prize leaderboards (public/athlete view)
      tags: &ref_371
        - Event Prizes
  /v2/events/{eventId}/prizes/winners:
    get:
      description: >-
        Returns only PUBLISHED winners per leaderboard, with a public winner
        projection (name / username / photo). Empty until the organizer
        publishes.
      operationId: EventPublicPrizesController.getPublicWinners
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Published winners retrieved
      summary: An event's published prize winners (public/athlete view)
      tags: *ref_371
  /v2/organizers/events/{eventId}/prizes/contributions:
    get:
      description: >-
        Each row carries the proposing brand's `sponsorBrandName` /
        `sponsorBrandLogoUrl` (public identity only) so the owner can tell whose
        goodie they are judging.
      operationId: EventPrizeContributionsController.listContributions
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_372
        - bearer: []
      summary: List sponsor goodie contributions for the event
      tags: &ref_373
        - Event Prizes
  /v2/organizers/events/{eventId}/prizes/contributions/{contributionId}/accept:
    patch:
      description: >-
        Attaches a sponsor-attributed product to the slab covering the target
        rank (optionally re-targeted). Creates the leaderboard + slab when the
        event has none.
      operationId: EventPrizeContributionsController.acceptContribution
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: contributionId
          required: true
          in: path
          description: Contribution ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AcceptEventGoodieDto'
      responses:
        '200':
          description: ''
      security: *ref_372
      summary: Accept a sponsor goodie onto a prize rank
      tags: *ref_373
  /v2/organizers/events/{eventId}/prizes/contributions/{contributionId}/reject:
    patch:
      operationId: EventPrizeContributionsController.rejectContribution
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: contributionId
          required: true
          in: path
          description: Contribution ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_372
      summary: Reject a sponsor goodie contribution
      tags: *ref_373
  /v2/organizers/events/{eventId}/prizes:
    get:
      operationId: EventPrizesController.getPrizes
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Prize leaderboards retrieved
      security: &ref_374
        - bearer: []
      summary: Read an event's prize leaderboards (organizer editor)
      tags: &ref_375
        - Event Prizes
    put:
      description: >-
        Send `segments` as a JSON string (array of up to 6 leaderboards) plus
        one file per product prize in field
        `prizeProductImage_<segmentIndex>_<slabIndex>`. Accepted sponsor goodies
        are NOT in `segments` and are carried across automatically; if one can
        no longer be placed the save is refused (400) naming the brand and rank.
        Re-send with `dropSponsorContributionIds` to drop such a goodie on
        purpose — that rejects the brand’s accepted contribution.
      operationId: EventPrizesController.replacePrizes
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Prize leaderboards saved
        '400':
          description: >-
            Validation failed, or the save would destroy an accepted sponsor
            goodie
      security: *ref_374
      summary: Replace all prize leaderboards for an event
      tags: *ref_375
  /v2/organizers/events/{eventId}/prizes/results:
    put:
      description: >-
        In-person events cannot auto-measure; the organizer declares one or more
        winners for each rank per segment. Fully replaces the prior set.
      operationId: EventPrizesController.setResults
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnnounceEventResultsDto'
      responses:
        '200':
          description: Winners saved
      security: *ref_374
      summary: Announce rank winners for each prize leaderboard
      tags: *ref_375
    get:
      operationId: EventPrizesController.getResults
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_374
      summary: Read the announced rank winners
      tags: *ref_375
  /v2/organizers/events/{eventId}/prizes/distribute:
    post:
      description: >-
        Pays cash/coins to winners’ wallets, ledgers organizer goodies as
        pending shipping, and fulfils sponsor goodies via the brand. Idempotent.
      operationId: EventPrizesController.distribute
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '201':
          description: Distribution run complete
      security: *ref_374
      summary: Distribute prizes to the announced winners
      tags: *ref_375
  /v2/organizers/events/{eventId}/prizes/results/publish:
    post:
      description: >-
        Makes the announced winners public (visible on GET
        /v2/events/:id/prizes/winners) and eligible for distribution.
      operationId: EventPrizesController.publishResults
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '201':
          description: Winners published
      security: *ref_374
      summary: Publish the announced winners
      tags: *ref_375
  /v2/organizers/events/{eventId}/prizes/results/unpublish:
    post:
      description: Hides winners publicly again; they remain saved as a draft.
      operationId: EventPrizesController.unpublishResults
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '201':
          description: Winners reverted to draft
      security: *ref_374
      summary: Unpublish the winners (revert to draft)
      tags: *ref_375
  /v2/sponsor/brands/{brandId}/events/{eventId}/prize-contributions:
    get:
      operationId: SponsorEventGoodiesController.list
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_376
        - bearer: []
      summary: This brand's goodie contributions for the event
      tags: &ref_377
        - 'Sponsor: Event Goodies'
    post:
      operationId: SponsorEventGoodiesController.propose
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProposeEventGoodieDto'
      responses:
        '201':
          description: Contribution proposed
      security: *ref_376
      summary: Propose a goodie for a rank of an event prize leaderboard
      tags: *ref_377
  /v2/sponsor/brands/{brandId}/events/{eventId}/prize-contributions/{contributionId}:
    delete:
      operationId: SponsorEventGoodiesController.withdraw
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: contributionId
          required: true
          in: path
          description: Contribution ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_376
      summary: Withdraw a still-pending goodie contribution
      tags: *ref_377
  /v2/sponsor/brands/{brandId}/prize-contributions:
    get:
      operationId: SponsorPrizeContributionsRollupController.listAll
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Every prize-goodie contribution this brand has made, across all events.
        Optional ?status= filter.
      tags:
        - 'Sponsor: Event Prize Goodies'
  /v2/events/video-uploads:
    post:
      operationId: EventsController.createEventVideoUpload
      parameters: []
      responses:
        '201':
          description: ''
      security: &ref_378
        - bearer: []
      tags: &ref_379
        - Events
  /v2/events/video-uploads/cleanup:
    post:
      operationId: EventsController.cleanupEventVideoUploads
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/results/state:
    get:
      operationId: EventsController.getResultsState
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/results/publish:
    post:
      operationId: EventsController.publishResults
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/results/unpublish:
    post:
      operationId: EventsController.unpublishResults
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/public-visibility/{kind}/{id}:
    get:
      operationId: EventsController.getPublicVisibility
      parameters:
        - name: kind
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/finance-truth/participation/{participationId}:
    get:
      operationId: EventsController.checkParticipationTruth
      parameters:
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/finance-truth/refund/{refundId}:
    get:
      operationId: EventsController.checkRefundTruth
      parameters:
        - name: refundId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/finance-truth/reward-pool/{poolId}:
    get:
      operationId: EventsController.checkRewardPoolTruth
      parameters:
        - name: poolId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/portal-readiness/{kind}/{id}:
    get:
      operationId: EventsController.getPortalReadiness
      parameters:
        - name: kind
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{eventId}/course/waypoints:
    get:
      operationId: EventsController.publicWaypoints
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{eventId}/refund-policy:
    get:
      operationId: EventsController.refundPolicyRead
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{eventId}/series:
    get:
      operationId: EventsController.listSeriesChildren
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{eventId}/photo-summary:
    get:
      operationId: EventsController.photoSummaryRead
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{eventId}/marketing-summary:
    get:
      operationId: EventsController.marketingSummaryRead
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{eventId}/roster.csv:
    get:
      operationId: EventsController.rosterCsv
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events:
    post:
      description: >-
        Create a new event with cover images and all related data including
        slots, tickets, location, etc.
      operationId: EventsController.createEvent
      parameters: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/CreateEventDto'
      responses:
        '201':
          description: Event created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Event created successfully
                  id:
                    type: string
                  status:
                    type: string
        '400':
          description: Bad Request - Validation failed
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - Invalid role
        '500':
          description: Internal Server Error
      security: *ref_378
      summary: Create a new event
      tags: *ref_379
    get:
      description: >-
        Retrieve events based on user role with optional filtering by status and
        timeframe
      operationId: EventsController.getEvents
      parameters:
        - name: status
          required: false
          in: query
          description: Filter by event status
          schema:
            enum:
              - active
              - inactive
            type: string
        - name: timeframe
          required: false
          in: query
          description: Filter by time period
          schema:
            enum:
              - past
              - live
              - upcoming
            type: string
        - name: categoryId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: Events retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                    title:
                      type: string
                    desktopCoverImage:
                      type: string
                    mobileCoverImage:
                      type: string
                    desktopVideoUrl:
                      type: string
                      nullable: true
                    desktopVideoPosterUrl:
                      type: string
                      nullable: true
                    promoVideoUrl:
                      type: string
                      nullable: true
                    promoVideoPosterUrl:
                      type: string
                      nullable: true
                    startDateTime:
                      type: string
                      format: date-time
                    endDateTime:
                      type: string
                      format: date-time
                    type:
                      type: string
                    isActive:
                      type: boolean
                    location:
                      type: object
                    organizer:
                      type: object
        '400':
          description: Bad Request - Invalid parameters
        '401':
          description: Unauthorized
      security: *ref_378
      summary: Get all events
      tags: *ref_379
  /v2/events/discover:
    get:
      operationId: EventsController.discoverEvents
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: timeframe
          required: true
          in: query
          schema:
            type: string
        - name: categoryId
          required: true
          in: query
          schema:
            type: string
        - name: categorySlug
          required: true
          in: query
          schema:
            type: string
        - name: city
          required: false
          in: query
          description: >-
            Discover-only optional filter; server-side filtering is a follow-up
            (TODO_DRIFT_LOG → EVENTS-DISCOVER-CITY-FILTER).
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/public:
    get:
      operationId: EventsController.getPublicEvents
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: timeframe
          required: true
          in: query
          schema:
            type: string
        - name: categoryId
          required: true
          in: query
          schema:
            type: string
        - name: categorySlug
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/featured:
    post:
      description: >-
        Allows admins and organizers to feature or unfeature multiple events at
        once
      operationId: EventsController.updateFeaturedEvents
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateFeaturedEventsDto'
      responses:
        '200':
          description: Events featured status updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      totalRequested:
                        type: number
                      successCount:
                        type: number
                      failedCount:
                        type: number
                      updatedEvents:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                            title:
                              type: string
                            featuredEvent:
                              type: boolean
                      failedEvents:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                            reason:
                              type: string
      security: *ref_378
      summary: Update featured status for multiple events
      tags: *ref_379
    get:
      description: >-
        Retrieve events based on user role with optional filtering by status and
        timeframe
      operationId: EventsController.getFeaturedEvents
      parameters:
        - name: status
          required: false
          in: query
          description: Filter by event status
          schema:
            enum:
              - active
              - inactive
            type: string
        - name: timeframe
          required: false
          in: query
          description: Filter by time period
          schema:
            enum:
              - past
              - live
              - upcoming
            type: string
        - name: categoryId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: Events retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                    title:
                      type: string
                    desktopCoverImage:
                      type: string
                    mobileCoverImage:
                      type: string
                    desktopVideoUrl:
                      type: string
                      nullable: true
                    desktopVideoPosterUrl:
                      type: string
                      nullable: true
                    promoVideoUrl:
                      type: string
                      nullable: true
                    promoVideoPosterUrl:
                      type: string
                      nullable: true
                    startDateTime:
                      type: string
                      format: date-time
                    endDateTime:
                      type: string
                      format: date-time
                    type:
                      type: string
                    isActive:
                      type: boolean
                    location:
                      type: object
                    organizer:
                      type: object
        '400':
          description: Bad Request - Invalid parameters
        '401':
          description: Unauthorized
      security: *ref_378
      summary: Get all events
      tags: *ref_379
  /v2/events/featured/public:
    get:
      operationId: EventsController.getPublicFeaturedEvents
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: timeframe
          required: true
          in: query
          schema:
            type: string
        - name: categoryId
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/public/feed:
    get:
      description: >-
        Discovery-grade list of public events (published/open/live/completed)
        using the same allowlist as public event detail. Never leaks
        draft/cancelled/private/test events.
      operationId: EventsController.listPublicEventFeed
      parameters:
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: city
          required: false
          in: query
          schema:
            type: string
        - name: type
          required: false
          in: query
          schema:
            type: string
        - name: q
          required: false
          in: query
          schema:
            type: string
        - name: priceMode
          required: false
          in: query
          schema:
            enum:
              - free
              - paid
              - any
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      summary: Public event discovery feed
      tags: *ref_379
  /v2/events/{id}:
    get:
      description: Retrieve a single event with all its details based on user role
      operationId: EventsController.getEvent
      parameters:
        - name: id
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          description: Filter by event status
          schema:
            enum:
              - active
              - inactive
            type: string
      responses:
        '200':
          description: Event retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  title:
                    type: string
                  description:
                    type: string
                  desktopCoverImage:
                    type: string
                  mobileCoverImage:
                    type: string
                  desktopVideoUrl:
                    type: string
                    nullable: true
                  desktopVideoPosterUrl:
                    type: string
                    nullable: true
                  promoVideoUrl:
                    type: string
                    nullable: true
                  promoVideoPosterUrl:
                    type: string
                    nullable: true
                  startDateTime:
                    type: string
                    format: date-time
                  endDateTime:
                    type: string
                    format: date-time
                  type:
                    type: string
                  language:
                    type: string
                  coinsDiscountPercentage:
                    type: number
                  location:
                    type: object
                  slots:
                    type: array
                  coupons:
                    type: array
                  addOns:
                    type: array
                  frequentlyAskedQuestions:
                    type: array
                  termsAndCondition:
                    type: object
                  privacyPolicy:
                    type: object
                  organizer:
                    type: object
                  forms:
                    type: array
                  isActive:
                    type: boolean
        '401':
          description: Unauthorized
        '404':
          description: Event not found
      security: *ref_378
      summary: Get event by ID
      tags: *ref_379
    patch:
      description: >-
        Update an existing event with optional new cover images. Organizers can
        only update their own events.
      operationId: EventsController.updateEvent
      parameters:
        - name: id
          required: true
          in: path
          description: Event ID to update
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/UpdateEventDto'
      responses:
        '200':
          description: Event updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Event updated successfully
                  id:
                    type: string
                  title:
                    type: string
                  description:
                    type: string
                  startDateTime:
                    type: string
                    format: date-time
                  endDateTime:
                    type: string
                    format: date-time
                  type:
                    type: string
                  desktopCoverImage:
                    type: string
                  mobileCoverImage:
                    type: string
                  desktopVideoUrl:
                    type: string
                    nullable: true
                  desktopVideoPosterUrl:
                    type: string
                    nullable: true
                  promoVideoUrl:
                    type: string
                    nullable: true
                  promoVideoPosterUrl:
                    type: string
                    nullable: true
                  location:
                    type: object
                  slots:
                    type: array
                  coupons:
                    type: array
                  addOns:
                    type: array
                  isActive:
                    type: boolean
        '400':
          description: Bad Request - Validation failed or business rule violation
        '403':
          description: Forbidden - Cannot update this event
        '404':
          description: Event not found
        '500':
          description: Internal Server Error
      security: *ref_378
      summary: Update an event
      tags: *ref_379
    delete:
      description: >-
        Deletes the event (soft-remove) for an admin, or the owning organizer.
        Allowed ONLY when the event has zero active participants (cancelled
        registrations are ignored). If any active registration exists, returns
        400 — cancel the event instead.
      operationId: EventsController.deleteEvent
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_378
      summary: Soft-delete an event (only when it has no participants)
      tags: *ref_379
  /v2/events/{idOrSlug}/public:
    get:
      operationId: EventsController.getPublicEvent
      parameters:
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/by-slug/{slug}:
    get:
      operationId: EventsController.getPublicEventBySlug
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/by-city/{city}:
    get:
      operationId: EventsController.listPublicEventsByCity
      parameters:
        - name: city
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/by-country/{country}:
    get:
      operationId: EventsController.listPublicEventsByCountry
      parameters:
        - name: country
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/readiness:
    get:
      operationId: EventsController.getReadiness
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/submit-for-approval:
    patch:
      operationId: EventsController.submitForApproval
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/unpublish:
    patch:
      operationId: EventsController.unpublishEvent
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/review:
    patch:
      description: Approve or reject an event and provide review feedback
      operationId: EventsController.reviewEvent
      parameters:
        - name: id
          required: true
          in: path
          description: Event ID to review
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: Event reviewed successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  title:
                    type: string
                  approvalStatus:
                    type: string
                  reviewReason:
                    type: string
                  reviewedBy:
                    type: string
                  isActive:
                    type: boolean
        '403':
          description: Forbidden - Admin role required
        '404':
          description: Event or Admin not found
      security: *ref_378
      summary: Review an event (Admin only)
      tags: *ref_379
  /v2/events/{id}/announcements:
    post:
      description: >-
        Send an announcement to all participants of a specific event. The
        announcement will be saved to the event and push notifications will be
        sent to all participants.
      operationId: EventsController.sendEventAnnouncement
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendEventAnnouncementDto'
      responses:
        '201':
          description: Event announcement sent successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Event announcement sent successfully!
        '400':
          description: Bad request - Invalid announcement data
        '401':
          description: Unauthorized - Invalid or missing authentication token
        '403':
          description: >-
            Forbidden - User does not have organizer role or access to this
            event
        '404':
          description: Event not found or not approved
        '500':
          description: Internal server error
      security: *ref_378
      summary: Send event announcement
      tags: *ref_379
  /v2/events/{id}/toggle-bookings:
    patch:
      description: >-
        Toggle ticket bookings for an event. When stopped, the event is no
        longer visible to users in the app. When started, the event becomes
        visible again.
      operationId: EventsController.toggleBookings
      parameters:
        - name: id
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Event bookings toggled successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Event bookings stopped successfully
                  id:
                    type: string
                  isActive:
                    type: boolean
        '400':
          description: Bad Request - Event not in valid status
        '404':
          description: Event not found
      security: *ref_378
      summary: Toggle event bookings
      tags: *ref_379
  /v2/events/{id}/cancel:
    post:
      description: >-
        Cancel a published event. Initiates refunds for all paid bookings,
        cancels free bookings, and marks the event as cancelled.
      operationId: EventsController.cancelEvent
      parameters:
        - name: id
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelEventDto'
      responses:
        '201':
          description: Event cancelled successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Event cancelled successfully
                  id:
                    type: string
                  status:
                    type: string
                    example: cancelled
                  totalBookingsCancelled:
                    type: number
        '400':
          description: Bad Request
        '404':
          description: Event not found or not published
      security: *ref_378
      summary: Cancel event
      tags: *ref_379
  /v2/events/{id}/toggle:
    patch:
      operationId: EventsController.toggleEventStatus
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_378
      tags: *ref_379
  /v2/events/{id}/desktop-cover:
    patch:
      description: >-
        Updates the desktop cover image for an event. The old image is deleted
        from S3.
      operationId: EventsController.updateDesktopCoverImage
      parameters:
        - name: id
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Desktop cover image updated successfully
        '400':
          description: Bad Request
        '403':
          description: Forbidden
        '404':
          description: Event not found
      security: *ref_378
      summary: Update event desktop cover image
      tags: *ref_379
  /v2/events/{id}/mobile-cover:
    patch:
      description: >-
        Updates the mobile cover image for an event. The old image is deleted
        from S3.
      operationId: EventsController.updateMobileCoverImage
      parameters:
        - name: id
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Mobile cover image updated successfully
        '400':
          description: Bad Request
        '403':
          description: Forbidden
        '404':
          description: Event not found
      security: *ref_378
      summary: Update event mobile cover image
      tags: *ref_379
  /v2/organizers/events/{eventId}/slots:
    get:
      operationId: EventSlotsController.getSlots
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Slots retrieved successfully
        '404':
          description: Event not found
      security: &ref_380
        - bearer: []
      summary: Get all slots for an event
      tags: &ref_381
        - Event Slots
    post:
      description: Create a slot with or without tickets. Tickets can be added later.
      operationId: EventSlotsController.createSlot
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSlotDto'
      responses:
        '201':
          description: Slot created successfully
        '400':
          description: Validation failed
        '404':
          description: Event not found
      security: *ref_380
      summary: Create a new slot for an event
      tags: *ref_381
  /v2/organizers/events/{eventId}/slots/{slotId}:
    get:
      operationId: EventSlotsController.getSlot
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
      responses:
        '200':
          description: Slot retrieved successfully
        '404':
          description: Slot not found
      security: *ref_380
      summary: Get a single slot by ID
      tags: *ref_381
    put:
      operationId: EventSlotsController.updateSlot
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSlotDto'
      responses:
        '200':
          description: Slot updated successfully
        '404':
          description: Slot not found
      security: *ref_380
      summary: Update a slot
      tags: *ref_381
    delete:
      operationId: EventSlotsController.deleteSlot
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
      responses:
        '200':
          description: Slot deleted successfully
        '400':
          description: Cannot delete slot with booked tickets
        '404':
          description: Slot not found
      security: *ref_380
      summary: Delete a slot (soft delete)
      tags: *ref_381
  /v2/organizers/events/{eventId}/slots/{slotId}/toggle-status:
    patch:
      operationId: EventSlotsController.toggleSlotStatus
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
      responses:
        '200':
          description: Slot status toggled successfully
        '404':
          description: Slot not found
      security: *ref_380
      summary: Toggle slot active status
      tags: *ref_381
  /v2/organizers/events/{eventId}/slots/{slotId}/tickets:
    get:
      operationId: EventTicketsController.getTickets
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
      responses:
        '200':
          description: Tickets retrieved successfully
        '404':
          description: Event or slot not found
      security: &ref_382
        - bearer: []
      summary: Get all tickets for a slot
      tags: &ref_383
        - Event Tickets
    post:
      operationId: EventTicketsController.createTicket
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTicketDto'
      responses:
        '201':
          description: Ticket created successfully
        '400':
          description: Validation failed
        '404':
          description: Event or slot not found
      security: *ref_382
      summary: Create a new ticket for a slot
      tags: *ref_383
  /v2/organizers/events/{eventId}/slots/{slotId}/tickets/{ticketId}:
    get:
      operationId: EventTicketsController.getTicket
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
        - name: ticketId
          required: true
          in: path
          description: Ticket ID
          schema:
            type: string
      responses:
        '200':
          description: Ticket retrieved successfully
        '404':
          description: Ticket not found
      security: *ref_382
      summary: Get a single ticket by ID
      tags: *ref_383
    put:
      operationId: EventTicketsController.updateTicket
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
        - name: ticketId
          required: true
          in: path
          description: Ticket ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTicketDto'
      responses:
        '200':
          description: Ticket updated successfully
        '404':
          description: Ticket not found
      security: *ref_382
      summary: Update a ticket
      tags: *ref_383
    delete:
      operationId: EventTicketsController.deleteTicket
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
        - name: ticketId
          required: true
          in: path
          description: Ticket ID
          schema:
            type: string
      responses:
        '200':
          description: Ticket deleted successfully
        '400':
          description: Cannot delete ticket with existing bookings
        '404':
          description: Ticket not found
      security: *ref_382
      summary: Delete a ticket (soft delete)
      tags: *ref_383
  /v2/organizers/events/{eventId}/slots/{slotId}/tickets/{ticketId}/toggle-status:
    patch:
      operationId: EventTicketsController.toggleTicketStatus
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: slotId
          required: true
          in: path
          description: Slot ID
          schema:
            type: string
        - name: ticketId
          required: true
          in: path
          description: Ticket ID
          schema:
            type: string
      responses:
        '200':
          description: Ticket status toggled successfully
        '404':
          description: Ticket not found
      security: *ref_382
      summary: Toggle ticket active status
      tags: *ref_383
  /v2/organizers/events/{eventId}/forms:
    get:
      operationId: EventFormsController.getForms
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Forms retrieved successfully
        '404':
          description: Event not found
      security: &ref_384
        - bearer: []
      summary: Get all forms for an event
      tags: &ref_385
        - Event Forms
    post:
      description: Create a registration, feedback, or survey form for an event.
      operationId: EventFormsController.createForm
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFormDto'
      responses:
        '201':
          description: Form created successfully
        '400':
          description: Validation failed or form type already exists
        '404':
          description: Event not found
      security: *ref_384
      summary: Create a new form for an event
      tags: *ref_385
  /v2/organizers/events/{eventId}/forms/{formId}:
    get:
      operationId: EventFormsController.getForm
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: formId
          required: true
          in: path
          description: Form ID
          schema:
            type: string
      responses:
        '200':
          description: Form retrieved successfully
        '404':
          description: Form not found
      security: *ref_384
      summary: Get a single form by ID
      tags: *ref_385
    put:
      operationId: EventFormsController.updateForm
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: formId
          required: true
          in: path
          description: Form ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateFormDto'
      responses:
        '200':
          description: Form updated successfully
        '404':
          description: Form not found
      security: *ref_384
      summary: Update a form (PUT)
      tags: *ref_385
    patch:
      operationId: EventFormsController.patchForm
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: formId
          required: true
          in: path
          description: Form ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateFormDto'
      responses:
        '200':
          description: Form updated successfully
        '404':
          description: Form not found
      security: *ref_384
      summary: Update a form (PATCH)
      tags: *ref_385
    delete:
      operationId: EventFormsController.deleteForm
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: formId
          required: true
          in: path
          description: Form ID
          schema:
            type: string
      responses:
        '200':
          description: Form deleted successfully
        '404':
          description: Form not found
      security: *ref_384
      summary: Delete a form (soft delete)
      tags: *ref_385
  /v2/organizers/events/{eventId}/forms/{formId}/toggle-status:
    patch:
      operationId: EventFormsController.toggleFormStatus
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: formId
          required: true
          in: path
          description: Form ID
          schema:
            type: string
      responses:
        '200':
          description: Form status toggled successfully
        '404':
          description: Form not found
      security: *ref_384
      summary: Toggle form active status
      tags: *ref_385
  /v2/organizers/events/{eventId}/waiver/available-variables:
    get:
      description: >-
        The ONLY variables the waiver builder may insert. Derived from the
        event's active registration form.
      operationId: EventWaiverController.getAvailableVariables
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Available variables
      security: &ref_386
        - bearer: []
      summary: Registration form field names insertable into the waiver
      tags: &ref_387
        - Event Waiver
  /v2/organizers/events/{eventId}/waiver:
    get:
      operationId: EventWaiverController.getWaiver
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_386
      summary: Get the event's active waiver template
      tags: *ref_387
    post:
      operationId: EventWaiverController.createWaiver
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventWaiverDto'
      responses:
        '201':
          description: Waiver created
        '400':
          description: Unknown variable / no registration form
      security: *ref_386
      summary: Create the waiver (validates variables)
      tags: *ref_387
    put:
      operationId: EventWaiverController.updateWaiver
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEventWaiverDto'
      responses:
        '200':
          description: ''
      security: *ref_386
      summary: Update the waiver (creates a new version)
      tags: *ref_387
    delete:
      operationId: EventWaiverController.deleteWaiver
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_386
      summary: Deactivate the waiver (untick "Add waiver")
      tags: *ref_387
  /v2/organizers/events/{eventId}/waiver/acceptances:
    get:
      operationId: EventWaiverController.listAcceptances
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_386
      summary: List participants who accepted the waiver
      tags: *ref_387
  /v2/organizers/events/{eventId}/waiver/acceptances/{participantId}/download:
    get:
      operationId: EventWaiverController.downloadParticipantWaiver
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          description: Event participant ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_386
      summary: Download a participant's filled waiver PDF
      tags: *ref_387
  /v2/organizers/events/{eventId}/certificates/variables:
    get:
      description: >-
        The fixed system fields (name, age, bib, event date, ...) always
        available from real user/event/participant data, plus the event's active
        registration form fields.
      operationId: EventCertificateController.getAvailableVariables
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_388
        - bearer: []
      summary: Available {{ }} variables for the certificate builder
      tags: &ref_389
        - Event Certificates
  /v2/organizers/events/{eventId}/certificates/status:
    get:
      operationId: EventCertificateController.getStatus
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_388
      summary: Publish status + eligible/issued counts
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/not-issued:
    get:
      description: >-
        Exactly who the next publish() call would issue to — eligible (joined +
        attended) minus already-issued for the active template.
      operationId: EventCertificateController.listNotIssued
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_388
      summary: Eligible participants who do not yet have a certificate issued
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/issuances:
    get:
      operationId: EventCertificateController.listIssuances
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_388
      summary: Roster of participants with an issued certificate
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/issuances/{participantId}/revoke:
    post:
      description: >-
        The issuance row is kept for audit; the participant loses download
        access and it drops off booking-detail reads. Reversible via unrevoke.
      operationId: EventCertificateController.revokeIssuance
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          description: Event participant ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_388
      summary: Revoke a participant's issued certificate (misprint, fraud, etc)
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/issuances/{participantId}/unrevoke:
    post:
      operationId: EventCertificateController.unrevokeIssuance
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          description: Event participant ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_388
      summary: Restore a previously revoked certificate
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/issuances/{participantId}/download:
    get:
      operationId: EventCertificateController.downloadParticipantCertificate
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          description: Event participant ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_388
      summary: Download a participant's issued certificate PDF
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/publish:
    post:
      description: >-
        Requires the event to be COMPLETED and an active certificate template.
        Eligible = joined + attended
        (EventParticipation.participationStatus=ATTENDED). Idempotent —
        participants already issued a certificate for the active template
        version are skipped.
      operationId: EventCertificateController.publish
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '400':
          description: Event not completed / no active template
      security: *ref_388
      summary: Publish — bulk-issue the certificate to every eligible participant
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/unpublish:
    post:
      operationId: EventCertificateController.unpublish
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_388
      summary: Unpublish — hide certificates from participants (issuances are kept)
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates:
    get:
      operationId: EventCertificateController.getTemplate
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_388
      summary: Get the event's active certificate template
      tags: *ref_389
    post:
      operationId: EventCertificateController.createTemplate
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventCertificateDto'
      responses:
        '201':
          description: Certificate template created
        '400':
          description: Unknown variable
      security: *ref_388
      summary: Create the certificate template (validates variables)
      tags: *ref_389
    put:
      operationId: EventCertificateController.updateTemplate
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEventCertificateDto'
      responses:
        '200':
          description: ''
      security: *ref_388
      summary: Update the certificate template (creates a new version)
      tags: *ref_389
    delete:
      operationId: EventCertificateController.deactivateTemplate
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_388
      summary: Deactivate the certificate template
      tags: *ref_389
  /v2/organizers/events/{eventId}/certificates/assets:
    post:
      description: >-
        Returns a public URL — plug it into `headerLogo` or `backgroundImageUrl`
        on the create/update template call. Does not itself modify the template.
      operationId: EventCertificateController.uploadAsset
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
      responses:
        '201':
          description: Asset uploaded
        '400':
          description: No file provided
      security: *ref_388
      summary: Upload certificate art (header logo / full-bleed background)
      tags: *ref_389
  /v2/organizers/events/certificates-overview:
    get:
      description: >-
        One row per event that has ended (COMPLETED, or a runnable status whose
        end time has passed) — design-ready flag, publish status, and
        eligible/issued counts.
      operationId: EventCertificatesOverviewController.overview
      parameters: []
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Certificate status across every ended event the organizer owns
      tags:
        - Event Certificates
  /v2/organizers/events/{eventId}/add-ons:
    get:
      operationId: EventAddOnsController.getAddOns
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Add-ons retrieved successfully
        '404':
          description: Event not found
      security: &ref_390
        - bearer: []
      summary: Get all add-ons for an event
      tags: &ref_391
        - Event Add-Ons
    post:
      description: Link an existing product to an event as an add-on.
      operationId: EventAddOnsController.createAddOn
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAddOnDto'
      responses:
        '201':
          description: Add-on created successfully
        '400':
          description: Validation failed or product already added
        '404':
          description: Event or product not found
      security: *ref_390
      summary: Add a product as add-on for an event
      tags: *ref_391
  /v2/organizers/events/{eventId}/add-ons/{addOnId}:
    get:
      operationId: EventAddOnsController.getAddOn
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: addOnId
          required: true
          in: path
          description: Add-On ID
          schema:
            type: string
      responses:
        '200':
          description: Add-on retrieved successfully
        '404':
          description: Add-on not found
      security: *ref_390
      summary: Get a single add-on by ID
      tags: *ref_391
    put:
      operationId: EventAddOnsController.updateAddOn
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: addOnId
          required: true
          in: path
          description: Add-On ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAddOnDto'
      responses:
        '200':
          description: Add-on updated successfully
        '404':
          description: Add-on not found
      security: *ref_390
      summary: Update an add-on
      tags: *ref_391
    delete:
      operationId: EventAddOnsController.deleteAddOn
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: addOnId
          required: true
          in: path
          description: Add-On ID
          schema:
            type: string
      responses:
        '200':
          description: Add-on deleted successfully
        '400':
          description: Cannot delete add-on with existing sales
        '404':
          description: Add-on not found
      security: *ref_390
      summary: Delete an add-on (soft delete)
      tags: *ref_391
  /v2/organizers/events/{eventId}/add-ons/{addOnId}/toggle-status:
    patch:
      operationId: EventAddOnsController.toggleAddOnStatus
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: addOnId
          required: true
          in: path
          description: Add-On ID
          schema:
            type: string
      responses:
        '200':
          description: Add-on status toggled successfully
        '404':
          description: Add-on not found
      security: *ref_390
      summary: Toggle add-on active status
      tags: *ref_391
  /v2/organizers/events/{eventId}/coupons:
    get:
      operationId: EventCouponsController.getCoupons
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Coupons retrieved successfully
        '404':
          description: Event not found
      security: &ref_392
        - bearer: []
      summary: Get all coupons attached to an event
      tags: &ref_393
        - Event Coupons
    post:
      description: >-
        Attach an existing coupon to an event. Optionally specify which tickets
        it applies to.
      operationId: EventCouponsController.attachCoupon
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttachCouponDto'
      responses:
        '201':
          description: Coupon attached successfully
        '400':
          description: Validation failed or coupon already attached
        '404':
          description: Event or coupon not found
      security: *ref_392
      summary: Attach a coupon to an event
      tags: *ref_393
  /v2/organizers/events/{eventId}/coupons/{couponId}:
    get:
      operationId: EventCouponsController.getCoupon
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: couponId
          required: true
          in: path
          description: Coupon ID
          schema:
            type: string
      responses:
        '200':
          description: Coupon retrieved successfully
        '404':
          description: Coupon not found
      security: *ref_392
      summary: Get a coupon details for an event
      tags: *ref_393
    delete:
      operationId: EventCouponsController.detachCoupon
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: couponId
          required: true
          in: path
          description: Coupon ID
          schema:
            type: string
      responses:
        '200':
          description: Coupon detached successfully
        '404':
          description: Coupon not attached to event
      security: *ref_392
      summary: Detach a coupon from an event
      tags: *ref_393
  /v2/organizers/events/{eventId}/coupons/{couponId}/tickets:
    put:
      operationId: EventCouponsController.updateCouponTickets
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: couponId
          required: true
          in: path
          description: Coupon ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCouponTicketsDto'
      responses:
        '200':
          description: Coupon tickets updated successfully
        '404':
          description: Coupon not attached to event
      security: *ref_392
      summary: Update which tickets a coupon applies to
      tags: *ref_393
  /v2/organizers/events/{eventId}/faqs:
    get:
      operationId: EventFaqsController.getFaqs
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: FAQs retrieved successfully
        '404':
          description: Event not found
      security: &ref_394
        - bearer: []
      summary: Get all FAQs attached to an event
      tags: &ref_395
        - Event FAQs
    post:
      description: Attach an existing FAQ to an event.
      operationId: EventFaqsController.attachFaq
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttachFaqDto'
      responses:
        '201':
          description: FAQ attached successfully
        '400':
          description: FAQ already attached
        '404':
          description: Event or FAQ not found
      security: *ref_394
      summary: Attach a FAQ to an event
      tags: *ref_395
    put:
      description: Replace all existing FAQs with a new list.
      operationId: EventFaqsController.replaceAllFaqs
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttachMultipleFaqsDto'
      responses:
        '200':
          description: FAQs replaced successfully
        '404':
          description: Event or FAQs not found
      security: *ref_394
      summary: Replace all FAQs for an event
      tags: *ref_395
  /v2/organizers/events/{eventId}/faqs/{faqId}:
    get:
      operationId: EventFaqsController.getFaq
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: faqId
          required: true
          in: path
          description: FAQ ID
          schema:
            type: string
      responses:
        '200':
          description: FAQ retrieved successfully
        '404':
          description: FAQ not found
      security: *ref_394
      summary: Get a single FAQ for an event
      tags: *ref_395
    delete:
      operationId: EventFaqsController.detachFaq
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: faqId
          required: true
          in: path
          description: FAQ ID
          schema:
            type: string
      responses:
        '200':
          description: FAQ detached successfully
        '404':
          description: FAQ not attached to event
      security: *ref_394
      summary: Detach a FAQ from an event
      tags: *ref_395
  /v2/organizers/events/{eventId}/faqs/bulk:
    post:
      description: Attach multiple existing FAQs to an event at once.
      operationId: EventFaqsController.attachMultipleFaqs
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttachMultipleFaqsDto'
      responses:
        '201':
          description: FAQs attached successfully
        '404':
          description: Event or FAQs not found
      security: *ref_394
      summary: Attach multiple FAQs to an event
      tags: *ref_395
  /v2/organizers/events/{eventId}/bookings:
    get:
      operationId: EventBookingsController.getEventBookings
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: ticketId
          required: true
          in: query
          schema:
            type: string
        - name: slotId
          required: true
          in: query
          schema:
            type: string
        - name: paymentStatus
          required: true
          in: query
          schema:
            type: string
        - name: checkedIn
          required: true
          in: query
          schema:
            type: string
        - name: bibAssigned
          required: true
          in: query
          schema:
            type: string
        - name: since
          required: true
          in: query
          schema:
            type: string
        - name: until
          required: true
          in: query
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: pageSize
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Bookings retrieved successfully
        '404':
          description: Event not found
      security: &ref_396
        - bearer: []
      summary: Get bookings for an event (filtered + paginated).
      tags: &ref_397
        - Event Bookings (Organizer)
  /v2/organizers/events/{eventId}/bookings/{participationId}:
    get:
      operationId: EventBookingsController.getBookingById
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          description: Participation/Booking ID
          schema:
            type: string
      responses:
        '200':
          description: Booking retrieved successfully
        '404':
          description: Booking not found
      security: *ref_396
      summary: Get one booking by participationId
      tags: *ref_397
  /v2/organizers/events/{eventId}/bookings/{participationId}/timeline:
    get:
      operationId: EventBookingsController.getBookingTimeline
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          description: Participation/Booking ID
          schema:
            type: string
      responses:
        '200':
          description: Timeline retrieved successfully
        '404':
          description: Booking not found
      security: *ref_396
      summary: >-
        Per-booking activity timeline (creation, cancels, refunds, transfers,
        deferrals).
      tags: *ref_397
  /v2/organizers/events/{eventId}/bookings/{participationId}/cancel:
    post:
      operationId: EventBookingsController.cancelWholeBooking
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          description: Participation/Booking ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelWholeBookingDto'
      responses:
        '200':
          description: Booking cancelled successfully
        '400':
          description: Booking already cancelled
        '404':
          description: Booking not found
      security: *ref_396
      summary: Cancel an entire booking (all participants)
      tags: *ref_397
  /v2/organizers/events/{eventId}/bookings/bulk-cancel:
    post:
      operationId: EventBookingsController.bulkCancelParticipations
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkCancelParticipantsDto'
      responses:
        '200':
          description: Per-row outcome list returned (some rows may have failed).
      security: *ref_396
      summary: >-
        Bulk-cancel a set of bookings with shared reason + optional per-row
        overrides.
      tags: *ref_397
  /v2/organizers/events/{eventId}/bookings/{participationId}/participants/{participantId}/cancel:
    post:
      operationId: EventBookingsController.cancelSingleParticipant
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          description: Participation/Booking ID
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          description: Participant ID to cancel
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelParticipantDto'
      responses:
        '200':
          description: Participant cancelled successfully
        '400':
          description: Participant already cancelled
        '404':
          description: Participant not found
      security: *ref_396
      summary: Cancel a single participant from a booking
      tags: *ref_397
  /v2/organizers/events/{eventId}/bookings/{participationId}/participants/{participantId}:
    patch:
      operationId: EventBookingsController.updateParticipantDetails
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          description: Participation/Booking ID
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          description: Participant ID to update
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateParticipantDetailsDto'
      responses:
        '200':
          description: Participant details updated successfully
        '404':
          description: Participant not found
      security: *ref_396
      summary: Update participant details
      tags: *ref_397
  /v2/organizers/events/{eventId}/bookings/{participationId}/participants/resend-ticket:
    post:
      description: >-
        Regenerates QR codes for all active participants in the booking and
        sends a push notification to the user.
      operationId: EventBookingsController.resendTickets
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          description: Participation/Booking ID
          schema:
            type: string
      responses:
        '201':
          description: Tickets resent successfully
        '404':
          description: Booking not found or not confirmed
      security: *ref_396
      summary: Resend tickets for all participants in a booking
      tags: *ref_397
  /v2/organizers/events/{eventId}/bookings/{participationId}/checkin:
    patch:
      operationId: EventBookingsController.toggleCheckIn
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          description: Participation/Booking ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ToggleBookingCheckInDto'
      responses:
        '200':
          description: Check-in state updated
        '404':
          description: Booking not found
      security: *ref_396
      summary: >-
        Toggle check-in for every active participant in a booking
        (participant-modal action).
      tags: *ref_397
  /v2/organizers/events/{eventId}/ticket-sales/slot-wise:
    get:
      operationId: EventTicketSalesController.getSlotWise
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Slot-wise breakdown retrieved
        '404':
          description: Event not found
      security: &ref_398
        - bearer: []
      summary: >-
        Slot-wise ticket-sales breakdown: each slot → its tickets (with
        per-ticket sold counts) → the participant list, drillable to full order
        + payment detail.
      tags: &ref_399
        - Event Ticket Sales (Organizer)
  /v2/organizers/events/{eventId}/ticket-sales/ticket-wise:
    get:
      operationId: EventTicketSalesController.getTicketWise
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Ticket-wise breakdown retrieved
        '404':
          description: Event not found
      security: *ref_398
      summary: >-
        Ticket-wise ticket-sales breakdown: each ticket (with its slot) → sold
        count → the participant list, drillable to full order + payment detail.
      tags: *ref_399
  /v2/organizers/events/{eventId}/gallery:
    get:
      operationId: EventGalleryController.getGalleryImages
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Gallery images retrieved successfully
        '404':
          description: Event not found
      security: &ref_400
        - bearer: []
      summary: Get all gallery images for an event
      tags: &ref_401
        - Event Gallery
    post:
      description: Upload a new image to the event gallery
      operationId: EventGalleryController.addGalleryImage
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                imageFile:
                  type: string
                  format: binary
                  description: Image file to upload
                imageUrl:
                  type: string
                  description: External image URL (if not uploading file)
      responses:
        '201':
          description: Gallery image added successfully
        '400':
          description: Validation failed
        '404':
          description: Event not found
      security: *ref_400
      summary: Add a new gallery image to an event
      tags: *ref_401
  /v2/organizers/events/{eventId}/gallery/{imageId}:
    delete:
      description: Permanently delete an image from the event gallery
      operationId: EventGalleryController.deleteGalleryImage
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: imageId
          required: true
          in: path
          description: Gallery Image ID
          schema:
            type: string
      responses:
        '200':
          description: Gallery image deleted successfully
        '404':
          description: Gallery image not found
      security: *ref_400
      summary: Delete a gallery image
      tags: *ref_401
  /v2/organizers/events/{eventId}/course:
    post:
      operationId: EventCoursesController.uploadGpx
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: declaredDistanceM
          required: false
          in: query
          description: >-
            Organizer-declared race distance (metres). Triggers PRD §33.1
            distance-verification warning if parsed distance differs by >5%.
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                gpx:
                  type: string
                  format: binary
              required:
                - gpx
      responses:
        '201':
          description: Course parsed + persisted.
        '400':
          description: Invalid GPX payload.
      security: &ref_402
        - bearer: []
      summary: Upload GPX for an event course (PRD §33.1 step 5).
      tags: &ref_403
        - Event Courses
    get:
      operationId: EventCoursesController.getCourse
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_402
      summary: Get full course bundle (geometry + elevation + waypoints).
      tags: *ref_403
  /v2/organizers/events/{eventId}/course/waypoints:
    get:
      operationId: EventCoursesController.listWaypoints
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_402
      summary: List waypoints for an event course.
      tags: *ref_403
    post:
      operationId: EventCoursesController.addWaypoint
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCourseWaypointDto'
      responses:
        '201':
          description: ''
      security: *ref_402
      summary: Add a waypoint to the course.
      tags: *ref_403
  /v2/organizers/events/{eventId}/course/waypoints/{waypointId}:
    patch:
      operationId: EventCoursesController.updateWaypoint
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: waypointId
          required: true
          in: path
          description: Waypoint ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCourseWaypointDto'
      responses:
        '200':
          description: ''
      security: *ref_402
      summary: Update a waypoint.
      tags: *ref_403
    delete:
      operationId: EventCoursesController.removeWaypoint
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: waypointId
          required: true
          in: path
          description: Waypoint ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_402
      summary: Remove a waypoint (soft delete).
      tags: *ref_403
  /v2/organizers/events/{eventId}/communications:
    get:
      operationId: EventCommunicationsController.list
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_404
        - bearer: []
      summary: List per-event communication templates (PRD §33.1 step 14).
      tags: &ref_405
        - Event Communications
    post:
      operationId: EventCommunicationsController.upsert
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventCommunicationTemplateDto'
      responses:
        '201':
          description: ''
      security: *ref_404
      summary: >-
        Create or upsert a per-event communication template for a given
        (trigger, channel).
      tags: *ref_405
  /v2/organizers/events/{eventId}/communications/{templateId}:
    get:
      operationId: EventCommunicationsController.getOne
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_404
      summary: Get a single communication template.
      tags: *ref_405
    patch:
      operationId: EventCommunicationsController.update
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEventCommunicationTemplateDto'
      responses:
        '200':
          description: ''
      security: *ref_404
      summary: Update an existing template.
      tags: *ref_405
    delete:
      operationId: EventCommunicationsController.remove
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_404
      summary: Soft-delete a template.
      tags: *ref_405
  /v2/organizers/events/{eventId}/communications/{templateId}/preview:
    post:
      operationId: EventCommunicationsController.preview
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: templateId
          required: true
          in: path
          description: Template ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewCommunicationTemplateDto'
      responses:
        '201':
          description: ''
      security: *ref_404
      summary: >-
        Render the template against a context bag and return the substituted
        output + computed fire-at moment.
      tags: *ref_405
  /v2/organizers/{organizerId}/ticket-bundles:
    get:
      operationId: EventTicketBundlesController.list
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_406
        - bearer: []
      summary: List ticket bundles for this organizer.
      tags: &ref_407
        - 'Organizer: Ticket Bundles'
    post:
      operationId: EventTicketBundlesController.createFromEvent
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBundleFromEventDto'
      responses:
        '201':
          description: ''
      security: *ref_406
      summary: >-
        Capture an event's slots/tiers/refund/add-ons/coupons into a reusable
        bundle.
      tags: *ref_407
  /v2/organizers/{organizerId}/ticket-bundles/{bundleId}:
    get:
      operationId: EventTicketBundlesController.get
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: bundleId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_406
      summary: Get one ticket bundle.
      tags: *ref_407
    delete:
      operationId: EventTicketBundlesController.delete
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: bundleId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_406
      summary: Delete a ticket bundle (soft).
      tags: *ref_407
  /v2/organizers/{organizerId}/ticket-bundles/{bundleId}/apply:
    post:
      operationId: EventTicketBundlesController.apply
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: bundleId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApplyBundleDto'
      responses:
        '201':
          description: ''
      security: *ref_406
      summary: Re-apply a bundle to a target event.
      tags: *ref_407
  /v2/clubs/{clubId}/events:
    post:
      operationId: ClubEventsController.createClubEvent
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventDto'
      responses:
        '201':
          description: ''
      summary: >-
        Create an event owned by the specified club. Caller must be the club's
        OWNER or ADMIN. NOTE: disabled at V3 launch — see controller-class
        comment / V3-TASK-P0-014.
      tags:
        - 'Clubs: Events'
  /v2/events/{eventId}/live-counts:
    get:
      operationId: PublicEventLiveController.liveCounts
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_408
        - 'Public: Event Live'
  /v2/events/{eventId}/share-link:
    get:
      operationId: PublicEventLiveController.shareLink
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_408
  /v2/bib-claim-terms:
    get:
      operationId: AdminBibClaimTermsController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_409
        - AdminBibClaimTerms
  /v2/bib-claim-terms/{eventId}:
    get:
      operationId: AdminBibClaimTermsController.get
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_409
    put:
      operationId: AdminBibClaimTermsController.publish
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_409
  /v2/admin/events/{eventId}/badge:
    get:
      operationId: AdminEventBadgeController.get
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - AdminEventBadge
  /v2/organizers/events/{eventId}/premium:
    get:
      operationId: OrganizerPremiumEventController.get
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_410
        - OrganizerPremiumEvent
    put:
      operationId: OrganizerPremiumEventController.put
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/premium/capabilities:
    get:
      operationId: OrganizerPremiumEventController.capabilities
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/premium/brand-partner-logos:
    post:
      operationId: OrganizerPremiumEventController.uploadBrandPartnerLogo
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/badge:
    put:
      operationId: OrganizerPremiumEventController.saveBadge
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/badge/icon:
    post:
      operationId: OrganizerPremiumEventController.uploadBadgeIcon
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/badge/back-image:
    post:
      operationId: OrganizerPremiumEventController.uploadBadgeBackImage
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/deliverables:
    get:
      operationId: OrganizerPremiumEventController.definitions
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
    post:
      operationId: OrganizerPremiumEventController.createDefinition
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/deliverables/assets:
    post:
      operationId: OrganizerPremiumEventController.uploadDeliverableAsset
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/deliverables/{definitionId}:
    patch:
      operationId: OrganizerPremiumEventController.updateDefinition
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: definitionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
    delete:
      operationId: OrganizerPremiumEventController.removeDefinition
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: definitionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/participants/import/preview:
    post:
      operationId: OrganizerPremiumEventController.preview
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PremiumEventImportPreviewDto'
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/participants/import/commit:
    post:
      operationId: OrganizerPremiumEventController.commit
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PremiumEventImportCommitDto'
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/participants/imports:
    get:
      operationId: OrganizerPremiumEventController.imports
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/participants/imported:
    get:
      operationId: OrganizerPremiumEventController.importedParticipants
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: search
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/participants/roster:
    get:
      operationId: OrganizerPremiumEventController.rosterParticipants
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: search
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/results/import/preview:
    post:
      operationId: OrganizerPremiumEventController.previewResults
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PremiumEventImportPreviewDto'
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/results/import/commit:
    post:
      operationId: OrganizerPremiumEventController.commitResults
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PremiumEventImportPreviewDto'
      responses:
        '201':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/fulfilment:
    get:
      operationId: OrganizerPremiumEventController.fulfillment
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/fulfilment/{id}:
    patch:
      operationId: OrganizerPremiumEventController.updateFulfillment
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/organizers/events/{eventId}/fulfilment/{id}/ship-via-shiprocket:
    patch:
      operationId: OrganizerPremiumEventController.shipFulfillmentViaShiprocket
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_410
  /v2/events/{eventId}/premium:
    get:
      operationId: AthletePremiumEventController.publicProfile
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_411
        - AthletePremiumEvent
  /v2/events/{eventId}/club-claim-page:
    get:
      operationId: AthletePremiumEventController.clubClaimPage
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_411
  /v2/events/{eventId}/registration-claim/terms:
    get:
      operationId: AthletePremiumEventController.claimTerms
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_411
  /v2/events/{eventId}/participants/by-bib:
    get:
      operationId: AthletePremiumEventController.participantByBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: bibNumber
          required: true
          in: query
          schema:
            type: string
        - name: x-api-key
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_411
  /v2/events/{eventId}/registration-claim/lookup:
    post:
      operationId: AthletePremiumEventController.lookup
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_411
  /v2/events/{eventId}/registration-claim/send-otp:
    post:
      operationId: AthletePremiumEventController.send
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_411
  /v2/events/{eventId}/registration-claim/mine:
    get:
      operationId: AthletePremiumEventController.myClaim
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: bibNumber
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_411
  /v2/events/{eventId}/registration-claim/verify:
    post:
      operationId: AthletePremiumEventController.verify
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_411
  /v2/events/{eventId}/registration-claim/confirm:
    post:
      operationId: AthletePremiumEventController.confirm
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_411
  /v2/event-participations/{bookingId}/race-pack:
    get:
      operationId: AthleteRacePackController.get
      parameters:
        - name: bookingId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_412
        - AthleteRacePack
  /v2/event-participations/{bookingId}/race-pack/reconcile:
    post:
      operationId: AthleteRacePackController.reconcile
      parameters:
        - name: bookingId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_412
  /v2/event-participations/{bookingId}/share-card-context:
    get:
      operationId: AthleteRacePackController.shareCardContext
      parameters:
        - name: bookingId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_412
  /v2/event-participations/{bookingId}/finisher-card-context:
    get:
      operationId: AthleteRacePackController.finisherCardContext
      parameters:
        - name: bookingId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_412
  /v2/event-participations/{bookingId}/deliverables:
    get:
      operationId: AthleteRacePackController.deliverables
      parameters:
        - name: bookingId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_412
  /v2/event-participations/{bookingId}/deliverables/{deliverableId}/claim:
    post:
      operationId: AthleteRacePackController.claim
      parameters:
        - name: bookingId
          required: true
          in: path
          schema:
            type: string
        - name: deliverableId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_412
  /v2/event-participations/{bookingId}/deliverables/{deliverableId}/address:
    patch:
      operationId: AthleteRacePackController.address
      parameters:
        - name: bookingId
          required: true
          in: path
          schema:
            type: string
        - name: deliverableId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_412
  /v2/bootstrap/home:
    get:
      operationId: BootstrapController.homeBootstrap
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_413
        - bearer: []
      summary: >-
        Home screen bootstrap — feed + activity summary + wallet + action-center
        + explore carousels in one request.
      tags: &ref_414
        - Bootstrap
  /v2/bootstrap/me:
    get:
      operationId: BootstrapController.meBootstrap
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_413
      summary: >-
        Profile screen bootstrap — user profile + follow counts + wallet summary
        in one request.
      tags: *ref_414
  /v2/app/version-check:
    get:
      operationId: AppVersionController.versionCheck
      parameters:
        - name: platform
          required: true
          in: query
          schema:
            type: string
        - name: version
          required: true
          in: query
          schema:
            type: string
        - name: build
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Per-platform force/soft update policy for the caller version. Fails
        open.
      tags:
        - App
  /v2/admin/app-version-policies:
    get:
      operationId: AppVersionPolicyAdminController.list
      parameters: []
      responses:
        '200':
          description: ''
      summary: List both platform policies + audit metadata.
      tags: &ref_415
        - 'Admin: App Versions'
  /v2/admin/app-version-policies/{platform}/impact:
    get:
      operationId: AppVersionPolicyAdminController.impact
      parameters:
        - name: platform
          required: true
          in: path
          schema:
            type: string
        - name: min
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Best-effort blast radius for a proposed minimum (users it would
        force-update).
      tags: *ref_415
  /v2/admin/app-version-policies/{platform}:
    put:
      operationId: AppVersionPolicyAdminController.update
      parameters:
        - name: platform
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAppVersionPolicyDto'
      responses:
        '200':
          description: ''
      summary: >-
        Update a platform policy. 400 on bad semver or min>latest (lockout
        guard).
      tags: *ref_415
  /v2/volunteers/me/profile:
    get:
      operationId: VolunteerMeController.profile
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_416
        - 'RA Crew: Volunteer (me)'
    patch:
      operationId: VolunteerMeController.update
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProfileDto'
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/memberships:
    get:
      operationId: VolunteerMeController.memberships
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/invites:
    get:
      operationId: VolunteerMeController.invites
      parameters:
        - name: x-organizer-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/invites/{id}/respond:
    post:
      operationId: VolunteerMeController.respondInvite
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RespondDto'
      responses:
        '201':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/consent:
    post:
      operationId: VolunteerMeController.consent
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/discoverable:
    patch:
      operationId: VolunteerMeController.disc
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/events:
    get:
      operationId: VolunteerMeController.events
      parameters:
        - name: x-organizer-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/volunteered-events:
    get:
      operationId: VolunteerMeController.volunteeredEvents
      parameters:
        - name: x-organizer-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/volunteered-events/{eventId}:
    get:
      operationId: VolunteerMeController.volunteeredEvent
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: x-organizer-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/me/shifts:
    get:
      operationId: VolunteerMeController.shifts
      parameters:
        - name: window
          required: true
          in: query
          schema:
            type: string
        - name: x-organizer-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_416
  /v2/volunteers/{userId}/statistics:
    get:
      operationId: VolunteerStatsController.stats
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'RA Crew: Volunteer (public)'
  /v2/orgs/{orgId}/volunteers:
    get:
      operationId: OrgVolunteersController.roster
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: includeInactive
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_417
        - 'RA Crew: Org volunteers'
    post:
      operationId: OrgVolunteersController.createVolunteer
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateVolunteerDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/volunteers/pool:
    get:
      operationId: OrgVolunteersController.pool
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/members/invite:
    post:
      operationId: OrgVolunteersController.invite
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InviteMemberDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/volunteers/{volunteerId}/rate:
    post:
      operationId: OrgVolunteersController.rate
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: volunteerId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RateDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/members/{membershipId}/role:
    post:
      operationId: OrgVolunteersController.setRole
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/members/{membershipId}/respond:
    post:
      operationId: OrgVolunteersController.respond
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RespondDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/members/{membershipId}/remove:
    post:
      operationId: OrgVolunteersController.removeMember
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewLifecycleReasonDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/members/{membershipId}/revoke:
    post:
      operationId: OrgVolunteersController.revokeMember
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewLifecycleReasonDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/members/{membershipId}/reinstate:
    post:
      operationId: OrgVolunteersController.reinstateMember
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: membershipId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewLifecycleReasonDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/volunteer-heads:
    get:
      operationId: OrgVolunteersController.listHeads
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_417
    post:
      operationId: OrgVolunteersController.createHead
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateVolunteerHeadDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/orgs/{orgId}/volunteers/{volunteerId}/head:
    post:
      operationId: OrgVolunteersController.setHead
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: volunteerId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetHeadDto'
      responses:
        '201':
          description: ''
      tags: *ref_417
  /v2/events/{eventId}/assignments:
    post:
      operationId: StaffingController.assign
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAssignmentDto'
      responses:
        '201':
          description: ''
      tags: &ref_418
        - 'RA Crew: Staffing'
    get:
      operationId: StaffingController.listAssignments
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: response
          required: true
          in: query
          schema:
            type: string
        - name: role
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_418
  /v2/events/{eventId}/assignments/{id}:
    delete:
      operationId: StaffingController.unassign
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewLifecycleReasonDto'
      responses:
        '200':
          description: ''
      tags: *ref_418
  /v2/assignments/{id}/respond:
    post:
      operationId: AssignmentController.respond
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags:
        - 'RA Crew: Assignments'
  /v2/crew/events/{eventId}:
    get:
      operationId: CrewStaffingController.event
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: x-organizer-id
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_419
        - 'RA Crew: Crew staffing (head)'
  /v2/crew/events/{eventId}/assignments:
    get:
      operationId: CrewStaffingController.listAssignments
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: response
          required: true
          in: query
          schema:
            type: string
        - name: role
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_419
    post:
      operationId: CrewStaffingController.assign
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAssignmentDto'
      responses:
        '201':
          description: ''
      tags: *ref_419
  /v2/crew/events/{eventId}/assignments/{id}:
    delete:
      operationId: CrewStaffingController.unassign
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_419
  /v2/crew/events/{eventId}/crew:
    get:
      operationId: CrewStaffingController.listEventCrew
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_419
  /v2/attendance/me/shifts:
    get:
      operationId: AttendanceController.myShifts
      parameters:
        - name: eventId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_420
        - 'RA Crew: Attendance'
  /v2/attendance/me:
    get:
      operationId: AttendanceController.myStatus
      parameters:
        - name: eventId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_420
  /v2/attendance/check-in:
    post:
      operationId: AttendanceController.checkIn
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttendanceCheckInDto'
      responses:
        '201':
          description: ''
      tags: *ref_420
  /v2/attendance/check-out:
    post:
      operationId: AttendanceController.checkOut
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttendanceCheckOutDto'
      responses:
        '201':
          description: ''
      tags: *ref_420
  /v2/attendance/sync-batch:
    post:
      operationId: AttendanceController.sync
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SyncBatchDto'
      responses:
        '201':
          description: ''
      tags: *ref_420
  /v2/attendance/pending:
    get:
      operationId: AttendanceController.pending
      parameters:
        - name: eventId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_420
  /v2/attendance/{id}/approve:
    post:
      operationId: AttendanceController.approve
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RespondDto'
      responses:
        '201':
          description: ''
      tags: *ref_420
  /v2/organizer/events/{eventId}/fulfillment/item-types:
    get:
      operationId: FulfillmentController.itemTypes
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_421
        - 'RA Crew: Fulfillment (goodie handout)'
    post:
      operationId: FulfillmentController.createItemType
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateItemTypeDto'
      responses:
        '201':
          description: ''
      tags: *ref_421
  /v2/organizer/events/{eventId}/fulfillment/participant:
    get:
      operationId: FulfillmentController.participant
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: qr
          required: true
          in: query
          schema:
            type: string
        - name: bib
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_421
  /v2/organizer/events/{eventId}/fulfillment/handout:
    post:
      operationId: FulfillmentController.handout
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HandoutDto'
      responses:
        '201':
          description: ''
      tags: *ref_421
  /v2/organizer/events/{eventId}/fulfillment/sync-batch:
    post:
      operationId: FulfillmentController.sync
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SyncBatchDto'
      responses:
        '201':
          description: ''
      tags: *ref_421
  /v2/organizer/events/{eventId}/fulfillment/summary:
    get:
      operationId: FulfillmentController.summary
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_421
  /v2/organizer/events/{eventId}/fulfillment/{handoutId}/undo:
    post:
      operationId: FulfillmentController.undo
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: handoutId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_421
  /v2/auth/crew/send-otp:
    post:
      operationId: CrewAuthController.sendPhoneOtp
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewSendOtpDto'
      responses:
        '201':
          description: ''
      summary: SMS a 4-digit crew login code. Creates no account on its own.
      tags: &ref_422
        - 'Auth: Crew login'
  /v2/auth/crew/verify-otp:
    post:
      operationId: CrewAuthController.verifyPhoneOtp
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewVerifyOtpDto'
      responses:
        '200':
          description: ''
      summary: >-
        Verify a crew SMS code and return a session. Auto-links every
        Volunteer/VolunteerHead row across all orgs that shares this phone.
      tags: *ref_422
  /v2/auth/crew/email/send-otp:
    post:
      operationId: CrewAuthController.sendOtp
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendCrewEmailOtpDto'
      responses:
        '200':
          description: ''
      summary: Email a 4-digit crew login code. Creates no account on its own.
      tags: *ref_422
  /v2/auth/crew/email/verify-otp:
    post:
      operationId: CrewAuthController.verifyOtp
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyCrewEmailOtpDto'
      responses:
        '200':
          description: ''
      summary: >-
        Verify a crew login code and return a session. Auto-links every
        Volunteer/VolunteerHead row across all orgs that shares this email.
      tags: *ref_422
  /v2/auth/crew/refresh-tokens:
    post:
      operationId: CrewAuthController.refreshTokens
      parameters: []
      responses:
        '200':
          description: ''
      summary: Refresh crew tokens.
      tags: *ref_422
  /v2/auth/crew/logout:
    post:
      operationId: CrewAuthController.logout
      parameters: []
      responses:
        '200':
          description: ''
      summary: Log out of the crew session.
      tags: *ref_422
  /v2/ra-crew/push-token:
    post:
      operationId: CrewPushController.register
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterPushTokenDto'
      responses:
        '204':
          description: ''
      summary: Register or refresh FCM push token
      tags: &ref_423
        - ra-crew
    delete:
      operationId: CrewPushController.unregister
      parameters: []
      responses:
        '204':
          description: ''
      summary: Unregister push token (logout)
      tags: *ref_423
  /v2/ra-crew/push-token/test:
    post:
      operationId: CrewPushController.sendTest
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TestPushDto'
      responses:
        '204':
          description: ''
      summary: Send a test push to the calling user (debug)
      tags: *ref_423
  /v2/crew/events/{eventId}/check-in/scan:
    post:
      operationId: CrewCheckInController.scan
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: mode
          required: true
          in: query
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScanQrDto'
      responses:
        '201':
          description: ''
      tags: &ref_424
        - 'RA Crew: Participant check-in'
  /v2/crew/events/{eventId}/check-in/scan-by-bib:
    post:
      operationId: CrewCheckInController.scanByBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: mode
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/check-in/sync-batch:
    post:
      operationId: CrewCheckInController.syncBatch
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SyncBatchCheckInDto'
      responses:
        '201':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/check-in/search:
    get:
      operationId: CrewCheckInController.search
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: bib
          required: true
          in: query
          schema:
            type: string
        - name: name
          required: true
          in: query
          schema:
            type: string
        - name: mode
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/check-in/checked-in:
    get:
      operationId: CrewCheckInController.checkedIn
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: mode
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/check-in/participant/{participantId}:
    get:
      operationId: CrewCheckInController.participantDetails
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
        - name: mode
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/check-in/{checkinId}/undo:
    post:
      operationId: CrewCheckInController.undo
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: checkinId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/check-in/participant/{participantId}/undo:
    post:
      operationId: CrewCheckInController.undoByParticipant
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/check-in/addons/{addOnId}/collect:
    post:
      operationId: CrewCheckInController.collectAddOn
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: addOnId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_424
  /v2/crew/events/{eventId}/participant/{participantId}/collect-bib:
    post:
      operationId: CrewBibController.collectBib
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags:
        - 'RA Crew: Participant check-in'
  /v2/crew/orgs/{orgId}/events/{eventId}/dashboard:
    get:
      operationId: SupervisorDashboardController.dashboard
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'RA Crew: Supervisor dashboard'
  /v2/orgs/{orgId}/crew-join-codes:
    post:
      operationId: ManagerCrewJoinCodesController.create
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCrewJoinCodeDto'
      responses:
        '201':
          description: ''
      tags: &ref_425
        - ManagerCrewJoinCodes
    get:
      operationId: ManagerCrewJoinCodesController.list
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_425
  /v2/orgs/{orgId}/crew-join-codes/{id}:
    patch:
      operationId: ManagerCrewJoinCodesController.update
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCrewJoinCodeDto'
      responses:
        '200':
          description: ''
      tags: *ref_425
  /v2/orgs/{orgId}/crew-join-codes/{id}/revoke:
    post:
      operationId: ManagerCrewJoinCodesController.revoke
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_425
  /v2/crew/join-codes/preview:
    post:
      operationId: CrewJoinCodesController.preview
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewJoinCodeInputDto'
      responses:
        '201':
          description: ''
      tags: &ref_426
        - CrewJoinCodes
  /v2/crew/join-codes/redeem:
    post:
      operationId: CrewJoinCodesController.redeem
      parameters:
        - name: x-app-version
          required: true
          in: header
          schema:
            type: string
        - name: x-platform
          required: true
          in: header
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrewJoinCodeInputDto'
      responses:
        '201':
          description: ''
      tags: *ref_426
  /v2/bank-verification/ifsc/{ifsc}:
    get:
      operationId: BankVerificationController.lookupIfsc
      parameters:
        - name: ifsc
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_427
        - bearer: []
      summary: Resolve the bank and branch for an Indian IFSC.
      tags: &ref_428
        - Bank Verification
  /v2/bank-verification/verify:
    post:
      operationId: BankVerificationController.verify
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyBankAccountDto'
      responses:
        '200':
          description: ''
      security: *ref_427
      summary: >-
        Penny-drop verify a bank account. Returns { verified, accountExists,
        accountHolderName, utr, amountDeposited, transactionId } on success, or
        { verified: false, reason, message } when the account could not be
        verified.
      tags: *ref_428
  /v2/badges:
    post:
      operationId: BadgesController.create
      parameters:
        - &ref_429
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBadgeDto'
      responses:
        '201':
          description: ''
      tags: &ref_430
        - Badges
    get:
      operationId: BadgesController.findAll
      parameters:
        - *ref_429
        - name: sourceSystem
          required: true
          in: query
          schema:
            type: string
        - name: rarity
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_430
  /v2/badges/{code}/public:
    get:
      operationId: BadgesController.findPublicByCode
      parameters:
        - *ref_429
        - name: code
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_430
  /v2/badges/{id}:
    get:
      operationId: BadgesController.findOne
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_430
    patch:
      operationId: BadgesController.update
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateBadgeDto'
      responses:
        '200':
          description: ''
      tags: *ref_430
    delete:
      operationId: BadgesController.remove
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_430
  /v2/badges/{id}/duplicate:
    post:
      operationId: BadgesController.duplicate
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_430
  /v2/badges/{id}/preview:
    post:
      operationId: BadgesController.preview
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_430
  /v2/badges/{id}/retroactive-award:
    post:
      operationId: BadgesController.retroactiveAward
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_430
  /v2/badges/{id}/stats:
    get:
      operationId: BadgesController.getStats
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_430
  /v2/badges/{id}/map-challenge:
    post:
      operationId: BadgesController.mapChallenge
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_430
    delete:
      operationId: BadgesController.unmapChallenge
      parameters:
        - *ref_429
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_430
  /v2/user-badges:
    get:
      operationId: UserBadgesController.findAll
      parameters:
        - &ref_431
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_432
        - User Badges
  /v2/user-badges/earned:
    get:
      operationId: UserBadgesController.findEarned
      parameters:
        - *ref_431
      responses:
        '200':
          description: ''
      tags: *ref_432
  /v2/user-badges/progress:
    get:
      operationId: UserBadgesController.findProgress
      parameters:
        - *ref_431
      responses:
        '200':
          description: ''
      tags: *ref_432
  /v2/user-badges/{badgeId}/seen:
    patch:
      operationId: UserBadgesController.markAsSeen
      parameters:
        - *ref_431
        - name: badgeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_432
  /v2/user-badges/recalculate:
    patch:
      operationId: UserBadgesController.recalculateAllUsersStats
      parameters:
        - *ref_431
      responses:
        '200':
          description: ''
      tags: *ref_432
  /v2/user-badges/user/{userId}:
    get:
      operationId: UserBadgesController.findPublicBadges
      parameters:
        - *ref_431
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_432
  /v2/users/me/payout-account:
    get:
      operationId: UserPayoutAccountController.get
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_433
        - bearer: []
      summary: >-
        My payout account. The account number is never returned — only its last
        four digits.
      tags: &ref_434
        - 'User: Payout account'
    put:
      operationId: UserPayoutAccountController.save
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_433
      summary: Save my payout account. Changing the number or IFSC resets verification.
      tags: *ref_434
  /v2/users/me/payout-account/verify:
    post:
      operationId: UserPayoutAccountController.verify
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_433
      summary: >-
        Verify it with a penny drop. Capped at 5 attempts — each one costs a
        real transfer.
      tags: *ref_434
  /v2/gears:
    post:
      operationId: GearsController.createGear
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateGearDto'
      responses:
        '201':
          description: ''
      tags: &ref_435
        - Gears
    get:
      operationId: GearsController.getGears
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_435
  /v2/gears/{id}:
    get:
      operationId: GearsController.getGear
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_435
    patch:
      operationId: GearsController.updateGear
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateGearDto'
      responses:
        '200':
          description: ''
      tags: *ref_435
    delete:
      operationId: GearsController.deleteGear
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_435
  /v2/schedules:
    post:
      operationId: SchedulesController.createSchedule
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateScheduleDto'
      responses:
        '201':
          description: ''
      tags: &ref_436
        - Schedules
    get:
      operationId: SchedulesController.getGears
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_436
  /v2/schedules/{id}:
    get:
      operationId: SchedulesController.getGear
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_436
    patch:
      operationId: SchedulesController.updateGear
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateScheduleDto'
      responses:
        '200':
          description: ''
      tags: *ref_436
    delete:
      operationId: SchedulesController.deleteGear
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_436
  /v2/activities:
    post:
      operationId: ActivitiesController.createActivity
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateActivityDto'
      responses:
        '201':
          description: ''
      tags: &ref_437
        - Activities
    get:
      operationId: ActivitiesController.getActivities
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_437
  /v2/activities/{id}/public:
    get:
      operationId: ActivitiesController.getPublicActivity
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_437
  /v2/activities/{id}:
    get:
      operationId: ActivitiesController.getActivity
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_437
    patch:
      operationId: ActivitiesController.updateActivity
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateActivityDto'
      responses:
        '200':
          description: ''
      tags: *ref_437
    delete:
      operationId: ActivitiesController.deleteActivity
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_437
  /v2/admin/activities/{id}/audit-log:
    get:
      operationId: AdminActivityAuditLogController.list
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: editorUserId
          required: false
          in: query
          schema:
            type: string
        - name: editorRole
          required: false
          in: query
          schema:
            enum:
              - SELF
              - ADMIN
            type: string
        - name: from
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: to
          required: false
          in: query
          schema:
            example: '2026-12-31'
            type: string
        - name: limit
          required: false
          in: query
          schema:
            example: 50
            type: string
        - name: offset
          required: false
          in: query
          schema:
            example: 0
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List edit-audit log entries for an activity (PRD §17.8 G-6). Admin-only.
        Filter by editor / role / date-range; pagination via limit + offset.
      tags:
        - 'Admin: Activity Audit Log'
  /v2/activities/{activityId}/triathlon-legs:
    get:
      operationId: TriathlonLegsController.list
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_438
        - Triathlon
    put:
      operationId: TriathlonLegsController.upsert
      parameters:
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_438
  /v2/triathlon-legs/{legId}/complete:
    patch:
      operationId: TriathlonLegOpsController.complete
      parameters:
        - name: legId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - Triathlon
  /v2/users/{userId}/activities/{activityId}/appeal:
    post:
      operationId: UserActivityAppealsController.submit
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitAppealDto'
      responses:
        '201':
          description: ''
      tags: &ref_439
        - Activity Appeals
  /v2/users/{userId}/activity-appeals:
    get:
      operationId: UserActivityAppealsController.listMine
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: cursor
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_439
  /v2/users/{userId}/activities/{activityId}/review-state:
    get:
      operationId: UserActivityAppealsController.reviewState
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_439
  /v2/challenge-participations/{challengeId}/multi-sport-progress:
    get:
      operationId: ChallengeParticipationsController.multiSportProgress
      parameters:
        - &ref_440
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_441
        - Challenge Participations
  /v2/challenge-participations/{challengeId}:
    post:
      operationId: ChallengeParticipationsController.userParticipateInChallenge
      parameters:
        - *ref_440
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserParticipateInChallengeDto'
      responses:
        '201':
          description: ''
      tags: *ref_441
    get:
      operationId: ChallengeParticipationsController.userGetParticipatedChallenge
      parameters:
        - *ref_440
      responses:
        '200':
          description: ''
      tags: *ref_441
    patch:
      operationId: ChallengeParticipationsController.userUpdateChallengeParticipation
      parameters:
        - *ref_440
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdateChallengeParticipationDto'
      responses:
        '200':
          description: ''
      tags: *ref_441
    delete:
      operationId: ChallengeParticipationsController.userLeaveChallenge
      parameters:
        - *ref_440
      responses:
        '200':
          description: ''
      tags: *ref_441
  /v2/challenge-participations/{challengeId}/verify-payment:
    post:
      operationId: ChallengeParticipationsController.verifyChallengeEntryPayment
      parameters:
        - *ref_440
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyChallengePaymentDto'
      responses:
        '201':
          description: ''
      tags: *ref_441
  /v2/challenge-participations/{challengeId}/payment-summary:
    get:
      operationId: ChallengeParticipationsController.getChallengeEntryPaymentSummary
      parameters:
        - *ref_440
        - name: rcDiscount
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_441
  /v2/challenge-participations:
    get:
      operationId: ChallengeParticipationsController.userGetParticipatedChallenges
      parameters:
        - *ref_440
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: timeframe
          required: false
          in: query
          description: >-
            Challenge-window filter. OMITTED = live + upcoming only, i.e. every
            challenge still able to earn progress — ended challenges are NOT
            returned. Pass `past` for the history view.
          schema:
            enum:
              - past
              - live
              - upcoming
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_441
  /v2/challenge-participations/badges/all:
    get:
      operationId: ChallengeParticipationsController.getAllBadges
      parameters:
        - *ref_440
      responses:
        '200':
          description: ''
      tags: *ref_441
  /v2/me/challenges/{id}/attestation.svg:
    get:
      operationId: ChallengeAttestationController.athleteAttestation
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: theme
          required: true
          in: query
          schema:
            type: string
        - name: download
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Render the athlete-only shareable completion attestation as SVG
        (1080x1920).
      tags:
        - Challenges — Completion Attestation
  /v2/users/me/pending-proofs:
    get:
      operationId: ActionCenterController.getPendingProofs
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_442
        - bearer: []
      summary: Editions in their proof window awaiting an effort
      tags: &ref_443
        - Action Center
  /v2/users/me/pending-proofs/{participationId}/submit:
    post:
      operationId: ActionCenterController.submitProof
      parameters:
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_442
      summary: Submit an effort for a virtual edition in its proof window
      tags: *ref_443
  /v2/users/me/claimable-rewards:
    get:
      operationId: ActionCenterController.getClaimableRewards
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_442
      summary: Challenge RC + earned badges ready to claim
      tags: *ref_443
  /v2/users/me/claimable-rewards/{claimId}/claim:
    post:
      operationId: ActionCenterController.claimReward
      parameters:
        - name: claimId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_442
      summary: Claim a reward (credits RC / acknowledges a badge)
      tags: *ref_443
  /v2/admin/proofs/review-queue:
    get:
      operationId: AdminProofReviewController.reviewQueue
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_444
        - bearer: []
      summary: Edition proofs awaiting manual anti-cheat review.
      tags: &ref_445
        - 'Admin: Proof Review'
  /v2/admin/proofs/{proofId}/resolve:
    post:
      operationId: AdminProofReviewController.resolve
      parameters:
        - name: proofId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_444
      summary: Approve or reject a pending edition proof (idempotent).
      tags: *ref_445
  /v2/admin/proofs/{proofId}/revoke:
    post:
      operationId: AdminProofReviewController.revoke
      parameters:
        - name: proofId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_444
      summary: >-
        A1 — revoke a granted (valid) proof: strip leaderboard, revoke
        certificate, claw back finisher RC.
      tags: *ref_445
  /v2/organizer/proofs/review-queue:
    get:
      operationId: OrganizerProofReviewController.reviewQueue
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_446
        - bearer: []
      summary: Edition proofs awaiting review, for this organizer's editions.
      tags: &ref_447
        - 'Organizer: Proof Review'
  /v2/organizer/proofs/{proofId}/resolve:
    post:
      operationId: OrganizerProofReviewController.resolve
      parameters:
        - name: proofId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_446
      summary: Approve or reject a proof on an edition you own (idempotent).
      tags: *ref_447
  /v2/wallets/me:
    get:
      operationId: WalletsController.getMyWallet
      parameters: []
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Get the authenticated user's primary wallet + recent txns.
      tags: &ref_448
        - Wallets
  /v2/wallets/me/summary:
    get:
      operationId: WalletsController.getMyWalletSummary
      parameters: []
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Get the authenticated user's primary wallet summary (no transactions
        array).
      tags: *ref_448
  /v2/wallets/me/transactions:
    get:
      operationId: WalletsController.listMyWalletTransactions
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Get the authenticated user's wallet transactions (paginated,
        owner-only).
      tags: *ref_448
  /v2/wallets/admin/sync:
    post:
      description: >-
        Manually triggers the wallet sync process. This includes syncing all
        wallet balances, reprocessing unprocessed activities, and completing
        pending transactions.
      operationId: WalletsController.triggerWalletSync
      parameters: []
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: Trigger manual wallet sync
      tags: *ref_448
  /v2/event-participations/public/preview:
    post:
      description: >-
        Calculates and returns billing breakdown without auth. Coins/wallet
        features are not available in public preview.
      operationId: EventParticipationsController.publicPreviewEventParticipation
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewEventParticipationDto'
      responses:
        '201':
          description: ''
      summary: Public preview billing breakdown for event participation
      tags: &ref_449
        - Event Participations
  /v2/event-participations/preview:
    post:
      description: >-
        Calculates and returns billing breakdown without creating any records.
        Use this before the create endpoint.
      operationId: EventParticipationsController.previewEventParticipation
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PreviewEventParticipationDto'
      responses:
        '201':
          description: ''
      summary: Preview billing breakdown for event participation
      tags: *ref_449
  /v2/event-participations:
    post:
      operationId: EventParticipationsController.participateInEvent
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventParticipationDto'
      responses:
        '201':
          description: ''
      tags: *ref_449
    get:
      operationId: EventParticipationsController.getEventParticipations
      parameters:
        - name: timeframe
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_449
  /v2/event-participations/events/{eventId}/form-uploads:
    post:
      description: >-
        Stores the uploaded document and returns its public URL. Submit that URL
        as the file field's `values` when creating the participation. The file
        is validated against the target form field's accept (MIME) and maxSizeMB
        rules.
      operationId: EventParticipationsController.uploadRegistrationFormFile
      parameters: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/UploadFormFileDto'
      responses:
        '201':
          description: ''
      summary: Upload a file answer (e.g. ID proof) for a registration form
      tags: *ref_449
  /v2/event-participations/{id}/resume-payment:
    post:
      description: >-
        Issues a fresh Cashfree payment session on an existing PENDING
        participation so the buyer can retry after cancelling / a decline,
        without creating a duplicate participation. Refuses if the booking is no
        longer pending or is already paid.
      operationId: EventParticipationsController.resumePayment
      parameters: []
      responses:
        '201':
          description: ''
      summary: Resume payment for an existing pending participation
      tags: *ref_449
  /v2/event-participations/by-event/{eventId}:
    get:
      operationId: EventParticipationsController.getEventParticipationsByEventId
      parameters:
        - name: status
          required: false
          in: query
          description: Filter by participation status
          schema:
            enum:
              - pending
              - confirmed
              - cancelled
              - attended
              - missed
              - deferred
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_449
  /v2/event-participations/waitlist:
    post:
      operationId: EventParticipationsController.joinWaitlist
      parameters: []
      requestBody:
        required: true
        description: '{ eventId: uuid, ticketId: uuid }'
        content:
          application/json:
            schema:
              type: object
              properties:
                eventId:
                  type: string
                  format: uuid
                ticketId:
                  type: string
                  format: uuid
              required:
                - eventId
                - ticketId
      responses:
        '201':
          description: ''
      summary: §20.7 — join the waitlist for a ticket on an event.
      tags: *ref_449
  /v2/event-participations/waitlist/mine:
    get:
      operationId: EventParticipationsController.listMyWaitlistEntries
      parameters: []
      responses:
        '200':
          description: ''
      summary: §20.7 — list the athlete's active waitlist entries.
      tags: *ref_449
  /v2/event-participations/waitlist/position:
    get:
      operationId: EventParticipationsController.getMyWaitlistPosition
      parameters:
        - name: eventId
          required: true
          in: query
          schema:
            type: string
        - name: ticketId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §20.7 — read the athlete's queue position for a ticket.
      tags: *ref_449
  /v2/event-participations/waitlist/{entryId}:
    delete:
      operationId: EventParticipationsController.cancelWaitlistEntry
      parameters:
        - name: entryId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §20.7 — cancel an active waitlist entry (owner only).
      tags: *ref_449
  /v2/event-participations/transfers:
    post:
      operationId: EventParticipationsController.initiateTransfer
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                participationId:
                  type: string
                  format: uuid
                recipientEmail:
                  type: string
                reason:
                  type: string
              required:
                - participationId
                - recipientEmail
      responses:
        '201':
          description: ''
      summary: §20.8 — initiate a registration transfer.
      tags: *ref_449
  /v2/event-participations/{participationId}/participants/{participantId}/self-edit:
    patch:
      operationId: EventParticipationsController.selfEditParticipant
      parameters:
        - name: participationId
          required: true
          in: path
          schema:
            type: string
        - name: participantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        §35.4 — athlete edits own participant details (t-shirt, emergency
        contact, medical info, form answers). Gated by the organizer's
        self-service policy.
      tags: *ref_449
  /v2/event-participations/transfers/mine:
    get:
      operationId: EventParticipationsController.listMyTransfers
      parameters: []
      responses:
        '200':
          description: ''
      summary: §20.8 — list the athlete's outgoing + incoming transfer offers.
      tags: *ref_449
  /v2/event-participations/transfers/{transferId}/accept:
    post:
      operationId: EventParticipationsController.acceptTransfer
      parameters:
        - name: transferId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: §20.8 — accept a transfer offered to your email.
      tags: *ref_449
  /v2/event-participations/transfers/by-token/{token}/accept:
    post:
      operationId: EventParticipationsController.acceptTransferByToken
      parameters:
        - name: token
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: §20.8 — accept a transfer invite by token (post sign-up flow).
      tags: *ref_449
  /v2/event-participations/transfers/by-token/{token}:
    get:
      operationId: EventParticipationsController.lookupTransferByToken
      parameters:
        - name: token
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §20.8 — public-safe lookup of a pending transfer by invite token.
      tags: *ref_449
  /v2/event-participations/transfers/{transferId}/reject:
    post:
      operationId: EventParticipationsController.rejectTransfer
      parameters:
        - name: transferId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: §20.8 — reject a transfer offer (recipient or originator).
      tags: *ref_449
  /v2/event-participations/transfers/{transferId}:
    delete:
      operationId: EventParticipationsController.cancelTransfer
      parameters:
        - name: transferId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §20.8 — cancel an outgoing transfer offer (originator only).
      tags: *ref_449
  /v2/event-participations/deferrals:
    post:
      operationId: EventParticipationsController.requestDeferral
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                sourceParticipationId:
                  type: string
                  format: uuid
                targetEventId:
                  type: string
                  format: uuid
                targetTicketId:
                  type: string
                  format: uuid
                reason:
                  type: string
              required:
                - sourceParticipationId
                - targetEventId
      responses:
        '201':
          description: ''
      summary: §20.9 — request a registration deferral.
      tags: *ref_449
  /v2/event-participations/deferrals/mine:
    get:
      operationId: EventParticipationsController.listMyDeferrals
      parameters: []
      responses:
        '200':
          description: ''
      summary: §20.9 — list the athlete's deferral requests.
      tags: *ref_449
  /v2/event-participations/deferrals/{deferralId}:
    delete:
      operationId: EventParticipationsController.cancelDeferral
      parameters:
        - name: deferralId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §20.9 — cancel a pending deferral request (requester only).
      tags: *ref_449
  /v2/event-participations/deferrals/pending:
    get:
      operationId: EventParticipationsController.listPendingDeferrals
      parameters:
        - name: eventId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: §20.9 — list REQUESTED deferrals (organizer/admin scope).
      tags: *ref_449
  /v2/event-participations/deferrals/{deferralId}/fulfil:
    post:
      operationId: EventParticipationsController.fulfilDeferral
      parameters:
        - name: deferralId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        description: >-
          Optional `linkedParticipationId` — the new participation row on the
          target event that the organizer issued for the athlete.
        content:
          application/json:
            schema:
              type: object
              properties:
                linkedParticipationId:
                  type: string
                  format: uuid
      responses:
        '201':
          description: ''
      summary: §20.9 — fulfil a REQUESTED deferral (organizer/admin scope).
      tags: *ref_449
  /v2/event-participations/deferrals/{deferralId}/reject:
    post:
      operationId: EventParticipationsController.rejectDeferralAsOperator
      parameters:
        - name: deferralId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: §20.9 — reject a REQUESTED deferral (organizer/admin scope).
      tags: *ref_449
  /v2/event-participations/deferrals/{deferralId}/issue-comp:
    post:
      operationId: EventParticipationsController.issueCompAndFulfilDeferral
      parameters:
        - name: deferralId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        §20.9 — auto-issue a complimentary participation on the target event and
        fulfil the deferral.
      tags: *ref_449
  /v2/event-participations/{id}:
    get:
      operationId: EventParticipationsController.getEventParticipation
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_449
    patch:
      operationId: EventParticipationsController.verifyEventParticipation
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyEventParticipationDto'
      responses:
        '200':
          description: ''
      tags: *ref_449
    delete:
      operationId: EventParticipationsController.cancelEventParticipation
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelEventParticipationDto'
      responses:
        '200':
          description: ''
      tags: *ref_449
  /v2/event-participations/check-in/{participantId}:
    put:
      operationId: EventParticipationsController.checkInByParticipantId
      parameters: []
      responses:
        '200':
          description: ''
      summary: Check-in participant by participant ID
      tags: *ref_449
  /v2/event-participations/check-in/by-booking/{eventId}:
    put:
      description: Enter only the last 7 digits of the booking ID to check-in a participant
      operationId: EventParticipationsController.checkInByBookingId
      parameters:
        - name: bookingId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Check-in participant by last 7 digits of booking ID
      tags: *ref_449
  /v2/event-participations/addons/{addOnId}/collect:
    put:
      operationId: EventParticipationsController.markAddOnAsCollected
      parameters:
        - name: addOnId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Mark addon product as collected
      tags: *ref_449
  /v2/event-participations/assign-booking-id/{participantId}:
    post:
      description: Dev/migration helper. Disabled in production.
      operationId: EventParticipationsController.assignBookingIdToParticipant
      parameters: []
      responses:
        '201':
          description: ''
      summary: Assign booking ID to a participant (one-time migration API)
      tags: *ref_449
  /v2/event-participations/assign-booking-ids-all:
    post:
      description: Dev/migration helper. Disabled in production.
      operationId: EventParticipationsController.assignBookingIdsToAllParticipants
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Assign booking IDs to all participants without one (one-time migration
        API)
      tags: *ref_449
  /v2/event-participations/reassign-all-booking-ids:
    post:
      description: Dev/migration helper. Disabled in production.
      operationId: EventParticipationsController.reassignAllBookingIds
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Reassign ALL booking IDs from scratch (fixes duplicates, use with
        caution)
      tags: *ref_449
  /v2/event-participations/test-check-in:
    post:
      description: Dev/test helper for bulk participant check-in. Disabled in production.
      operationId: EventParticipationsController.testCheckInParticipants
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TestCheckInDto'
      responses:
        '201':
          description: ''
      summary: 'Test API: Bulk check-in/check-out participants by IDs'
      tags: *ref_449
  /v2/event-participations/reassign-event-booking-ids/{eventId}:
    post:
      description: Dev/migration helper. Disabled in production.
      operationId: EventParticipationsController.reassignBookingIdsForEvent
      parameters:
        - name: startFrom
          required: true
          in: query
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Reassign booking IDs for a specific event starting from a custom number
      tags: *ref_449
  /v2/event-participations/webhooks/cashfree:
    post:
      operationId: EventParticipationsWebhookController.cashfree
      parameters:
        - name: x-webhook-signature
          required: true
          in: header
          schema:
            type: string
        - name: x-webhook-timestamp
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Payment Webhooks'
  /v2/event-bookmarks/{eventId}/toggle:
    post:
      operationId: EventBookmarksController.toggle
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Bookmark / un-bookmark an event for the viewer
      tags: &ref_450
        - Event Bookmarks
  /v2/event-bookmarks/{eventId}/status:
    get:
      operationId: EventBookmarksController.status
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Whether the viewer has bookmarked an event
      tags: *ref_450
  /v2/event-bookmarks/mine:
    get:
      operationId: EventBookmarksController.mine
      parameters: []
      responses:
        '200':
          description: ''
      summary: Viewer's saved events, newest first
      tags: *ref_450
  /v2/reviews:
    post:
      operationId: ReviewsController.createReview
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateReviewDto'
      responses:
        '201':
          description: ''
      tags: &ref_451
        - Reviews
    get:
      operationId: ReviewsController.getReviews
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_451
  /v2/reviews/stats:
    get:
      operationId: ReviewsController.getReviewStats
      parameters:
        - name: reviewAbout
          required: true
          in: query
          schema:
            type: string
        - name: reviewAboutId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_451
  /v2/reviews/item:
    get:
      operationId: ReviewsController.getReviewsForItem
      parameters:
        - name: reviewAbout
          required: true
          in: query
          schema:
            type: string
        - name: reviewAboutId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_451
  /v2/reviews/{id}:
    get:
      operationId: ReviewsController.getReview
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_451
    patch:
      operationId: ReviewsController.updateReview
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateReviewDto'
      responses:
        '200':
          description: ''
      tags: *ref_451
    delete:
      operationId: ReviewsController.deleteReview
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_451
  /v2/user/training-plans/generate:
    post:
      description: >-
        Creates a personalized training plan using AI based on user profile and
        event details
      operationId: TrainingPlansController.generateTrainingPlan
      parameters:
        - &ref_452
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenerateTrainingPlanDto'
      responses:
        '201':
          description: Training plan generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingPlanResponseDto'
        '400':
          description: Invalid request or event date too soon
      summary: Generate AI-based training plan
      tags: &ref_453
        - Training Plans
  /v2/user/training-plans/generate-test:
    post:
      description: >-
        Seeds a training plan against a hardcoded test event fixture. Refuses to
        run outside NODE_ENV=development|test so this dev-only helper can never
        be fired from production.
      operationId: TrainingPlansController.generateTestTrainingPlan
      parameters:
        - *ref_452
      responses:
        '201':
          description: Training plan generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingPlanResponseDto'
        '403':
          description: Endpoint disabled outside development/test environments
      summary: Generate AI-based training plan (DEV/TEST MODE)
      tags: *ref_453
  /v2/user/training-plans:
    get:
      description: Returns all training plans created by the current user
      operationId: TrainingPlansController.getUserTrainingPlans
      parameters:
        - *ref_452
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: Training plans retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TrainingPlanResponseDto'
      summary: Get all training plans for current user
      tags: *ref_453
    delete:
      description: Soft deletes all training plans for the current user
      operationId: TrainingPlansController.deleteAllTrainingPlans
      parameters:
        - *ref_452
      responses:
        '200':
          description: All training plans deleted successfully
      summary: Delete all training plans
      tags: *ref_453
  /v2/user/training-plans/{id}:
    get:
      description: Returns a specific training plan with all daily workouts
      operationId: TrainingPlansController.getTrainingPlan
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Training plan retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingPlanResponseDto'
        '404':
          description: Training plan not found
      summary: Get training plan by ID
      tags: *ref_453
    delete:
      description: Soft deletes a training plan and all associated workouts
      operationId: TrainingPlansController.deleteTrainingPlan
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Training plan deleted successfully
        '404':
          description: Training plan not found
      summary: Delete training plan
      tags: *ref_453
  /v2/user/training-plans/{id}/workouts/{workoutId}:
    get:
      description: Returns details of a specific workout from a training plan
      operationId: TrainingPlansController.getWorkout
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          description: Training plan ID
          schema:
            type: string
        - name: workoutId
          required: true
          in: path
          description: Workout ID
          schema:
            type: string
      responses:
        '200':
          description: Workout retrieved successfully
        '404':
          description: Workout not found
      summary: Get a specific workout
      tags: *ref_453
    patch:
      description: Update workout completion status and actual performance data
      operationId: TrainingPlansController.updateWorkout
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          description: Training plan ID
          schema:
            type: string
        - name: workoutId
          required: true
          in: path
          description: Workout ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkoutDto'
      responses:
        '200':
          description: Workout updated successfully
        '404':
          description: Workout not found
      summary: Update workout status
      tags: *ref_453
  /v2/user/training-plans/{id}/match-activity:
    post:
      description: >-
        Automatically matches a tracked activity to the scheduled workout and
        updates completion status
      operationId: TrainingPlansController.matchActivity
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MatchActivityDto'
      responses:
        '200':
          description: Activity matched successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutMatchResponseDto'
        '404':
          description: No scheduled workout found for the activity date
      summary: Match activity to training plan workout
      tags: *ref_453
  /v2/user/training-plans/{id}/progress:
    get:
      description: >-
        Returns statistics about plan completion including completed, missed,
        and pending workouts
      operationId: TrainingPlansController.getPlanProgress
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Plan progress retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanProgressResponseDto'
      summary: Get training plan progress
      tags: *ref_453
  /v2/user/training-plans/{id}/adjust:
    post:
      description: >-
        Modifies the training plan based on progress, injuries, schedule
        conflicts, or performance issues using AI. Only available for GOAT plan
        subscribers.
      operationId: TrainingPlansController.adjustPlan
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdjustPlanDto'
      responses:
        '200':
          description: Plan adjusted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanAdjustmentResponseDto'
        '400':
          description: Invalid adjustment request or event date too soon
        '403':
          description: Plan adjustments are only available with GOAT plan
        '404':
          description: Training plan not found
      summary: Adjust training plan (GOAT plan only)
      tags: *ref_453
  /v2/user/training-plans/{id}/adjustment-suggestions:
    get:
      description: >-
        Returns automated suggestions for plan adjustments based on current
        progress without applying them. Only available for GOAT plan
        subscribers.
      operationId: TrainingPlansController.getAdjustmentSuggestions
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Suggestions retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdjustmentSuggestionsResponseDto'
        '403':
          description: Adjustment suggestions are only available with GOAT plan
        '404':
          description: Training plan not found
      summary: Get AI-powered adjustment suggestions (GOAT plan only)
      tags: *ref_453
  /v2/user/training-plans/{id}/fitness-score:
    get:
      description: >-
        Calculates overall fitness score with breakdowns for consistency,
        volume, intensity, and progression. Includes readiness assessment and
        projected performance. Available for ATHLETE and GOAT plan subscribers.
      operationId: TrainingPlansController.getFitnessScore
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Fitness score calculated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FitnessScoreResponseDto'
        '403':
          description: Fitness analytics are only available with ATHLETE or GOAT plan
        '404':
          description: Training plan not found
      summary: Get comprehensive fitness score (ATHLETE & GOAT plans)
      tags: *ref_453
  /v2/user/training-plans/{id}/fitness-history:
    get:
      description: >-
        Returns fitness score history over the past weeks to show trends and
        improvements. Available for ATHLETE and GOAT plan subscribers.
      operationId: TrainingPlansController.getFitnessHistory
      parameters:
        - *ref_452
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Fitness history retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FitnessHistoryResponseDto'
        '403':
          description: Fitness analytics are only available with ATHLETE or GOAT plan
        '404':
          description: Training plan not found
      summary: Get historical fitness scores (ATHLETE & GOAT plans)
      tags: *ref_453
  /v2/user/training-plans/chat:
    post:
      description: >-
        Chat with AI assistant about fitness, nutrition, training, and events.
        Requires an active training plan.
      operationId: TrainingPlansController.sendChatMessage
      parameters:
        - *ref_452
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendChatMessageDto'
      responses:
        '200':
          description: Message sent and response received
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatMessageResponseDto'
        '403':
          description: User does not have an active training plan
      summary: Send message to AI fitness chatbot
      tags: *ref_453
  /v2/user/training-plans/chat/sessions:
    get:
      description: Returns list of all chat sessions for the user
      operationId: TrainingPlansController.getChatSessions
      parameters:
        - *ref_452
      responses:
        '200':
          description: Chat sessions retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ChatSessionListDto'
      summary: Get all chat sessions
      tags: *ref_453
  /v2/user/training-plans/chat/sessions/{sessionId}:
    get:
      description: Returns all messages in a specific chat session
      operationId: TrainingPlansController.getChatHistory
      parameters:
        - *ref_452
        - name: sessionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Chat history retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatHistoryResponseDto'
      summary: Get chat history for a session
      tags: *ref_453
    delete:
      description: Deletes all messages in a chat session
      operationId: TrainingPlansController.deleteChatSession
      parameters:
        - *ref_452
        - name: sessionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Chat session deleted successfully
      summary: Delete a chat session
      tags: *ref_453
  /v2/user/training-plans/chat/access:
    get:
      description: >-
        Checks if user has access to the AI chatbot (requires active training
        plan)
      operationId: TrainingPlansController.checkChatAccess
      parameters:
        - *ref_452
      responses:
        '200':
          description: Access status retrieved successfully
      summary: Check chatbot access
      tags: *ref_453
  /v2/user/training-plans/offer/{eventId}:
    get:
      description: >-
        Check eligibility and get pricing for training plan purchase for a
        specific event
      operationId: TrainingPlansController.getTrainingPlanOffer
      parameters:
        - *ref_452
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Training plan offer retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingPlanOfferResponseDto'
        '404':
          description: Event not found
      summary: Get training plan offer for an event
      tags: *ref_453
  /v2/user/training-plans/purchase/initiate:
    post:
      description: >-
        Creates a Cashfree payment order for training plan purchase. Returns
        payment session for completing payment.
      operationId: TrainingPlansController.initiateTrainingPlanPurchase
      parameters:
        - *ref_452
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InitiateTrainingPlanPurchaseDto'
      responses:
        '200':
          description: Payment order created successfully
        '400':
          description: User not eligible for training plan
        '404':
          description: Event not found
      summary: Initiate training plan purchase
      tags: *ref_453
  /v2/user/training-plans/purchase/verify:
    post:
      deprecated: true
      description: >-
        Verifies payment completion and generates the training plan. Use
        /purchase/verify-payment and /purchase/generate separately instead.
      operationId: TrainingPlansController.verifyTrainingPlanPurchase
      parameters:
        - *ref_452
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyTrainingPlanPurchaseDto'
      responses:
        '200':
          description: Training plan created successfully
        '400':
          description: Payment not completed or already processed
        '404':
          description: Order not found
      summary: '[DEPRECATED] Verify training plan purchase and generate plan'
      tags: *ref_453
  /v2/user/training-plans/purchase/verify-payment:
    post:
      description: >-
        Verifies payment completion without generating the training plan. Use
        this to check payment status before generating the plan.
      operationId: TrainingPlansController.verifyPayment
      parameters:
        - *ref_452
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyPaymentDto'
      responses:
        '200':
          description: Payment status retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerifyPaymentResponseDto'
        '404':
          description: Order not found
      summary: Verify payment status only
      tags: *ref_453
  /v2/user/training-plans/purchase/generate:
    post:
      description: >-
        Generates the training plan. For free plans, generates directly. For
        paid plans, verifies payment first then generates.
      operationId: TrainingPlansController.generateTrainingPlanFromOrder
      parameters:
        - *ref_452
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenerateTrainingPlanFromOrderDto'
      responses:
        '201':
          description: Training plan created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GenerateTrainingPlanResponseDto'
        '400':
          description: Payment not completed (for paid plans) or invalid request
        '404':
          description: Event or order not found
      summary: Generate training plan
      tags: *ref_453
  /v2/user/training-plans/pricing:
    get:
      description: Get current pricing for Normal and Advanced training plans
      operationId: TrainingPlansController.getTrainingPlanPricing
      parameters:
        - *ref_452
      responses:
        '200':
          description: Pricing retrieved successfully
      summary: Get training plan pricing
      tags: *ref_453
  /v2/user/calendar/month:
    get:
      description: >-
        Returns all calendar events (training workouts, custom workouts, events,
        challenges) for a specific month
      operationId: CalendarController.getMonthlyCalendar
      parameters:
        - &ref_454
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: year
          required: true
          in: query
          schema:
            example: 2025
            type: number
        - name: month
          required: true
          in: query
          schema:
            example: 2
            type: number
      responses:
        '200':
          description: Monthly calendar retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalendarMonthResponseDto'
      summary: Get monthly calendar
      tags: &ref_455
        - Calendar
  /v2/user/calendar/range:
    get:
      description: Returns all calendar events for a custom date range
      operationId: CalendarController.getCalendarByRange
      parameters:
        - *ref_454
        - name: startDate
          required: true
          in: query
          schema:
            example: '2025-01-01'
            type: string
        - name: endDate
          required: true
          in: query
          schema:
            example: '2025-01-31'
            type: string
      responses:
        '200':
          description: Calendar range retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalendarRangeResponseDto'
      summary: Get calendar for date range
      tags: *ref_455
  /v2/user/calendar/daily:
    get:
      description: Returns all calendar events for a specific date
      operationId: CalendarController.getDailyCalendar
      parameters:
        - *ref_454
        - name: date
          required: true
          in: query
          schema:
            example: '2025-01-15'
            type: string
      responses:
        '200':
          description: Daily calendar retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CalendarEventDto'
      summary: Get daily calendar
      tags: *ref_455
  /v2/user/calendar/today:
    get:
      description: Returns all calendar events for today
      operationId: CalendarController.getTodayCalendar
      parameters:
        - *ref_454
      responses:
        '200':
          description: Today's calendar retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CalendarEventDto'
      summary: Get today's calendar
      tags: *ref_455
  /v2/user/calendar/workouts:
    post:
      description: Create a custom workout entry in your calendar
      operationId: CalendarController.createWorkout
      parameters:
        - *ref_454
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserWorkoutDto'
      responses:
        '201':
          description: Workout created successfully
      summary: Create a manual workout
      tags: *ref_455
    get:
      description: Get all custom workouts created by the user
      operationId: CalendarController.getWorkouts
      parameters:
        - *ref_454
        - name: startDate
          required: false
          in: query
          schema:
            example: '2025-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2025-01-31'
            type: string
      responses:
        '200':
          description: Workouts retrieved successfully
      summary: Get all manual workouts
      tags: *ref_455
  /v2/user/calendar/workouts/month:
    get:
      description: Get all custom workouts for a specific month
      operationId: CalendarController.getWorkoutsByMonth
      parameters:
        - *ref_454
        - name: year
          required: true
          in: query
          schema:
            example: 2025
            type: number
        - name: month
          required: true
          in: query
          schema:
            example: 2
            type: number
      responses:
        '200':
          description: Workouts retrieved successfully
      summary: Get workouts for a month
      tags: *ref_455
  /v2/user/calendar/workouts/statistics:
    get:
      description: Get statistics for user workouts
      operationId: CalendarController.getWorkoutStatistics
      parameters:
        - *ref_454
        - name: startDate
          required: false
          in: query
          schema:
            example: '2025-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2025-12-31'
            type: string
      responses:
        '200':
          description: Statistics retrieved successfully
      summary: Get workout statistics
      tags: *ref_455
  /v2/user/calendar/workouts/{workoutId}:
    get:
      description: Get details of a specific workout
      operationId: CalendarController.getWorkout
      parameters:
        - *ref_454
        - name: workoutId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Workout retrieved successfully
      summary: Get a specific workout
      tags: *ref_455
    put:
      description: Update a custom workout
      operationId: CalendarController.updateWorkout
      parameters:
        - *ref_454
        - name: workoutId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserWorkoutDto'
      responses:
        '200':
          description: Workout updated successfully
      summary: Update a workout
      tags: *ref_455
    delete:
      description: Delete a custom workout
      operationId: CalendarController.deleteWorkout
      parameters:
        - *ref_454
        - name: workoutId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Workout deleted successfully
      summary: Delete a workout
      tags: *ref_455
  /v2/user/calendar/workouts/{workoutId}/complete:
    put:
      description: Toggle workout completion status
      operationId: CalendarController.markWorkoutCompleted
      parameters:
        - *ref_454
        - name: workoutId
          required: true
          in: path
          schema:
            type: string
        - name: completed
          required: false
          in: query
          schema:
            example: true
            type: boolean
      responses:
        '200':
          description: Workout status updated successfully
      summary: Mark workout as completed
      tags: *ref_455
  /v2/transactions:
    get:
      description: >-
        Get all user transactions — event tickets, cloud image purchases,
        training plans, refunds, challenge entry fees (RC coin or money),
        challenge RC rewards, RC wallet movements
        (steps/referral/promotion/adjustment), and RC Store redemptions — merged
        into one feed, with pagination.
      operationId: TransactionsController.getMyTransactions
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: string
        - name: pageSize
          required: false
          in: query
          description: 'Items per page (default: 20, max: 50)'
          schema:
            type: string
        - name: type
          required: false
          in: query
          description: Filter by transaction type
          schema:
            enum:
              - event_ticket
              - cloud_image_purchase
              - training_plan
              - refund
              - challenge_entry_fee
              - challenge_reward
              - rc_wallet
              - rc_store_redemption
            type: string
      responses:
        '200':
          description: ''
      summary: Get my transactions
      tags:
        - User Transactions
  /v2/users/me/payments/{paymentId}/receipt:
    get:
      operationId: UserPaymentsController.getReceipt
      parameters:
        - name: paymentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a receipt for the caller's own payment
      tags:
        - 'User: Payments'
  /v2/clubs/{clubId}/sponsorship-proposals:
    get:
      operationId: ClubSponsorshipProposalsController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Brand sponsorship proposals addressed to this club's challenges.
      tags: &ref_456
        - Clubs — sponsorship proposals
  /v2/clubs/{clubId}/sponsorship-proposals/{proposalId}:
    get:
      operationId: ClubSponsorshipProposalsController.get
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: proposalId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        One proposal in full — the brand behind it, the challenge it targets,
        and the decision so far.
      tags: *ref_456
  /v2/clubs/{clubId}/sponsorship-proposals/{proposalId}/accept:
    post:
      operationId: ClubSponsorshipProposalsController.accept
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: proposalId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Accept a proposal. The brand is attached to the challenge and may then
        add goodie products to its leaderboard.
      tags: *ref_456
  /v2/clubs/{clubId}/sponsorship-proposals/{proposalId}/decline:
    post:
      operationId: ClubSponsorshipProposalsController.decline
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: proposalId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Decline a proposal, with a reason for the brand.
      tags: *ref_456
  /v2/clubs/{clubId}/sponsorship-earnings:
    get:
      operationId: ClubSponsorshipMoneyController.list
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Sponsorship money owed to or paid to this club — what a brand agreed,
        whether it has paid, whether Repeak still holds it, and when it settles.
      tags: &ref_457
        - Clubs — sponsorship money
  /v2/clubs/{clubId}/sponsorship-earnings/{contractId}:
    get:
      operationId: ClubSponsorshipMoneyController.one
      parameters:
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: contractId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: One sponsorship, in full.
      tags: *ref_457
  /v2/organizers/{organizerId}/sponsorship-earnings:
    get:
      operationId: OrganizerSponsorshipMoneyController.list
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Sponsorship money owed to or paid to this organizer. Same shape as the
        club surface.
      tags:
        - Organizers — sponsorship money
  /v2/admin/sponsorship-finance/dashboard:
    get:
      operationId: AdminSponsorshipFinanceController.dashboard
      parameters: []
      responses:
        '200':
          description: ''
      summary: >-
        Platform-wide sponsorship finance totals — collected, retained, held,
        settled.
      tags: &ref_458
        - Admin — sponsorship finance
  /v2/admin/sponsorship-finance/payments:
    get:
      operationId: AdminSponsorshipFinanceController.payments
      parameters:
        - name: stage
          required: false
          in: query
          schema:
            type: string
        - name: brandId
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: >-
        The sponsorship payment ledger: brand → Repeak → payee, with the gateway
        leg, the settlement leg, and the frozen fee breakdown on every row.
      tags: *ref_458
  /v2/admin/sponsorship-finance/payments/{contractId}:
    get:
      operationId: AdminSponsorshipFinanceController.one
      parameters:
        - name: contractId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        One sponsorship in full. Release actions stay on /v2/settlements/:id —
        use `settlement.id` from this row.
      tags: *ref_458
  /v2/organizer/brand/saas/plans:
    get:
      operationId: OrganizerBrandController.plansList
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_459
        - 'Organizer: Brand + Training'
  /v2/organizer/brand/saas/my:
    get:
      operationId: OrganizerBrandController.mySaas
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/saas/subscribe:
    post:
      operationId: OrganizerBrandController.subscribe
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/saas/cancel:
    post:
      operationId: OrganizerBrandController.cancelSaas
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/page:
    get:
      operationId: OrganizerBrandController.myPage
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_459
    patch:
      operationId: OrganizerBrandController.updatePage
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/cascade-defaults:
    get:
      operationId: OrganizerBrandController.getCascadeDefaults
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_459
    patch:
      operationId: OrganizerBrandController.updateCascadeDefaults
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/prep-programs:
    get:
      operationId: OrganizerBrandController.listPrograms
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_459
    post:
      operationId: OrganizerBrandController.createProgram
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/prep-programs/{id}:
    get:
      operationId: OrganizerBrandController.getProgram
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_459
    patch:
      operationId: OrganizerBrandController.updateProgram
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/prep-programs/{id}/weekly-plan:
    patch:
      operationId: OrganizerBrandController.updateWeeklyPlan
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/prep-programs/{id}/assign:
    post:
      operationId: OrganizerBrandController.assignProgram
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/followers:
    get:
      operationId: OrganizerBrandController.listFollowers
      parameters:
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_459
  /v2/organizer/brand/followers/export.csv:
    get:
      operationId: OrganizerBrandController.exportFollowersCsv
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_459
  /v2/user/brand/{organizerId}/follow:
    post:
      operationId: UserBrandController.follow
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_460
        - 'User: Brand Follow + Prep Programs'
  /v2/user/brand/{organizerId}/unfollow:
    post:
      operationId: UserBrandController.unfollow
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_460
  /v2/user/brand/prep-programs/my:
    get:
      operationId: UserBrandController.myPrograms
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_460
  /v2/user/org/{slug}/following:
    get:
      operationId: UserBrandPageSlugController.isFollowing
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_461
        - 'User: Brand Page (slug actions)'
  /v2/user/org/{slug}/follow:
    post:
      operationId: UserBrandPageSlugController.follow
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_461
  /v2/user/org/{slug}/unfollow:
    post:
      operationId: UserBrandPageSlugController.unfollow
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_461
  /v2/public/organizers/sitemap-rows:
    get:
      operationId: PublicBrandController.sitemapRows
      parameters:
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_462
        - 'Public: Organizer Brand Page'
  /v2/public/organizers/{slug}:
    get:
      operationId: PublicBrandController.page
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_462
  /v2/public/organizers/events/{eventId}/prep-programs:
    get:
      operationId: PublicBrandController.prepForEvent
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_462
  /v2/organizations/{orgId}/brand-prep-programs:
    get:
      operationId: OrganizationPrepProgramsController.listForOrganization
      parameters:
        - name: orgId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Organization: Prep Programs'
  /v2/sponsors/featured:
    get:
      operationId: SponsorMarketplaceController.featured
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_463
        - Sponsor Marketplace
  /v2/sponsors:
    get:
      operationId: SponsorMarketplaceController.list
      parameters:
        - name: featuredOnly
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_463
  /v2/sponsors/{slug}:
    put:
      operationId: SponsorMarketplaceController.upsert
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_463
  /v2/sponsors/attachments:
    post:
      operationId: SponsorMarketplaceController.attach
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_463
  /v2/sponsors/attachments/{targetType}/{targetId}:
    get:
      operationId: SponsorMarketplaceController.listAttachments
      parameters:
        - name: targetType
          required: true
          in: path
          schema:
            type: string
        - name: targetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_463
  /v2/sponsors/organizer/attachments/{targetType}/{targetId}:
    get:
      operationId: SponsorMarketplaceController.listAttachmentsForOrganizer
      parameters:
        - name: targetType
          required: true
          in: path
          schema:
            type: string
        - name: targetId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_463
  /v2/sponsors/attachments/pending:
    get:
      operationId: SponsorMarketplaceController.pending
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_463
  /v2/sponsors/attachments/{id}/status:
    patch:
      operationId: SponsorMarketplaceController.setStatus
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_463
  /v2/sponsor/me/brands:
    get:
      operationId: SponsorPersonaController.myBrands
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_464
        - Sponsor Persona
  /v2/sponsor/brands:
    post:
      operationId: SponsorPersonaController.createSelfServe
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/apply:
    post:
      operationId: SponsorPersonaController.applyForApproval
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}:
    get:
      operationId: SponsorPersonaController.brand
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_464
    patch:
      operationId: SponsorPersonaController.updateBrand
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/shipping/pickup-address:
    get:
      operationId: SponsorPersonaController.brandPickupAddress
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_464
    post:
      operationId: SponsorPersonaController.saveBrandPickupAddress
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/logo:
    post:
      operationId: SponsorPersonaController.uploadLogo
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/banner:
    post:
      operationId: SponsorPersonaController.uploadBanner
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/campaign-creative-image:
    post:
      operationId: SponsorPersonaController.uploadCampaignCreativeImage
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/ambassador-product-image:
    post:
      operationId: SponsorPersonaController.uploadAmbassadorProductImage
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brand-tiers:
    get:
      operationId: SponsorPersonaController.brandTiers
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/tier:
    post:
      operationId: SponsorPersonaController.selectTier
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/attachments:
    get:
      operationId: SponsorPersonaController.attachments
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/contracts:
    get:
      operationId: SponsorPersonaController.contracts
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_464
    post:
      operationId: SponsorPersonaController.proposeContract
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/contracts/{contractId}/payment-summary:
    get:
      operationId: SponsorPersonaController.contractPaymentSummary
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: contractId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/contracts/{contractId}/pay:
    post:
      operationId: SponsorPersonaController.payContract
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: contractId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/contracts/{contractId}/payments/{paymentId}/verify:
    post:
      operationId: SponsorPersonaController.verifyContractPayment
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: contractId
          required: true
          in: path
          schema:
            type: string
        - name: paymentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/kyc:
    get:
      operationId: SponsorPersonaController.kycStatus
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/kyc/submit-profile:
    post:
      operationId: SponsorPersonaController.submitProfile
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/kyc/run-identity:
    post:
      operationId: SponsorPersonaController.runIdentity
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/kyc/run-bank-penny-drop:
    post:
      operationId: SponsorPersonaController.runBank
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_464
  /v2/sponsor/brands/{brandId}/inventory:
    get:
      operationId: SponsorInventoryController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_465
        - bearer: []
      summary: List inventory items for a brand.
      tags: &ref_466
        - 'Brand: Inventory'
    post:
      operationId: SponsorInventoryController.create
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_465
      summary: Create an inventory item.
      tags: *ref_466
  /v2/sponsor/brands/{brandId}/inventory/{itemId}/movements:
    get:
      operationId: SponsorInventoryController.movements
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: itemId
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_465
      summary: >-
        Stock movement history for one item (delta / before / after), newest
        first. Derived from the audit trail, so it is a recent history rather
        than a permanent ledger.
      tags: *ref_466
  /v2/sponsor/brands/{brandId}/inventory/{itemId}:
    patch:
      operationId: SponsorInventoryController.update
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: itemId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_465
      summary: Update an item name / low-stock threshold.
      tags: *ref_466
  /v2/sponsor/brands/{brandId}/inventory/{itemId}/stock:
    patch:
      operationId: SponsorInventoryController.adjustStock
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: itemId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_465
      summary: >-
        Adjust stock by a delta (positive = restock, negative = consume).
        Crossing the threshold emits a low-stock audit alert.
      tags: *ref_466
  /v2/sponsor/brands/{brandId}/reward-grants:
    get:
      operationId: BrandRewardGrantController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_467
        - bearer: []
      summary: List recent per-athlete reward grants.
      tags: &ref_468
        - 'Brand: Reward Grants'
    post:
      operationId: BrandRewardGrantController.grant
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_467
      summary: >-
        Grant a reward to a specific athlete. Reason required; amount validated;
        idempotent on sequenceKey; audit-emitting.
      tags: *ref_468
  /v2/sponsor/brands/{brandId}/events:
    post:
      operationId: SponsorWritesController.createEvent
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventDto'
      responses:
        '201':
          description: ''
      tags: &ref_469
        - 'Sponsor: Writes'
  /v2/sponsor/brands/{brandId}/challenges:
    post:
      operationId: SponsorWritesController.createChallenge
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateChallengeDto'
      responses:
        '201':
          description: ''
      tags: *ref_469
    get:
      operationId: SponsorWritesController.listChallenges
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}:
    get:
      operationId: SponsorWritesController.getChallenge
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
    patch:
      operationId: SponsorWritesController.updateChallenge
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateChallengeDto'
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/prizes:
    get:
      operationId: SponsorWritesController.getChallengePrizes
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/audiences:
    get:
      operationId: SponsorWritesController.listChallengeAudiences
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
    post:
      operationId: SponsorWritesController.bindChallengeAudience
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/audiences/{audienceId}:
    delete:
      operationId: SponsorWritesController.unbindChallengeAudience
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
        - name: audienceId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/rewards:
    get:
      operationId: SponsorWritesController.listChallengeRewards
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/rewards/distribute-all:
    post:
      operationId: SponsorWritesController.distributeAllChallengeRewards
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/readiness:
    get:
      operationId: SponsorWritesController.getChallengeReadiness
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/reward-eligibility:
    get:
      operationId: SponsorWritesController.getChallengeRewardEligibility
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
        - name: userId
          required: true
          in: query
          schema:
            type: string
        - name: rewardPoolId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/promo-stories:
    get:
      operationId: SponsorWritesController.listPromoStories
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: filter
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/promo-stories:
    post:
      operationId: SponsorWritesController.createChallengePromoStory
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/cancel:
    post:
      operationId: SponsorWritesController.cancelChallenge
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/analytics:
    get:
      operationId: SponsorWritesController.challengeAnalytics
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/sponsor/brands/{brandId}/rc-attribution:
    get:
      operationId: SponsorWritesController.monthlyRcAttribution
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: monthKey
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_469
  /v2/admin/sponsors/brands/{brandId}/accounts:
    get:
      operationId: AdminSponsorAccountsController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_470
        - 'Admin: Sponsor Accounts'
    post:
      operationId: AdminSponsorAccountsController.invite
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_470
  /v2/admin/sponsors/accounts/{accountId}/status:
    patch:
      operationId: AdminSponsorAccountsController.setStatus
      parameters:
        - name: accountId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_470
  /v2/admin/sponsors/brands/{brandId}/approval:
    patch:
      operationId: AdminSponsorAccountsController.reviewBrandApproval
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_470
  /v2/admin/sponsors/accounts/{accountId}/activity:
    get:
      operationId: AdminSponsorAccountsController.activity
      parameters:
        - name: accountId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_470
  /v2/admin/sponsors/brands/{brandId}/contracts:
    get:
      operationId: AdminSponsorAccountsController.listContracts
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_470
    post:
      operationId: AdminSponsorAccountsController.createContract
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_470
  /v2/admin/sponsors/contracts/{contractId}/activate:
    post:
      operationId: AdminSponsorAccountsController.activateContract
      parameters:
        - name: contractId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_470
  /v2/admin/sponsors/contracts/{contractId}/end:
    post:
      operationId: AdminSponsorAccountsController.endContract
      parameters:
        - name: contractId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_470
  /v2/admin/sponsors/contracts/{contractId}/cancel:
    post:
      operationId: AdminSponsorAccountsController.cancelContract
      parameters:
        - name: contractId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_470
  /v2/users/me/goodies:
    get:
      operationId: UserGoodiesController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_471
        - 'User: Goodies'
  /v2/users/me/goodies/summary:
    get:
      operationId: UserGoodiesController.goodieSummary
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_471
  /v2/users/me/goodies/{goodieId}:
    get:
      operationId: UserGoodiesController.detail
      parameters:
        - name: goodieId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_471
  /v2/users/me/goodies/{goodieId}/address:
    patch:
      operationId: UserGoodiesController.captureAddress
      parameters:
        - name: goodieId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_471
  /v2/sponsor/brands/{brandId}/goodies:
    get:
      operationId: SponsorGoodiesController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_472
        - 'Sponsor: Goodies'
    post:
      operationId: SponsorGoodiesController.award
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_472
  /v2/sponsor/goodies/{goodieId}/ship:
    patch:
      operationId: SponsorGoodieOpsController.ship
      parameters:
        - name: goodieId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_473
        - 'Sponsor: Goodies'
  /v2/sponsor/goodies/{goodieId}/deliver:
    patch:
      operationId: SponsorGoodieOpsController.deliver
      parameters:
        - name: goodieId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_473
  /v2/sponsor/goodies/{goodieId}/cancel:
    patch:
      operationId: SponsorGoodieOpsController.cancel
      parameters:
        - name: goodieId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_473
  /v2/sponsor/goodies/{goodieId}/ship-via-shiprocket:
    patch:
      operationId: SponsorGoodieOpsController.shipViaShiprocket
      parameters:
        - name: goodieId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Create a Shiprocket order for this goodie and stamp tracking on the row.
        503 when Shiprocket is not configured.
      tags: *ref_473
  /v2/organizers/challenges/{challengeId}/goodies:
    get:
      operationId: OrganizerChallengeGoodiesController.list
      parameters:
        - name: challengeId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Goodies awarded against one of the caller's own challenges.
      tags:
        - 'Organizer: Challenge Goodies'
  /v2/organizers/events/{eventId}/goodies:
    get:
      operationId: OrganizerEventGoodiesController.list
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Goodies awarded against one of the caller's own events.
      tags:
        - 'Organizer: Event Goodies'
  /v2/sponsor/brands/{brandId}/recipients:
    get:
      operationId: BrandRecipientsController.search
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Search this brand's eligible goodie recipients by name/email/phone.
      tags: &ref_474
        - 'Sponsor: Recipients'
  /v2/sponsor/brands/{brandId}/recipients/lookup:
    get:
      operationId: BrandRecipientsController.lookup
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: email
          required: false
          in: query
          schema:
            type: string
        - name: phone
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Resolve a raffle winner to a userId by exact email or phone match.
      tags: *ref_474
  /v2/integrations/shiprocket/webhook:
    post:
      operationId: ShiprocketWebhookController.webhook
      parameters:
        - name: x-api-key
          required: true
          in: header
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Shiprocket status update webhook. Verifies x-api-key against
        SHIPROCKET_WEBHOOK_TOKEN. Tries goodies, RC Store redemptions, challenge
        rewards, and ambassador deals in turn — one dashboard webhook URL covers
        every shipment source.
      tags:
        - 'Integrations: Shiprocket'
  /v2/sponsors/analytics/impressions:
    post:
      operationId: SponsorAnalyticsPublicController.logImpression
      parameters: []
      responses:
        '201':
          description: ''
      tags: &ref_475
        - 'Sponsor: Analytics (Public)'
  /v2/sponsors/analytics/content-events:
    post:
      operationId: SponsorAnalyticsPublicController.logContentEvent
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_475
  /v2/sponsor/brands/{brandId}/metrics:
    get:
      operationId: SponsorMetricsController.metrics
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_476
        - 'Sponsor: Analytics'
  /v2/sponsor/brands/{brandId}/metrics/content:
    get:
      operationId: SponsorMetricsController.contentMetrics
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_476
  /v2/sponsor/brands/{brandId}/metrics/campaigns/{campaignId}/audience:
    get:
      operationId: SponsorMetricsController.campaignAudience
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_476
  /v2/admin/sponsors/brands/{brandId}/metrics:
    get:
      operationId: AdminSponsorMetricsController.metrics
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Admin: Sponsor Analytics'
  /v2/admin/sponsors/attachments/{id}/history:
    get:
      operationId: AdminSponsorAttachmentsController.history
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Admin: Sponsor Attachments'
  /v2/admin/goodies/auto-award-config/list:
    get:
      operationId: AdminGoodieConfigController.list
      parameters:
        - &ref_477
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: eventId
          required: true
          in: query
          schema:
            type: string
        - name: challengeId
          required: true
          in: query
          schema:
            type: string
        - name: brandId
          required: true
          in: query
          schema:
            type: string
        - name: trigger
          required: true
          in: query
          schema:
            type: string
        - name: configured
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: include
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List sponsor attachments with auto-award trigger config (admin
        master-detail).
      tags: &ref_478
        - Admin - Goodies
  /v2/admin/goodies/auto-award-config:
    get:
      operationId: AdminGoodieConfigController.read
      parameters:
        - *ref_477
        - name: sponsorAttachmentId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Read goodie auto-award trigger config for one sponsor attachment.
      tags: *ref_478
  /v2/admin/goodies/auto-award-config/{sponsorAttachmentId}:
    patch:
      operationId: AdminGoodieConfigController.update
      parameters:
        - *ref_477
        - name: sponsorAttachmentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Update goodie auto-award trigger config for one sponsor attachment.
      tags: *ref_478
  /v2/organizer/saas/plans:
    get:
      operationId: OrganizerSaasController.listPlans
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_479
        - 'Organizer: SaaS Tier'
  /v2/organizer/saas/subscription:
    get:
      operationId: OrganizerSaasController.mySubscription
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_479
  /v2/organizer/saas/subscribe:
    post:
      operationId: OrganizerSaasController.subscribe
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_479
  /v2/organizer/saas/cancel:
    post:
      operationId: OrganizerSaasController.cancel
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_479
  /v2/admin/saas/plans:
    get:
      operationId: AdminSaasPlansController.list
      parameters:
        - name: includeInactive
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_480
        - 'Admin: Organizer SaaS Plans'
  /v2/admin/saas/plans/{planKey}:
    put:
      operationId: AdminSaasPlansController.upsert
      parameters:
        - name: planKey
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_480
  /v2/admin/saas/subscriptions:
    get:
      operationId: AdminSaasSubscriptionsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: planId
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Admin: Organizer SaaS Subscriptions'
  /v2/organizer/brands:
    get:
      operationId: OrganizerSponsorshipMarketplaceController.listBrands
      parameters:
        - name: search
          required: true
          in: query
          schema:
            type: string
        - name: industry
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: offset
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Browse the brand directory. Returns id, name, logo, description,
        industry, categories and more so the organizer can select a brand to
        approach.
      tags: &ref_481
        - 'Organizer: Sponsorship marketplace'
  /v2/organizer/brands/{id}:
    get:
      operationId: OrganizerSponsorshipMarketplaceController.getBrand
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a single brand profile (to review before sending a proposal).
      tags: *ref_481
  /v2/organizer/sponsorship-opportunities:
    get:
      operationId: OrganizerSponsorshipMarketplaceController.listMine
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List my sponsorship opportunities.
      tags: *ref_481
    post:
      operationId: OrganizerSponsorshipMarketplaceController.create
      parameters: []
      responses:
        '201':
          description: ''
      summary: >-
        Create a sponsorship opportunity (DRAFT). priceMin and priceMax are
        required. Send as multipart/form-data and attach a media file (PDF or
        image ≤10 MB) under field "file" to describe what brands get instead of
        a mediaUrl — description is optional when a file is attached. Plain JSON
        body (no file) also still works. Optional openAt sets a scheduled
        open/start time, distinct from deadline (close time).
      tags: *ref_481
  /v2/organizer/sponsorship-opportunities/{id}/media:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.uploadMedia
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Upload a media file (PDF or image ≤10 MB) describing what brands get.
        Replaces the text description. Send as multipart/form-data with field
        name "file".
      tags: *ref_481
  /v2/organizer/sponsorship-opportunities/{id}:
    get:
      operationId: OrganizerSponsorshipMarketplaceController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get one of my opportunities by id.
      tags: *ref_481
    patch:
      operationId: OrganizerSponsorshipMarketplaceController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Edit DRAFT or OPEN opportunity fields.
      tags: *ref_481
    delete:
      operationId: OrganizerSponsorshipMarketplaceController.deleteOpportunity
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Delete a DRAFT opportunity. Returns 400 if the opportunity is OPEN,
        CLOSED, or FULFILLED — transition or cancel it first.
      tags: *ref_481
  /v2/organizer/sponsorship-opportunities/{id}/transition:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.transition
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Transition opportunity state (DRAFT→OPEN, OPEN→CLOSED, OPEN→FULFILLED).
      tags: *ref_481
  /v2/organizer/sponsorship-opportunities/{id}/cancel:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.cancelOpportunity
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Cancel a DRAFT or OPEN opportunity — sets status to CLOSED. Returns 400
        if already CLOSED or FULFILLED.
      tags: *ref_481
  /v2/organizer/sponsorship-opportunities/{id}/proposals:
    get:
      operationId: OrganizerSponsorshipMarketplaceController.listProposals
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List proposals for one of my opportunities.
      tags: *ref_481
  /v2/organizer/sponsorship-proposals/{id}:
    get:
      operationId: OrganizerSponsorshipMarketplaceController.getProposal
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get a single proposal detail (any lane).
      tags: *ref_481
  /v2/organizer/sponsorship-proposals:
    get:
      operationId: OrganizerSponsorshipMarketplaceController.listAllProposals
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Unified inbox — all proposals across both lanes (opportunity + package)
        plus outbound proposals the organizer created directly.
      tags: *ref_481
  /v2/organizer/sponsorship-proposals/{id}/accept:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.acceptProposal
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Accept a proposal. Auto-declines every other PENDING proposal on the
        same opportunity and flips it to FULFILLED.
      tags: *ref_481
  /v2/organizer/sponsorship-proposals/{id}/decline:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.declineProposal
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Decline a proposal.
      tags: *ref_481
  /v2/organizer/sponsorship-proposals/{id}/counter:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.counterProposal
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Counter a brand proposal with a new offer.
      tags: *ref_481
  /v2/organizer/brands/{brandId}/sponsorship-proposals:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.submitOutbound
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Organizer sends outbound proposal directly to a brand.
      tags: *ref_481
  /v2/organizer/sponsorship-proposals/{id}/withdraw:
    post:
      operationId: OrganizerSponsorshipMarketplaceController.withdrawProposal
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Withdraw an outbound proposal the organizer sent (only works for
        ORGANIZER-initiated proposals in PENDING or COUNTERED state).
      tags: *ref_481
  /v2/sponsor/sponsorship-opportunities:
    get:
      operationId: SponsorSponsorshipMarketplaceController.discover
      parameters:
        - name: kind
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
        - name: cursor
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Discover OPEN opportunities across organizers.
      tags: &ref_482
        - 'Sponsor: Sponsorship marketplace'
  /v2/sponsor/sponsorship-opportunities/{id}:
    get:
      operationId: SponsorSponsorshipMarketplaceController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Read one opportunity (OPEN or FULFILLED).
      tags: *ref_482
  /v2/sponsor/brands/{brandId}/sponsorship-proposals/direct:
    post:
      operationId: SponsorSponsorshipMarketplaceController.submitDirect
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitDirectProposalDto'
      responses:
        '201':
          description: ''
      summary: >-
        Submit a proposal directly against an event or challenge, with no
        opportunity or package involved. The owner (organizer or club) approves
        it.
      tags: *ref_482
  /v2/sponsor/brands/{brandId}/sponsorship-proposals:
    post:
      operationId: SponsorSponsorshipMarketplaceController.submit
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Submit a proposal on behalf of the brand. Supply EITHER opportunityId OR
        packageId (Part E Wave 1) — exactly one.
      tags: *ref_482
    get:
      operationId: SponsorSponsorshipMarketplaceController.listMine
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List proposals authored by this brand.
      tags: *ref_482
  /v2/sponsor/brands/{brandId}/sponsorship-proposals/{id}/withdraw:
    post:
      operationId: SponsorSponsorshipMarketplaceController.withdraw
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Withdraw a pending proposal.
      tags: *ref_482
  /v2/sponsor/brands/{brandId}/sponsorship-proposals/inbound:
    get:
      operationId: SponsorSponsorshipMarketplaceController.listInbound
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List inbound proposals organizers sent to this brand.
      tags: *ref_482
  /v2/sponsor/brands/{brandId}/sponsorship-proposals/{id}/accept:
    post:
      operationId: SponsorSponsorshipMarketplaceController.acceptInbound
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Brand accepts an organizer offer or organizer counter.
      tags: *ref_482
  /v2/sponsor/brands/{brandId}/sponsorship-proposals/{id}/counter:
    post:
      operationId: SponsorSponsorshipMarketplaceController.counterInbound
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Brand counters an organizer offer.
      tags: *ref_482
  /v2/sponsor/sponsorship-packages:
    get:
      operationId: BrandSponsorshipPackagesController.list
      parameters:
        - name: eventId
          required: false
          in: query
          schema:
            type: string
        - name: placementType
          required: false
          in: query
          schema:
            enum:
              - LOGO_EVENT_PAGE
              - LOGO_BIBS
              - LOGO_TSHIRTS
              - LOGO_CERTIFICATES
              - LOGO_RACE_CARDS
              - ON_STAGE_MENTION
              - EMAIL_MENTION
              - SOCIAL_MENTION
              - PRIZE_CONTRIBUTION
              - BOOTH
              - OTHER
            type: string
        - name: minPrice
          required: false
          in: query
          schema:
            type: number
        - name: maxPrice
          required: false
          in: query
          schema:
            type: number
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_483
        - bearer: []
      summary: >-
        Discover ACTIVE sponsorship packages on PUBLIC + PUBLISHED events.
        Closed-allowlist projection — no organizer-private fields.
      tags: &ref_484
        - 'Sponsor: Sponsorship packages'
  /v2/sponsor/sponsorship-packages/{packageId}:
    get:
      operationId: BrandSponsorshipPackagesController.getOne
      parameters:
        - name: packageId
          required: true
          in: path
          description: Sponsorship package id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_483
      summary: >-
        Get a single brand-visible sponsorship package by id. Same-shape 404 for
        invisible packages (no existence leak).
      tags: *ref_484
  /v2/sponsor/brands/{brandId}/audience/segments:
    get:
      operationId: BrandAudienceController.preBuilt
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_485
        - bearer: []
      summary: >-
        List 7 pre-built audience segments + their live size estimates for this
        brand. Aggregate-only (no athlete rows).
      tags: &ref_486
        - 'Sponsor: Audience targeting'
  /v2/sponsor/brands/{brandId}/audience/discovery:
    get:
      operationId: BrandAudienceController.discovery
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_485
      summary: >-
        Onboarding step 4 — platform audience discovery: real reachable-athlete
        totals, top sports, indicative segment sizes, and a comparable-brand
        benchmark. Aggregate-only, k-anonymity suppressed.
      tags: *ref_486
  /v2/sponsor/brands/{brandId}/audience/estimate:
    post:
      operationId: BrandAudienceController.estimate
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_485
      summary: >-
        Estimate the size of a custom criteria-driven segment for this brand.
        Suppressed when below k-anonymity threshold.
      tags: *ref_486
  /v2/sponsor/brands/{brandId}/audience/saved-segments:
    get:
      operationId: BrandAudienceController.listSaved
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PENDING_APPROVAL
              - APPROVED
              - REJECTED
              - ARCHIVED
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_485
      summary: >-
        List saved segments for this brand (with live re-estimated sizes).
        Optional ?status= and ?search= filters.
      tags: *ref_486
    post:
      operationId: BrandAudienceController.saveSegment
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_485
      summary: Save a named cohort/segment as DRAFT for reuse + future estimates.
      tags: *ref_486
  /v2/sponsor/brands/{brandId}/audience/saved-segments/{segmentId}:
    get:
      operationId: BrandAudienceController.getSaved
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: segmentId
          required: true
          in: path
          description: Segment id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_485
      summary: Owner-only saved-segment detail (with live re-estimate).
      tags: *ref_486
    patch:
      operationId: BrandAudienceController.updateSegment
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: segmentId
          required: true
          in: path
          description: Segment id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_485
      summary: >-
        Edit a cohort — name, description and/or criteria. All fields optional;
        omitted fields are left unchanged. Re-runs the size estimate.
        Owner-only; ARCHIVED cohorts return 400 COHORT_NOT_EDITABLE.
      tags: *ref_486
    delete:
      operationId: BrandAudienceController.deleteSegment
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: segmentId
          required: true
          in: path
          description: Segment id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_485
      summary: >-
        Soft-delete a saved segment (status → ARCHIVED, deletedBy/deletedAt
        stamped). Refused with 400 COHORT_IN_USE + campaignCount while any
        PENDING_APPROVAL / SCHEDULED / LIVE / PAUSED campaign still targets it —
        deleting one would silently stop delivering those campaigns. Cross-brand
        returns same-shape 404.
      tags: *ref_486
  /v2/sponsor/brands/{brandId}/audience/saved-segments/{segmentId}/activate:
    post:
      operationId: BrandAudienceController.activate
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: segmentId
          required: true
          in: path
          description: Segment id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_485
      summary: >-
        §47 Wave 1 — activate a DRAFT or REJECTED cohort. Auto-approved (no
        admin review step); the cohort is immediately usable in a campaign.
        Owner-only.
      tags: *ref_486
  /v2/sponsor/brands/{brandId}/athlete-discovery:
    get:
      operationId: AthleteDiscoveryController.discover
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: q
          required: false
          in: query
          description: Name or username
          schema:
            type: string
        - name: city
          required: false
          in: query
          schema:
            type: string
        - name: sportId
          required: false
          in: query
          description: Sport uuid
          schema:
            type: string
        - name: sort
          required: false
          in: query
          description: >-
            top (default, composite ambassadorScore) · events · challenges ·
            clubs · followers · posts · recent.
          schema:
            enum:
              - top
              - events
              - challenges
              - clubs
              - followers
              - posts
              - recent
            type: string
        - name: page
          required: false
          in: query
          schema:
            example: 1
            type: string
        - name: limit
          required: false
          in: query
          schema:
            example: 20
            type: string
      responses:
        '200':
          description: ''
      security: &ref_487
        - bearer: []
      summary: >-
        Discover athletes who have opted in to brand collaborations, ranked by
        activity. Returns identified athletes — opted-in only, never contact
        details.
      tags: &ref_488
        - 'Sponsor: Athlete discovery'
  /v2/sponsor/brands/{brandId}/athlete-discovery/top:
    get:
      operationId: AthleteDiscoveryController.top
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: q
          required: false
          in: query
          description: Name or username
          schema:
            type: string
        - name: city
          required: false
          in: query
          schema:
            type: string
        - name: sportId
          required: false
          in: query
          description: Sport uuid
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Default 20, max 50.
          schema:
            example: 20
            type: string
      responses:
        '200':
          description: ''
      security: *ref_487
      summary: >-
        Top ambassador candidates for this brand — opted-in athletes ranked by a
        composite of events, followers, challenge active-days, posts and logged
        activities.
      tags: *ref_488
  /v2/sponsor/brands/{brandId}/goodie-placements:
    get:
      operationId: GoodiePlacementsController.list
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand id
          schema:
            type: string
        - name: state
          required: false
          in: query
          description: Defaults to all.
          schema:
            enum:
              - upcoming
              - live
              - all
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Events and challenges this brand sponsors, split by whether its goodie
        is on the leaderboard yet. live = at least one ACCEPTED contribution;
        upcoming = sponsored, not finished, no accepted goodie yet.
      tags:
        - 'Sponsor: Goodie placements'
  /v2/admin/prize-contributions:
    get:
      operationId: AdminPrizeContributionsController.list
      parameters:
        - name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: brandId
          required: false
          in: query
          description: Sponsor brand id (uuid). A malformed id is a 400, not a 500.
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - proposed
              - accepted
              - rejected
              - withdrawn
            type: string
        - name: targetType
          required: false
          in: query
          schema:
            enum:
              - EVENT
              - CHALLENGE
            type: string
        - name: limit
          required: false
          in: query
          description: Defaults to 100, capped at 200.
          schema:
            type: string
        - name: offset
          required: false
          in: query
          description: Defaults to 0.
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        List sponsor goodie prize contributions across every brand and both
        lanes (event + challenge), newest first.
      tags:
        - Admin - Goodies
  /v2/sponsor/brands/{brandId}/discover-targets:
    get:
      operationId: SponsorshipTargetsController.discoverTargets
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: type
          required: false
          in: query
          description: >-
            ALL (default) · EVENT · CHALLENGE. An unrecognised value falls back
            to ALL.
          schema:
            enum:
              - ALL
              - EVENT
              - CHALLENGE
            type: string
        - name: q
          required: false
          in: query
          description: Case-insensitive title search.
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            example: 1
            type: string
        - name: limit
          required: false
          in: query
          description: Capped at 50.
          schema:
            example: 20
            type: string
      responses:
        '200':
          description: ''
      security: &ref_489
        - bearer: []
      summary: >-
        Discover every upcoming or live event and challenge this brand could
        approach — whether or not its owner published a sponsorship package.
        Returns the owner to ask, whether a prize ladder already exists, and
        this brand’s current standing with each target.
      tags: &ref_490
        - 'Sponsor: Sponsorship discovery'
  /v2/sponsor/brands/{brandId}/discover-targets/{type}/{id}:
    get:
      operationId: SponsorshipTargetsController.discoverTarget
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: type
          required: true
          in: path
          description: Which table the id belongs to. ALL is not accepted here.
          schema:
            enum:
              - EVENT
              - CHALLENGE
            type: string
        - name: id
          required: true
          in: path
          description: Event or challenge id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_489
      summary: >-
        One discoverable event or challenge, with the owner to approach, whether
        a prize ladder already exists, and this brand’s current standing with
        it. Subject to the same approachability gates as the list — an
        unapproachable target answers 404, never 403.
      tags: *ref_490
  /v2/sponsor/brands/{brandId}/ambassador-offers:
    get:
      operationId: BrandAmbassadorOffersController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_491
        - bearer: []
      summary: List this brand’s ambassador offers.
      tags: &ref_492
        - 'Sponsor: Ambassador offers'
    post:
      operationId: BrandAmbassadorOffersController.send
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Send an ambassador offer to one or more athletes.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}:
    get:
      operationId: BrandAmbassadorOffersController.getOne
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_491
      summary: Get one ambassador offer for this brand.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/pay:
    post:
      operationId: BrandAmbassadorOffersController.pay
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Counter the athlete’s counter-offer.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/payments/{paymentId}/verify:
    post:
      operationId: BrandAmbassadorOffersController.verifyPayment
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
        - name: paymentId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Verify an ambassador payment with Cashfree and activate escrow.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/complete:
    post:
      operationId: BrandAmbassadorOffersController.complete
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Mark all approved work complete and release payout.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/release-early:
    post:
      operationId: BrandAmbassadorOffersController.releaseEarly
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Release held payout without checking deliverable completion.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/timeline:
    get:
      operationId: BrandAmbassadorOffersController.timeline
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_491
      summary: This deal’s history, oldest first.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/counter:
    post:
      operationId: BrandAmbassadorOffersController.counter
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/accept:
    post:
      operationId: BrandAmbassadorOffersController.accept
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Accept the athlete’s counter-offer.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/shipment:
    post:
      operationId: BrandAmbassadorOffersController.ship
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Mark an accepted product deal as shipped.
      tags: *ref_492
    patch:
      operationId: BrandAmbassadorOffersController.editShipment
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_491
      summary: Correct the tracking details on a shipped deal.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/shipment/cancel:
    post:
      operationId: BrandAmbassadorOffersController.cancelShipment
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: >-
        Cancel an undelivered Shiprocket shipment and reopen the deal for
        dispatch.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/shipment/reopen:
    post:
      operationId: BrandAmbassadorOffersController.reopenShipment
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: >-
        Reopen an RTO/returned/lost/damaged shipment so a replacement can be
        dispatched.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/dispute:
    post:
      operationId: BrandAmbassadorOffersController.dispute
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Raise a dispute on a held payout. Stops release until Repeak decides.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/dispute/withdraw:
    post:
      operationId: BrandAmbassadorOffersController.withdrawDispute
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Withdraw a dispute you raised.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/withdraw:
    post:
      operationId: BrandAmbassadorOffersController.withdraw
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Withdraw an offer.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/termination-request:
    post:
      operationId: BrandAmbassadorOffersController.requestTermination
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: Request mutual termination of an accepted ambassador relationship.
      tags: *ref_492
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/ship-via-shiprocket:
    post:
      operationId: BrandAmbassadorOffersController.shipViaShiprocket
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_491
      summary: >-
        Create a Shiprocket order for this deal and stamp tracking. 400 when
        Shiprocket is not configured.
      tags: *ref_492
  /v2/user/me/ambassador-offers:
    get:
      operationId: AthleteAmbassadorOffersController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_493
        - bearer: []
      summary: Ambassador offers sent to me.
      tags: &ref_494
        - 'User: Ambassador offers'
  /v2/user/me/ambassador-offers/{offerId}/accept:
    post:
      operationId: AthleteAmbassadorOffersController.accept
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_493
      summary: Accept an offer — joins the brand’s roster.
      tags: *ref_494
  /v2/user/me/ambassador-offers/{offerId}/accept-agreement:
    post:
      operationId: AthleteAmbassadorOffersController.acceptAgreement
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_493
      summary: Accept the frozen ambassador agreement.
      tags: *ref_494
  /v2/user/me/ambassador-offers/{offerId}/decline:
    post:
      operationId: AthleteAmbassadorOffersController.decline
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_493
      summary: Decline an offer.
      tags: *ref_494
  /v2/user/me/ambassador-offers/{offerId}/shipping-address:
    post:
      operationId: AthleteAmbassadorOffersController.saveAddress
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_493
      summary: >-
        Save where my products should ship. Athlete-written only — the brand
        never types this.
      tags: *ref_494
  /v2/user/me/ambassador-offers/{offerId}/confirm-delivery:
    post:
      operationId: AthleteAmbassadorOffersController.confirmDelivery
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_493
      summary: Confirm I received the products.
      tags: *ref_494
  /v2/user/me/ambassador-offers/{offerId}/timeline:
    get:
      operationId: AthleteAmbassadorOffersController.timeline
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_493
      summary: This deal’s history, oldest first.
      tags: *ref_494
  /v2/user/me/ambassador-offers/{offerId}/counter:
    post:
      operationId: AthleteAmbassadorOffersController.counter
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_493
      summary: Counter with a different amount.
      tags: *ref_494
  /v2/user/me/ambassador-offers/{offerId}/termination-response:
    post:
      operationId: AthleteAmbassadorOffersController.respondToTermination
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_493
      summary: Accept or decline a brand termination request.
      tags: *ref_494
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/deliverables:
    get:
      operationId: BrandAmbassadorDeliverablesController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_495
        - bearer: []
      summary: Everything the athlete has submitted on this deal.
      tags: &ref_496
        - 'Brand: Ambassador deliverables'
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/deliverables/{submissionId}/review:
    post:
      operationId: BrandAmbassadorDeliverablesController.review
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
        - name: submissionId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_495
      summary: >-
        Approve or reject a submission. Rejection requires a reason; approving
        the last one starts the payout hold.
      tags: *ref_496
  /v2/user/me/ambassador-offers/{offerId}/deliverables:
    get:
      operationId: AthleteAmbassadorDeliverablesController.list
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_497
        - bearer: []
      summary: What I have submitted on this deal, oldest first.
      tags: &ref_498
        - 'User: Ambassador deliverables'
    post:
      operationId: AthleteAmbassadorDeliverablesController.submit
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_497
      summary: >-
        Submit proof for one deliverable. Replaces a rejected attempt; refused
        once approved.
      tags: *ref_498
  /v2/user/me/ambassador-offers/{offerId}/deliverable-image:
    post:
      operationId: AthleteAmbassadorDeliverablesController.uploadProofImage
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_497
      summary: Upload a screenshot to attach as proof.
      tags: *ref_498
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/messages:
    get:
      operationId: BrandAmbassadorMessagesController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_499
        - bearer: []
      summary: The conversation on this deal, oldest first.
      tags: &ref_500
        - 'Brand: Ambassador messages'
    post:
      operationId: BrandAmbassadorMessagesController.post
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_499
      summary: Send a message to the athlete.
      tags: *ref_500
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/message-attachment:
    post:
      operationId: BrandAmbassadorMessagesController.uploadAttachment
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_499
      tags: *ref_500
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/messages/{messageId}:
    delete:
      operationId: BrandAmbassadorMessagesController.deleteMessage
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_499
      tags: *ref_500
  /v2/sponsor/brands/{brandId}/ambassador-offers/{offerId}/messages/read:
    post:
      operationId: BrandAmbassadorMessagesController.markRead
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_499
      summary: Mark everything from the athlete as read.
      tags: *ref_500
  /v2/user/me/ambassador-offers/{offerId}/messages:
    get:
      operationId: AthleteAmbassadorMessagesController.list
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_501
        - bearer: []
      summary: The conversation on this deal, oldest first.
      tags: &ref_502
        - 'User: Ambassador messages'
    post:
      operationId: AthleteAmbassadorMessagesController.post
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_501
      summary: Send a message to the brand.
      tags: *ref_502
  /v2/user/me/ambassador-offers/{offerId}/message-attachment:
    post:
      operationId: AthleteAmbassadorMessagesController.uploadAttachment
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_501
      tags: *ref_502
  /v2/user/me/ambassador-offers/{offerId}/messages/{messageId}:
    delete:
      operationId: AthleteAmbassadorMessagesController.deleteMessage
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
        - name: messageId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_501
      tags: *ref_502
  /v2/user/me/ambassador-offers/{offerId}/messages/read:
    post:
      operationId: AthleteAmbassadorMessagesController.markRead
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_501
      summary: Mark everything from the brand as read.
      tags: *ref_502
  /v2/admin/ambassador/offers/{offerId}/messages:
    get:
      operationId: AdminAmbassadorMessagesController.list
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_503
        - bearer: []
      summary: Read a deal’s conversation.
      tags: &ref_504
        - 'Admin: Ambassador messages'
    post:
      operationId: AdminAmbassadorMessagesController.post
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_503
      summary: Post into a deal’s conversation as Repeak. Both sides are told.
      tags: *ref_504
  /v2/admin/ambassador/commission-settings:
    get:
      operationId: AdminAmbassadorMoneyController.settings
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_505
        - bearer: []
      summary: The commission rate and hold window in force.
      tags: &ref_506
        - 'Admin: Ambassador money'
    put:
      operationId: AdminAmbassadorMoneyController.setSettings
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_505
      summary: >-
        Set the commission rate. Applies to deals accepted from now on — never
        to ones already agreed.
      tags: *ref_506
  /v2/admin/ambassador/payouts:
    get:
      operationId: AdminAmbassadorMoneyController.payouts
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_505
      summary: Deals ready to pay out.
      tags: *ref_506
  /v2/admin/ambassador/shipments:
    get:
      operationId: AdminAmbassadorMoneyController.shipments
      parameters:
        - name: stage
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_505
      summary: Product-deal delivery queue and carrier exceptions.
      tags: *ref_506
  /v2/admin/ambassador/payouts/{offerId}/settle:
    post:
      operationId: AdminAmbassadorMoneyController.settle
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_505
      summary: >-
        Record that a matured deal was actually paid. Requires a verified payout
        account.
      tags: *ref_506
  /v2/admin/ambassador/payouts/{offerId}/instructions:
    get:
      operationId: AdminAmbassadorMoneyController.instructions
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_505
      summary: Payout instructions for one deal — masked account + net of TDS.
      tags: *ref_506
  /v2/admin/ambassador/payouts/{offerId}/mark-brand-paid:
    post:
      operationId: AdminAmbassadorMoneyController.markBrandPaid
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_505
      summary: Record that the brand’s money was received.
      tags: *ref_506
  /v2/admin/ambassador/payouts/release-matured:
    post:
      operationId: AdminAmbassadorMoneyController.releaseMatured
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_505
      summary: Release every hold whose window has matured.
      tags: *ref_506
  /v2/admin/ambassador/payouts/{offerId}/release:
    post:
      operationId: AdminAmbassadorMoneyController.releaseOne
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_505
      summary: Release one held deal early. Refused while a dispute is open.
      tags: *ref_506
  /v2/admin/ambassador/payouts/{offerId}/hold:
    post:
      operationId: AdminAmbassadorMoneyController.holdOne
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_505
      summary: >-
        Put a payout back on hold, with a reason the athlete can read. Omit
        `until` to hold indefinitely.
      tags: *ref_506
  /v2/admin/ambassador/disputes:
    get:
      operationId: AdminAmbassadorMoneyController.disputes
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_505
      summary: Deals with an open dispute, oldest first.
      tags: *ref_506
  /v2/admin/ambassador/disputes/{offerId}/resolve:
    post:
      operationId: AdminAmbassadorMoneyController.resolveDispute
      parameters:
        - name: offerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_505
      summary: >-
        Decide a dispute. RELEASED/WITHDRAWN let the payout proceed; UPHELD
        leaves it held for a manual refund.
      tags: *ref_506
  /v2/admin/sponsor-cohorts:
    get:
      operationId: AdminSponsorCohortsController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PENDING_APPROVAL
              - APPROVED
              - REJECTED
              - ARCHIVED
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_507
        - bearer: []
      summary: >-
        List sponsor cohorts in the review queue. Defaults to PENDING_APPROVAL;
        supports ?status= and standard ?page=&limit= pagination.
      tags: &ref_508
        - 'Admin: Sponsor cohorts'
  /v2/admin/sponsor-cohorts/{cohortId}/approve:
    post:
      operationId: AdminSponsorCohortsController.approve
      parameters:
        - name: cohortId
          required: true
          in: path
          description: Cohort id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_507
      summary: Approve a PENDING_APPROVAL sponsor cohort.
      tags: *ref_508
  /v2/admin/sponsor-cohorts/{cohortId}/reject:
    post:
      operationId: AdminSponsorCohortsController.reject
      parameters:
        - name: cohortId
          required: true
          in: path
          description: Cohort id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_507
      summary: >-
        Reject a PENDING_APPROVAL sponsor cohort. Reason is required (10-500
        chars) and is returned verbatim to the brand owner.
      tags: *ref_508
  /v2/sponsor/brands/{brandId}/campaigns:
    get:
      operationId: SponsorCampaignsController.list
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PENDING_APPROVAL
              - APPROVED
              - SCHEDULED
              - LIVE
              - PAUSED
              - REJECTED
              - COMPLETED
              - ARCHIVED
            type: string
        - name: objective
          required: false
          in: query
          schema:
            enum:
              - AWARENESS
              - LEAD_GENERATION
              - EVENT_REGISTRATION
              - APP_INSTALL
              - OFFER_REDEMPTION
              - COMMUNITY_GROWTH
            type: string
        - name: channel
          required: false
          in: query
          schema:
            enum:
              - IN_APP
              - PUSH
              - EMAIL
              - WHATSAPP
              - EVENT_PLACEMENT
              - PUBLIC_WEB
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_509
        - bearer: []
      summary: >-
        List campaigns for this brand. Optional ?status=, ?objective=,
        ?channel=, ?search= filters.
      tags: &ref_510
        - 'Sponsor: Campaigns'
    post:
      operationId: SponsorCampaignsController.create
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_509
      summary: >-
        Create a new campaign as DRAFT. Cohort must be APPROVED + same brand +
        non-suppressed.
      tags: *ref_510
  /v2/sponsor/brands/{brandId}/campaigns/{campaignId}:
    get:
      operationId: SponsorCampaignsController.detail
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_509
      summary: Owner-only campaign detail.
      tags: *ref_510
    patch:
      operationId: SponsorCampaignsController.update
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_509
      summary: >-
        Edit a DRAFT or REJECTED campaign. Other statuses return 400
        CAMPAIGN_NOT_EDITABLE.
      tags: *ref_510
    delete:
      operationId: SponsorCampaignsController.remove
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_509
      summary: >-
        Soft-delete a DRAFT, REJECTED, COMPLETED, PAUSED or ARCHIVED campaign.
        LIVE / SCHEDULED / PENDING_APPROVAL return 400 CAMPAIGN_NOT_DELETABLE; a
        campaign with in-flight sponsorship deals returns 400
        CAMPAIGN_HAS_ACTIVE_DEALS.
      tags: *ref_510
  /v2/sponsor/brands/{brandId}/campaigns/{campaignId}/submit:
    post:
      operationId: SponsorCampaignsController.submit
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_509
      summary: §48 Wave 2 — submit a DRAFT or REJECTED campaign for admin review.
      tags: *ref_510
  /v2/sponsor/brands/{brandId}/campaigns/{campaignId}/pause:
    post:
      operationId: SponsorCampaignsController.pause
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_509
      summary: Pause a LIVE or SCHEDULED campaign.
      tags: *ref_510
  /v2/sponsor/brands/{brandId}/campaigns/{campaignId}/resume:
    post:
      operationId: SponsorCampaignsController.resume
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_509
      summary: Resume a PAUSED campaign.
      tags: *ref_510
  /v2/sponsor/brands/{brandId}/campaigns/{campaignId}/archive:
    post:
      operationId: SponsorCampaignsController.archive
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_509
      summary: >-
        Archive a DRAFT, REJECTED, COMPLETED, or PAUSED campaign. LIVE /
        SCHEDULED / PENDING return 400.
      tags: *ref_510
  /v2/admin/sponsor-campaigns:
    get:
      operationId: AdminSponsorCampaignsController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PENDING_APPROVAL
              - APPROVED
              - SCHEDULED
              - LIVE
              - PAUSED
              - REJECTED
              - COMPLETED
              - ARCHIVED
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_511
        - bearer: []
      summary: >-
        List sponsor campaigns in the review queue. Defaults to
        PENDING_APPROVAL; supports ?status= and ?page=&limit=.
      tags: &ref_512
        - 'Admin: Sponsor campaigns'
  /v2/admin/sponsor-campaigns/{campaignId}/approve:
    post:
      operationId: AdminSponsorCampaignsController.approve
      parameters:
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_511
      summary: >-
        Approve a PENDING_APPROVAL campaign. Transitions to LIVE if startDate ≤
        now, otherwise SCHEDULED.
      tags: *ref_512
  /v2/admin/sponsor-campaigns/{campaignId}/reject:
    post:
      operationId: AdminSponsorCampaignsController.reject
      parameters:
        - name: campaignId
          required: true
          in: path
          description: Campaign id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_511
      summary: >-
        Reject a PENDING_APPROVAL campaign. Reason required (10-500 chars);
        returned verbatim to brand owner.
      tags: *ref_512
  /v2/users/me/campaigns:
    get:
      operationId: AthleteCampaignsController.feed
      parameters:
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_513
        - bearer: []
      summary: >-
        Campaigns currently targeting me. Returns creative + brand identity only
        — never cohort, budget or targeting data.
      tags: &ref_514
        - 'Athlete: Campaigns'
  /v2/users/me/campaigns/{campaignId}/view:
    post:
      operationId: AthleteCampaignsController.view
      parameters:
        - name: campaignId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_513
      summary: Record a view of a campaign I was served.
      tags: *ref_514
  /v2/users/me/campaigns/{campaignId}/click:
    post:
      operationId: AthleteCampaignsController.click
      parameters:
        - name: campaignId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_513
      summary: Record a tap on the campaign CTA, and get back the URL to open.
      tags: *ref_514
  /v2/sponsor/brands/{brandId}/rc-grants:
    post:
      operationId: SponsorRcGrantsController.request
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: &ref_515
        - bearer: []
      summary: >-
        Request RC coins. kind=PURCHASE (paying for coins) or
        SETTLEMENT_ADJUSTMENT (net off sponsorship earnings). One open request
        at a time.
      tags: &ref_516
        - 'Sponsor: RC Grants'
    get:
      operationId: SponsorRcGrantsController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_515
      summary: My brand's coin requests, newest first.
      tags: *ref_516
  /v2/sponsor/brands/{brandId}/rc-grants/{grantId}/cancel:
    post:
      operationId: SponsorRcGrantsController.cancel
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: grantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_515
      summary: Withdraw a request that is still awaiting review.
      tags: *ref_516
  /v2/admin/sponsor-rc-grants:
    get:
      operationId: AdminSponsorRcGrantsController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - REQUESTED
              - APPROVED
              - REJECTED
              - CANCELLED
            type: string
        - name: brandId
          required: false
          in: query
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_517
        - bearer: []
      summary: Queue. Defaults to every status; filter with ?status=.
      tags: &ref_518
        - 'Admin: Sponsor RC Grants'
  /v2/admin/sponsor-rc-grants/{grantId}/approve:
    post:
      operationId: AdminSponsorRcGrantsController.approve
      parameters:
        - name: grantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_517
      summary: >-
        Approve and credit the brand wallet. approvedRc may be less than
        requested, never more. Re-running is a no-op.
      tags: *ref_518
  /v2/admin/sponsor-rc-grants/{grantId}/reject:
    post:
      operationId: AdminSponsorRcGrantsController.reject
      parameters:
        - name: grantId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_517
      summary: Reject. Reason is mandatory, 10-500 chars.
      tags: *ref_518
  /v2/sponsor/brands/{brandId}/engagement-levers:
    get:
      operationId: EngagementLeversController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_519
        - bearer: []
      summary: List engagement levers for a brand.
      tags: &ref_520
        - 'Sponsor: Engagement Levers'
    post:
      operationId: EngagementLeversController.create
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_519
      summary: Create an engagement lever (DRAFT).
      tags: *ref_520
  /v2/sponsor/brands/{brandId}/engagement-levers/{id}:
    get:
      operationId: EngagementLeversController.getOne
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_519
      summary: Get an engagement lever.
      tags: *ref_520
    patch:
      operationId: EngagementLeversController.update
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_519
      summary: Update an engagement lever.
      tags: *ref_520
  /v2/sponsor/brands/{brandId}/engagement-levers/{id}/activate:
    post:
      operationId: EngagementLeversController.activate
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_519
      summary: Activate an engagement lever.
      tags: *ref_520
  /v2/sponsor/brands/{brandId}/engagement-levers/{id}/deactivate:
    post:
      operationId: EngagementLeversController.deactivate
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_519
      summary: Deactivate an engagement lever.
      tags: *ref_520
  /v2/sponsor/brands/{brandId}/sponsorship-deals:
    get:
      operationId: SponsorshipDealsController.list
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PROPOSED
              - UNDER_REVIEW
              - COUNTERED
              - ACCEPTED
              - REJECTED
              - CONTRACT_PENDING
              - CONTRACT_UPLOADED
              - ACTIVE
              - COMPLETED
              - CANCELLED
            type: string
        - name: eventId
          required: false
          in: query
          schema:
            type: string
        - name: packageType
          required: false
          in: query
          schema:
            enum:
              - TITLE_SPONSOR
              - POWERED_BY
              - ASSOCIATE_SPONSOR
              - BOOTH
              - DIGITAL_PLACEMENT
              - COUPON_PARTNER
              - CUSTOM
            type: string
        - name: search
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_521
        - bearer: []
      summary: >-
        List sponsorship deals for this brand. Optional ?status=, ?eventId=,
        ?packageType=, ?search= filters.
      tags: &ref_522
        - 'Sponsor: Sponsorship deals'
    post:
      operationId: SponsorshipDealsController.create
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_521
      summary: Create a new deal as DRAFT.
      tags: *ref_522
  /v2/sponsor/brands/{brandId}/sponsorship-deals/{dealId}:
    get:
      operationId: SponsorshipDealsController.detail
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_521
      summary: Owner-only deal detail.
      tags: *ref_522
    patch:
      operationId: SponsorshipDealsController.update
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_521
      summary: >-
        Edit a DRAFT, COUNTERED, or REJECTED deal. Other statuses return 400
        DEAL_NOT_EDITABLE.
      tags: *ref_522
    delete:
      operationId: SponsorshipDealsController.remove
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_521
      summary: >-
        Soft-delete a deal in a terminal status (DRAFT, REJECTED, CANCELLED,
        COMPLETED). A deal still held by the admin queue or carrying a live
        commitment returns 400 DEAL_NOT_DELETABLE; one with a payable contract
        still attached returns 400 DEAL_HAS_LIVE_CONTRACT.
      tags: *ref_522
  /v2/sponsor/brands/{brandId}/sponsorship-deals/{dealId}/submit:
    post:
      operationId: SponsorshipDealsController.submit
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_521
      summary: §49 Wave 3 — submit a DRAFT or REJECTED deal for admin review.
      tags: *ref_522
  /v2/sponsor/brands/{brandId}/sponsorship-deals/{dealId}/accept-counter:
    post:
      operationId: SponsorshipDealsController.acceptCounter
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_521
      summary: >-
        Brand accepts an admin counter-offer. Counter amount becomes the binding
        amount.
      tags: *ref_522
  /v2/sponsor/brands/{brandId}/sponsorship-deals/{dealId}/reject-counter:
    post:
      operationId: SponsorshipDealsController.rejectCounter
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_521
      summary: Brand rejects an admin counter-offer.
      tags: *ref_522
  /v2/sponsor/brands/{brandId}/sponsorship-deals/{dealId}/upload-contract:
    post:
      operationId: SponsorshipDealsController.uploadContract
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_521
      summary: >-
        Submit signed contract URL (https only). Transitions CONTRACT_PENDING →
        CONTRACT_UPLOADED. Direct multipart upload deferred — v1 accepts an
        off-band-signed URL.
      tags: *ref_522
  /v2/sponsor/brands/{brandId}/sponsorship-deals/{dealId}/cancel:
    post:
      operationId: SponsorshipDealsController.cancel
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_521
      summary: >-
        Cancel a deal in safe statuses (DRAFT, REJECTED, CONTRACT_PENDING,
        CONTRACT_UPLOADED).
      tags: *ref_522
  /v2/admin/sponsorship-deals:
    get:
      operationId: AdminSponsorshipDealsController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PROPOSED
              - UNDER_REVIEW
              - COUNTERED
              - ACCEPTED
              - REJECTED
              - CONTRACT_PENDING
              - CONTRACT_UPLOADED
              - ACTIVE
              - COMPLETED
              - CANCELLED
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_523
        - bearer: []
      summary: >-
        List sponsorship deals in the review queue. Defaults to PROPOSED;
        supports ?status= and ?page=&limit=.
      tags: &ref_524
        - 'Admin: Sponsorship deals'
  /v2/admin/sponsorship-deals/{dealId}/under-review:
    post:
      operationId: AdminSponsorshipDealsController.underReview
      parameters:
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_523
      summary: Mark a PROPOSED deal as UNDER_REVIEW (lighter touch than accept).
      tags: *ref_524
  /v2/admin/sponsorship-deals/{dealId}/accept:
    post:
      operationId: AdminSponsorshipDealsController.accept
      parameters:
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_523
      summary: Accept a PROPOSED or UNDER_REVIEW deal. Transitions to CONTRACT_PENDING.
      tags: *ref_524
  /v2/admin/sponsorship-deals/{dealId}/counter:
    post:
      operationId: AdminSponsorshipDealsController.counter
      parameters:
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_523
      summary: >-
        Counter-offer a PROPOSED or UNDER_REVIEW deal. amount > 0; notes 10-500
        chars (returned verbatim to brand).
      tags: *ref_524
  /v2/admin/sponsorship-deals/{dealId}/reject:
    post:
      operationId: AdminSponsorshipDealsController.reject
      parameters:
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_523
      summary: >-
        Reject a PROPOSED, UNDER_REVIEW, or COUNTERED deal. Reason required
        (10-500 chars), returned verbatim to brand.
      tags: *ref_524
  /v2/admin/sponsorship-deals/{dealId}/activate:
    post:
      operationId: AdminSponsorshipDealsController.activate
      parameters:
        - name: dealId
          required: true
          in: path
          description: Deal id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_523
      summary: Activate a CONTRACT_UPLOADED deal. Transitions to ACTIVE.
      tags: *ref_524
  /v2/sponsor/brands/{brandId}/reporting/summary:
    get:
      operationId: BrandReportingController.summary
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: from
          required: false
          in: query
          schema:
            type: string
        - name: to
          required: false
          in: query
          schema:
            type: string
        - name: campaignId
          required: false
          in: query
          schema:
            type: string
        - name: cohortId
          required: false
          in: query
          schema:
            type: string
        - name: dealId
          required: false
          in: query
          schema:
            type: string
        - name: channel
          required: false
          in: query
          schema:
            enum:
              - IN_APP
              - PUSH
              - EMAIL
              - WHATSAPP
              - EVENT_PLACEMENT
              - PUBLIC_WEB
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
        - name: windowDays
          required: false
          in: query
          description: >-
            Trailing window for engagement telemetry only
            (impressions/clicks/CTR). Entity counts stay right-now state.
            Default 30.
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_525
        - bearer: []
      summary: >-
        Brand reporting summary. Aggregates §47 cohorts + §48 campaigns + §49
        deals into a single safe DTO with honest sourceStatus per metric.
      tags: &ref_526
        - 'Sponsor: Reporting'
  /v2/sponsor/brands/{brandId}/reporting/breakdown:
    get:
      operationId: BrandReportingController.breakdown
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: groupBy
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: campaignId
          required: true
          in: query
          schema:
            type: string
        - name: cohortId
          required: true
          in: query
          schema:
            type: string
        - name: dealId
          required: true
          in: query
          schema:
            type: string
        - name: channel
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_525
      summary: >-
        Brand reporting breakdown. groupBy = campaign | cohort | deal | channel
        | status | date.
      tags: *ref_526
  /v2/sponsor/brands/{brandId}/reporting/export.csv:
    get:
      operationId: BrandReportingController.exportCsv
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
        - name: campaignId
          required: true
          in: query
          schema:
            type: string
        - name: cohortId
          required: true
          in: query
          schema:
            type: string
        - name: dealId
          required: true
          in: query
          schema:
            type: string
        - name: channel
          required: true
          in: query
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: windowDays
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_525
      summary: >-
        Brand reporting CSV export. Returns text/csv with the same metrics as
        /summary; no PII columns.
      tags: *ref_526
  /v2/sponsor/brands/{brandId}/audience/insights:
    get:
      operationId: BrandInsightsController.insights
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: window
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Brand audience insights — aggregate distributions over the brand engaged
        user set within a 30/60/90-day window.
      tags:
        - 'Sponsor: Audience insights'
  /v2/sponsor/brands/{brandId}/stories:
    get:
      operationId: SponsorBrandStoriesController.list
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PUBLISHED
              - ARCHIVED
            type: string
      responses:
        '200':
          description: ''
      security: &ref_527
        - bearer: []
      summary: List brand stories (any status by default).
      tags: &ref_528
        - 'Sponsor: Brand stories'
    post:
      operationId: SponsorBrandStoriesController.create
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_527
      summary: >-
        Create a brand story (DRAFT). OWNER + MANAGER. Multipart — optional
        `mediaFile` image (JPG/PNG/WebP, ≤5MB).
      tags: *ref_528
  /v2/sponsor/brands/{brandId}/stories/{storyId}:
    patch:
      operationId: SponsorBrandStoriesController.update
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: storyId
          required: true
          in: path
          description: Story id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_527
      summary: >-
        Update a brand story (non-archived only). Multipart — `mediaFile`
        replaces the image, `removeMedia=true` clears it.
      tags: *ref_528
    delete:
      operationId: SponsorBrandStoriesController.archive
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: storyId
          required: true
          in: path
          description: Story id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_527
      summary: Archive a story (terminal).
      tags: *ref_528
  /v2/sponsor/brands/{brandId}/stories/{storyId}/status:
    patch:
      operationId: SponsorBrandStoriesController.transitionStatus
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: storyId
          required: true
          in: path
          description: Story id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_527
      summary: Transition status (DRAFT ⇄ PUBLISHED → ARCHIVED).
      tags: *ref_528
  /v2/public/brands/{slug}:
    get:
      operationId: PublicSponsorBrandController.profile
      parameters:
        - name: slug
          required: true
          in: path
          description: Brand slug
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Public sponsor brand profile by slug. Closed-allowlist projection — no
        contact email / KYC / audit fields.
      tags: &ref_529
        - 'Public: Sponsor brand profile'
  /v2/public/brands/{slug}/stories:
    get:
      operationId: PublicSponsorBrandController.stories
      parameters:
        - name: slug
          required: true
          in: path
          description: Brand slug
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Public list of PUBLISHED brand stories by slug (most recent first).
      tags: *ref_529
  /v2/admin/brand-stories:
    get:
      operationId: AdminBrandStoriesController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - DRAFT
              - PUBLISHED
              - ARCHIVED
            type: string
        - name: brandId
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_530
        - bearer: []
      summary: List brand stories across every brand (moderation queue).
      tags: &ref_531
        - 'Admin: Brand stories'
  /v2/admin/brand-stories/{storyId}/takedown:
    post:
      operationId: AdminBrandStoriesController.takedown
      parameters:
        - name: storyId
          required: true
          in: path
          description: Story id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_530
      summary: >-
        Force a story out of public view (→ ARCHIVED), bypassing brand
        ownership. Requires an audited reason (≥10 chars).
      tags: *ref_531
  /v2/sponsor/brands/{brandId}/reward-pools:
    get:
      operationId: SponsorRewardPoolsController.list
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_532
        - bearer: []
      summary: >-
        List reward pool requirements + statuses for this brand. Funding state
        reflects external payment reconciliation done by admin (no self-serve
        checkout yet).
      tags: &ref_533
        - 'Sponsor: Reward pools'
    post:
      operationId: SponsorRewardPoolsController.declare
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_532
      summary: >-
        Declare a reward-pool requirement. Status starts at
        REQUIREMENT_DECLARED; admin transitions to MANUALLY_FUNDED after
        out-of-band payment.
      tags: *ref_533
  /v2/sponsor/brands/{brandId}/reward-pools/{poolId}/cancel:
    post:
      operationId: SponsorRewardPoolsController.cancel
      parameters:
        - name: brandId
          required: true
          in: path
          description: Brand id
          schema:
            type: string
        - name: poolId
          required: true
          in: path
          description: Reward pool id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_532
      summary: >-
        Cancel an UNFUNDED requirement. Once admin reviews / funds, cancellation
        is admin-only via support.
      tags: *ref_533
  /v2/sponsor/brands/{brandId}/crm-export:
    get:
      operationId: SponsorCrmExportController.export
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: kind
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Download brand CRM export as CSV (goodies or proposals). Defaults to
        goodies.
      tags:
        - 'Sponsor: CRM export'
  /v2/sponsor/brands/{brandId}/ambassadors:
    get:
      operationId: SponsorBrandAmbassadorsController.list
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_534
        - 'Sponsor: Brand Ambassadors'
    post:
      operationId: SponsorBrandAmbassadorsController.grant
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_534
  /v2/sponsor/brands/{brandId}/ambassadors/{ambassadorId}:
    delete:
      operationId: SponsorBrandAmbassadorsController.remove
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
        - name: ambassadorId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_534
  /v2/sponsor/brands/{brandId}/ambassadors/order:
    patch:
      operationId: SponsorBrandAmbassadorsController.reorder
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_534
  /v2/sponsor/brands/{brandId}/ambassadors/bulk:
    post:
      operationId: SponsorBrandAmbassadorsController.bulk
      parameters:
        - name: brandId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_534
  /v2/public/brands/{slug}/ambassadors:
    get:
      operationId: PublicBrandAmbassadorsController.listPublic
      parameters:
        - name: slug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags:
        - 'Public: Brand Ambassadors'
  /v2/sponsor/challenges/pricing/quote:
    post:
      operationId: BrandChallengePricingController.quote
      parameters: []
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: >-
        Quote the cost of sponsoring a brand challenge (reach × engagement ×
        tier × duration, clamped ₹50K–₹50L). Indicative, not a charge.
      tags:
        - 'Sponsor: Challenge pricing'
  /v2/me/activity-tracking-preferences:
    get:
      operationId: ActivityTrackingPreferencesController.get
      parameters:
        - &ref_535
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get my Activity Tracking preferences (PRD §30.1).
      tags: &ref_536
        - 'Me: Activity Tracking Preferences'
    patch:
      operationId: ActivityTrackingPreferencesController.update
      parameters:
        - *ref_535
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateActivityTrackingPreferencesDto'
      responses:
        '200':
          description: ''
      summary: >-
        Update Activity Tracking preferences. Partial — only fields present in
        the body are written.
      tags: *ref_536
  /v2/users/{userId}/activities/tracking-preferences:
    get:
      operationId: UserScopedActivityTrackingPreferencesController.get
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Get Activity Tracking preferences by userId (mobile alias for
        /v2/me/activity-tracking-preferences).
      tags: &ref_537
        - 'Me: Activity Tracking Preferences'
    patch:
      operationId: UserScopedActivityTrackingPreferencesController.update
      parameters:
        - name: userId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateActivityTrackingPreferencesDto'
      responses:
        '200':
          description: ''
      summary: >-
        Update Activity Tracking preferences by userId (mobile alias for PATCH
        /v2/me/activity-tracking-preferences).
      tags: *ref_537
  /v2/settings:
    post:
      description: >-
        Create platform settings including fees, taxes, and training plan
        pricing
      operationId: SettingsController.createSettings
      parameters:
        - &ref_538
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSettingDto'
      responses:
        '201':
          description: Settings created successfully
        '403':
          description: Forbidden - Admin role required
      summary: Create settings (Admin only)
      tags: &ref_539
        - Settings
    get:
      description: >-
        Get platform settings including fees, taxes, and training plan pricing
        (trainingPlanNormalPrice, trainingPlanAdvancedPrice,
        trainingPlanMinDaysBeforeEvent)
      operationId: SettingsController.getSettings
      parameters:
        - *ref_538
      responses:
        '200':
          description: Settings retrieved successfully
      summary: Get current settings
      tags: *ref_539
    patch:
      description: >-
        Update platform settings. Use this to update training plan pricing:
        trainingPlanNormalPrice (default ₹999 per PRD §22.9),
        trainingPlanAdvancedPrice (default ₹2,999 per PRD §22.9),
        trainingPlanMinDaysBeforeEvent (default 15 days). Sprint 1 Session 8
        fix: previous "₹9 / ₹15" Swagger defaults were USD-looking test units
        inconsistent with the PRD INR ranges (₹999–2,999 standard, ₹4,999–9,999
        coach-attached).
      operationId: SettingsController.updateSettings
      parameters:
        - *ref_538
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSettingDto'
      responses:
        '200':
          description: Settings updated successfully
        '403':
          description: Forbidden - Admin role required
      summary: Update settings (Admin only)
      tags: *ref_539
  /v2/settings/public:
    get:
      description: >-
        Get platform settings including fees, taxes, and training plan pricing
        (trainingPlanNormalPrice, trainingPlanAdvancedPrice,
        trainingPlanMinDaysBeforeEvent)
      operationId: SettingsController.getPlatformSettings
      parameters:
        - *ref_538
      responses:
        '200':
          description: Settings retrieved successfully
      summary: Get current settings
      tags: *ref_539
  /v2/settlements:
    get:
      operationId: SettlementsController.getAllSettlements
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
            type: string
        - name: type
          required: false
          in: query
          schema:
            enum:
              - event
              - challenge
              - photo
              - club
              - hybrid_race
              - sponsorship
              - training_program
              - brand_challenge
            type: string
        - name: driftStatus
          required: false
          in: query
          schema:
            enum:
              - none
              - flagged
              - accepted_baseline
              - accepted_manual
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          description: Max 50
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_540
        - bearer: []
      summary: >-
        Get all settlements (Admin only). Pass `page` to opt into paginated
        response `{ items, meta }`; absent `page` returns the legacy unpaginated
        array.
      tags: &ref_541
        - Settlements
  /v2/settlements/drift/count:
    get:
      operationId: SettlementsController.getDriftCount
      parameters: []
      responses:
        '200':
          description: >-
            { data: { total: number, byStatus: { flagged: number,
            accepted_baseline: number, accepted_manual: number } } }
      security: *ref_540
      summary: >-
        Drift state breakdown across the three reviewable statuses. Powers the
        baseline-sweep modal (reads byStatus.flagged) and the drift-queue header
        per-state summary.
      tags: *ref_541
  /v2/settlements/eligible:
    get:
      operationId: SettlementsController.getEligibleSettlements
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: Get settlements eligible for processing (Admin only)
      tags: *ref_541
  /v2/settlements/{id}:
    get:
      operationId: SettlementsController.getSettlementById
      parameters:
        - name: id
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: Get settlement by ID (Admin only)
      tags: *ref_541
    patch:
      operationId: SettlementsController.updateSettlement
      parameters:
        - name: id
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSettlementDto'
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: Update settlement (Admin only)
      tags: *ref_541
  /v2/settlements/{id}/detailed:
    get:
      operationId: SettlementsController.getSettlementDetailedById
      parameters:
        - name: id
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      responses:
        '200':
          description: Detailed settlement with all payment details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SettlementDetailResponseDto'
      security: *ref_540
      summary: Get detailed settlement with payment breakdown (Admin only)
      tags: *ref_541
  /v2/settlements/{id}/process:
    post:
      description: >-
        Admin can manually mark a settlement as completed after transferring
        funds. This works even for settlements that were on hold due to KYC
        issues.
      operationId: SettlementsController.processSettlement
      parameters:
        - name: id
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProcessSettlementDto'
      responses:
        '201':
          description: ''
      security: *ref_540
      summary: Process settlement - Mark as completed with transaction ID (Admin only)
      tags: *ref_541
  /v2/settlements/{id}/payout/initiate:
    post:
      description: >-
        Routes through `PayoutRoutingService` to attempt a provider-driven
        transfer (Stripe Connect / Razorpay Routes / future). Lifecycle:
        ELIGIBLE → PROCESSING → COMPLETED on provider success, ELIGIBLE on
        UNSUPPORTED/FAILED so the operator can retry the manual
        `processSettlement(transactionId)` paste-flow. Idempotent — a settlement
        with an existing transactionId rejects to prevent double-transfer.
      operationId: SettlementsController.initiateAutomatedPayout
      parameters:
        - name: id
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_540
      summary: >-
        Initiate automated payout transfer for an ELIGIBLE settlement (Admin
        only)
      tags: *ref_541
  /v2/settlements/{id}/hold:
    post:
      operationId: SettlementsController.holdSettlement
      parameters:
        - name: id
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HoldSettlementDto'
      responses:
        '201':
          description: ''
      security: *ref_540
      summary: Put settlement on hold (Admin only)
      tags: *ref_541
  /v2/settlements/{id}/refresh-kyc:
    post:
      description: >-
        Re-check the organizer KYC and bank details status. If now complete,
        settlement will move from on_hold to pending.
      operationId: SettlementsController.refreshSettlementKycStatus
      parameters:
        - name: id
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_540
      summary: Refresh settlement KYC status (Admin only)
      tags: *ref_541
  /v2/settlements/organizer/{organizerId}:
    get:
      operationId: SettlementsController.getOrganizerSettlements
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: Get settlements for an organizer
      tags: *ref_541
  /v2/settlements/organizer/{organizerId}/settlement/{settlementId}:
    get:
      description: >-
        Returns full settlement details including earnings breakdown,
        deductions, payment list per user, and KYC status.
      operationId: SettlementsController.getOrganizerSettlementDetailed
      parameters:
        - name: organizerId
          required: true
          in: path
          description: Organizer ID
          schema:
            type: string
        - name: settlementId
          required: true
          in: path
          description: Settlement ID
          schema:
            type: string
      responses:
        '200':
          description: Detailed settlement with all payment details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SettlementDetailResponseDto'
      security: *ref_540
      summary: Get detailed settlement for organizer
      tags: *ref_541
  /v2/settlements/rollup/by-stream:
    get:
      operationId: SettlementsController.rollupByStream
      parameters:
        - name: startDate
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2026-04-18'
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: >-
        Rollup settlement totals grouped by stream. Optional status + date range
        filters.
      tags: *ref_541
  /v2/settlements/rollup/by-organizer:
    get:
      operationId: SettlementsController.rollupByOrganizer
      parameters:
        - name: startDate
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2026-04-18'
            type: string
        - name: organizerIds
          required: false
          in: query
          description: >-
            Comma-separated list of organizer UUIDs. Omit to roll up across all
            organizers.
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: >-
        Rollup settlement totals grouped by organizer. Optional organizerIds
        filter (comma-separated).
      tags: *ref_541
  /v2/settlements/rollup/by-organizer-stream:
    get:
      operationId: SettlementsController.rollupByOrganizerStream
      parameters:
        - name: startDate
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2026-04-18'
            type: string
        - name: organizerId
          required: false
          in: query
          schema:
            format: uuid
            type: string
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: 'Rollup one organizer across all six streams. Required: organizerId.'
      tags: *ref_541
  /v2/settlements/export:
    get:
      operationId: SettlementsController.exportCsv
      parameters:
        - name: startDate
          required: false
          in: query
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          schema:
            example: '2026-04-18'
            type: string
        - name: organizerId
          required: false
          in: query
          schema:
            format: uuid
            type: string
        - name: streamKey
          required: false
          in: query
          schema:
            type: string
            enum:
              - REGISTRATION
              - HYBRID_RACE
              - CLUB
              - PHOTO
              - CHALLENGE
              - SPONSORSHIP
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
      responses:
        '200':
          description: ''
      security: *ref_540
      summary: >-
        Download filtered settlements as CSV. Hard 50k row cap; filter that
        selects more returns 400 with actual count.
      tags: *ref_541
  /v2/settlements/baseline-drift:
    post:
      operationId: SettlementsController.baselineDrift
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaselineDriftDto'
      responses:
        '201':
          description: ''
      security: *ref_540
      summary: >-
        One-shot baseline sweep: seal all FLAGGED settlements as
        ACCEPTED_BASELINE. Requires confirm=true and a matching expectedCount;
        mismatched count returns 409 with actualCount.
      tags: *ref_541
  /v2/settlements/{id}/accept-drift:
    post:
      operationId: SettlementsController.acceptDrift
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AcceptDriftDto'
      responses:
        '201':
          description: ''
      security: *ref_540
      summary: >-
        Accept a flagged drift on a single settlement. Transitions FLAGGED →
        ACCEPTED_MANUAL.
      tags: *ref_541
  /v2/organizer/settlements/events/{eventId}/summary:
    get:
      operationId: OrganizerEventSettlementController.getEventSettlementSummary
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Per-event settlement summary for the Money tab (Missing-API P2,
        BACKEND_API_SPEC.md §2.3).
      tags:
        - 'Organizer: Settlements'
  /v2/club-organizer-accounts:
    post:
      operationId: ClubOrganizerAccountsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateClubOrganizerAccountDto'
      responses:
        '201':
          description: ''
      summary: Create or complete one linked club + organizer account pair
      tags: &ref_542
        - Linked club and organizer accounts
  /v2/club-organizer-accounts/repair:
    post:
      operationId: ClubOrganizerAccountsController.repair
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RepairClubOrganizerAccountDto'
      responses:
        '201':
          description: ''
      summary: >-
        Idempotently create and link the missing side of a legacy Club +
        Organizer account pair
      tags: *ref_542
  /v2/admin/platform-feature-flags:
    get:
      operationId: AdminFeatureFlagsController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_543
        - 'Admin: Feature Flags'
    post:
      operationId: AdminFeatureFlagsController.upsert
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_543
  /v2/admin/platform-feature-flags/{key}/rollout:
    patch:
      operationId: AdminFeatureFlagsController.setRollout
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_543
  /v2/admin/platform-feature-flags/{key}:
    delete:
      operationId: AdminFeatureFlagsController.archive
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_543
  /v2/admin/platform-feature-flags/guarded:
    post:
      operationId: AdminFeatureFlagsController.upsertGuarded
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_543
  /v2/me/feature-flags/evaluate:
    post:
      operationId: UserFeatureFlagsController.evaluate
      parameters: []
      responses:
        '201':
          description: ''
      tags:
        - 'User: Feature Flags'
  /v2/admin/feature-flags/inventory:
    get:
      operationId: FeatureFlagInventoryController.list
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_544
        - 'Admin: Feature Flag Inventory'
  /v2/admin/feature-flags/inventory/{key}:
    get:
      operationId: FeatureFlagInventoryController.resolve
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_544
  /v2/admin/feature-flags/canonical:
    get:
      operationId: FeatureFlagInventoryController.canonical
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_544
  /v2/admin/feature-flags/canonical/{key}:
    get:
      operationId: FeatureFlagInventoryController.canonicalOne
      parameters:
        - name: key
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_544
  /v2/admin/feature-flags/mutation-check:
    post:
      operationId: FeatureFlagInventoryController.mutationCheck
      parameters: []
      responses:
        '201':
          description: ''
      tags: *ref_544
  /v2/event-participations/participants/{participantId}/waiver/download:
    get:
      operationId: ParticipantWaiverController.downloadMyWaiver
      parameters:
        - name: participantId
          required: true
          in: path
          description: Event participant ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Download my filled waiver PDF for a registration
      tags:
        - Event Waiver
  /v2/event-participations/participants/{participantId}/certificate/download:
    get:
      operationId: ParticipantCertificateController.downloadMyCertificate
      parameters:
        - name: participantId
          required: true
          in: path
          description: Event participant ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Download my issued certificate PDF for a registration
      tags:
        - Event Certificates
  /v2/users/me/certificates:
    get:
      operationId: MyCertificatesController.listMyCertificates
      parameters:
        - name: ensurePdf
          required: false
          in: query
          description: >-
            Render any not-yet-rendered certificate PDFs inline so every row
            comes back with a direct `pdfUrl` (capped per request). Slower —
            leave off for a plain list and use `downloadUrl` instead.
          schema:
            type: boolean
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: All event certificates earned by the caller, across all events
      tags:
        - Event Certificates
  /v2/admin/ai-config:
    get:
      description: Returns all AI provider configurations for different features
      operationId: AIConfigController.getAllConfigs
      parameters:
        - &ref_545
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '200':
          description: AI configurations retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AIConfigResponseDto'
      summary: Get all AI configurations
      tags: &ref_546
        - Admin - AI Configuration
  /v2/admin/ai-config/{feature}:
    get:
      description: >-
        Returns AI provider configuration for training_plan, chatbot, or
        plan_adjustment
      operationId: AIConfigController.getConfigByFeature
      parameters:
        - *ref_545
        - name: feature
          required: true
          in: path
          description: Feature type
          schema:
            enum:
              - training_plan
              - chatbot
              - plan_adjustment
            type: string
      responses:
        '200':
          description: AI configuration retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AIConfigResponseDto'
        '400':
          description: Invalid feature type
      summary: Get AI configuration for a specific feature
      tags: *ref_546
    put:
      description: >-
        Update the AI provider settings for a specific feature (training_plan,
        chatbot, plan_adjustment)
      operationId: AIConfigController.updateConfig
      parameters:
        - *ref_545
        - name: feature
          required: true
          in: path
          description: Feature type to update
          schema:
            enum:
              - training_plan
              - chatbot
              - plan_adjustment
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAIConfigDto'
      responses:
        '200':
          description: AI configuration updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AIConfigResponseDto'
        '400':
          description: Invalid feature type or configuration
      summary: Update AI configuration for a feature
      tags: *ref_546
  /v2/admin/ai-config/providers/info:
    get:
      description: Returns information about available AI providers and their capabilities
      operationId: AIConfigController.getProvidersInfo
      parameters:
        - *ref_545
      responses:
        '200':
          description: Provider information retrieved successfully
      summary: Get available AI providers information
      tags: *ref_546
  /v2/challenges/promo-stories:
    get:
      operationId: ChallengePromoStoriesController.list
      parameters:
        - &ref_547
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: filter
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_548
        - Challenges — Promo Stories
    post:
      operationId: ChallengePromoStoriesController.create
      parameters:
        - *ref_547
      responses:
        '201':
          description: ''
      tags: *ref_548
  /v2/challenges/promo-stories/{id}/insights:
    get:
      operationId: ChallengePromoStoriesController.insights
      parameters:
        - *ref_547
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_548
  /v2/challenges/promo-stories/{id}/reactions:
    get:
      operationId: ChallengePromoStoriesController.reactions
      parameters:
        - *ref_547
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_548
  /v2/challenges/promo-stories/{id}/replies:
    get:
      operationId: ChallengePromoStoriesController.replies
      parameters:
        - *ref_547
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_548
  /v2/challenges/promo-stories/{id}:
    delete:
      operationId: ChallengePromoStoriesController.remove
      parameters:
        - *ref_547
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_548
  /v2/challenges/video-uploads:
    post:
      operationId: ChallengesController.createChallengeVideoUpload
      parameters:
        - &ref_549
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: &ref_550
        - Challenges
  /v2/challenges/video-uploads/cleanup:
    post:
      operationId: ChallengesController.cleanupChallengeVideoUploads
      parameters:
        - *ref_549
      responses:
        '201':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}/readiness:
    get:
      operationId: ChallengesController.getChallengeReadiness
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{idOrSlug}/public:
    get:
      operationId: ChallengesController.getPublicChallenge
      parameters:
        - *ref_549
        - name: idOrSlug
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}/rewards/distribute:
    post:
      operationId: ChallengesController.distributeReward
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Distribute a winning-athlete reward (CASH / DISCOUNT / MERCH /
        EVENT_ENTRY).
      tags: *ref_550
  /v2/challenges/{id}/rewards/distribute-all:
    post:
      operationId: ChallengesController.distributeAllRewards
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: >-
        Distribute all rank-wise prizes (Cash/RC Coin/Product) for a completed
        challenge.
      tags: *ref_550
  /v2/challenges/{id}/rewards:
    get:
      operationId: ChallengesController.listChallengeRewards
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List reward distributions for a challenge.
      tags: *ref_550
  /v2/challenges/{id}/rewards/{rewardId}/address:
    patch:
      operationId: ChallengesController.captureRewardAddress
      parameters:
        - *ref_549
        - name: rewardId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Submit shipping address for a MERCH/PRODUCT reward.
      tags: *ref_550
  /v2/challenges/{id}/rewards/{rewardId}/ship:
    patch:
      operationId: ChallengesController.shipReward
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: rewardId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Manually mark a MERCH/PRODUCT reward shipped.
      tags: *ref_550
  /v2/challenges/{id}/rewards/{rewardId}/deliver:
    patch:
      operationId: ChallengesController.deliverReward
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: rewardId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Mark a MERCH/PRODUCT reward delivered.
      tags: *ref_550
  /v2/challenges/{id}/rewards/{rewardId}/cancel:
    patch:
      operationId: ChallengesController.cancelReward
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: rewardId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Cancel a MERCH/PRODUCT reward shipment.
      tags: *ref_550
  /v2/challenges/{id}/rewards/{rewardId}/ship-via-shiprocket:
    patch:
      operationId: ChallengesController.shipRewardViaShiprocket
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: rewardId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Create a Shiprocket order for this reward and stamp tracking. 400 when
        Shiprocket is not configured.
      tags: *ref_550
  /v2/challenges/{id}/prizes:
    get:
      operationId: ChallengesController.getChallengePrizesPreview
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: >-
        Get the rank-wise prize breakdown (Cash/RC Coin/Product) for a
        challenge.
      tags: *ref_550
  /v2/challenges/{id}/participants:
    get:
      operationId: ChallengesController.listParticipants
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: List participants of a challenge (paginated).
      tags: *ref_550
  /v2/challenges/{id}/leaderboard:
    get:
      operationId: ChallengesController.leaderboard
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: scope
          required: false
          in: query
          description: '''all-time'' | ''weekly'' | ''monthly'' (default ''all-time'')'
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Ranked leaderboard for a challenge.
      tags: *ref_550
  /v2/challenges/{id}/leaderboard/paged:
    get:
      operationId: ChallengesController.leaderboardPaged
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: scope
          required: false
          in: query
          description: '''all-time'' | ''weekly'' | ''monthly'' (default ''all-time'')'
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: Paginated challenge leaderboard + the viewer rank.
      tags: *ref_550
  /v2/challenges/{id}/analytics:
    get:
      operationId: ChallengesController.analytics
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Per-challenge analytics aggregate.
      tags: *ref_550
  /v2/challenges/{id}/events:
    get:
      operationId: ChallengesController.listAttachedEvents
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List events that this challenge is attached to.
      tags: *ref_550
  /v2/challenges/{id}/attach-to-event/{eventId}:
    post:
      operationId: ChallengesController.attachToEvent
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Attach a challenge to an organizer event.
      tags: *ref_550
    delete:
      operationId: ChallengesController.detachFromEvent
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Detach a challenge from an organizer event.
      tags: *ref_550
  /v2/challenges/{id}/audiences:
    get:
      operationId: ChallengesController.listAudiences
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List audience bindings on a challenge.
      tags: *ref_550
    post:
      operationId: ChallengesController.bindAudience
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Bind an audience to a challenge.
      tags: *ref_550
  /v2/challenges/{id}/audiences/{audienceId}:
    delete:
      operationId: ChallengesController.unbindAudience
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: audienceId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Remove a challenge audience binding.
      tags: *ref_550
  /v2/challenges/tags/taxonomy:
    get:
      operationId: ChallengesController.listTaxonomy
      parameters:
        - *ref_549
      responses:
        '200':
          description: ''
      summary: List the canonical 14-tag challenge taxonomy.
      tags: *ref_550
  /v2/challenges/tags/{slug}/challenges:
    get:
      operationId: ChallengesController.listChallengesByTag
      parameters:
        - *ref_549
        - name: slug
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: offset
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: >-
        List challengeIds that wear the given canonical tag slug. Pair with
        /v2/challenges/discover for the full payload.
      tags: *ref_550
  /v2/challenges/{id}/tags:
    get:
      operationId: ChallengesController.getChallengeTags
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_550
    patch:
      operationId: ChallengesController.setChallengeTags
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}/calendar.ics:
    get:
      operationId: ChallengesController.challengeCalendarIcs
      parameters:
        - *ref_549
      responses:
        '200':
          description: ''
      summary: Download an .ics calendar invite for a challenge the athlete has joined.
      tags: *ref_550
  /v2/challenges:
    post:
      operationId: ChallengesController.createChallenge
      parameters:
        - *ref_549
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateChallengeDto'
      responses:
        '201':
          description: ''
      tags: *ref_550
    get:
      operationId: ChallengesController.getAllChallenges
      parameters:
        - *ref_549
        - name: categoriseBySports
          required: true
          in: query
          schema:
            type: boolean
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/club/{clubId}:
    post:
      operationId: ChallengesController.createClubChallenge
      parameters:
        - *ref_549
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateChallengeDto'
      responses:
        '201':
          description: ''
      tags: *ref_550
    get:
      operationId: ChallengesController.listClubChallenges
      parameters:
        - *ref_549
        - name: clubId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List a club's own challenges (all statuses, all timeframes)
      tags: *ref_550
  /v2/challenges/discover:
    get:
      operationId: ChallengesController.discoverChallenges
      parameters:
        - *ref_549
        - name: sportIds
          required: false
          in: query
          description: Comma-separated sport UUIDs.
          schema:
            type: string
        - name: timeFrame
          required: false
          in: query
          schema:
            enum:
              - past
              - live
              - upcoming
            type: string
        - name: entryFeeMode
          required: false
          in: query
          description: '''free'' | ''paid'' | ''low'' | ''medium'' | ''high'' | ''any'''
          schema:
            type: string
        - name: status
          required: false
          in: query
          description: '''open_for_join'' | ''active'' | ''ending_soon'' | ''coming_soon'''
          schema:
            type: string
        - name: difficulty
          required: false
          in: query
          schema:
            type: string
        - name: clubId
          required: false
          in: query
          description: Scope to challenges authored by a specific club (§18.3 Tab 6).
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: page
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/explore:
    get:
      operationId: ChallengesController.exploreChallenges
      parameters:
        - *ref_549
        - name: categoriseBySports
          required: true
          in: query
          schema:
            type: boolean
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/featured:
    get:
      operationId: ChallengesController.getFeaturedChallenges
      parameters:
        - *ref_549
        - name: timeframe
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}:
    get:
      operationId: ChallengesController.getChallenge
      parameters:
        - *ref_549
      responses:
        '200':
          description: ''
      tags: *ref_550
    patch:
      operationId: ChallengesController.updateChallenge
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateChallengeDto'
      responses:
        '200':
          description: ''
      tags: *ref_550
    delete:
      operationId: ChallengesController.deleteChallenge
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/club/{clubId}/{id}:
    patch:
      operationId: ChallengesController.updateClubChallenge
      parameters:
        - *ref_549
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateChallengeDto'
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}/badges:
    get:
      operationId: ChallengesController.getBadges
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}/review:
    patch:
      operationId: ChallengesController.reviewChallenge
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}/toggle:
    patch:
      operationId: ChallengesController.toggleChallengeStatus
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_550
  /v2/challenges/{id}/cancel:
    post:
      operationId: ChallengesController.cancelChallengeAndRefund
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_550
  /v2/challenges/club/{clubId}/{id}/cancel:
    post:
      operationId: ChallengesController.cancelClubChallenge
      parameters:
        - *ref_549
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Cancel a club's own challenge and run the refund cascade
      tags: *ref_550
  /v2/challenges/club/{clubId}/{id}/toggle:
    patch:
      operationId: ChallengesController.toggleClubChallengeStatus
      parameters:
        - *ref_549
        - name: clubId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Pause or resume a club's own challenge
      tags: *ref_550
  /v2/challenges/{id}/promo-story:
    post:
      operationId: ChallengesController.createPromoStory
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateChallengePromoStoryDto'
      responses:
        '201':
          description: ''
      summary: >-
        Create a challenge promo story that appears in the athlete-app story
        feed.
      tags: *ref_550
  /v2/challenges/{id}/promo-stories:
    get:
      operationId: ChallengesController.listPromoStories
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List active promo stories for a challenge.
      tags: *ref_550
  /v2/challenges/{id}/promo-stories/{storyId}:
    delete:
      operationId: ChallengesController.deletePromoStory
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: storyId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Delete a challenge promo story.
      tags: *ref_550
  /v2/challenges/{id}/promo-stories/{storyId}/insights:
    get:
      operationId: ChallengesController.promoStoryInsights
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: storyId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Aggregate view / like / comment stats for a promo story.
      tags: *ref_550
  /v2/challenges/{id}/promo-stories/{storyId}/reactions:
    get:
      operationId: ChallengesController.promoStoryReactions
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: storyId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Paginated list of athletes who liked a promo story.
      tags: *ref_550
  /v2/challenges/{id}/promo-stories/{storyId}/replies:
    get:
      operationId: ChallengesController.promoStoryReplies
      parameters:
        - *ref_549
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: storyId
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Paginated list of athlete comments on a promo story.
      tags: *ref_550
  /v2/challenges/{challengeId}/prizes/contributions:
    get:
      description: >-
        Returns an OBJECT, not an array. `items` are the contributions, each
        enriched with the proposing brand's `sponsorBrandName` /
        `sponsorBrandLogoUrl` (public identity only). `hasRankSlabs` is true
        when the challenge already has at least one non-PARTICIPATION prize slab
        — false means accepting a goodie will create the prize rank for it. The
        flag ships here because the prize-ladder route is organizer-guarded and
        unreachable for club admins.
      operationId: ChallengePrizeContributionsController.list
      parameters:
        - name: challengeId
          required: true
          in: path
          description: Challenge ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_551
        - bearer: []
      summary: Owner goodie inbox — { items, hasRankSlabs } for the challenge
      tags: &ref_552
        - Challenge Prizes
  /v2/challenges/{challengeId}/prizes/contributions/{contributionId}/accept:
    patch:
      description: >-
        Attaches a sponsor-attributed product to the slab covering the target
        rank. Refused when no slab covers that rank.
      operationId: ChallengePrizeContributionsController.accept
      parameters:
        - name: challengeId
          required: true
          in: path
          description: Challenge ID
          schema:
            type: string
        - name: contributionId
          required: true
          in: path
          description: Contribution ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AcceptChallengeGoodieDto'
      responses:
        '200':
          description: ''
      security: *ref_551
      summary: Accept a sponsor goodie onto a challenge prize rank
      tags: *ref_552
  /v2/challenges/{challengeId}/prizes/contributions/{contributionId}/reject:
    patch:
      operationId: ChallengePrizeContributionsController.reject
      parameters:
        - name: challengeId
          required: true
          in: path
          description: Challenge ID
          schema:
            type: string
        - name: contributionId
          required: true
          in: path
          description: Contribution ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RejectChallengeGoodieDto'
      responses:
        '200':
          description: ''
      security: *ref_551
      summary: Reject a sponsor goodie contribution
      tags: *ref_552
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/prize-contributions:
    get:
      operationId: SponsorChallengeGoodiesController.list
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          description: Challenge ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_553
        - bearer: []
      summary: This brand's goodie contributions for the challenge
      tags: &ref_554
        - 'Sponsor: Challenge Goodies'
    post:
      operationId: SponsorChallengeGoodiesController.propose
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          description: Challenge ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProposeChallengeGoodieDto'
      responses:
        '201':
          description: Contribution proposed
      security: *ref_553
      summary: Propose a goodie for a rank of a challenge prize ladder
      tags: *ref_554
  /v2/sponsor/brands/{brandId}/challenges/{challengeId}/prize-contributions/{contributionId}:
    delete:
      operationId: SponsorChallengeGoodiesController.withdraw
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: challengeId
          required: true
          in: path
          description: Challenge ID
          schema:
            type: string
        - name: contributionId
          required: true
          in: path
          description: Contribution ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_553
      summary: Withdraw a still-pending goodie contribution
      tags: *ref_554
  /v2/sponsor/brands/{brandId}/challenge-prize-contributions:
    get:
      operationId: SponsorChallengeContributionsRollupController.listAll
      parameters:
        - name: brandId
          required: true
          in: path
          description: Sponsor brand ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Every prize-goodie contribution this brand has made, across all
        challenges. Optional ?status= filter.
      tags:
        - 'Sponsor: Challenge Goodies'
  /v2/ticket-types:
    post:
      operationId: TicketTypesController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTicketTypeDto'
      responses:
        '201':
          description: ''
      tags: &ref_555
        - Ticket Types
    get:
      operationId: TicketTypesController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_555
  /v2/ticket-types/{id}:
    get:
      operationId: TicketTypesController.findOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_555
    patch:
      operationId: TicketTypesController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTicketTypeDto'
      responses:
        '200':
          description: ''
      tags: *ref_555
    delete:
      operationId: TicketTypesController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_555
  /v2/ticket-types/{id}/review:
    patch:
      operationId: TicketTypesController.review
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      tags: *ref_555
  /v2/ticket-templates:
    post:
      operationId: TicketTemplatesController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTicketTemplateDto'
      responses:
        '201':
          description: ''
      security: &ref_556
        - bearer: []
      tags: &ref_557
        - Ticket Templates
    get:
      operationId: TicketTemplatesController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_556
      tags: *ref_557
  /v2/ticket-templates/{id}:
    get:
      operationId: TicketTemplatesController.findOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_556
      tags: *ref_557
    patch:
      operationId: TicketTemplatesController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTicketTemplateDto'
      responses:
        '200':
          description: ''
      security: *ref_556
      tags: *ref_557
    delete:
      operationId: TicketTemplatesController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_556
      tags: *ref_557
  /v2/ticket-templates/{id}/review:
    patch:
      operationId: TicketTemplatesController.review
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      security: *ref_556
      tags: *ref_557
  /v2/ticket-templates/{id}/toggle:
    patch:
      operationId: TicketTemplatesController.toggleTicketTemplateStatus
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_556
      tags: *ref_557
  /v2/frequently-asked-questions:
    post:
      operationId: FrequentlyAskedQuestionsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFaqDto'
      responses:
        '201':
          description: ''
      security: &ref_558
        - bearer: []
      tags: &ref_559
        - Frequently Asked Questions
    get:
      operationId: FrequentlyAskedQuestionsController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_558
      tags: *ref_559
  /v2/frequently-asked-questions/{id}:
    get:
      operationId: FrequentlyAskedQuestionsController.findOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_558
      tags: *ref_559
    patch:
      operationId: FrequentlyAskedQuestionsController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateFaqDto'
      responses:
        '200':
          description: ''
      security: *ref_558
      tags: *ref_559
    delete:
      operationId: FrequentlyAskedQuestionsController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_558
      tags: *ref_559
  /v2/frequently-asked-questions/{id}/review:
    patch:
      operationId: FrequentlyAskedQuestionsController.review
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      security: *ref_558
      tags: *ref_559
  /v2/frequently-asked-questions/{id}/toggle:
    patch:
      operationId: FrequentlyAskedQuestionsController.toggleFAQStatus
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_558
      tags: *ref_559
  /v2/terms-and-conditions:
    post:
      operationId: TermsAndConditionsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTermsAndConditionDto'
      responses:
        '201':
          description: ''
      security: &ref_560
        - bearer: []
      tags: &ref_561
        - Terms and Conditions
    get:
      operationId: TermsAndConditionsController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_560
      tags: *ref_561
  /v2/terms-and-conditions/{id}:
    get:
      operationId: TermsAndConditionsController.findOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_560
      tags: *ref_561
    patch:
      operationId: TermsAndConditionsController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTermsAndConditionDto'
      responses:
        '200':
          description: ''
      security: *ref_560
      tags: *ref_561
    delete:
      operationId: TermsAndConditionsController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_560
      tags: *ref_561
  /v2/terms-and-conditions/{id}/public:
    get:
      operationId: TermsAndConditionsController.findOnePublic
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_560
      tags: *ref_561
  /v2/terms-and-conditions/{id}/review:
    patch:
      operationId: TermsAndConditionsController.review
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      security: *ref_560
      tags: *ref_561
  /v2/terms-and-conditions/{id}/toggle:
    patch:
      operationId: TermsAndConditionsController.toggleTNCStatus
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_560
      tags: *ref_561
  /v2/privacy-policies:
    post:
      operationId: PrivacyPoliciesController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePrivacyPolicyDto'
      responses:
        '201':
          description: ''
      security: &ref_562
        - bearer: []
      tags: &ref_563
        - Privacy Policies
    get:
      operationId: PrivacyPoliciesController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_562
      tags: *ref_563
  /v2/privacy-policies/{id}:
    get:
      operationId: PrivacyPoliciesController.findOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_562
      tags: *ref_563
    patch:
      operationId: PrivacyPoliciesController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePrivacyPolicyDto'
      responses:
        '200':
          description: ''
      security: *ref_562
      tags: *ref_563
    delete:
      operationId: PrivacyPoliciesController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_562
      tags: *ref_563
  /v2/privacy-policies/{id}/public:
    get:
      operationId: PrivacyPoliciesController.findOnePublic
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_562
      tags: *ref_563
  /v2/privacy-policies/{id}/review:
    patch:
      operationId: PrivacyPoliciesController.review
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      security: *ref_562
      tags: *ref_563
  /v2/privacy-policies/{id}/toggle:
    patch:
      operationId: PrivacyPoliciesController.togglePPStatus
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_562
      tags: *ref_563
  /v2/organizer/events/{eventId}/participations/export:
    get:
      operationId: EventParticipationsController.exportCsv
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: status
          required: true
          in: query
          schema:
            type: string
        - name: ticketId
          required: true
          in: query
          schema:
            type: string
        - name: checkedIn
          required: true
          in: query
          schema:
            type: string
        - name: bibAssigned
          required: true
          in: query
          schema:
            type: string
        - name: registrationType
          required: true
          in: query
          schema:
            type: string
        - name: since
          required: true
          in: query
          schema:
            type: string
        - name: until
          required: true
          in: query
          schema:
            type: string
        - name: q
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_564
        - 'Organizer: Event Participations'
  /v2/organizer/events/{eventId}/participations/offline-reg:
    post:
      operationId: EventParticipationsController.offlineReg
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/{participationId}/transfer:
    post:
      operationId: EventParticipationsController.transfer
      parameters:
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/{participationId}/defer:
    post:
      operationId: EventParticipationsController.defer
      parameters:
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/bulk-transfer:
    post:
      operationId: EventParticipationsController.bulkTransfer
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/bulk-defer:
    post:
      operationId: EventParticipationsController.bulkDefer
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/bulk-notify/preview:
    post:
      operationId: EventParticipationsController.bulkNotifyPreview
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/bulk-notify:
    post:
      operationId: EventParticipationsController.bulkNotify
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/{participationId}/notify:
    post:
      operationId: EventParticipationsController.notifyOne
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/summary:
    get:
      operationId: EventParticipationsController.summary
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_564
  /v2/organizer/events/{eventId}/participations/{participationId}:
    get:
      operationId: EventParticipationsController.getParticipationDetail
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_564
  /v2/organizer/participants/search:
    get:
      operationId: ParticipantsSearchController.search
      parameters: []
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Cross-event participant search (PRD §35.1) — ILIKE on name/email/phone,
        plus exact participationId match.
      tags:
        - 'Organizer: Participants Search'
  /v2/organizers/{organizerId}/marketing/bulk-notify:
    post:
      operationId: CrossEventMarketingController.bulkNotify
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CrossEventBulkNotifyDto'
      responses:
        '201':
          description: ''
      security:
        - bearer: []
      summary: >-
        Send a bulk notification across all (or a subset of) the organizer's
        events. Recipients are deduped globally.
      tags:
        - 'Organizer: Cross-event Marketing'
  /v2/podcasts:
    get:
      operationId: PodcastsController.get
      parameters: []
      responses:
        '200':
          description: ''
      tags: &ref_565
        - Podcasts
    post:
      operationId: PodcastsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePodcastDto'
      responses:
        '201':
          description: ''
      tags: *ref_565
  /v2/podcasts/{id}:
    get:
      operationId: PodcastsController.findOne
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_565
    patch:
      operationId: PodcastsController.updatePodcast
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePodcastDto'
      responses:
        '200':
          description: ''
      tags: *ref_565
    delete:
      operationId: PodcastsController.delete
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_565
  /v2/podcasts/{id}/review:
    patch:
      operationId: PodcastsController.reviewPodcast
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      tags: *ref_565
  /v2/podcasts/{id}/toggle:
    patch:
      operationId: PodcastsController.togglePodcastStatus
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_565
  /v2/challenge-templates:
    post:
      operationId: ChallengeTemplatesController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateChallengeTemplateDto'
      responses:
        '201':
          description: ''
      security: &ref_566
        - bearer: []
      summary: Save a reusable challenge template.
      tags: &ref_567
        - Challenge Templates
    get:
      operationId: ChallengeTemplatesController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_566
      summary: List the organizer's saved challenge templates.
      tags: *ref_567
  /v2/challenge-templates/{id}:
    delete:
      operationId: ChallengeTemplatesController.remove
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_566
      summary: Delete a saved challenge template.
      tags: *ref_567
  /v2/form:
    post:
      operationId: FormController.create
      parameters:
        - &ref_568
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFormDto'
      responses:
        '201':
          description: ''
      tags: &ref_569
        - Forms
    get:
      operationId: FormController.findAll
      parameters:
        - *ref_568
      responses:
        '200':
          description: ''
      tags: *ref_569
  /v2/form/{id}:
    get:
      operationId: FormController.findOne
      parameters:
        - *ref_568
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_569
    put:
      operationId: FormController.update
      parameters:
        - *ref_568
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_569
    delete:
      operationId: FormController.remove
      parameters:
        - *ref_568
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_569
  /v2/form/{id}/toggle:
    patch:
      operationId: FormController.toggleFormStatus
      parameters:
        - *ref_568
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_569
  /v2/approvals:
    get:
      operationId: ApprovalsController.getAllApprovals
      parameters:
        - &ref_570
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: type
          required: false
          in: query
          description: Filter by approval type
          schema:
            type: string
            enum:
              - business_kyc
              - event
              - event_add_on
              - ticket_template
              - ticket_type
              - form
              - challenge
              - prep_program
              - product
              - product_category
              - coupon
              - podcast
              - terms_and_condition
              - privacy_policy
              - faq
        - name: status
          required: false
          in: query
          description: Filter by approval status
          schema:
            type: string
            enum:
              - pending
              - approved
              - rejected
              - suspended
        - name: page
          required: false
          in: query
          description: Page number for pagination
          schema:
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Number of items per page
          schema:
            default: 10
            type: number
      responses:
        '200':
          description: ''
      summary: Get all approvals with filters and pagination
      tags: &ref_571
        - Approvals
  /v2/approvals/summary:
    get:
      operationId: ApprovalsController.getApprovalSummary
      parameters:
        - *ref_570
      responses:
        '200':
          description: ''
      summary: Get approval summary (counts by status)
      tags: *ref_571
  /v2/approvals/{type}/{id}:
    get:
      operationId: ApprovalsController.getApprovalDetails
      parameters:
        - *ref_570
        - name: type
          required: true
          in: path
          description: Type of approval
          schema:
            enum:
              - business_kyc
              - event
              - event_add_on
              - ticket_template
              - ticket_type
              - form
              - challenge
              - prep_program
              - product
              - product_category
              - coupon
              - podcast
              - terms_and_condition
              - privacy_policy
              - faq
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get approval details by type and ID
      tags: *ref_571
  /v2/approvals/{type}/{id}/review:
    patch:
      operationId: ApprovalsController.reviewApproval
      parameters:
        - *ref_570
        - name: type
          required: true
          in: path
          description: Type of approval
          schema:
            enum:
              - business_kyc
              - event
              - event_add_on
              - ticket_template
              - ticket_type
              - form
              - challenge
              - prep_program
              - product
              - product_category
              - coupon
              - podcast
              - terms_and_condition
              - privacy_policy
              - faq
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewApprovalDto'
      responses:
        '200':
          description: ''
      summary: Review (approve/reject) any approval type
      tags: *ref_571
  /v2/approvals/kyc/{id}:
    get:
      operationId: ApprovalsController.getKycDetails
      parameters:
        - *ref_570
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get KYC details by ID
      tags: *ref_571
  /v2/approvals/kyc/{id}/review:
    patch:
      operationId: ApprovalsController.reviewKyc
      parameters:
        - *ref_570
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewKycDto'
      responses:
        '200':
          description: ''
      summary: Review (approve/reject) KYC
      tags: *ref_571
  /v2/admins/declaration-form-templates:
    post:
      description: >-
        Create a new declaration form template with HTML content and required
        fields. Only one template can be active at a time.
      operationId: DeclarationFormTemplatesController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDeclarationFormTemplateDto'
      responses:
        '201':
          description: Declaration form template created successfully
      security: &ref_572
        - bearer: []
      summary: Create a new declaration form template
      tags: &ref_573
        - Admin - Declaration Form Templates
    get:
      description: Retrieve all declaration form templates including deleted
      operationId: DeclarationFormTemplatesController.findAll
      parameters: []
      responses:
        '200':
          description: List of declaration form templates
      security: *ref_572
      summary: Get all declaration form templates
      tags: *ref_573
  /v2/admins/declaration-form-templates/active:
    get:
      description: Retrieve the currently active declaration form template
      operationId: DeclarationFormTemplatesController.findActive
      parameters: []
      responses:
        '200':
          description: Active declaration form template
      security: *ref_572
      summary: Get active declaration form template
      tags: *ref_573
  /v2/admins/declaration-form-templates/{id}:
    get:
      description: Retrieve a specific declaration form template
      operationId: DeclarationFormTemplatesController.findOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Declaration form template found
      security: *ref_572
      summary: Get a declaration form template by ID
      tags: *ref_573
    patch:
      description: >-
        Update a declaration form template. Setting isActive=true will
        deactivate all other templates.
      operationId: DeclarationFormTemplatesController.update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateDeclarationFormTemplateDto'
      responses:
        '200':
          description: Declaration form template updated successfully
      security: *ref_572
      summary: Update a declaration form template
      tags: *ref_573
    delete:
      description: Soft delete a declaration form template. Cannot delete active template.
      operationId: DeclarationFormTemplatesController.delete
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Declaration form template deleted successfully
      security: *ref_572
      summary: Delete a declaration form template
      tags: *ref_573
  /v2/admins/declaration-form-templates/{id}/activate:
    patch:
      description: Set a template as active. This will deactivate all other templates.
      operationId: DeclarationFormTemplatesController.activate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: Declaration form template activated successfully
      security: *ref_572
      summary: Activate a declaration form template
      tags: *ref_573
  /v2/organizer/payouts/requests:
    get:
      operationId: OrganizerPayoutsController.listPayoutRequests
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_574
        - bearer: []
      summary: List the organizer’s own payout requests.
      tags: &ref_575
        - 'Organizer: Payouts'
  /v2/organizer/payouts/{settlementId}/request:
    post:
      operationId: OrganizerPayoutsController.requestPayout
      parameters:
        - name: settlementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_574
      summary: >-
        Request a payout for a settlement. Idempotent — a second open request
        returns the existing one.
      tags: *ref_575
  /v2/organizer/payouts/requests/{id}/cancel:
    post:
      operationId: OrganizerPayoutsController.cancelPayout
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_574
      summary: Cancel an open payout request (reason required).
      tags: *ref_575
  /v2/organizer/payouts:
    get:
      operationId: OrganizerPayoutsController.list
      parameters:
        - name: from
          required: false
          in: query
          description: Inclusive lower bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-01-01'
            type: string
        - name: to
          required: false
          in: query
          description: Inclusive upper bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-04-18'
            type: string
        - name: stream
          required: false
          in: query
          schema:
            type: string
            enum:
              - REGISTRATION
              - HYBRID_RACE
              - CLUB
              - PHOTO
              - CHALLENGE
              - SPONSORSHIP
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
        - name: minAmount
          required: false
          in: query
          description: >-
            Inclusive lower bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 1000
            type: number
        - name: maxAmount
          required: false
          in: query
          description: >-
            Inclusive upper bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 50000
            type: number
        - name: participantUserId
          required: false
          in: query
          description: >-
            Filter transaction-log rows to participations owned by this athlete
            user ID. Applies to /transactions-export only.
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            minimum: 1
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          schema:
            minimum: 1
            maximum: 100
            default: 20
            type: number
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        List settlement (payout) rows for the authenticated organizer.
        Paginated, filterable by date / stream / status.
      tags: *ref_575
  /v2/organizer/payouts/summary:
    get:
      operationId: OrganizerPayoutsController.summary
      parameters:
        - name: from
          required: false
          in: query
          description: Inclusive lower bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-01-01'
            type: string
        - name: to
          required: false
          in: query
          description: Inclusive upper bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-04-18'
            type: string
        - name: stream
          required: false
          in: query
          schema:
            type: string
            enum:
              - REGISTRATION
              - HYBRID_RACE
              - CLUB
              - PHOTO
              - CHALLENGE
              - SPONSORSHIP
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
        - name: minAmount
          required: false
          in: query
          description: >-
            Inclusive lower bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 1000
            type: number
        - name: maxAmount
          required: false
          in: query
          description: >-
            Inclusive upper bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 50000
            type: number
        - name: participantUserId
          required: false
          in: query
          description: >-
            Filter transaction-log rows to participations owned by this athlete
            user ID. Applies to /transactions-export only.
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Filter-aware totals for the ledger. Returns overall + per-stream
        breakdown.
      tags: *ref_575
  /v2/organizer/payouts/balance:
    get:
      operationId: OrganizerPayoutsController.balance
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Payout balance: available, pending, in-transit, paid + next payout date
        (PRD §42.4).
      tags: *ref_575
  /v2/organizer/payouts/{settlementId}/statement.pdf:
    get:
      operationId: OrganizerPayoutsController.statementPdf
      parameters:
        - name: settlementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Generate / fetch the settlement statement PDF (PRD §42.4 D-114). Returns
        S3 URL info.
      tags: *ref_575
  /v2/organizer/payouts/{settlementId}/fee-breakdown:
    get:
      operationId: OrganizerPayoutsController.feeBreakdown
      parameters:
        - name: settlementId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Per-transaction fee breakdown for a single settlement (PRD §42.3
        G-42-9). Returns gross / platformFee / gatewayFee / gst / net +
        reconciliation delta.
      tags: *ref_575
  /v2/organizer/payouts/year-over-year:
    get:
      operationId: OrganizerPayoutsController.yearOverYear
      parameters:
        - name: from
          required: true
          in: query
          description: Inclusive lower bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-01-01'
            type: string
        - name: to
          required: true
          in: query
          description: Inclusive upper bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-04-18'
            type: string
        - name: stream
          required: false
          in: query
          schema:
            type: string
            enum:
              - REGISTRATION
              - HYBRID_RACE
              - CLUB
              - PHOTO
              - CHALLENGE
              - SPONSORSHIP
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
        - name: minAmount
          required: false
          in: query
          description: >-
            Inclusive lower bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 1000
            type: number
        - name: maxAmount
          required: false
          in: query
          description: >-
            Inclusive upper bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 50000
            type: number
        - name: participantUserId
          required: false
          in: query
          description: >-
            Filter transaction-log rows to participations owned by this athlete
            user ID. Applies to /transactions-export only.
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Year-over-year revenue comparison (current window vs same window prior
        year). Requires explicit from + to dates (PRD §42.1 G-42-4).
      tags: *ref_575
  /v2/organizer/payouts/export:
    get:
      operationId: OrganizerPayoutsController.export
      parameters:
        - name: from
          required: false
          in: query
          description: Inclusive lower bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-01-01'
            type: string
        - name: to
          required: false
          in: query
          description: Inclusive upper bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-04-18'
            type: string
        - name: stream
          required: false
          in: query
          schema:
            type: string
            enum:
              - REGISTRATION
              - HYBRID_RACE
              - CLUB
              - PHOTO
              - CHALLENGE
              - SPONSORSHIP
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
        - name: minAmount
          required: false
          in: query
          description: >-
            Inclusive lower bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 1000
            type: number
        - name: maxAmount
          required: false
          in: query
          description: >-
            Inclusive upper bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 50000
            type: number
        - name: participantUserId
          required: false
          in: query
          description: >-
            Filter transaction-log rows to participations owned by this athlete
            user ID. Applies to /transactions-export only.
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: Download the current filter state as CSV.
      tags: *ref_575
  /v2/organizer/payouts/transactions-export:
    get:
      operationId: OrganizerPayoutsController.exportTransactions
      parameters:
        - name: from
          required: false
          in: query
          description: Inclusive lower bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-01-01'
            type: string
        - name: to
          required: false
          in: query
          description: Inclusive upper bound on settlement createdAt (ISO 8601).
          schema:
            example: '2026-04-18'
            type: string
        - name: stream
          required: false
          in: query
          schema:
            type: string
            enum:
              - REGISTRATION
              - HYBRID_RACE
              - CLUB
              - PHOTO
              - CHALLENGE
              - SPONSORSHIP
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - pending
              - eligible
              - processing
              - completed
              - failed
              - on_hold
        - name: minAmount
          required: false
          in: query
          description: >-
            Inclusive lower bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 1000
            type: number
        - name: maxAmount
          required: false
          in: query
          description: >-
            Inclusive upper bound on settlement net amount (INR). Filter on the
            organizer-take-home figure.
          schema:
            example: 50000
            type: number
        - name: participantUserId
          required: false
          in: query
          description: >-
            Filter transaction-log rows to participations owned by this athlete
            user ID. Applies to /transactions-export only.
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Download per-participant transaction-log as CSV. PRD §42.2 columns: date
        / time / participant / amount / payment method / status / reference IDs.
      tags: *ref_575
  /v2/organizer/payouts/payout-schedule:
    get:
      operationId: OrganizerPayoutsController.getPayoutSchedule
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Get the caller organizer's payout cadence (PRD §42.4). Returns {
        organizerId, schedule }.
      tags: *ref_575
    patch:
      operationId: OrganizerPayoutsController.updatePayoutSchedule
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePayoutScheduleDto'
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Update the caller organizer's payout cadence (PRD §42.4). OWNER + ADMIN
        only; VIEWER blocked.
      tags: *ref_575
  /v2/organizer/payouts/events/{eventId}/finance:
    get:
      operationId: OrganizerPayoutsController.getEventFinance
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_574
      summary: >-
        Per-event finance aggregator (PRD §42 / §44) — gross / net / fees /
        by-stream scoped to one event.
      tags: *ref_575
  /v2/organizer/disputes:
    get:
      operationId: OrganizerDisputesController.list
      parameters:
        - name: status
          required: false
          in: query
          schema:
            enum:
              - INITIATED
              - DEFENDED
              - ACCEPTED
              - REFUNDED
            type: string
        - name: eventId
          required: false
          in: query
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: &ref_576
        - bearer: []
      summary: >-
        List chargebacks affecting this organizer's events. Read-only per PRD
        §42.6 G-42-15.
      tags: &ref_577
        - 'Organizer: Disputes'
  /v2/organizer/disputes/summary:
    get:
      operationId: OrganizerDisputesController.summary
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_576
      summary: Aggregate dispute counts + next deadline (drives partner-portal banner).
      tags: *ref_577
  /v2/organizer/disputes/{id}:
    get:
      operationId: OrganizerDisputesController.getOne
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_576
      summary: >-
        Get a single dispute by id (cross-org leak guard returns 404 on
        mismatch).
      tags: *ref_577
  /v2/organizer/disputes/{id}/response:
    patch:
      operationId: OrganizerDisputesController.respond
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RespondToChargebackDto'
      responses:
        '200':
          description: ''
      security: *ref_576
      summary: >-
        Submit a draft / final response for a chargeback (PRD §42.6 G-42-16).
        OWNER + ADMIN only; VIEWER read-only.
      tags: *ref_577
  /v2/organizer/disputes/{id}/evidence:
    post:
      operationId: OrganizerDisputesController.uploadEvidence
      parameters:
        - name: id
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_576
      summary: >-
        Upload an evidence file for a chargeback (PRD §42.6). OWNER + ADMIN
        only.
      tags: *ref_577
  /v2/organizer/disputes/{id}/evidence/{fileKey}:
    delete:
      operationId: OrganizerDisputesController.removeEvidence
      parameters:
        - name: id
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
        - name: fileKey
          required: true
          in: path
          description: S3 object key (URL-encoded)
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_576
      summary: >-
        Remove an uploaded evidence file from a chargeback (PRD §42.6). OWNER +
        ADMIN only.
      tags: *ref_577
  /v2/organizer/disputes/{id}/evidence/{fileKey}/download:
    get:
      operationId: OrganizerDisputesController.evidenceDownloadUrl
      parameters:
        - name: id
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
        - name: fileKey
          required: true
          in: path
          description: S3 object key (URL-encoded)
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_576
      summary: >-
        Get a short-lived (15-min) signed download URL for an uploaded evidence
        file. OWNER + ADMIN + VIEWER read.
      tags: *ref_577
  /v2/organizer/disputes/{id}/thread:
    get:
      operationId: OrganizerDisputesController.getThread
      parameters:
        - name: id
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: *ref_576
      summary: >-
        Paginated dispute thread for a chargeback (PRD §42.6). Read-only — OWNER
        + ADMIN + VIEWER.
      tags: *ref_577
    post:
      operationId: OrganizerDisputesController.postThreadMessage
      parameters:
        - name: id
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostThreadMessageDto'
      responses:
        '201':
          description: ''
      security: *ref_576
      summary: >-
        Post a thread message on a chargeback (PRD §42.6 G-42-16). OWNER + ADMIN
        only; status must be INITIATED.
      tags: *ref_577
  /v2/organizer/disputes/{id}/audit:
    get:
      operationId: OrganizerDisputesController.getAuditTrail
      parameters:
        - name: id
          required: true
          in: path
          description: Chargeback id
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: *ref_576
      summary: >-
        Paginated audit trail for a chargeback (PRD §42.6). Read-only — OWNER +
        ADMIN + VIEWER.
      tags: *ref_577
  /v2/organizer/refunds:
    get:
      operationId: OrganizerRefundsController.list
      parameters:
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: to
          required: false
          in: query
          schema: {}
        - name: from
          required: false
          in: query
          schema: {}
        - name: eventId
          required: false
          in: query
          schema: {}
        - name: status
          required: false
          in: query
          schema: {}
      responses:
        '200':
          description: ''
      security: &ref_578
        - bearer: []
      summary: >-
        Cross-event refund queue (PRD §35 / §72). Filterable by status / event /
        date. Cursor pagination.
      tags: &ref_579
        - 'Organizer: Refunds'
  /v2/organizer/refunds/quote:
    post:
      operationId: OrganizerRefundsController.quote
      parameters: []
      responses:
        '201':
          description: ''
      security: *ref_578
      summary: >-
        Deterministic pro-rated refund quote for an event cancellation. Preview
        only — no mutation.
      tags: *ref_579
  /v2/organizer/events/{eventId}/money:
    get:
      operationId: OrganizerEventMoneyController.getMoneyTab
      parameters:
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
        - name: refundsLimit
          required: true
          in: query
          schema:
            type: string
        - name: invoicesLimit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: >-
        Money tab for one event: settlement breakdown
        (gross→platform→gateway→TDS→net), GST invoices, refunds, disputes.
      tags:
        - 'Organizer: Event Money Tab'
  /v2/organizer/suggested-actions/refresh:
    post:
      operationId: OrganizerSuggestedActionsController.refresh
      parameters: []
      responses:
        '201':
          description: ''
      security: &ref_580
        - bearer: []
      summary: Regenerate suggested actions from current signals (idempotent).
      tags: &ref_581
        - 'Organizer: Suggested Actions'
  /v2/organizer/suggested-actions:
    get:
      operationId: OrganizerSuggestedActionsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_580
      summary: List suggested actions (defaults to OPEN).
      tags: *ref_581
  /v2/organizer/suggested-actions/{id}/dismiss:
    post:
      operationId: OrganizerSuggestedActionsController.dismiss
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_580
      summary: Dismiss a suggested action.
      tags: *ref_581
  /v2/organizer/suggested-actions/{id}/complete:
    post:
      operationId: OrganizerSuggestedActionsController.complete
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_580
      summary: Mark a suggested action complete.
      tags: *ref_581
  /v2/organizer/suggested-actions/{id}/snooze:
    post:
      operationId: OrganizerSuggestedActionsController.snooze
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_580
      summary: Snooze a suggested action for N days.
      tags: *ref_581
  /v2/organizer/benchmarking/events/{eventId}:
    get:
      operationId: OrganizerBenchmarkingController.benchmarkEvent
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: metricKey
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Benchmark an event against comparable peers (aggregate-only).
      tags:
        - 'Organizer: Benchmarking'
  /v2/organizer/demographics:
    get:
      operationId: OrganizerDemographicsController.drillIn
      parameters:
        - name: dimension
          required: true
          in: query
          schema:
            type: string
        - name: eventId
          required: true
          in: query
          schema:
            type: string
        - name: from
          required: true
          in: query
          schema:
            type: string
        - name: to
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security:
        - bearer: []
      summary: Aggregate participant demographics by a dimension (k-anon safe).
      tags:
        - 'Organizer: Demographics'
  /v2/organizer/recommendations/refresh:
    post:
      operationId: OrganizerRecommendationsController.refresh
      parameters: []
      responses:
        '201':
          description: ''
      security: &ref_582
        - bearer: []
      summary: Regenerate recommendations (idempotent).
      tags: &ref_583
        - 'Organizer: Recommendations'
  /v2/organizer/recommendations:
    get:
      operationId: OrganizerRecommendationsController.list
      parameters:
        - name: status
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_582
      summary: List recommendations (defaults to OPEN).
      tags: *ref_583
  /v2/organizer/recommendations/{id}/dismiss:
    post:
      operationId: OrganizerRecommendationsController.dismiss
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_582
      summary: Dismiss a recommendation.
      tags: *ref_583
  /v2/organizer/recommendations/{id}/complete:
    post:
      operationId: OrganizerRecommendationsController.complete
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_582
      summary: Mark a recommendation as actioned.
      tags: *ref_583
  /v2/organizer/analytics/events/{eventId}/funnel:
    get:
      operationId: OrganizerAnalyticsController.funnel
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: &ref_584
        - bearer: []
      summary: >-
        Per-event funnel counts: registered → paid → checked-in → attended →
        (finished if hybrid). Earlier stages (view, interest) not instrumented;
        see VD-A1.
      tags: &ref_585
        - 'Organizer: Analytics drill-down'
  /v2/organizer/analytics/cohorts:
    get:
      operationId: OrganizerAnalyticsController.cohorts
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_584
      summary: >-
        Cohort retention matrix for this organizer. Requires 10 participants + 2
        events as a minimum; smaller orgs get a structured insufficient-data
        response.
      tags: *ref_585
  /v2/organizer/analytics/attribution:
    get:
      operationId: >-
        OrganizerAnalyticsController.attribution_get_v2_organizer_analytics_attribution
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_584
      summary: >-
        UTM attribution placeholder — UTM capture on registration is not
        instrumented today. Tracked under VD-A2.
      tags: *ref_585
  /v2/organizer/analytics/events/{eventId}/funnel.csv:
    get:
      operationId: OrganizerAnalyticsController.funnelCsv
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_584
      summary: >-
        Per-event funnel as CSV — deterministic headers
        (stage,count,conversionFromPrev,percentOfPeak).
      tags: *ref_585
  /v2/organizer/analytics/events/{eventId}/avg-ticket-price:
    get:
      operationId: OrganizerAnalyticsController.avgTicketPrice
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_584
      summary: >-
        Per-event weighted-average ticket price + paid-only avg + free share
        (PRD §42.1 G-42-2).
      tags: *ref_585
  /v2/organizer/analytics/events/{eventId}/sales:
    get:
      operationId: OrganizerAnalyticsController.sales
      parameters:
        - name: eventId
          required: true
          in: path
          schema:
            type: string
        - name: recentOrdersLimit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_584
      summary: >-
        Per-event sales tab (complement to organizer/events/:eventId/finance):
        sales-by-category, coupons, add-ons, recent orders, ticket inventory.
      tags: *ref_585
  /v2/organizers/{organizerId}/reports/schema:
    get:
      operationId: OrganizerReportsController.schema
      parameters: []
      responses:
        '200':
          description: ''
      security: &ref_586
        - bearer: []
      summary: Report-builder schema (whitelisted sources/columns/aggregations).
      tags: &ref_587
        - 'Organizer: Custom Reports'
  /v2/organizers/{organizerId}/reports:
    post:
      operationId: OrganizerReportsController.create
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_586
      summary: Create a custom report template (DRAFT).
      tags: *ref_587
    get:
      operationId: OrganizerReportsController.list
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_586
      summary: List all report templates for the organizer.
      tags: *ref_587
  /v2/organizers/{organizerId}/reports/{id}:
    patch:
      operationId: OrganizerReportsController.update
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_586
      summary: Update a report template definition.
      tags: *ref_587
    get:
      operationId: OrganizerReportsController.getOne
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_586
      summary: Fetch a single report template.
      tags: *ref_587
  /v2/organizers/{organizerId}/reports/{id}/archive:
    post:
      operationId: OrganizerReportsController.archive
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_586
      summary: Archive a report template (terminal).
      tags: *ref_587
  /v2/organizers/{organizerId}/reports/{id}/run:
    post:
      operationId: OrganizerReportsController.run
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      security: *ref_586
      summary: Execute the template now and return result rows (limited).
      tags: *ref_587
  /v2/organizers/{organizerId}/reports/{id}/schedule:
    patch:
      operationId: OrganizerReportsController.setSchedule
      parameters:
        - name: organizerId
          required: true
          in: path
          schema:
            type: string
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_586
      summary: >-
        Set or update the cron schedule + recipient emails. PUBLISHED on first
        set.
      tags: *ref_587
  /v2/targets:
    post:
      operationId: TargetsController.createTarget
      parameters:
        - &ref_588
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: Content-Type
          in: header
          description: multipart/form-data
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              example:
                bannerFile: file
      responses:
        '201':
          description: ''
      summary: Create a single Target
      tags: &ref_589
        - Targets
    get:
      operationId: TargetsController.getAllTargets
      parameters:
        - *ref_588
      responses:
        '200':
          description: ''
      summary: Retrieve multiple Targets
      tags: *ref_589
  /v2/targets/{id}:
    get:
      operationId: TargetsController.getTarget
      parameters:
        - *ref_588
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Retrieve a single Target
      tags: *ref_589
    patch:
      operationId: TargetsController.updateTarget
      parameters:
        - *ref_588
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: Content-Type
          in: header
          description: multipart/form-data
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              example:
                bannerFile: file
      responses:
        '200':
          description: ''
      summary: Update a single Target
      tags: *ref_589
    delete:
      operationId: TargetsController.deleteTarget
      parameters:
        - *ref_588
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Delete a single Target
      tags: *ref_589
  /v2/sports:
    post:
      operationId: SportsController.createSport
      parameters:
        - &ref_590
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSportDto'
      responses:
        '201':
          description: ''
      tags: &ref_591
        - Sports
    get:
      operationId: SportsController.getSports
      parameters:
        - *ref_590
      responses:
        '200':
          description: ''
      tags: *ref_591
  /v2/sports/{id}:
    get:
      operationId: SportsController.getSport
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_591
    patch:
      operationId: SportsController.updateSport
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSportDto'
      responses:
        '200':
          description: ''
      tags: *ref_591
    delete:
      operationId: SportsController.deleteSport
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_591
  /v2/sports/{id}/topics:
    get:
      operationId: SportsController.getSportTopics
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_591
    post:
      operationId: SportsController.createSportTopic
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSportTopicDto'
      responses:
        '201':
          description: ''
      tags: *ref_591
  /v2/sports/{id}/topics/order:
    put:
      operationId: SportsController.reorderSportTopics
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReorderSportTaxonomyDto'
      responses:
        '200':
          description: ''
      tags: *ref_591
  /v2/sports/{id}/topics/{topicId}/subtopics/order:
    put:
      operationId: SportsController.reorderSportSubtopics
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: topicId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReorderSportTaxonomyDto'
      responses:
        '200':
          description: ''
      tags: *ref_591
  /v2/sports/{id}/topics/{topicId}:
    patch:
      operationId: SportsController.updateSportTopic
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: topicId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSportTopicDto'
      responses:
        '200':
          description: ''
      tags: *ref_591
    delete:
      operationId: SportsController.deleteSportTopic
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: topicId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_591
  /v2/sports/{id}/topics/{topicId}/subtopics:
    get:
      operationId: SportsController.getSportSubtopics
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: topicId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_591
    post:
      operationId: SportsController.createSportSubtopic
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: topicId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSportSubtopicDto'
      responses:
        '201':
          description: ''
      tags: *ref_591
  /v2/sports/{id}/topics/{topicId}/subtopics/{subtopicId}:
    patch:
      operationId: SportsController.updateSportSubtopic
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: topicId
          required: true
          in: path
          schema:
            type: string
        - name: subtopicId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSportSubtopicDto'
      responses:
        '200':
          description: ''
      tags: *ref_591
    delete:
      operationId: SportsController.deleteSportSubtopic
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: topicId
          required: true
          in: path
          schema:
            type: string
        - name: subtopicId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_591
  /v2/sports/{id}/challenges:
    get:
      operationId: SportsController.getChallengesBySport
      parameters:
        - *ref_590
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: 'Items per page (default: 10)'
          schema:
            type: number
        - name: page
          required: false
          in: query
          description: 'Page number (default: 1)'
          schema:
            type: number
      responses:
        '200':
          description: ''
      tags: *ref_591
  /v2/gear-types:
    post:
      operationId: GearTypesController.createGearType
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateGearTypeDto'
      responses:
        '201':
          description: ''
      tags: &ref_592
        - Gear Types
    get:
      operationId: GearTypesController.getGearTypes
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_592
  /v2/gear-types/{id}:
    get:
      operationId: GearTypesController.getGearType
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_592
    patch:
      operationId: GearTypesController.updateGearType
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateGearTypeDto'
      responses:
        '200':
          description: ''
      tags: *ref_592
    delete:
      operationId: GearTypesController.deleteGearType
      parameters: []
      responses:
        '200':
          description: ''
      tags: *ref_592
  /v2/products:
    post:
      operationId: ProductsController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProductDto'
      responses:
        '201':
          description: ''
      security: &ref_593
        - bearer: []
      tags: &ref_594
        - Products
    get:
      operationId: ProductsController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_593
      tags: *ref_594
  /v2/products/{id}:
    get:
      operationId: ProductsController.findOne
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_593
      tags: *ref_594
    patch:
      operationId: ProductsController.update
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProductDto'
      responses:
        '200':
          description: ''
      security: *ref_593
      tags: *ref_594
    delete:
      operationId: ProductsController.remove
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_593
      tags: *ref_594
  /v2/products/{id}/review:
    patch:
      operationId: ProductsController.review
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      security: *ref_593
      tags: *ref_594
  /v2/products/{id}/toggle:
    patch:
      operationId: ProductsController.toggleProductStatus
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_593
      tags: *ref_594
  /v2/product-categories:
    post:
      operationId: ProductCategoriesController.create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProductCategoryDto'
      responses:
        '201':
          description: ''
      security: &ref_595
        - bearer: []
      summary: Create a product category
      tags: &ref_596
        - Product Categories
    get:
      operationId: ProductCategoriesController.findAll
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_595
      summary: Get all product categories
      tags: *ref_596
  /v2/product-categories/{id}:
    get:
      operationId: ProductCategoriesController.findOne
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_595
      summary: Get a product category by id
      tags: *ref_596
    patch:
      operationId: ProductCategoriesController.update
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProductCategoryDto'
      responses:
        '200':
          description: ''
      security: *ref_595
      summary: Update a product category by id
      tags: *ref_596
    delete:
      operationId: ProductCategoriesController.remove
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_595
      summary: Delete a product category by id
      tags: *ref_596
  /v2/product-categories/{id}/review:
    patch:
      operationId: ProductCategoriesController.review
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewDto'
      responses:
        '200':
          description: ''
      security: *ref_595
      summary: Review a product category by id
      tags: *ref_596
  /v2/product-categories/{id}/toggle:
    patch:
      operationId: ProductCategoriesController.toggleStatus
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_595
      summary: Toggle a product category status
      tags: *ref_596
  /v2/form-fields:
    post:
      operationId: FormFieldsController.create
      parameters:
        - &ref_597
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFormFieldDto'
      responses:
        '201':
          description: ''
      tags: &ref_598
        - Form Fields
    get:
      operationId: FormFieldsController.findAll
      parameters:
        - *ref_597
      responses:
        '200':
          description: ''
      tags: *ref_598
  /v2/form-fields/{id}:
    get:
      operationId: FormFieldsController.findOne
      parameters:
        - *ref_597
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_598
    patch:
      operationId: FormFieldsController.update
      parameters:
        - *ref_597
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateFormFieldDto'
      responses:
        '200':
          description: ''
      tags: *ref_598
    delete:
      operationId: FormFieldsController.remove
      parameters:
        - *ref_597
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_598
  /v2/event-categories:
    post:
      operationId: EventCategoriesController.create
      parameters:
        - &ref_599
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventCategoriesDto'
      responses:
        '201':
          description: ''
      tags: &ref_600
        - Event Categories
    get:
      operationId: EventCategoriesController.findAll
      parameters:
        - *ref_599
      responses:
        '200':
          description: ''
      tags: *ref_600
  /v2/event-categories/{id}:
    get:
      operationId: EventCategoriesController.findOne
      parameters:
        - *ref_599
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_600
    patch:
      operationId: EventCategoriesController.update
      parameters:
        - *ref_599
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEventCategoriesDto'
      responses:
        '200':
          description: ''
      tags: *ref_600
    delete:
      operationId: EventCategoriesController.remove
      parameters:
        - *ref_599
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_600
  /v2/app-privacy-policies:
    post:
      operationId: PrivacyPoliciesController.create_post_v2_app_privacy_policies
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePrivacyPolicyDto'
      responses:
        '201':
          description: ''
      security: &ref_601
        - bearer: []
      tags: &ref_602
        - App Privacy Policies
    get:
      operationId: PrivacyPoliciesController.findAll_get_v2_app_privacy_policies
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_601
      tags: *ref_602
  /v2/app-privacy-policies/active:
    get:
      operationId: PrivacyPoliciesController.findActive
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_601
      tags: *ref_602
  /v2/app-privacy-policies/{id}:
    get:
      operationId: PrivacyPoliciesController.findOne_get_v2_app_privacy_policies_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_601
      tags: *ref_602
    patch:
      operationId: PrivacyPoliciesController.update_patch_v2_app_privacy_policies_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePrivacyPolicyDto'
      responses:
        '200':
          description: ''
      security: *ref_601
      tags: *ref_602
    delete:
      operationId: PrivacyPoliciesController.remove_delete_v2_app_privacy_policies_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_601
      tags: *ref_602
  /v2/app-privacy-policies/{id}/public:
    get:
      operationId: >-
        PrivacyPoliciesController.findOnePublic_get_v2_app_privacy_policies_id_public
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_601
      tags: *ref_602
  /v2/app-privacy-policies/{id}/toggle:
    patch:
      operationId: >-
        PrivacyPoliciesController.togglePPStatus_patch_v2_app_privacy_policies_id_toggle
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_601
      tags: *ref_602
  /v2/app-terms-and-conditions:
    post:
      operationId: TermsAndConditionsController.create_post_v2_app_terms_and_conditions
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTermsAndConditionDto'
      responses:
        '201':
          description: ''
      security: &ref_603
        - bearer: []
      tags: &ref_604
        - App Terms and Conditions
    get:
      operationId: TermsAndConditionsController.findAll_get_v2_app_terms_and_conditions
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_603
      tags: *ref_604
  /v2/app-terms-and-conditions/active:
    get:
      operationId: TermsAndConditionsController.findActive
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_603
      tags: *ref_604
  /v2/app-terms-and-conditions/{id}:
    get:
      operationId: TermsAndConditionsController.findOne_get_v2_app_terms_and_conditions_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_603
      tags: *ref_604
    patch:
      operationId: TermsAndConditionsController.update_patch_v2_app_terms_and_conditions_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTermsAndConditionDto'
      responses:
        '200':
          description: ''
      security: *ref_603
      tags: *ref_604
    delete:
      operationId: >-
        TermsAndConditionsController.remove_delete_v2_app_terms_and_conditions_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_603
      tags: *ref_604
  /v2/app-terms-and-conditions/{id}/public:
    get:
      operationId: >-
        TermsAndConditionsController.findOnePublic_get_v2_app_terms_and_conditions_id_public
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_603
      tags: *ref_604
  /v2/app-terms-and-conditions/{id}/toggle:
    patch:
      operationId: >-
        TermsAndConditionsController.toggleTNCStatus_patch_v2_app_terms_and_conditions_id_toggle
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_603
      tags: *ref_604
  /v2/app-frequently-asked-questions:
    post:
      operationId: >-
        FrequentlyAskedQuestionsController.create_post_v2_app_frequently_asked_questions
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFrequentlyAskedQuestionDto'
      responses:
        '201':
          description: ''
      security: &ref_605
        - bearer: []
      tags: &ref_606
        - App Frequently Asked Questions
    get:
      operationId: >-
        FrequentlyAskedQuestionsController.findAll_get_v2_app_frequently_asked_questions
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_605
      tags: *ref_606
  /v2/app-frequently-asked-questions/public:
    get:
      operationId: FrequentlyAskedQuestionsController.findAllPublic
      parameters: []
      responses:
        '200':
          description: ''
      security: *ref_605
      tags: *ref_606
  /v2/app-frequently-asked-questions/public/search:
    get:
      operationId: FrequentlyAskedQuestionsController.searchPublic
      parameters:
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      security: *ref_605
      summary: Public KB search — relevance-ranked results across question + answer.
      tags: *ref_606
  /v2/app-frequently-asked-questions/{id}:
    get:
      operationId: >-
        FrequentlyAskedQuestionsController.findOne_get_v2_app_frequently_asked_questions_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_605
      tags: *ref_606
    patch:
      operationId: >-
        FrequentlyAskedQuestionsController.update_patch_v2_app_frequently_asked_questions_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateFrequentlyAskedQuestionDto'
      responses:
        '200':
          description: ''
      security: *ref_605
      tags: *ref_606
    delete:
      operationId: >-
        FrequentlyAskedQuestionsController.remove_delete_v2_app_frequently_asked_questions_id
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_605
      tags: *ref_606
  /v2/app-frequently-asked-questions/{id}/public:
    get:
      operationId: FrequentlyAskedQuestionsController.findOnePublic
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_605
      tags: *ref_606
  /v2/app-frequently-asked-questions/{id}/toggle:
    patch:
      operationId: >-
        FrequentlyAskedQuestionsController.toggleFAQStatus_patch_v2_app_frequently_asked_questions_id_toggle
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      security: *ref_605
      tags: *ref_606
  /v2/admin/training-plans/stats:
    get:
      description: >-
        Returns comprehensive statistics including total plans, revenue
        breakdown, program level distribution, sport type distribution, and
        monthly trends.
      operationId: AdminTrainingPlansController.getTrainingPlanStats
      parameters:
        - &ref_607
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: startDate
          required: false
          in: query
          description: Filter start date (ISO 8601)
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: Filter end date (ISO 8601)
          schema:
            example: '2026-12-31'
            type: string
        - name: programLevel
          required: false
          in: query
          description: Filter by program level
          schema:
            enum:
              - active
              - athlete
              - goat
            type: string
        - name: sportType
          required: false
          in: query
          description: Filter by sport type
          schema:
            enum:
              - running
              - cycling
              - swimming
              - triathlon
              - hiking_trekking
            type: string
      responses:
        '200':
          description: Training plan statistics retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingPlanStatsResponseDto'
        '403':
          description: Forbidden - Admin role required
      summary: Get training plan statistics for dashboard
      tags: &ref_608
        - Admin - Training Plans
  /v2/admin/training-plans/users:
    get:
      description: >-
        Returns a paginated list of users with their training plan statistics
        including total plans, revenue, and active plans.
      operationId: AdminTrainingPlansController.getUserTrainingPlanStats
      parameters:
        - *ref_607
        - name: startDate
          required: false
          in: query
          description: Filter start date (ISO 8601)
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: Filter end date (ISO 8601)
          schema:
            example: '2026-12-31'
            type: string
        - name: programLevel
          required: false
          in: query
          description: Filter by program level
          schema:
            enum:
              - active
              - athlete
              - goat
            type: string
        - name: sportType
          required: false
          in: query
          description: Filter by sport type
          schema:
            enum:
              - running
              - cycling
              - swimming
              - triathlon
              - hiking_trekking
            type: string
        - name: page
          required: false
          in: query
          description: Page number (1-based)
          schema:
            default: 1
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Items per page (max 100)
          schema:
            default: 20
            example: 20
            type: number
        - name: status
          required: false
          in: query
          description: Filter by plan status
          schema:
            enum:
              - active
              - completed
              - cancelled
              - expired
            type: string
      responses:
        '200':
          description: User training plan statistics retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserTrainingPlanListResponseDto'
        '403':
          description: Forbidden - Admin role required
      summary: Get user-wise training plan statistics
      tags: *ref_608
  /v2/admin/training-plans/list:
    get:
      description: >-
        Returns a paginated list of all training plans with detailed information
        for admin review.
      operationId: AdminTrainingPlansController.getTrainingPlansList
      parameters:
        - *ref_607
        - name: startDate
          required: false
          in: query
          description: Filter start date (ISO 8601)
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: Filter end date (ISO 8601)
          schema:
            example: '2026-12-31'
            type: string
        - name: programLevel
          required: false
          in: query
          description: Filter by program level
          schema:
            enum:
              - active
              - athlete
              - goat
            type: string
        - name: sportType
          required: false
          in: query
          description: Filter by sport type
          schema:
            enum:
              - running
              - cycling
              - swimming
              - triathlon
              - hiking_trekking
            type: string
        - name: page
          required: false
          in: query
          description: Page number (1-based)
          schema:
            default: 1
            example: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Items per page (max 100)
          schema:
            default: 20
            example: 20
            type: number
        - name: status
          required: false
          in: query
          description: Filter by plan status
          schema:
            enum:
              - active
              - completed
              - cancelled
              - expired
            type: string
      responses:
        '200':
          description: Training plans list retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingPlanListResponseDto'
        '403':
          description: Forbidden - Admin role required
      summary: Get all training plans with filters
      tags: *ref_608
  /v2/admin/training-plans/revenue:
    get:
      description: >-
        Returns detailed revenue breakdown including total revenue, paid/free
        plans count, and revenue by program level.
      operationId: AdminTrainingPlansController.getRevenueSummary
      parameters:
        - *ref_607
        - name: startDate
          required: false
          in: query
          description: Filter start date (ISO 8601)
          schema:
            example: '2026-01-01'
            type: string
        - name: endDate
          required: false
          in: query
          description: Filter end date (ISO 8601)
          schema:
            example: '2026-12-31'
            type: string
      responses:
        '200':
          description: Revenue summary retrieved successfully
        '403':
          description: Forbidden - Admin role required
      summary: Get revenue summary
      tags: *ref_608
  /v2/admin/challenge-management/stats:
    get:
      operationId: ChallengeManagementController.getChallengeProgressStats
      parameters:
        - &ref_609
          name: Authorization
          in: header
          description: Bearer Token (Admin)
          schema:
            type: string
        - name: challengeId
          required: false
          in: query
          description: Filter by challenge ID
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get challenge progress dashboard stats
      tags: &ref_610
        - Admin - Challenge Management
  /v2/admin/challenge-management/activities:
    get:
      operationId: ChallengeManagementController.getUserActivities
      parameters:
        - *ref_609
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: userId
          required: false
          in: query
          description: Filter by user ID
          schema:
            type: string
        - name: sportName
          required: false
          in: query
          description: Filter by sport name (walking, running, cycling)
          schema:
            type: string
        - name: date
          required: false
          in: query
          description: Filter by date (YYYY-MM-DD)
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get all user activities (admin view)
      tags: *ref_610
  /v2/admin/challenge-management/activities/{activityId}:
    get:
      operationId: ChallengeManagementController.getUserActivityDetail
      parameters:
        - *ref_609
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get activity detail by ID
      tags: *ref_610
  /v2/admin/challenge-management/activities/{activityId}/validation:
    patch:
      operationId: ChallengeManagementController.setActivityValidation
      parameters:
        - *ref_609
        - name: activityId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Set an activity validation status (operator)
      tags: *ref_610
  /v2/admin/challenge-management/participations:
    get:
      operationId: ChallengeManagementController.getChallengeParticipations
      parameters:
        - *ref_609
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: challengeId
          required: false
          in: query
          description: Filter by challenge ID
          schema:
            type: string
        - name: userId
          required: false
          in: query
          description: Filter by user ID
          schema:
            type: string
        - name: isCompleted
          required: false
          in: query
          description: Filter by completion status (true/false)
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get all challenge participations (admin view)
      tags: *ref_610
  /v2/admin/challenge-management/participations/{participationId}:
    get:
      operationId: ChallengeManagementController.getChallengeParticipationDetail
      parameters:
        - *ref_609
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get challenge participation detail with daily progress
      tags: *ref_610
  /v2/admin/challenge-management/history-logs:
    get:
      operationId: ChallengeManagementController.getChallengeUpdateHistoryLogs
      parameters:
        - *ref_609
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: userId
          required: false
          in: query
          description: Filter by user ID
          schema:
            type: string
        - name: challengeId
          required: false
          in: query
          description: Filter by challenge ID
          schema:
            type: string
        - name: activityId
          required: false
          in: query
          description: Filter by activity ID
          schema:
            type: string
        - name: status
          required: false
          in: query
          description: Filter by status (success, failed, skipped)
          schema:
            type: string
        - name: action
          required: false
          in: query
          description: >-
            Filter by action (activity_created, activity_updated,
            cron_reconcile)
          schema:
            type: string
        - name: date
          required: false
          in: query
          description: Filter by activity date (YYYY-MM-DD)
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get challenge update history logs
      tags: *ref_610
  /v2/admin/challenge-management/users/{userId}/summary:
    get:
      operationId: ChallengeManagementController.getUserChallengesSummary
      parameters:
        - *ref_609
        - name: userId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get user challenge summary (participations, activities, logs)
      tags: *ref_610
  /v2/admin/challenge-management/challenges:
    get:
      operationId: ChallengeManagementController.listChallenges
      parameters:
        - *ref_609
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: search
          required: false
          in: query
          description: Filter by title
          schema:
            type: string
        - name: isActive
          required: false
          in: query
          description: Filter by active state (true/false)
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List challenges (admin moderation table)
      tags: *ref_610
  /v2/admin/challenge-management/challenges/{id}/close:
    patch:
      operationId: ChallengeManagementController.closeChallenge
      parameters:
        - *ref_609
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ModerationActionDto'
      responses:
        '200':
          description: ''
      summary: Force-close a challenge (deactivate)
      tags: *ref_610
  /v2/admin/challenge-management/challenges/{id}/reopen:
    patch:
      operationId: ChallengeManagementController.reopenChallenge
      parameters:
        - *ref_609
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ModerationActionDto'
      responses:
        '200':
          description: ''
      summary: Reopen a previously force-closed challenge
      tags: *ref_610
  /v2/admin/challenge-management/participations/{participationId}/revoke:
    post:
      operationId: ChallengeManagementController.revokeParticipation
      parameters:
        - *ref_609
        - name: participationId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ModerationActionDto'
      responses:
        '201':
          description: ''
      summary: Revoke an athlete challenge participation
      tags: *ref_610
  /v2/admin/events:
    get:
      operationId: AdminEventsController.listEvents
      parameters:
        - &ref_611
          name: Authorization
          in: header
          description: Bearer Token (Admin)
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: status
          required: false
          in: query
          description: Filter by event status
          schema:
            type: string
        - name: visibility
          required: false
          in: query
          description: public | private
          schema:
            type: string
        - name: search
          required: false
          in: query
          description: Title / name / organizer
          schema:
            type: string
        - name: organizerId
          required: false
          in: query
          description: Filter by organizer
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List all events across organizers (admin)
      tags: &ref_612
        - Admin - Events Oversight
  /v2/admin/events/stats:
    get:
      operationId: AdminEventsController.getEventStats
      parameters:
        - *ref_611
      responses:
        '200':
          description: ''
      summary: Event status breakdown (dashboard tiles)
      tags: *ref_612
  /v2/admin/events/{id}:
    get:
      operationId: AdminEventsController.getEvent
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get one event (admin detail)
      tags: *ref_612
  /v2/admin/events/{id}/bookings:
    get:
      operationId: AdminEventsController.getEventBookings
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: List registrations/bookings for an event (admin)
      tags: *ref_612
  /v2/admin/events/{id}/participants:
    get:
      operationId: AdminEventsController.getEventParticipants
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
      responses:
        '200':
          description: ''
      summary: List participants for an event (admin roster)
      tags: *ref_612
  /v2/admin/events/{id}/revenue:
    get:
      operationId: AdminEventsController.getEventRevenue
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Revenue summary for an event (admin)
      tags: *ref_612
  /v2/admin/events/{id}/status:
    patch:
      operationId: AdminEventsController.updateStatus
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEventStatusDto'
      responses:
        '200':
          description: ''
      summary: Override an event status (suspend / reinstate / cancel)
      tags: *ref_612
  /v2/admin/events/{id}/restore-cancelled:
    post:
      operationId: AdminEventsController.restoreCancelled
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RestoreCancelledEventDto'
      responses:
        '201':
          description: ''
      summary: Restore a cancelled event to a public, active published listing
      tags: *ref_612
  /v2/admin/events/{id}/replace-uuid:
    post:
      operationId: AdminEventsController.replaceUuid
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReplaceEventUuidDto'
      responses:
        '201':
          description: ''
      summary: Replace an event primary UUID and move all relational references
      tags: *ref_612
  /v2/admin/events/{id}/suspend:
    post:
      operationId: AdminEventsController.suspend
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SuspendEventDto'
      responses:
        '201':
          description: ''
      summary: Suspend an event (blocks writes + new registrations, holds settlements)
      tags: *ref_612
  /v2/admin/events/{id}/unsuspend:
    post:
      operationId: AdminEventsController.unsuspend
      parameters:
        - *ref_611
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '201':
          description: ''
      summary: Unsuspend an event (restores prior status, clears holds)
      tags: *ref_612
  /v2/admin/events/{eventId}/ticket-sales/slot-wise:
    get:
      operationId: AdminEventTicketSalesController.getSlotWise
      parameters:
        - &ref_613
          name: Authorization
          in: header
          description: Bearer Token (Admin)
          schema:
            type: string
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Slot-wise breakdown retrieved
        '404':
          description: Event not found
      summary: Slot-wise ticket-sales breakdown for any event (admin, cross-organizer).
      tags: &ref_614
        - Admin - Event Ticket Sales
  /v2/admin/events/{eventId}/ticket-sales/ticket-wise:
    get:
      operationId: AdminEventTicketSalesController.getTicketWise
      parameters:
        - *ref_613
        - name: eventId
          required: true
          in: path
          description: Event ID
          schema:
            type: string
      responses:
        '200':
          description: Ticket-wise breakdown retrieved
        '404':
          description: Event not found
      summary: >-
        Ticket-wise ticket-sales breakdown for any event (admin,
        cross-organizer).
      tags: *ref_614
  /v2/admin/editions:
    get:
      operationId: AdminEditionsController.listEditions
      parameters:
        - &ref_615
          name: Authorization
          in: header
          description: Bearer Token (Admin)
          schema:
            type: string
        - name: page
          required: false
          in: query
          schema:
            type: number
        - name: limit
          required: false
          in: query
          schema:
            type: number
        - name: status
          required: false
          in: query
          schema:
            type: string
        - name: type
          required: false
          in: query
          schema:
            type: string
        - name: search
          required: false
          in: query
          description: Title / slug / city
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: List all editions across events/organizers
      tags: &ref_616
        - Admin - Editions Oversight
  /v2/admin/editions/stats:
    get:
      operationId: AdminEditionsController.getEditionStats
      parameters:
        - *ref_615
      responses:
        '200':
          description: ''
      summary: Edition status breakdown (dashboard tiles)
      tags: *ref_616
  /v2/admin/editions/{id}:
    get:
      operationId: AdminEditionsController.getEdition
      parameters:
        - *ref_615
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      summary: Get one edition (admin detail)
      tags: *ref_616
  /v2/admin/editions/{id}/status:
    patch:
      operationId: AdminEditionsController.updateStatus
      parameters:
        - *ref_615
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEditionStatusDto'
      responses:
        '200':
          description: ''
      summary: Override an edition status (publish / cancel / etc.)
      tags: *ref_616
  /v2/admin/users:
    get:
      operationId: AdminUsersController.search
      parameters:
        - name: q
          required: true
          in: query
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: &ref_617
        - 'Admin: Users'
  /v2/admin/users/{id}/overview:
    get:
      operationId: AdminUsersController.overview
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_617
  /v2/admin/users/{id}/challenges:
    get:
      operationId: AdminUsersController.challenges
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_617
  /v2/admin/users/{id}/activities:
    get:
      operationId: AdminUsersController.activities
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_617
  /v2/admin/users/{id}/events:
    get:
      operationId: AdminUsersController.events
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_617
  /v2/admin/users/{id}/wallet/history:
    get:
      operationId: AdminUsersController.walletHistory
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: page
          required: true
          in: query
          schema:
            type: string
        - name: limit
          required: true
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_617
  /v2/challenges/{creatorType}/{creatorId}/badge-requests:
    post:
      operationId: ChallengeBadgeRequestsController.create
      parameters:
        - &ref_618
          name: Authorization
          in: header
          description: Bearer Token
          schema:
            type: string
        - name: creatorType
          required: true
          in: path
          schema:
            type: string
        - name: creatorId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBadgeRequestDto'
      responses:
        '201':
          description: ''
      tags: &ref_619
        - Challenge Badge Requests
    get:
      operationId: ChallengeBadgeRequestsController.list
      parameters:
        - *ref_618
        - name: creatorType
          required: true
          in: path
          schema:
            type: string
        - name: creatorId
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
      tags: *ref_619
info:
  title: Repeak Backend API
  description: >-
    Unified OpenAPI reference for the Repeak backend. Covers public, user,
    organizer, sponsor, and admin endpoints with live try-it support.
  version: v2
  contact: {}
tags: []
servers:
  - url: https://api.repeak.in
    description: Current origin
components:
  securitySchemes:
    bearer:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: Paste an access token here to test authenticated endpoints.
  schemas:
    BadgeConditionDto:
      type: object
      properties:
        condition_type:
          type: string
          example: events_attended_count
        operator:
          type: string
          example: gte
          enum:
            - gte
            - lte
            - eq
            - between
            - in
        value:
          type: object
          example: 1
        value2:
          type: number
          example: 10
        time_window:
          type: string
          example: all_time
          enum:
            - all_time
            - daily
            - weekly
            - monthly
            - yearly
        activity_type_filter:
          type: string
          example: running
          enum:
            - running
            - hiking
            - cycling
            - walking
      required:
        - condition_type
        - operator
        - value
    CreateBadgeDto:
      type: object
      properties:
        name:
          type: string
          description: Badge name
          example: First Finish
        description:
          type: string
          description: Badge description
          example: Attend your first event
        iconUrl:
          type: string
          description: Icon URL
        color:
          type: string
          description: Hex color
          example: '#FF5733'
        sourceSystem:
          type: string
          description: Source system
          enum: &ref_681
            - event
            - activity
            - steps
            - challenge
            - special
          example: event
        activityTypeFilter:
          type: string
          description: Activity type filter
          enum: &ref_682
            - running
            - hiking
            - cycling
            - walking
        rarity:
          type: string
          description: Rarity tier
          enum: &ref_683
            - bronze
            - silver
            - gold
            - diamond
            - platinum
            - legendary
          example: bronze
        points:
          type: number
          description: Points value
          example: 50
        conditions:
          description: Conditions array
          type: array
          items:
            $ref: '#/components/schemas/BadgeConditionDto'
        conditionLogic:
          type: string
          description: Condition logic (AND/OR)
          enum: &ref_684
            - AND
            - OR
          default: AND
        isHidden:
          type: boolean
          description: Hidden until earned?
          default: false
        isRepeatable:
          type: boolean
          description: Can badge be earned multiple times?
          default: false
        repeatCooldownDays:
          type: number
          description: Cooldown days for repeatable badges
        isTimeLimited:
          type: boolean
          description: Is time-limited?
          default: false
        availableFrom:
          format: date-time
          type: string
          description: Available from date
        availableUntil:
          format: date-time
          type: string
          description: Available until date
        mappedChallengeId:
          type: string
          description: Mapped challenge ID
        isActive:
          type: boolean
          description: Is badge active?
          default: true
      required:
        - name
        - description
        - sourceSystem
        - rarity
        - points
        - conditions
    RejectBadgeRequestDto:
      type: object
      properties:
        reason:
          type: string
          description: Reason the badge request is being rejected
      required:
        - reason
    OAuthLoginDto:
      type: object
      properties:
        role:
          type: string
          description: >-
            Which account type to resolve into. Defaults to athlete login.
            Organizer login never creates an account — an unmatched email 404s.
          enum: &ref_620
            - user
            - organizer
          example: user
    AppleOAuthSessionDto:
      type: object
      properties:
        webReturnUri:
          type: string
          description: >-
            Exact web return URL. Its origin must be listed in
            APPLE_WEB_RETURN_ORIGINS.
        codeChallenge:
          type: string
          description: Base64url SHA-256 challenge for the browser-held verifier.
    AppleOAuthCallbackDto:
      type: object
      properties:
        code:
          type: string
        id_token:
          type: string
        state:
          type: string
        user:
          type: string
          description: First-authorization profile JSON supplied by Apple.
        error:
          type: string
    AppleOAuthWebExchangeDto:
      type: object
      properties:
        result:
          type: string
        codeVerifier:
          type: string
      required:
        - result
        - codeVerifier
    AppleOAuthLoginDto:
      type: object
      properties:
        role:
          type: string
          description: >-
            Which account type to resolve into. Defaults to athlete login.
            Organizer login never creates an account — an unmatched email 404s.
          enum: *ref_620
          example: user
        authorizationCode:
          type: string
          description: >-
            Single-use authorization code returned by Apple. Required with state
            for current clients; omitted only by legacy iOS releases.
        state:
          type: string
          description: >-
            Opaque state minted by /auth/oauth/apple/session. Required with
            authorizationCode for current clients.
    SendOTPDto:
      type: object
      properties:
        isBot:
          type: boolean
          description: >-
            Set to true to register or log in a bot account using the configured
            bot OTP. No SMS is sent.
          example: false
        phoneNumber:
          type: string
          description: >-
            Phone number of the user based in india (user) or dubai (merchant).
            Required for bot login too.
          example: '+917710957578'
      required:
        - phoneNumber
    VerifyOTPDto:
      type: object
      properties:
        isBot:
          type: boolean
          description: >-
            Set to true to register or log in a bot account using the configured
            bot OTP. No SMS is sent.
          example: false
        phoneNumber:
          type: string
          description: >-
            Phone number of the user based in india (user) or dubai (merchant).
            Required for bot login too.
          example: '+917710957578'
        role:
          type: string
          description: 'Role of the user '
          enum:
            - user
            - organizer
            - admin
            - sponsor
            - volunteer
          example: user
        otp:
          type: string
          description: >-
            OTP sent to the phone number. Bot accounts use the
            environment-configured default bot OTP.
          example: '7710'
        totpCode:
          type: string
          description: >-
            TOTP 2FA code (6 digits) or 16-char recovery code. Required when the
            identity has 2FA enabled or enforced.
      required:
        - phoneNumber
        - role
        - otp
    BindPhoneDto:
      type: object
      properties:
        phoneNumber:
          type: string
          description: The new phone number to attach (E.164, +91…).
          example: '+917710957578'
        otp:
          type: string
          description: The 4-digit OTP sent to phoneNumber.
          example: '1234'
      required:
        - phoneNumber
        - otp
    SendEmailOtpDto:
      type: object
      properties:
        email:
          type: string
          description: Email address to send the 4-digit login code to.
          example: athlete@example.com
        role:
          type: string
          description: >-
            Which account type to resolve into. Defaults to athlete login.
            Organizer login never creates an account — an unmatched email 404s.
          enum: &ref_621
            - user
            - organizer
          example: user
      required:
        - email
    VerifyEmailOtpDto:
      type: object
      properties:
        email:
          type: string
          description: Email address to send the 4-digit login code to.
          example: athlete@example.com
        role:
          type: string
          description: >-
            Which account type to resolve into. Defaults to athlete login.
            Organizer login never creates an account — an unmatched email 404s.
          enum: *ref_621
          example: user
        otp:
          type: string
          description: The 4-digit code emailed to the address.
          example: '4819'
        totpCode:
          type: string
          description: >-
            TOTP 2FA code (6 digits) or 16-char recovery code. Required when the
            account has 2FA enabled or enforced.
      required:
        - email
        - otp
    CreateAdminDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the Admin
        handle:
          type: string
          description: >-
            Unique handle for the Admin (lowercase, alphanumeric, underscores,
            hyphens)
        phoneNumber:
          type: string
          description: Phone number of the Admin
        email:
          type: string
          description: Email address of the Admin
        isActive:
          type: boolean
          description: Is the admin active
          default: true
        permissions:
          type: array
          description: Admin permissions
          items: &ref_622
            type: string
            enum:
              - super_admin
              - view_admins
              - create_admins
              - update_admins
              - delete_admins
              - view_users
              - update_users
              - delete_users
              - view_organizers
              - update_organizers
              - delete_organizers
              - view_events
              - create_events
              - update_events
              - delete_events
              - view_challenges
              - create_challenges
              - update_challenges
              - delete_challenges
              - view_notifications
              - create_notifications
              - update_notifications
              - delete_notifications
              - view_templates
              - create_templates
              - update_templates
              - delete_templates
              - view_payments
              - update_payments
              - view_settings
              - update_settings
              - view_badges
              - create_badges
              - update_badges
              - delete_badges
              - view_approvals
              - update_approvals
              - view_logs
              - view_analytics
              - view_full_pii
      required:
        - name
        - phoneNumber
        - email
    GetManyAdminResponseDto:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Admin'
        count:
          type: number
        total:
          type: number
        page:
          type: number
        pageCount:
          type: number
      required:
        - data
        - count
        - total
        - page
        - pageCount
    Admin:
      type: object
      properties: {}
    UpdateAdminDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the Admin
        handle:
          type: string
          description: >-
            Unique handle for the Admin (lowercase, alphanumeric, underscores,
            hyphens)
        phoneNumber:
          type: string
          description: Phone number of the Admin
        email:
          type: string
          description: Email address of the Admin
        isActive:
          type: boolean
          description: Is the admin active
          default: true
        permissions:
          type: array
          description: Admin permissions
          items: *ref_622
    UpdateAdminNotificationPreferenceDto:
      type: object
      properties:
        smsEnabled:
          type: boolean
          description: Enable or disable SMS notifications
        emailEnabled:
          type: boolean
          description: Enable or disable Email notifications
        whatsappEnabled:
          type: boolean
          description: Enable or disable WhatsApp notifications
    CreateManyAdminDto:
      type: object
      properties:
        bulk:
          type: array
          items:
            $ref: '#/components/schemas/Admin'
      required:
        - bulk
    UpsertOfficialPartnerExclusiveTabDto:
      type: object
      properties:
        officialPartnerId:
          type: string
          format: uuid
        tabTitle:
          type: string
          example: Partner
          maxLength: 7
        tabLogoImageUrl:
          type: string
        destinationType:
          type: string
          enum:
            - EVENT_DETAIL
            - CHALLENGE_DETAIL
        destinationId:
          type: string
          format: uuid
        isEnabled:
          type: boolean
          default: true
        expectedVersion:
          type: number
          description: Current admin projection version. Rejects a stale concurrent write.
          minimum: 1
      required:
        - officialPartnerId
        - tabTitle
        - tabLogoImageUrl
        - destinationType
        - destinationId
    UpsertOfficialPartnerDto:
      type: object
      properties:
        subjectType:
          type: string
          enum:
            - ORGANIZER
            - CLUB
        subjectId:
          type: string
          format: uuid
          description: Existing Organizer or Club id selected from the candidates endpoint.
        partnershipTitle:
          type: string
          example: Official Endurance Partner
        participantCardTagline:
          type: string
          nullable: true
          maxLength: 100
          description: Plain-text campaign line shown on participant race-share cards.
          example: Run the city. Own the finish.
        partnerLogo3dUrl:
          type: string
        partnerLogoImageUrl:
          type: string
          description: >-
            Public URL returned by POST /v2/admin/official-partners/logo-images.
            Preferred replacement for partnerLogo3dUrl.
          nullable: true
        benefits:
          type: object
          description: >-
            Extensible benefit-code map. Known codes are validated server-side;
            unknown codes are preserved for future features.
          example:
            platformFeeDiscountPct: 25
            freeCloudStorageGb: 100
            featuredEventEnabled: true
            premiumEventDetailsEnabled: true
        benefitsVersion:
          type: number
          default: 1
        validFrom:
          type: string
        validUntil:
          type: string
          nullable: true
        isEnabled:
          type: boolean
          default: true
        internalNotes:
          type: string
      required:
        - subjectType
        - subjectId
        - partnershipTitle
        - benefits
        - validFrom
    RemoveOfficialPartnerDto:
      type: object
      properties:
        reason:
          type: string
          description: >-
            Free-text justification for the destructive action. 10–500 chars
            after trim. Stored as audit metadata length only — the raw text is
            NEVER stored in the audit log.
          minLength: 10
          maxLength: 500
      required:
        - reason
    UpsertMobileExperienceDto:
      type: object
      properties: {}
    CreateOrganizerIfNotExistsDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the Organizer
        phoneNumber:
          type: string
          description: Phone number of the Organizer
        email:
          type: string
          description: Email address of the Organizer
        companyName:
          type: string
          description: Name of the company
      required:
        - name
        - phoneNumber
        - email
        - companyName
    UpdateOrganizerDeclarationDetailsDto:
      type: object
      properties:
        panNumber:
          type: string
          description: PAN number (10 characters, alphanumeric)
          example: ABCDE1234F
        businessRegistrationNumber:
          type: string
          description: Business registration number
          example: U74999MH2021PTC123456
        address:
          type: string
          description: Complete address
          example: 123, ABC Street, Near XYZ Mall
        city:
          type: string
          description: City
          example: Mumbai
        state:
          type: string
          description: State
          example: Maharashtra
        pincode:
          type: string
          description: Pincode (6 digits)
          example: '400001'
    CreateOrganizerStaffTaskDto:
      type: object
      properties: {}
    UpdateOrganizerStaffTaskDto:
      type: object
      properties: {}
    VerifyBankAccountDto:
      type: object
      properties:
        accountNumber:
          type: string
          description: Bank account number — digits only, 4–30 characters.
          example: '50100123456789'
          minLength: 4
          maxLength: 30
        ifsc:
          type: string
          description: >-
            IFSC code — exactly 11 characters: 4 letters, a 0, then 6
            alphanumerics.
          example: HDFC0000123
          minLength: 11
          maxLength: 11
      required:
        - accountNumber
        - ifsc
    SuspendOrganizerDto:
      type: object
      properties:
        reason:
          type: string
          description: Why the organizer is being suspended (required).
          minLength: 3
          maxLength: 1000
      required:
        - reason
    UnsuspendOrganizerDto:
      type: object
      properties:
        note:
          type: string
          description: Optional note for the audit trail.
          maxLength: 1000
    UpdateMasterEventConfigDto:
      type: object
      properties: {}
    ReplaceMasterComponentsDto:
      type: object
      properties: {}
    ConfigureMasterEventDto:
      type: object
      properties: {}
    UpdateMasterAdminStatusDto:
      type: object
      properties: {}
    FulfillMasterRewardDto:
      type: object
      properties: {}
    CreateMarketingDraftDto:
      type: object
      properties: {}
    UpdateMarketingDraftDto:
      type: object
      properties: {}
    EditMessageDto:
      type: object
      properties:
        body:
          type: string
          description: New message body (max 4000 chars)
      required:
        - body
    CreateUserDto:
      type: object
      properties:
        name:
          type: string
          description: Full name of the user
        email:
          type: string
          description: Email address of the user
        phoneNumber:
          type: string
          description: Contact number of the user
        dateOfBirth:
          type: string
          description: 'Date of birth of the user (format: DD/MM/YYYY)'
          example: 31/12/1990
        city:
          type: string
          description: City of the user
        state:
          type: string
          description: State of the user
        targets:
          type: array
          description: User-specific fitness or performance goals
          items:
            type: string
        dailyStepsTarget:
          type: number
          description: Daily steps target of the user
        exerciseLevel:
          type: string
          description: Current exercise proficiency level of the user
          enum:
            - beginner
            - intermediate
            - advanced
        activitiesCount:
          type: number
          description: Number of activities performed by the user
        height:
          type: number
          description: Height of the user in centimeters
        weight:
          type: number
          description: Weight of the user in kilograms
        gender:
          type: string
          description: Gender of the user
          enum:
            - male
            - female
            - other
        isActive:
          type: boolean
          description: Status indicating if the user is active or not
      required:
        - name
        - email
        - phoneNumber
        - dateOfBirth
        - dailyStepsTarget
        - exerciseLevel
        - activitiesCount
        - height
        - weight
        - gender
        - isActive
    GetManyUserResponseDto:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/User'
        count:
          type: number
        total:
          type: number
        page:
          type: number
        pageCount:
          type: number
      required:
        - data
        - count
        - total
        - page
        - pageCount
    User:
      type: object
      properties: {}
    UpdateUserDto:
      type: object
      properties:
        name:
          type: string
          description: Full name of the user
        username:
          type: string
          description: >-
            Chosen username / public Repeak ID. Reserved atomically at save; 409
            username_taken on collision.
          example: ash_ketchum
        email:
          type: string
          description: Email address of the user
        phoneNumber:
          type: string
          description: Phone number of the user
          example: '+919876543210'
        dateOfBirth:
          type: string
          description: 'Date of birth of the user (format: DD/MM/YYYY)'
          example: 31/12/1990
        city:
          type: string
          description: City of the user
        state:
          type: string
          description: State of the user
        targets:
          type: array
          description: User-specific fitness or performance goals
          items:
            type: string
        dailyStepsTarget:
          type: number
          description: Daily steps target of the user
        exerciseLevel:
          type: string
          description: Current exercise proficiency level of the user
          enum:
            - beginner
            - intermediate
            - advanced
        activitiesCount:
          type: number
          description: Number of activities performed by the user
        height:
          type: number
          description: Height of the user in centimeters
        weight:
          type: number
          description: Weight of the user in kilograms
        gender:
          type: string
          description: Gender of the user
          enum:
            - male
            - female
            - other
        privacyLevel:
          type: string
          description: >-
            Profile visibility. Set to PRIVATE to require follow-request
            approval before others can follow / see your activity.
          enum:
            - public
            - athletes_only
            - followers_only
            - private
        bio:
          type: string
          description: Short bio or description for the user profile
    EnablePushNotificationDto:
      type: object
      properties:
        deviceType:
          type: string
          description: Type of the device (e.g., android, ios, web)
          example: android
          enum:
            - android
            - ios
            - web
        notificationToken:
          type: string
          description: FCM notification token
          example: fcm_token_123456
      required:
        - deviceType
        - notificationToken
    DisablePushNotificationDto:
      type: object
      properties:
        deviceType:
          type: string
          description: Type of the device (e.g., android, ios, web)
          example: android
          enum:
            - android
            - ios
            - web
      required:
        - deviceType
    DeepLinkParamsDto:
      type: object
      properties:
        eventId:
          type: string
          description: Event ID for event-related screens
          example: evt_12345
        participationId:
          type: string
          description: Event participation ID for participation-related screens
          example: ep_12345
        bookingId:
          type: string
          description: Booking (event participation) ID for booking/ticket-detail screens
          example: ep_12345
        tab:
          type: string
          description: >-
            Sub-tab the target screen should open on (e.g. "results" on the
            booking screen)
          example: results
        challengeId:
          type: string
          description: Challenge ID for challenge-related screens
          example: ch_12345
        sportId:
          type: string
          description: Sport ID for sport-related screens
          example: sport_running
        planId:
          type: string
          description: Training plan ID for training plan screens
          example: plan_xyz789
        workoutId:
          type: string
          description: Daily workout ID for training plan workout screens
          example: workout_abc123
        ticketId:
          type: string
          description: Support ticket ID for support screens
          example: ticket_001
        tabIndex:
          type: number
          description: Tab index for dashboard screen (0-4)
          example: 0
        feedEventId:
          type: string
          description: Feed event ID for feed-detail / post screens
          example: fe_12345
        userId:
          type: string
          description: User ID for user-profile screens (e.g. someone followed you)
          example: usr_12345
    DeepLinkDto:
      type: object
      properties:
        screen:
          type: string
          description: Target screen name (case-sensitive)
          example: EventDetailScreen
        params:
          description: Parameters required by the screen
          allOf:
            - $ref: '#/components/schemas/DeepLinkParamsDto'
      required:
        - screen
    SendPushNotificationDto:
      type: object
      properties:
        title:
          type: string
          description: Title of the notification
          example: Welcome to the App!
        body:
          type: string
          description: Body of the notification (optional)
          example: Thank you for signing up.
        type:
          type: string
          description: Type of notification
          example: like
          enum:
            - like
            - comment
            - mention
            - new_follower
            - new_activity
            - challenge_completed
            - challenge_reward
            - challenge_invitation
            - challenge_reminder
            - event_announcement
            - event_registered
            - booking_cancelled
            - payment_success
            - payment_failed
            - refund_initiated
            - refund_completed
            - schedule_added
            - schedule_missed
            - training_workout_reminder
            - training_nutrition_reminder
            - training_rest_day
            - training_plan_completed
            - tracking_share_invite
            - trust_alert
            - new_message
            - club_message
            - support_reply
            - marketing
            - crew_invite
            - crew_assignment
            - crew_assignment_response
            - crew_role_changed
            - shift_reminder
            - attendance_approval_needed
            - attendance_decided
            - ambassador_offer_received
            - ambassador_offer_countered
            - ambassador_offer_withdrawn
            - ambassador_offer_shipped
        deepLink:
          description: Deep link configuration for navigation when notification is tapped
          example:
            screen: EventDetailScreen
            params:
              eventId: evt_12345
          allOf:
            - $ref: '#/components/schemas/DeepLinkDto'
        subjectType:
          type: string
          description: >-
            Entity type the notification is about (e.g. FEED_EVENT,
            SOCIAL_EDGE). Forwarded to FCM data so the mobile app can deep-link
            without parsing deepLink JSON.
          example: FEED_EVENT
        subjectId:
          type: string
          description: >-
            UUID of the entity the notification is about. Forwarded verbatim to
            FCM data.
          example: 019ed4da-90a0-adde-e2ea-3ac7e870302f
      required:
        - title
        - type
    SingleNotificationCategoryPreference:
      type: object
      properties:
        type:
          type: string
          description: >-
            The category of notification to update preference for (challenges,
            events, activity)
          enum:
            - challenges
            - events
            - activity
            - training
            - transactional
            - social
            - club
            - event
            - discovery
            - marketing
            - crew
          example: challenges
        isEnabled:
          type: boolean
          description: Whether the notification category should be enabled or disabled
          example: true
      required:
        - type
        - isEnabled
    UpdateNotificationCategoryPreferencesDto:
      type: object
      properties:
        preferences:
          description: Array of notification category preferences to update
          example:
            - type: challenges
              isEnabled: true
            - type: events
              isEnabled: false
          type: array
          items:
            $ref: '#/components/schemas/SingleNotificationCategoryPreference'
      required:
        - preferences
    UserCreateGearDto:
      type: object
      properties:
        typeId:
          type: string
          description: ID of the type of gear
          example: 23ews3-3wrds-4ewdsf-23rdwd
        sportId:
          type: string
          description: ID of the default sport for the Gear
          example: 4ewdsf-23rdwd-23ews3-3wrds
        brand:
          type: string
          description: Brand of the Gear
          example: Adidas
        model:
          type: string
          description: Model of the Gear
          example: Adidas Ultraboost
        weight:
          type: number
          description: Weight of the Gear
          example: 180
      required:
        - typeId
        - sportId
        - brand
        - model
        - weight
    UserUpdateGearDto:
      type: object
      properties:
        typeId:
          type: string
          description: ID of the type of gear
          example: 23ews3-3wrds-4ewdsf-23rdwd
        sportId:
          type: string
          description: ID of the default sport for the Gear
          example: 4ewdsf-23rdwd-23ews3-3wrds
        brand:
          type: string
          description: Brand of the Gear
          example: Adidas
        model:
          type: string
          description: Model of the Gear
          example: Adidas Ultraboost
        weight:
          type: number
          description: Weight of the Gear
          example: 180
    UserCreateScheduleDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the schedule
          maxLength: 100
        sportId:
          type: string
          description: UUID of the sport
        scheduledAt:
          type: string
          description: Scheduled date and time in ISO format
        isCompleted:
          type: boolean
          description: Status indicating if the schedule is completed
      required:
        - name
        - sportId
        - scheduledAt
    UserUpdateScheduleDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the schedule
          maxLength: 100
        sportId:
          type: string
          description: UUID of the sport
        scheduledAt:
          type: string
          description: Scheduled date and time in ISO format
        isCompleted:
          type: boolean
          description: Status indicating if the schedule is completed
    UserCreateActivityDto:
      type: object
      properties:
        polyline:
          type: string
          description: >-
            Encoded Polyline Algorithm Format (Google Encoded Polyline). Omit
            for manual log entries.
          example: _p~iF~ps|U_ulLnnqC_mqNvxq`@
        sportId:
          type: string
          description: ID of the sport associated with the activity
        completedAt:
          type: object
          description: Date and time when the activity was completed
          example: '2024-02-10T10:00:00'
        distanceInMeters:
          type: number
          description: Distance covered in meters
          example: 5250
        durationInSeconds:
          type: number
          description: Duration of the activity in seconds
          example: 3600
        stepsCount:
          type: number
          description: >-
            Number of steps taken during the activity. Omit or send 0 for
            non-pedometer sports (cycling, swimming).
          example: 8000
        cadenceSpm:
          type: number
          description: >-
            Hardware-derived average foot cadence in steps per minute. Omit when
            unavailable.
          example: 172
        name:
          type: string
          description: Name of the activity
          example: Morning Run
        description:
          type: string
          description: Athlete-authored activity description; may be empty
          example: A refreshing morning jog
        mapType:
          type: string
          description: Type of map used
          enum: &ref_623
            - standard
            - satelite
            - hybrid
          example: standard
        gearId:
          type: string
          description: ID of the gear associated with the activity
        hideStatistics:
          type: string
          description: Whether statistics should be hidden like calories or avgPace
          example: calories
        exertion:
          type: string
          description: Exertion level of the activity
          enum: &ref_624
            - easy
            - moderate
            - max_effort
          example: moderate
        elevationGain:
          type: number
          description: Cumulative uphill elevation climbed in meters
          example: 312
        elevationLoss:
          type: number
          description: Cumulative downhill elevation descended in meters
          example: 298
        privacy:
          type: string
          description: Privacy scope for social surfaces.
          enum: &ref_625
            - PUBLIC
            - FOLLOWERS
            - PRIVATE
        shareToFeed:
          type: boolean
          default: true
        splits:
          description: >-
            Per-km splits produced by the tracker. `elevationGainM` /
            `elevationLossM` are optional and omitted when the device reported
            no altitude.
          type: array
          items:
            type: string
        laps:
          description: Athlete-marked laps captured during the recording.
          type: array
          items:
            type: string
        streams:
          type: object
          description: >-
            Downsampled per-sample recording stream backing the activity-detail
            charts (elevation-vs-distance, pace-vs-distance). Column-oriented
            and index-aligned: `distanceM[i]` / `elapsedS[i]` / `altitudeM?[i]`
            describe the same sample. Mobile caps at ~400 samples; arrays MUST
            be <= 1000 entries — the service truncates anything longer before
            save so a bad client cannot bloat the row. Omit for manual logs.
          example: &ref_626
            distanceM:
              - 0
              - 250
              - 500
            elapsedS:
              - 0
              - 78
              - 155
            altitudeM:
              - 12
              - 14
              - 13
        deviceSource:
          type: string
          description: Device identifier / user-agent.
        clientTelemetry:
          type: object
          description: >-
            §17 / §70.10 — structured device telemetry captured at finish.
            Mobile populates from platform APIs (deviceModel, osVersion,
            appVersion, manufacturer, batteryPct, gpsHealthy, etc.). Mirrors
            hybrid-race FinishHybridRaceDto.clientTelemetry for shared
            anti-cheat observation.
        signedTelemetry:
          type: string
          description: >-
            HMAC-signed device telemetry payload produced by the mobile app.
            Consumed by Stage 6 device-integrity scoring.
        mockLocationDetected:
          type: boolean
          description: >-
            Whether the mobile OS reported a mock/simulated location during this
            recording.
        externalId:
          type: string
          description: External system activity id (e.g. Strava activity id).
        challengeId:
          type: string
          description: Linked challenge id.
        eventRegistrationId:
          type: string
          description: Linked event registration id.
        hybridRaceResultId:
          type: string
          description: Linked hybrid race result id.
        weather:
          type: object
          description: >-
            PRD §17.6 — captured weather snapshot at activity completion.
            Free-form so mobile can extend without schema change.
        mood:
          type: string
          description: >-
            PRD §17.6 — athlete-picked mood tag (e.g. FELT_STRONG, AVERAGE,
            TIRED, INJURED). Not enum-constrained at the DB layer so the picker
            can extend.
          example: FELT_STRONG
        tags:
          description: >-
            PRD §17.6 — athlete-defined free-text tags (e.g. "tempo run", "long
            run", "recovery").
          type: array
          items:
            type: string
        eventId:
          type: string
          description: >-
            Event ID to link this activity to a virtual or hybrid event
            registration. When provided: the backend verifies the user has an
            active registration, checks the event time window, and for virtual
            events updates the proof fields (proofStatus → submitted,
            proofActivityId, proofDistanceMeters). Challenge progress is NOT
            credited for event activities.
          example: 019ed4da-90a0-adde-e2ea-3ac7e870302f
      required:
        - sportId
        - completedAt
        - distanceInMeters
        - durationInSeconds
        - name
        - description
        - mapType
        - hideStatistics
        - exertion
    ManualLogActivityDto:
      type: object
      properties:
        name:
          type: string
          example: Morning run
        sportId:
          type: string
          description: ID of the sport for this effort
        gearId:
          type: string
          description: Athlete-owned gear used for this effort
        distanceInMeters:
          type: number
          example: 5200
          description: Distance in meters
        durationInSeconds:
          type: number
          example: 1680
          description: Duration in seconds
        completedAt:
          type: string
          example: '2026-05-25T07:00:00.000Z'
        description:
          type: string
          example: Easy shakeout on the treadmill.
        exertion:
          type: string
          enum:
            - easy
            - moderate
            - max_effort
        privacy:
          type: string
          enum:
            - PUBLIC
            - FOLLOWERS
            - PRIVATE
        indoor:
          type: boolean
          description: Whether this was completed indoors
        stepsCount:
          type: number
          example: 6800
          description: Steps, if known
        elevationGain:
          type: number
          example: 18
          description: Elevation gain in meters
      required:
        - name
        - sportId
        - distanceInMeters
        - durationInSeconds
        - completedAt
    UserUpdateActivityDto:
      type: object
      properties:
        polyline:
          type: string
          description: >-
            Encoded Polyline Algorithm Format (Google Encoded Polyline). Omit
            for manual log entries.
          example: _p~iF~ps|U_ulLnnqC_mqNvxq`@
        sportId:
          type: string
          description: ID of the sport associated with the activity
        completedAt:
          type: object
          description: Date and time when the activity was completed
          example: '2024-02-10T10:00:00'
        distanceInMeters:
          type: number
          description: Distance covered in meters
          example: 5250
        durationInSeconds:
          type: number
          description: Duration of the activity in seconds
          example: 3600
        stepsCount:
          type: number
          description: >-
            Number of steps taken during the activity. Omit or send 0 for
            non-pedometer sports (cycling, swimming).
          example: 8000
        cadenceSpm:
          type: number
          description: >-
            Hardware-derived average foot cadence in steps per minute. Omit when
            unavailable.
          example: 172
        name:
          type: string
          description: Name of the activity
          example: Morning Run
        description:
          type: string
          description: Athlete-authored activity description; may be empty
          example: A refreshing morning jog
        mapType:
          type: string
          description: Type of map used
          enum: *ref_623
          example: standard
        gearId:
          type: string
          description: ID of the gear associated with the activity
        hideStatistics:
          type: string
          description: Whether statistics should be hidden like calories or avgPace
          example: calories
        exertion:
          type: string
          description: Exertion level of the activity
          enum: *ref_624
          example: moderate
        elevationGain:
          type: number
          description: Cumulative uphill elevation climbed in meters
          example: 312
        elevationLoss:
          type: number
          description: Cumulative downhill elevation descended in meters
          example: 298
        privacy:
          type: string
          description: Privacy scope for social surfaces.
          enum: *ref_625
        shareToFeed:
          type: boolean
          default: true
        splits:
          description: >-
            Per-km splits produced by the tracker. `elevationGainM` /
            `elevationLossM` are optional and omitted when the device reported
            no altitude.
          type: array
          items:
            type: string
        laps:
          description: Athlete-marked laps captured during the recording.
          type: array
          items:
            type: string
        streams:
          type: object
          description: >-
            Downsampled per-sample recording stream backing the activity-detail
            charts (elevation-vs-distance, pace-vs-distance). Column-oriented
            and index-aligned: `distanceM[i]` / `elapsedS[i]` / `altitudeM?[i]`
            describe the same sample. Mobile caps at ~400 samples; arrays MUST
            be <= 1000 entries — the service truncates anything longer before
            save so a bad client cannot bloat the row. Omit for manual logs.
          example: *ref_626
        deviceSource:
          type: string
          description: Device identifier / user-agent.
        clientTelemetry:
          type: object
          description: >-
            §17 / §70.10 — structured device telemetry captured at finish.
            Mobile populates from platform APIs (deviceModel, osVersion,
            appVersion, manufacturer, batteryPct, gpsHealthy, etc.). Mirrors
            hybrid-race FinishHybridRaceDto.clientTelemetry for shared
            anti-cheat observation.
        signedTelemetry:
          type: string
          description: >-
            HMAC-signed device telemetry payload produced by the mobile app.
            Consumed by Stage 6 device-integrity scoring.
        mockLocationDetected:
          type: boolean
          description: >-
            Whether the mobile OS reported a mock/simulated location during this
            recording.
        externalId:
          type: string
          description: External system activity id (e.g. Strava activity id).
        challengeId:
          type: string
          description: Linked challenge id.
        eventRegistrationId:
          type: string
          description: Linked event registration id.
        hybridRaceResultId:
          type: string
          description: Linked hybrid race result id.
        weather:
          type: object
          description: >-
            PRD §17.6 — captured weather snapshot at activity completion.
            Free-form so mobile can extend without schema change.
        mood:
          type: string
          description: >-
            PRD §17.6 — athlete-picked mood tag (e.g. FELT_STRONG, AVERAGE,
            TIRED, INJURED). Not enum-constrained at the DB layer so the picker
            can extend.
          example: FELT_STRONG
        tags:
          description: >-
            PRD §17.6 — athlete-defined free-text tags (e.g. "tempo run", "long
            run", "recovery").
          type: array
          items:
            type: string
        eventId:
          type: string
          description: >-
            Event ID to link this activity to a virtual or hybrid event
            registration. When provided: the backend verifies the user has an
            active registration, checks the event time window, and for virtual
            events updates the proof fields (proofStatus → submitted,
            proofActivityId, proofDistanceMeters). Challenge progress is NOT
            credited for event activities.
          example: 019ed4da-90a0-adde-e2ea-3ac7e870302f
    UserUpdateChallengeParticipationDto:
      type: object
      properties:
        progress:
          type: number
          description: The progress of the user in the challenge (percentage-based)
          example: 50
          minimum: 0
          maximum: 100
        isCompleted:
          type: boolean
          description: Indicates whether the challenge has been completed
          example: false
        completedOn:
          format: date-time
          type: string
          description: The date when the challenge was completed (if applicable)
          example: '2025-03-03'
    UserCreateStepsDto:
      type: object
      properties:
        count:
          type: number
          description: Step count
          example: 5000
          minimum: 0
        source:
          type: string
          description: Source of step data
          enum:
            - pedometer
            - google_fit
            - apple_health
          example: pedometer
          default: pedometer
        manualSourced:
          type: boolean
          description: >-
            True when the resolved daily total came only from a manually-entered
            source (mobile HealthSourceResolver,
            docs/HEALTH_INGEST_FIELD_MAPPING.md). A2: a manual-sourced total is
            untrusted and must NOT be credited.
          example: false
          default: false
        date:
          format: date-time
          type: string
          description: Start date of the challenge (YYYY-MM-DD)
          example: '2025-01-01'
      required:
        - count
        - date
    WorkspaceSwitchDto:
      type: object
      properties:
        toWorkspaceId:
          type: string
          description: >-
            Synthetic workspace id from GET /v2/users/me/workspaces (format:
            <type>-<entityId>)
          example: org-018f9d6e-c2b8-7c0d-9b5e-5b1d3a8a8b9b
        toWorkspaceType:
          type: string
          description: Workspace type for fast lookup.
          enum:
            - ORGANIZER
            - BRAND
            - CLUB
            - COMMUNITY
        fromWorkspaceId:
          type: string
          description: The synthetic workspace id the user was on, if any.
      required:
        - toWorkspaceId
        - toWorkspaceType
    MintActivationTokenDto:
      type: object
      properties:
        product:
          type: string
          enum:
            - ORGANIZER
            - BRAND
            - CLUB
        entityId:
          type: string
          description: organizerId / brandId / clubId — the entity being activated into.
      required:
        - product
        - entityId
    ExchangeActivationTokenDto:
      type: object
      properties:
        activationToken:
          type: string
      required:
        - activationToken
    ChannelTogglesDto:
      type: object
      properties:
        push:
          type: boolean
        email:
          type: boolean
        sms:
          type: boolean
        whatsapp:
          type: boolean
        inApp:
          type: boolean
    NotificationTypePreferenceDto:
      type: object
      properties:
        type:
          type: string
          enum:
            - like
            - comment
            - mention
            - new_follower
            - new_activity
            - challenge_completed
            - challenge_reward
            - challenge_invitation
            - challenge_reminder
            - event_announcement
            - event_registered
            - booking_cancelled
            - payment_success
            - payment_failed
            - refund_initiated
            - refund_completed
            - schedule_added
            - schedule_missed
            - training_workout_reminder
            - training_nutrition_reminder
            - training_rest_day
            - training_plan_completed
            - tracking_share_invite
            - trust_alert
            - new_message
            - club_message
            - support_reply
            - marketing
            - crew_invite
            - crew_assignment
            - crew_assignment_response
            - crew_role_changed
            - shift_reminder
            - attendance_approval_needed
            - attendance_decided
            - ambassador_offer_received
            - ambassador_offer_countered
            - ambassador_offer_withdrawn
            - ambassador_offer_shipped
        isEnabled:
          type: boolean
          description: >-
            Master toggle for this notification type. When false, every channel
            is suppressed regardless of `channels` overrides.
        channels:
          $ref: '#/components/schemas/ChannelTogglesDto'
      required:
        - type
    QuietHoursDto:
      type: object
      properties:
        enabled:
          type: boolean
        startTime:
          type: string
          description: 24h HH:mm string, e.g. "22:00".
        endTime:
          type: string
          description: 24h HH:mm string, e.g. "07:00".
        timezone:
          type: string
          description: IANA timezone, e.g. "Asia/Kolkata".
      required:
        - enabled
    UpdateNotificationPreferencesBodyDto:
      type: object
      properties:
        preferences:
          type: array
          items:
            $ref: '#/components/schemas/NotificationTypePreferenceDto'
        quietHours:
          $ref: '#/components/schemas/QuietHoursDto'
    CreateNotificationPreferencesType:
      type: object
      properties:
        type:
          type: string
          example: schedule_added
      required:
        - type
    DeleteNotificationPreferencesType:
      type: object
      properties:
        type:
          type: string
          example: schedule_missed
      required:
        - type
    AgeRestrictionDto:
      type: object
      properties:
        minAge:
          type: number
          description: Minimum age required
          example: 18
          minimum: 0
          maximum: 120
        maxAge:
          type: number
          description: Maximum age allowed
          example: 65
          minimum: 0
          maximum: 120
    CreateCouponDto:
      type: object
      properties:
        code:
          type: string
          example: REPEAK50
        name:
          type: string
        discountType:
          type: string
          enum: &ref_663
            - PERCENT
            - FLAT
            - FREE_PERIOD
            - TRIAL_EXTENSION
        percentValue:
          type: number
          description: PERCENT only — whole percent 1–100
        flatAmountMinor:
          type: number
          description: FLAT only — minor units
        currency:
          type: string
          description: Required for FLAT
        maxDiscountMinor:
          type: number
          description: PERCENT cap, minor units
        minPurchaseMinor:
          type: number
          description: Minimum order, minor units
        freePeriodCount:
          type: number
          description: FREE_PERIOD only — cycles free
        trialExtensionDays:
          type: number
          description: TRIAL_EXTENSION only — extra days
        appliesToRenewals:
          type: boolean
          default: true
          description: >-
            false = first cycle only. Requires a provider that supports a first
            charge differing from the mandate amount, or the discount silently
            repeats on every renewal.
        newSubscribersOnly:
          type: boolean
          default: false
        maxRedemptions:
          type: number
          description: Total redemptions; null = unlimited
        maxRedemptionsPerUser:
          type: number
          description: Per-user redemptions; null = unlimited
        stackable:
          type: boolean
          default: false
        startsAt:
          format: date-time
          type: string
        endsAt:
          format: date-time
          type: string
        publicDescription:
          type: string
          description: Shown to the user when the code is rejected
        internalNote:
          type: string
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/CouponScopeDto'
      required:
        - code
        - name
        - discountType
    UpdateCouponDto:
      type: object
      properties:
        name:
          type: string
        publicDescription:
          type: string
        internalNote:
          type: string
        percentValue:
          type: number
          description: Frozen once the coupon has been claimed
        flatAmountMinor:
          type: number
          description: Frozen once the coupon has been claimed
        maxDiscountMinor:
          type: number
          description: Frozen once the coupon has been claimed
        minPurchaseMinor:
          type: number
        maxRedemptions:
          type: number
        maxRedemptionsPerUser:
          type: number
        appliesToRenewals:
          type: boolean
        newSubscribersOnly:
          type: boolean
        stackable:
          type: boolean
        startsAt:
          format: date-time
          type: string
        endsAt:
          format: date-time
          type: string
        status:
          type: string
          enum:
            - ACTIVE
            - PAUSED
            - EXPIRED
            - ARCHIVED
    ReviewDto:
      type: object
      properties:
        approvalStatus:
          type: string
          description: Approval status of the entity
          enum:
            - pending
            - approved
            - rejected
            - suspended
        reviewReason:
          type: string
          description: Reason for the review
      required:
        - approvalStatus
    CreateSupportTicketDto:
      type: object
      properties:
        subject:
          type: string
          description: Subject of the support ticket
          example: Unable to complete event registration
          minLength: 5
          maxLength: 255
        description:
          type: string
          description: Detailed description of the issue
          example: >-
            I am trying to register for the marathon event but getting an
            error...
          minLength: 20
        category:
          type: string
          enum: &ref_627
            - BOOKING_ISSUE
            - PAYMENT_ISSUE
            - REFUND_REQUEST
            - CANCELLATION_REQUEST
            - EVENT_INQUIRY
            - CHALLENGE_INQUIRY
            - TECHNICAL_ISSUE
            - APP_BUG_REPORT
            - ACCOUNT_ISSUE
            - PROFILE_UPDATE
            - KYC_VERIFICATION
            - FEEDBACK_SUGGESTION
            - GENERAL_INQUIRY
            - OTHER
            - EVENT_MANAGEMENT
            - CHALLENGE_MANAGEMENT
            - SETTLEMENT_PAYOUT
            - COMMISSION_DISPUTE
            - PARTICIPANT_ISSUE
            - COUPON_DISCOUNT
            - ONBOARDING_ISSUE
            - GST_TAX_ISSUE
          description: Category of the support ticket
          example: BOOKING_ISSUE
        priority:
          type: string
          enum: &ref_628
            - LOW
            - MEDIUM
            - HIGH
            - URGENT
          description: Priority of the support ticket
          example: MEDIUM
          default: MEDIUM
        eventParticipationId:
          type: string
          description: Event participation ID if ticket is related to an event booking
          example: 123e4567-e89b-12d3-a456-426614174000
        challengeParticipationId:
          type: string
          description: Challenge participation ID if ticket is related to a challenge
          example: 123e4567-e89b-12d3-a456-426614174000
        eventId:
          type: string
          description: Event ID if ticket is related to an event (for organizers)
          example: 123e4567-e89b-12d3-a456-426614174000
        challengeId:
          type: string
          description: Challenge ID if ticket is related to a challenge (for organizers)
          example: 123e4567-e89b-12d3-a456-426614174000
      required:
        - subject
        - description
        - category
    SupportTicket:
      type: object
      properties: {}
    CreatePublicContactDto:
      type: object
      properties:
        name:
          type: string
          example: Jane Doe
          minLength: 2
          maxLength: 120
        email:
          type: string
          example: jane@example.com
        phone:
          type: string
          example: '+919876543210'
        subject:
          type: string
          example: Trouble signing up for the 10K event
          minLength: 5
          maxLength: 255
        message:
          type: string
          example: >-
            I get an "invalid OTP" error when I try to verify my phone during
            signup. Tried three times.
          minLength: 20
        category:
          type: string
          enum:
            - BOOKING_ISSUE
            - PAYMENT_ISSUE
            - REFUND_REQUEST
            - CANCELLATION_REQUEST
            - EVENT_INQUIRY
            - CHALLENGE_INQUIRY
            - TECHNICAL_ISSUE
            - APP_BUG_REPORT
            - ACCOUNT_ISSUE
            - PROFILE_UPDATE
            - KYC_VERIFICATION
            - FEEDBACK_SUGGESTION
            - GENERAL_INQUIRY
            - OTHER
            - EVENT_MANAGEMENT
            - CHALLENGE_MANAGEMENT
            - SETTLEMENT_PAYOUT
            - COMMISSION_DISPUTE
            - PARTICIPANT_ISSUE
            - COUPON_DISCOUNT
            - ONBOARDING_ISSUE
            - GST_TAX_ISSUE
          description: >-
            Optional category hint from the UI. Server falls back to
            GENERAL_INQUIRY if omitted or invalid.
      required:
        - name
        - email
        - subject
        - message
    UpdateSupportTicketDto:
      type: object
      properties:
        subject:
          type: string
          description: Subject of the support ticket
          example: Unable to complete event registration
          minLength: 5
          maxLength: 255
        description:
          type: string
          description: Detailed description of the issue
          example: >-
            I am trying to register for the marathon event but getting an
            error...
          minLength: 20
        category:
          type: string
          enum: *ref_627
          description: Category of the support ticket
          example: BOOKING_ISSUE
        priority:
          type: string
          enum: *ref_628
          description: Priority of the support ticket
          example: MEDIUM
          default: MEDIUM
        eventParticipationId:
          type: string
          description: Event participation ID if ticket is related to an event booking
          example: 123e4567-e89b-12d3-a456-426614174000
        challengeParticipationId:
          type: string
          description: Challenge participation ID if ticket is related to a challenge
          example: 123e4567-e89b-12d3-a456-426614174000
        eventId:
          type: string
          description: Event ID if ticket is related to an event (for organizers)
          example: 123e4567-e89b-12d3-a456-426614174000
        challengeId:
          type: string
          description: Challenge ID if ticket is related to a challenge (for organizers)
          example: 123e4567-e89b-12d3-a456-426614174000
        status:
          type: string
          enum:
            - OPEN
            - IN_PROGRESS
            - WAITING_FOR_USER
            - RESOLVED
            - CLOSED
            - CANCELLED
          description: Status of the support ticket
          example: IN_PROGRESS
        assignedToId:
          type: string
          description: Admin ID to assign the ticket to
          example: 123e4567-e89b-12d3-a456-426614174000
        resolutionNotes:
          type: string
          description: Resolution notes for the ticket
          example: Issue resolved by updating user account settings
    CreateSupportTicketMessageDto:
      type: object
      properties:
        message:
          type: string
          description: Message content
          example: Thank you for contacting support. We are looking into your issue.
          minLength: 1
        isInternal:
          type: boolean
          description: Whether this is an internal message (visible only to admins)
          example: false
          default: false
      required:
        - message
    AddUserRatingDto:
      type: object
      properties:
        userRating:
          type: number
          description: User satisfaction rating
          example: 4
          minimum: 1
          maximum: 5
        userFeedback:
          type: string
          description: User feedback about the support experience
          example: The support team was very helpful and resolved my issue quickly.
      required:
        - userRating
    SupportTicketAttachment:
      type: object
      properties: {}
    FoodItemDto:
      type: object
      properties:
        name:
          type: string
          example: Idli (2 pcs)
        calories:
          type: number
        proteinGrams:
          type: number
        carbohydratesGrams:
          type: number
        fatGrams:
          type: number
        fiberGrams:
          type: number
        quantity:
          type: number
        unit:
          type: string
    TotalNutritionDto:
      type: object
      properties:
        calories:
          type: number
        proteinGrams:
          type: number
        carbohydratesGrams:
          type: number
        fatGrams:
          type: number
        fiberGrams:
          type: number
    SaveNutritionLogDto:
      type: object
      properties:
        mealType:
          type: string
          enum:
            - BREAKFAST
            - LUNCH
            - DINNER
            - SNACK
        loggedAt:
          type: string
          example: '2026-04-19T08:30:00.000Z'
        foodItems:
          type: array
          items:
            $ref: '#/components/schemas/FoodItemDto'
        totalNutrition:
          $ref: '#/components/schemas/TotalNutritionDto'
        healthScore:
          type: number
          minimum: 0
          maximum: 100
        healthCategory:
          type: string
        logType:
          type: string
          enum:
            - SCAN
            - QUICK_ADD
            - MANUAL
        scanImageUrl:
          type: string
        notes:
          type: string
      required:
        - mealType
        - loggedAt
        - foodItems
    QuickAddNutritionLogDto:
      type: object
      properties:
        quickAddItemId:
          type: string
        mealType:
          type: string
          enum:
            - BREAKFAST
            - LUNCH
            - DINNER
            - SNACK
        loggedAt:
          type: string
          example: '2026-04-19T08:30:00.000Z'
        quantity:
          type: number
          default: 1
          minimum: 1
        notes:
          type: string
      required:
        - quickAddItemId
        - mealType
        - loggedAt
    UpdateHealthStatsDto:
      type: object
      properties:
        heightCm:
          type: number
        weightKg:
          type: number
        age:
          type: number
        gender:
          type: string
        activityLevel:
          type: string
          enum:
            - SEDENTARY
            - LIGHT
            - MODERATE
            - ACTIVE
            - VERY_ACTIVE
        goal:
          type: string
          enum:
            - LOSE
            - MAINTAIN
            - GAIN
        dailyCalorieTarget:
          type: number
        dailyProteinTarget:
          type: number
        dailyCarbTarget:
          type: number
        dailyFatTarget:
          type: number
    DailyReportDto:
      type: object
      properties:
        date:
          type: string
          example: '2026-04-19'
      required:
        - date
    CreateStoragePlanDto:
      type: object
      properties:
        name:
          type: string
          example: Basic 10GB Plan
        description:
          type: string
          example: 10GB storage for event photos and videos
        planType:
          type: string
          enum: &ref_629
            - size_based
            - count_based
          example: size_based
        storageBytesLimit:
          type: number
          example: 10737418240
        maxPhotoCount:
          type: number
          example: 500
        maxVideoCount:
          type: number
          example: 50
        price:
          type: number
          example: 999
        billingCycle:
          type: string
          enum: &ref_630
            - monthly
            - quarterly
            - half_yearly
            - yearly
          example: monthly
        sortOrder:
          type: number
          example: 1
      required:
        - name
        - planType
        - price
        - billingCycle
    UpdateStoragePlanDto:
      type: object
      properties:
        name:
          type: string
          example: Basic 10GB Plan
        description:
          type: string
          example: 10GB storage for event photos and videos
        planType:
          type: string
          enum: *ref_629
          example: size_based
        storageBytesLimit:
          type: number
          example: 10737418240
        maxPhotoCount:
          type: number
          example: 500
        maxVideoCount:
          type: number
          example: 50
        price:
          type: number
          example: 999
        billingCycle:
          type: string
          enum: *ref_630
          example: monthly
        sortOrder:
          type: number
          example: 1
    PurchaseSubscriptionDto:
      type: object
      properties:
        storagePlanId:
          type: string
          example: uuid-of-storage-plan
      required:
        - storagePlanId
    AssignGallerySubscriptionDto:
      type: object
      properties:
        subscriptionId:
          type: string
          example: uuid-of-active-subscription
          description: One of the organizer's currently active subscriptions.
      required:
        - subscriptionId
    CheckUploadLimitsDto:
      type: object
      properties:
        eventId:
          type: string
          example: uuid-of-event
        mediaType:
          type: string
          enum:
            - image
            - video
          example: image
        fileCount:
          type: number
          example: 10
        totalBytes:
          type: number
          example: 20971520
      required:
        - eventId
        - mediaType
        - fileCount
        - totalBytes
    RegisterMediaDto:
      type: object
      properties:
        eventId:
          type: string
          example: uuid-of-event
        mediaType:
          type: string
          enum:
            - image
            - video
          example: image
        originalUrl:
          type: string
          example: https://s3.amazonaws.com/bucket/photo.jpg
        watermarkedUrl:
          type: string
          example: https://s3.amazonaws.com/bucket/photo-watermarked.jpg
        thumbnailUrl:
          type: string
          example: https://s3.amazonaws.com/bucket/photo-thumb.jpg
        fileSize:
          type: number
          example: 2048576
        mimeType:
          type: string
          example: image/jpeg
        originalFilename:
          type: string
          example: IMG_20260101_001.jpg
        width:
          type: number
          example: 1920
        height:
          type: number
          example: 1080
        videoDuration:
          type: number
          example: 120
        faceCount:
          type: number
          example: 3
      required:
        - eventId
        - mediaType
        - originalUrl
        - fileSize
    PurchaseImagesDto:
      type: object
      properties:
        eventId:
          type: string
          example: uuid-of-event
        imageCount:
          type: number
          example: 3
          description: >-
            Number of images to purchase (for PER_IMAGE pricing). If not
            provided, all pending images are purchased. Ignored for BUNDLE
            pricing.
      required:
        - eventId
    IngestImagesDto:
      type: object
      properties:
        eventId:
          type: string
          example: uuid-of-event
          description: Event UUID
        compress:
          type: boolean
          example: false
          description: Losslessly optimize images before storing to S3
      required:
        - eventId
    DeleteImagesDto:
      type: object
      properties:
        eventId:
          type: string
          example: uuid-of-event
        assetUrls:
          example:
            - >-
              https://storage.googleapis.com/repeak-media-eazr/events/<eventId>/photos/photo1.jpg
          description: >-
            Asset URLs of the images to delete. Preferred over the legacy
            `s3ImageUrls`.
          type: array
          items:
            type: string
        s3ImageUrls:
          example:
            - https://s3.amazonaws.com/bucket/photo1.jpg
          description: Deprecated alias for `assetUrls`.
          type: array
          items:
            type: string
      required:
        - eventId
    FaceSearchDto:
      type: object
      properties:
        eventId:
          type: string
          example: uuid-of-event
          description: Event UUID
        sensitivity:
          type: number
          example: 0.6
          description: Sensitivity for face matching (0.0 - 1.0)
      required:
        - eventId
    FillDeclarationVariablesDto:
      type: object
      properties:
        variables:
          type: object
          description: Object containing variable key-value pairs
          example:
            organizerName: John Doe
            panNumber: ABCDE1234F
            address: 123 Main Street
            city: Mumbai
            state: Maharashtra
            pincode: '400001'
      required:
        - variables
    TemplateVariableDto:
      type: object
      properties:
        key:
          type: string
          description: Variable key used in template (e.g., organizerName)
        type:
          type: string
          description: Variable type
          enum:
            - text
            - date
            - number
        required:
          type: boolean
          description: Whether this field is required
        label:
          type: string
          description: Display label for the field
        placeholder:
          type: string
          description: Placeholder text for input
        pattern:
          type: string
          description: Validation regex pattern
        errorMessage:
          type: string
          description: Error message for validation failure
      required:
        - key
        - type
        - required
    CreateGstDeclarationTemplateDto:
      type: object
      properties:
        name:
          type: string
          description: Template name
        description:
          type: string
          description: Template description
        htmlContent:
          type: string
          description: HTML template content with {{variable}} placeholders
        variables:
          description: Array of template variables
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        isActive:
          type: boolean
          description: Whether this template is active
          default: false
        headerLogo:
          type: string
          description: Header logo URL
        footerText:
          type: string
          description: Footer text for PDF
        cssStyles:
          type: string
          description: CSS styles for template
      required:
        - name
        - htmlContent
        - variables
    UpdateGstDeclarationTemplateDto:
      type: object
      properties:
        name:
          type: string
          description: Template name
        description:
          type: string
          description: Template description
        htmlContent:
          type: string
          description: HTML template content with {{variable}} placeholders
        variables:
          description: Array of template variables
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        isActive:
          type: boolean
          description: Whether this template is active
          default: false
        headerLogo:
          type: string
          description: Header logo URL
        footerText:
          type: string
          description: Footer text for PDF
        cssStyles:
          type: string
          description: CSS styles for template
    CreateNotificationCategoryDto:
      type: object
      properties:
        name:
          type: string
          example: promotion
        description:
          type: string
          example: Promotional notifications
        type:
          type: string
          enum: &ref_631
            - system
            - marketing
          default: marketing
          example: marketing
      required:
        - name
    UpdateNotificationCategoryDto:
      type: object
      properties:
        name:
          type: string
          example: promotion
        description:
          type: string
          example: Promotional notifications
        type:
          type: string
          enum: *ref_631
          default: marketing
          example: marketing
        isActive:
          type: boolean
          example: true
          description: Toggle the category active/inactive.
    CreateSmsTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event Registration SMS
        msg91TemplateId:
          type: string
          example: '1234567890'
        dltTemplateId:
          type: string
          example: DLT-123456
        content:
          type: string
          example: Dear {#name#}, your registration for {#event#} is confirmed.
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        approvalStatus:
          type: string
          enum: &ref_632
            - pending
            - approved
            - rejected
        visibility:
          type: string
          enum: &ref_633
            - admin_only
            - organizer
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.25
        categoryId:
          type: string
      required:
        - name
        - msg91TemplateId
        - dltTemplateId
        - content
    UpdateSmsTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event Registration SMS
        msg91TemplateId:
          type: string
          example: '1234567890'
        dltTemplateId:
          type: string
          example: DLT-123456
        content:
          type: string
          example: Dear {#name#}, your registration for {#event#} is confirmed.
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        approvalStatus:
          type: string
          enum: *ref_632
        visibility:
          type: string
          enum: *ref_633
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.25
        categoryId:
          type: string
    CreateSmsViaMsg91Dto:
      type: object
      properties:
        name:
          type: string
          example: Event Registration SMS
        content:
          type: string
          example: 'Dear ##name##, your registration for ##event## is confirmed.'
          description: 'SMS content. Use ##VAR## syntax for variables.'
        senderId:
          type: string
          example: RACEAB
          description: Sender ID registered with MSG91
        dltTemplateId:
          type: string
          example: '1234567890123456789'
          description: DLT Template ID from TRAI/operator for Indian SMS
        smsType:
          type: string
          example: NORMAL
          enum:
            - NORMAL
            - TRANSACTIONAL
            - PROMOTIONAL
          description: SMS type. Defaults to NORMAL.
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        visibility:
          type: string
          enum:
            - admin_only
            - organizer
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.25
        categoryId:
          type: string
      required:
        - name
        - content
        - senderId
        - dltTemplateId
    AddSmsTemplateVersionDto:
      type: object
      properties:
        content:
          type: string
          example: 'Dear ##name##, your updated registration for ##event## is confirmed.'
          description: 'New SMS content for this version. Use ##VAR## syntax for variables.'
        senderId:
          type: string
          example: RACEAB
          description: Sender ID registered with MSG91
        dltTemplateId:
          type: string
          example: '1234567890123456789'
          description: DLT Template ID from TRAI/operator for Indian SMS
      required:
        - content
        - senderId
        - dltTemplateId
    UpdateTemplatePricingDto:
      type: object
      properties:
        pricePerUnit:
          type: number
          example: 0.25
        freeForOrganizer:
          type: boolean
          example: false
      required:
        - pricePerUnit
    CreateEmailTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event Registration Email
        msg91TemplateId:
          type: string
          example: msg91-template-id-123
        subject:
          type: string
          example: Your event registration is confirmed
        description:
          type: string
          example: Email template for event registration confirmation
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        visibility:
          type: string
          enum: &ref_634
            - admin_only
            - organizer
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.1
        categoryId:
          type: string
      required:
        - name
        - msg91TemplateId
    CreateEmailViaMsg91Dto:
      type: object
      properties:
        name:
          type: string
          example: Event Registration Confirmation
        subject:
          type: string
          example: Your event registration is confirmed!
        htmlContent:
          type: string
          example: >-
            <html><body>Hi {{name}}, your registration for {{event}} is
            confirmed.</body></html>
          description: HTML content of the email template
        fromName:
          type: string
          example: RaceAbove
        fromEmail:
          type: string
          example: no-reply@raceabove.com
        description:
          type: string
          example: Email template for event registration
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        visibility:
          type: string
          enum:
            - admin_only
            - organizer
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.1
        categoryId:
          type: string
      required:
        - name
        - subject
        - htmlContent
    UpdateEmailTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event Registration Email
        msg91TemplateId:
          type: string
          example: msg91-template-id-123
        subject:
          type: string
          example: Your event registration is confirmed
        description:
          type: string
          example: Email template for event registration confirmation
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        visibility:
          type: string
          enum: *ref_634
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.1
        categoryId:
          type: string
    CreateWhatsappTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event Reminder WhatsApp
        metaTemplateId:
          type: string
          example: event_reminder_template
        language:
          type: string
          example: en
        content:
          type: string
          example: Hi {{1}}, your event {{2}} starts tomorrow.
        headerType:
          type: string
          example: text
        headerContent:
          type: string
        footerContent:
          type: string
        buttons:
          type: array
          items:
            type: string
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        approvalStatus:
          type: string
          enum: &ref_635
            - pending
            - approved
            - rejected
        metaApprovalStatus:
          type: string
        visibility:
          type: string
          enum: &ref_636
            - admin_only
            - organizer
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.5
        categoryId:
          type: string
      required:
        - name
        - metaTemplateId
    UpdateWhatsappTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event Reminder WhatsApp
        metaTemplateId:
          type: string
          example: event_reminder_template
        language:
          type: string
          example: en
        content:
          type: string
          example: Hi {{1}}, your event {{2}} starts tomorrow.
        headerType:
          type: string
          example: text
        headerContent:
          type: string
        footerContent:
          type: string
        buttons:
          type: array
          items:
            type: string
        variables:
          type: array
          items:
            $ref: '#/components/schemas/TemplateVariableDto'
        approvalStatus:
          type: string
          enum: *ref_635
        metaApprovalStatus:
          type: string
        visibility:
          type: string
          enum: *ref_636
        freeForOrganizer:
          type: boolean
          example: false
        pricePerUnit:
          type: number
          example: 0.5
        categoryId:
          type: string
    CreatePushTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: New device login alert
        slug:
          type: string
          description: >-
            Stable machine key, lowercase kebab-case. Used to reference and
            re-seed the template idempotently.
          example: user-new-device-login
        title:
          type: string
          description: >-
            Notification title. Supports {{variable}} placeholders filled from
            the dispatch variables.
          example: New device login
        body:
          type: string
          description: Notification body. Supports {{variable}} placeholders.
          example: Hi {{user_name}}, we noticed a login from {{device_name}}.
        description:
          type: string
        deepLink:
          type: object
          description: >-
            In-app destination. String leaves are placeholder-interpolated, so
            params can reference the triggering entity.
          example: &ref_637
            screen: EventDetail
            params:
              id: '{{event_id}}'
        pushType:
          type: string
          description: Client-side type tag (drives icon + grouping on the device).
          example: GENERAL
        imageUrl:
          type: string
          description: Rich-notification image URL.
        variables:
          description: >-
            Declared placeholders. `required: true` ones are reported in the
            dispatch log when a trigger fails to supply them.
          example: &ref_638
            - key: user_name
              required: true
              label: Athlete name
          type: array
          items:
            type: string
        visibility:
          type: string
          enum: &ref_639
            - admin_only
            - organizer
        freeForOrganizer:
          type: boolean
        pricePerUnit:
          type: number
        categoryId:
          type: string
      required:
        - name
        - slug
        - title
        - body
    UpdatePushTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: New device login alert
        slug:
          type: string
          description: >-
            Stable machine key, lowercase kebab-case. Used to reference and
            re-seed the template idempotently.
          example: user-new-device-login
        title:
          type: string
          description: >-
            Notification title. Supports {{variable}} placeholders filled from
            the dispatch variables.
          example: New device login
        body:
          type: string
          description: Notification body. Supports {{variable}} placeholders.
          example: Hi {{user_name}}, we noticed a login from {{device_name}}.
        description:
          type: string
        deepLink:
          type: object
          description: >-
            In-app destination. String leaves are placeholder-interpolated, so
            params can reference the triggering entity.
          example: *ref_637
        pushType:
          type: string
          description: Client-side type tag (drives icon + grouping on the device).
          example: GENERAL
        imageUrl:
          type: string
          description: Rich-notification image URL.
        variables:
          description: >-
            Declared placeholders. `required: true` ones are reported in the
            dispatch log when a trigger fails to supply them.
          example: *ref_638
          type: array
          items:
            type: string
        visibility:
          type: string
          enum: *ref_639
        freeForOrganizer:
          type: boolean
        pricePerUnit:
          type: number
        categoryId:
          type: string
    AdjustOrganizerWalletDto:
      type: object
      properties:
        amount:
          type: number
          example: 100
        type:
          type: string
          enum:
            - credit
            - debit
            - refund
            - adjustment
        description:
          type: string
          example: Manual top-up by admin
      required:
        - amount
        - type
    ManualRecipientDto:
      type: object
      properties: {}
    ParticipationCriteriaDto:
      type: object
      properties:
        minEvents:
          type: number
          minimum: 1
          description: Positive integer
        lastEventAfter:
          type: string
          description: ISO-8601 date / date-time
        lastEventBefore:
          type: string
          description: ISO-8601 date / date-time
        dormantOnly:
          type: boolean
          description: Server-resolved dormant cohort shorthand
        cohortTag:
          type: string
          enum:
            - DORMANT
            - REPEAT
            - FIRST_TIME
          description: First-class audience-tag activation
    AudienceSpecDto:
      type: object
      properties:
        kind:
          type: string
          enum:
            - event_registrants
            - past_participants
            - organizer_followers
        eventId:
          type: string
        participationCriteria:
          $ref: '#/components/schemas/ParticipationCriteriaDto'
      required:
        - kind
    SendNotificationDto:
      type: object
      properties:
        channel:
          type: string
          enum:
            - sms
            - email
            - whatsapp
            - push
        templateId:
          type: string
        eventId:
          type: string
        recipientSource:
          type: string
          enum:
            - event_participants
            - csv_upload
            - manual
        recipientFileUrl:
          type: string
        manualRecipients:
          type: array
          items:
            $ref: '#/components/schemas/ManualRecipientDto'
        variables:
          type: object
        audienceSpec:
          $ref: '#/components/schemas/AudienceSpecDto'
        scheduledAt:
          type: string
      required:
        - channel
        - templateId
        - recipientSource
    CreateSystemNotificationMappingDto:
      type: object
      properties:
        event:
          type: string
          enum:
            - event_approved
            - event_rejected
            - event_registered
            - event_cancelled
            - event_announcement
            - event_reminder
            - challenge_approved
            - challenge_rejected
            - challenge_announcement
            - challenge_completed
            - challenge_reward
            - payment_success
            - payment_failed
            - refund_initiated
            - refund_completed
            - welcome
            - new_follower
            - kyc_pending_admin
            - kyc_approved
            - kyc_rejected
            - organizer_registration_confirmation
            - subscription_renewal
            - team_invite
            - event_assignment_invited
            - assignment_responded
            - crew_role_changed
            - shift_reminder
            - attendance_approval_needed
            - attendance_decided
          example: event_approved
        channel:
          type: string
          enum:
            - sms
            - email
            - whatsapp
            - push
          default: email
        emailTemplateId:
          type: string
          description: UUID of the EmailTemplate to map
        enabled:
          type: boolean
          default: true
        description:
          type: string
          example: Email sent when an event is approved
      required:
        - event
        - emailTemplateId
    UpdateSystemNotificationMappingDto:
      type: object
      properties:
        emailTemplateId:
          type: string
          description: UUID of the EmailTemplate to map
        enabled:
          type: boolean
        description:
          type: string
    SendPromotionDto:
      type: object
      properties:
        promotionTemplateId:
          type: string
        channels:
          type: array
          items:
            type: string
            enum:
              - sms
              - email
              - whatsapp
              - push
        audienceSpec:
          $ref: '#/components/schemas/AudienceSpecDto'
        variables:
          type: object
        scheduledAt:
          type: string
      required:
        - promotionTemplateId
        - audienceSpec
    AudiencePreviewDto:
      type: object
      properties: {}
    TopUpWalletDto:
      type: object
      properties:
        amount:
          type: number
          example: 500
      required:
        - amount
    PromotionChannelTemplateIdsDto:
      type: object
      properties: {}
    CreatePromotionTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event launch announcement
        description:
          type: string
        eligiblePartnerTypes:
          type: array
          items: &ref_640
            type: string
            enum:
              - organizer
              - brand
              - club
        channelTemplateIds:
          example: &ref_641
            sms: 019...
            email: 019...
            whatsapp: 019...
            push: 019...
          allOf:
            - $ref: '#/components/schemas/PromotionChannelTemplateIdsDto'
        variables:
          example: &ref_642
            - key: event_name
              required: true
              label: Event name
          type: array
          items:
            type: string
        consentCategory:
          type: string
          default: marketing
        enabled:
          type: boolean
          default: true
      required:
        - name
        - eligiblePartnerTypes
        - channelTemplateIds
    UpdatePromotionTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: Event launch announcement
        description:
          type: string
        eligiblePartnerTypes:
          type: array
          items: *ref_640
        channelTemplateIds:
          example: *ref_641
          allOf:
            - $ref: '#/components/schemas/PromotionChannelTemplateIdsDto'
        variables:
          example: *ref_642
          type: array
          items:
            type: string
        consentCategory:
          type: string
          default: marketing
        enabled:
          type: boolean
          default: true
    PromotionStudioSendDto:
      type: object
      properties:
        promotionTemplateId:
          type: string
        channels:
          type: array
          items:
            type: string
            enum:
              - sms
              - email
              - whatsapp
              - push
        audienceKind:
          type: string
          enum:
            - all_users
            - connected_audience
            - event_registrants
            - past_participants
            - organizer_followers
        eventId:
          type: string
        variables:
          type: object
        scheduledAt:
          type: string
      required:
        - promotionTemplateId
    CreateTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: KYC Pending Email V1
        channel:
          type: string
          enum: &ref_643
            - push
            - email
            - sms
            - whatsapp
          example: email
        provider:
          type: string
          enum: &ref_644
            - fcm
            - msg91
            - meta
          example: msg91
        templateId:
          type: string
          example: tpl_abc123
          description: Provider template ID
        description:
          type: string
          example: Email sent when KYC is pending review
        sampleContent:
          type: string
          example: Hi {{organizer_name}}, your KYC is under review.
      required:
        - name
        - channel
        - provider
        - templateId
    UpdateTemplateDto:
      type: object
      properties:
        name:
          type: string
          example: KYC Pending Email V1
        channel:
          type: string
          enum: *ref_643
          example: email
        provider:
          type: string
          enum: *ref_644
          example: msg91
        templateId:
          type: string
          example: tpl_abc123
          description: Provider template ID
        description:
          type: string
          example: Email sent when KYC is pending review
        sampleContent:
          type: string
          example: Hi {{organizer_name}}, your KYC is under review.
    CreateMappingDto:
      type: object
      properties:
        stepId:
          type: string
          example: ADMIN_KYC_SUBMITTED
          description: Notification step ID
        channel:
          type: string
          enum:
            - push
            - email
            - sms
            - whatsapp
          example: email
        templateId:
          type: string
          description: UUID of notification_templates row
      required:
        - stepId
        - channel
        - templateId
    BulkCreateMappingDto:
      type: object
      properties:
        mappings:
          type: array
          items:
            $ref: '#/components/schemas/CreateMappingDto'
      required:
        - mappings
    UpdateMappingDto:
      type: object
      properties:
        templateId:
          type: string
          description: UUID of notification_templates row
        isActive:
          type: boolean
          default: true
      required:
        - templateId
    UpdateJourneyStepDto:
      type: object
      properties:
        journeyPhase:
          type: string
          example: Event lifecycle
        journeyOrder:
          type: number
          example: 120
        recipientDescription:
          type: string
          example: The organizer who owns the event
    CreateClubDto:
      type: object
      properties:
        termsAccepted:
          type: boolean
          description: >-
            Must be true. Confirms the creator accepted the current
            platform-authored Club creation terms.
          example: true
        termsVersion:
          type: number
          description: Version returned by GET /v2/settings/public
          example: 1
        name:
          type: string
          example: Bangalore Runners
        slug:
          type: string
          example: bangalore-runners
        description:
          type: string
        logoUrl:
          type: string
          description: Logo image URL (http/https only)
        bannerUrl:
          type: string
          description: Banner image URL (http/https only)
        city:
          type: string
        country:
          type: string
        sports:
          description: Sport ids (uuid array, max 12)
          type: array
          items:
            type: string
        isPublic:
          type: boolean
        requiresApproval:
          type: boolean
        membershipRequiresPayment:
          type: boolean
          description: >-
            When true, POST /:id/join refuses a bare join (no tierId) — a caller
            must pick one of this club's active tiers and pay before becoming a
            member at all. Independent of requiresApproval.
        foundedDate:
          type: string
        tagline:
          type: string
          description: One-line subtitle for cards/headers.
        colorTheme:
          type: string
          description: Hex color (#RRGGBB).
          example: '#0EA5E9'
        mission:
          type: string
          description: Long-form mission statement.
        rules:
          type: string
          description: Long-form rules document.
        memberExpectations:
          type: string
          description: Long-form member-expectations.
        onboardingMessage:
          type: string
          description: Greeting copy after join.
      required:
        - termsAccepted
        - termsVersion
        - name
        - slug
    RsvpClubRunDto:
      type: object
      properties:
        response:
          type: string
          enum:
            - GOING
            - MAYBE
            - NOT_GOING
        occurrenceStart:
          type: string
      required:
        - response
    SubmitOrganizerClubSetupDto:
      type: object
      properties: {}
    RefundPolicyInput:
      type: object
      properties: {}
    UpdateClubDto:
      type: object
      properties:
        termsAccepted:
          type: boolean
          description: >-
            Must be true. Confirms the creator accepted the current
            platform-authored Club creation terms.
          example: true
        termsVersion:
          type: number
          description: Version returned by GET /v2/settings/public
          example: 1
        name:
          type: string
          example: Bangalore Runners
        slug:
          type: string
          example: bangalore-runners
        description:
          type: string
        logoUrl:
          type: string
          description: Logo image URL (http/https only)
        bannerUrl:
          type: string
          description: Banner image URL (http/https only)
        city:
          type: string
        country:
          type: string
        sports:
          description: Sport ids (uuid array, max 12)
          type: array
          items:
            type: string
        isPublic:
          type: boolean
        requiresApproval:
          type: boolean
        membershipRequiresPayment:
          type: boolean
          description: >-
            When true, POST /:id/join refuses a bare join (no tierId) — a caller
            must pick one of this club's active tiers and pay before becoming a
            member at all. Independent of requiresApproval.
        foundedDate:
          type: string
        tagline:
          type: string
          description: One-line subtitle for cards/headers.
        colorTheme:
          type: string
          description: Hex color (#RRGGBB).
          example: '#0EA5E9'
        mission:
          type: string
          description: Long-form mission statement.
        rules:
          type: string
          description: Long-form rules document.
        memberExpectations:
          type: string
          description: Long-form member-expectations.
        onboardingMessage:
          type: string
          description: Greeting copy after join.
        monetizationAdminOverride:
          type: boolean
        refundPolicy:
          $ref: '#/components/schemas/RefundPolicyInput'
    CreateClubAnnouncementDto:
      type: object
      properties:
        title:
          type: string
        body:
          type: string
        type:
          type: string
          enum:
            - ROUTINE
            - IMPORTANT
            - URGENT
        pinned:
          type: boolean
          description: Pin to top of feed.
        push:
          type: boolean
          description: Send push notification (default true).
        sendEmail:
          type: boolean
          description: >-
            Send email blast in addition to push. Routed through the
            notifications engine; if no email provider is configured the flag is
            logged and ignored.
        scheduledFor:
          type: string
          description: ISO timestamp; if set the announcement is scheduled for this time.
      required:
        - title
        - body
    CreateClubRunDto:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        startDateTime:
          type: string
          example: '2026-05-01T06:00:00Z'
        endDateTime:
          type: string
        locationCoordinate:
          type: object
          example: &ref_645
            type: Point
            coordinates:
              - 77.5946
              - 12.9716
        meetingAddress:
          type: string
        sportId:
          type: string
        distanceMeters:
          type: number
        paceTargetSecPerKm:
          type: number
        recurrenceRule:
          type: string
          example: FREQ=WEEKLY;BYDAY=SU
        paceGroup:
          type: string
          enum: &ref_646
            - BEGINNER
            - INTERMEDIATE
            - ADVANCED
        requiredGear:
          example: &ref_647
            - Hydration pack
            - Headlamp
          type: array
          items:
            type: string
        capacity:
          type: number
          description: RSVP cap; null = unlimited
        paceCapacities:
          type: object
          description: >-
            Per-pace-band caps, e.g. { "BEGINNER": 30, "INTERMEDIATE": 50,
            "ADVANCED": 20 }. Sum must not exceed capacity.
          example: &ref_648
            BEGINNER: 30
            INTERMEDIATE: 50
            ADVANCED: 20
        feeMinor:
          type: number
          description: Fee in minor units (paise/cents).
        feeCurrency:
          type: string
          example: INR
        routeId:
          type: string
      required:
        - name
        - startDateTime
    UpdateClubRunDto:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        startDateTime:
          type: string
          example: '2026-05-01T06:00:00Z'
        endDateTime:
          type: string
        locationCoordinate:
          type: object
          example: *ref_645
        meetingAddress:
          type: string
        sportId:
          type: string
        distanceMeters:
          type: number
        paceTargetSecPerKm:
          type: number
        recurrenceRule:
          type: string
          example: FREQ=WEEKLY;BYDAY=SU
        paceGroup:
          type: string
          enum: *ref_646
        requiredGear:
          example: *ref_647
          type: array
          items:
            type: string
        capacity:
          type: number
          description: RSVP cap; null = unlimited
        paceCapacities:
          type: object
          description: >-
            Per-pace-band caps, e.g. { "BEGINNER": 30, "INTERMEDIATE": 50,
            "ADVANCED": 20 }. Sum must not exceed capacity.
          example: *ref_648
        feeMinor:
          type: number
          description: Fee in minor units (paise/cents).
        feeCurrency:
          type: string
          example: INR
        routeId:
          type: string
    RequestClubOwnershipTransferDto:
      type: object
      properties: {}
    CreateClubTierDto:
      type: object
      properties:
        name:
          type: string
          example: Gold
        description:
          type: string
        priceAmount:
          type: number
          description: Major currency units, e.g. 499 for ₹499
        currency:
          type: string
          example: INR
        billingPeriod:
          type: string
          enum: &ref_649
            - MONTHLY
            - QUARTERLY
            - ANNUAL
          default: MONTHLY
        benefits:
          description: Max 20 entries, 200 chars each
          type: array
          items:
            type: string
        maxMembers:
          type: number
        trialDays:
          type: number
          description: Free trial window in days, 0..365
        annualDiscountPct:
          type: number
          description: Annual pre-pay discount pct, 0..100
      required:
        - name
        - priceAmount
    UpdateClubTierDto:
      type: object
      properties:
        name:
          type: string
          example: Gold
        description:
          type: string
        priceAmount:
          type: number
          description: Major currency units, e.g. 499 for ₹499
        currency:
          type: string
          example: INR
        billingPeriod:
          type: string
          enum: *ref_649
          default: MONTHLY
        benefits:
          description: Max 20 entries, 200 chars each
          type: array
          items:
            type: string
        maxMembers:
          type: number
          description: Member cap; null clears it.
        trialDays:
          type: number
          description: Free trial window in days, 0..365
        annualDiscountPct:
          type: number
          description: Annual pre-pay discount pct, 0..100
        isActive:
          type: boolean
    AdminDeactivateClubDto:
      type: object
      properties:
        reason:
          type: string
          description: >-
            Required ops-supplied reason. Stored on the club, returned to the
            club owner by the admin status endpoint, and recorded on the
            club.deactivated audit entry.
          minLength: 3
          maxLength: 500
      required:
        - reason
    AdminCreateClubMembershipDto:
      type: object
      properties:
        userId:
          type: string
          description: Target user UUID
        status:
          type: string
          enum: &ref_650
            - ACTIVE
            - PENDING
            - REMOVED
            - LEFT
            - MUTED
            - BANNED
        tierId:
          type: string
          description: Paid-tier UUID (optional)
        role:
          type: string
          description: Free-form role hint (e.g. FOUNDER)
      required:
        - userId
    AdminUpdateClubMembershipDto:
      type: object
      properties:
        userId:
          type: string
          description: Target user UUID
        status:
          type: string
          enum: *ref_650
        tierId:
          type: string
          description: Paid-tier UUID (optional)
        role:
          type: string
          description: Free-form role hint (e.g. FOUNDER)
    AdminCreateClubAnnouncementDto:
      type: object
      properties:
        title:
          type: string
        body:
          type: string
        visibility:
          type: string
          enum:
            - PUBLIC
            - MEMBERS_ONLY
            - STAFF_ONLY
          description: Audience gate. Forwarded to entity when schema lands.
        pinUntil:
          type: string
          description: ISO timestamp — pin until. Forwarded when schema lands.
      required:
        - title
        - body
    HideClubContentDto:
      type: object
      properties:
        reason:
          type: string
          description: >-
            Why this content is being hidden. Sent verbatim to the author and
            shown back to the club on the hidden-content list. Must not identify
            a reporter.
          minLength: 5
          maxLength: 300
          example: Off-topic promotion of a paid product.
      required:
        - reason
    ClubSetupWizardDto:
      type: object
      properties:
        tagline:
          type: string
        colorTheme:
          type: string
          example: '#0EA5E9'
        mission:
          type: string
        rules:
          type: string
        memberExpectations:
          type: string
        onboardingMessage:
          type: string
        name:
          type: string
          description: Club name (2–150 chars)
        slug:
          type: string
          description: Public Club URL slug
        description:
          type: string
          description: Long-form about/description text
        logoUrl:
          type: string
          description: Logo image URL (http/https only)
        bannerUrl:
          type: string
          description: Banner image URL (http/https only)
        city:
          type: string
          description: City
        country:
          type: string
          description: Country
        sports:
          description: Sport ids (uuid array, max 12)
          type: array
          items:
            type: string
        isPublic:
          type: boolean
          description: Public discovery flag (false = members-only club)
        requiresApproval:
          type: boolean
          description: Approval gate (true = gated, applications need admin approval)
        membershipRequiresPayment:
          type: boolean
          description: >-
            When true, a bare /join (no tierId) is refused — membership itself
            requires paying for one of this club's active tiers.
        refundPolicy:
          $ref: '#/components/schemas/RefundPolicyInput'
        pickupLocation:
          type: string
          description: >-
            Shiprocket pickup location name, as registered in the club’s own
            Shiprocket dashboard (Settings → Pickup Addresses). Used when this
            club ships goodies via Shiprocket.
    CreateClubInviteDto:
      type: object
      properties:
        email:
          type: string
          description: >-
            Invitee email. Supply at most one of email / phoneNumber; supply
            neither for a shareable link invite.
        phoneNumber:
          type: string
          description: Invitee phone (E.164 or digits). Mutually exclusive with email.
        expiresInDays:
          type: number
          description: >-
            Days until a LINK invite expires. Ignored for targeted invites,
            which name a recipient and so carry no forwarding risk.
          minimum: 1
          maximum: 365
        inviteRole:
          type: string
          description: >-
            Club role granted the moment this invite is accepted. Omit for a
            plain member. ADMIN may only be issued by an OWNER, mirroring the
            promote endpoint. OWNER is never accepted — use transfer-ownership.
            Role-bearing invites must name a recipient (email or phone); a
            forwardable link cannot carry a role.
          enum:
            - ADMIN
            - MODERATOR
        role:
          type: string
          deprecated: true
          description: Legacy no-op. Only "MEMBER" was ever valid. Use inviteRole.
          enum:
            - MEMBER
    RejectClubDto:
      type: object
      properties: {}
    DeactivateClubDto:
      type: object
      properties:
        reason:
          type: string
          description: >-
            Optional owner-supplied reason, recorded on the club.deactivated
            audit entry.
          maxLength: 500
    PreviewClubTierBreakdownDto:
      type: object
      properties:
        priceAmount:
          type: number
          description: Major currency units, e.g. 499 for ₹499
        billingPeriod:
          type: string
          enum: *ref_649
          default: MONTHLY
        currency:
          type: string
          example: INR
      required:
        - priceAmount
    AcceptClubOwnershipTransferDto:
      type: object
      properties: {}
    AdminSetTierCommissionDto:
      type: object
      properties:
        commissionPct:
          type: number
          description: >-
            Per-tier platform commission percent. Send null to clear the
            override.
          minimum: 0
          maximum: 100
          nullable: true
    AdminSetClubCommissionDto:
      type: object
      properties:
        tierCommissionPct:
          type: number
          description: >-
            Club-wide platform commission percent for paid membership tiers.
            Send null to clear the override.
          minimum: 0
          maximum: 100
          nullable: true
    VerifyClubKycBankDto:
      type: object
      properties:
        accountNumber:
          type: string
          description: Bank account number — digits only, 4–30 characters.
          example: '50100123456789'
          minLength: 4
          maxLength: 30
        ifsc:
          type: string
          description: >-
            IFSC code — exactly 11 characters: 4 letters, a 0, then 6
            alphanumerics.
          example: HDFC0000123
          minLength: 11
          maxLength: 11
      required:
        - accountNumber
        - ifsc
    ReviewClubKycDto:
      type: object
      properties:
        reason:
          type: string
          description: Reason shown to the club (10–500 chars)
          example: The uploaded PAN card is illegible. Please re-upload a clear scan.
          minLength: 10
          maxLength: 500
      required:
        - reason
    CreateClubRcGrantRequestDto:
      type: object
      properties:
        requestedRc:
          type: number
          description: RC Coins the club is asking for. Positive, at most 2 decimal places.
          example: 5000
          minimum: 1
          maximum: 10000000
        reason:
          type: string
          description: Why the club needs the coins. Shown verbatim to the reviewing admin.
          example: Seeding RC Coin prize slabs for our monsoon 10K series.
          minLength: 10
          maxLength: 1000
      required:
        - requestedRc
    ApproveClubRcGrantDto:
      type: object
      properties:
        approvedRc:
          type: number
          description: >-
            RC Coins actually granted. Defaults to the full requested amount.
            May be lower than requested, never higher.
          example: 2500
          minimum: 1
          maximum: 10000000
        decisionReason:
          type: string
          description: >-
            Context for the decision — required in practice when the granted
            amount is trimmed, so the club can see why.
          example: Approving 2,500 of the 5,000 requested until first payout lands.
          minLength: 10
          maxLength: 1000
    RejectClubRcGrantDto:
      type: object
      properties:
        decisionReason:
          type: string
          description: Reason shown to the club (10-1000 chars).
          example: >-
            Club KYC is not approved yet. Re-request once settlement details are
            verified.
          minLength: 10
          maxLength: 1000
      required:
        - decisionReason
    ReviewDecisionDto:
      type: object
      properties:
        decision:
          type: string
          enum:
            - VALID
            - INVALID
            - PARTIAL_CREDIT
            - ESCALATE
            - REQUEST_INFO
        notes:
          type: string
        escalationReason:
          type: string
          description: >-
            §71.11 — required-ish for ESCALATE; surfaced to the senior reviewer
            queue.
        requestedInfoPrompt:
          type: string
          description: >-
            §71.11 — REQUEST_INFO prompt shown to athlete (e.g. "upload Strava
            raw .fit").
        requestedInfoDueAt:
          type: string
          description: §71.11 — REQUEST_INFO deadline (ISO 8601).
      required:
        - decision
    AppealDecisionDto:
      type: object
      properties:
        decision:
          type: string
          enum:
            - UPHELD
            - REJECTED
        resolutionNotes:
          type: string
      required:
        - decision
    PostLiveSignalsDto:
      type: object
      properties: {}
    AppealEvidenceItemDto:
      type: object
      properties:
        type:
          type: string
          enum:
            - URL
            - EXTERNAL_SYNC
            - SCREENSHOT
        value:
          type: string
      required:
        - type
        - value
    SubmitAppealDto:
      type: object
      properties:
        reason:
          type: string
          description: >-
            Athlete's reason for appeal. PRD §71.12 requires substantive
            reasoning — minimum 10 chars (legacy per-flag route) / minimum 30
            chars (per-activity wrapper) per the Wave 1 brief. Stored verbatim
            on the appeal record.
        evidence:
          type: array
          items:
            $ref: '#/components/schemas/AppealEvidenceItemDto'
      required:
        - reason
    SubmitFlagInfoResponseDto:
      type: object
      properties:
        message:
          type: string
          minLength: 10
          maxLength: 2000
        attachmentUrls:
          description: >-
            Optional already-uploaded absolute http(s) URLs (max 8 per
            response).
          type: array
          items:
            type: string
      required:
        - message
    ScanQrDto:
      type: object
      properties:
        qrPayload:
          type: string
          description: Signed QR payload previously issued to a participant.
      required:
        - qrPayload
    SyncBatchCheckInActionDto:
      type: object
      properties:
        clientActionId:
          type: string
          description: >-
            Stable client-generated id for this action. Same id replayed N times
            → 1 server-side check-in. Use a UUID v4 or any unique 8-64 char
            token.
          example: c8a7b1f0-3a2e-4b6d-9f12-2a8e1c4f7d51
        type:
          type: string
          description: >-
            Type of scan: SCAN_QR (qrPayload required) or SCAN_BIB (bibNumber
            required).
          enum:
            - SCAN_QR
            - SCAN_BIB
        qrPayload:
          type: string
          description: QR payload (when type=SCAN_QR).
        bibNumber:
          type: string
          description: Bib number (when type=SCAN_BIB).
        stationId:
          type: string
          description: >-
            Volunteer-station identifier (e.g., "gate-A", "tent-1"). Stamped on
            the audit log so admins can see which station scanned first when
            conflicts surface.
          example: gate-A
        localTimestamp:
          type: string
          description: >-
            Client-clock ISO timestamp at the moment the volunteer captured the
            scan. Diverges from server `scannedAt` when an offline scan replays
            minutes/hours later.
          example: '2026-05-06T14:23:45.123Z'
      required:
        - clientActionId
        - type
    SyncBatchCheckInDto:
      type: object
      properties:
        actions:
          description: Batch of queued offline scan actions to replay.
          type: array
          items:
            $ref: '#/components/schemas/SyncBatchCheckInActionDto'
      required:
        - actions
    BibAssignmentItemDto:
      type: object
      properties: {}
    BulkAssignBibsDto:
      type: object
      properties:
        assignments:
          type: array
          items:
            $ref: '#/components/schemas/BibAssignmentItemDto'
      required:
        - assignments
    AutoAssignBibsDto:
      type: object
      properties:
        strategy:
          type: string
          enum:
            - MANUAL
            - AUTO_BY_REGISTRATION
            - AUTO_BY_TICKET_TYPE
            - AUTO_BY_DISTANCE
            - AUTO_BY_WAVE
        startingNumber:
          type: number
          default: 1
        dryRun:
          type: boolean
          description: When true, returns a preview without persisting.
          default: true
      required:
        - strategy
    UpdateBibDto:
      type: object
      properties:
        bibNumber:
          type: string
      required:
        - bibNumber
    StartHybridRaceDto:
      type: object
      properties:
        localRouteId:
          type: string
          description: Optional client-picked local route id (from /suggest).
        startCoordinate:
          type: object
          description: Optional client start coordinate { lat, lng }.
        registeredCityLatLng:
          type: object
          description: >-
            Athlete-registered city coordinates from onboarding ({ lat, lng }).
            PRD §21.3 + §21.8 city-radius gate.
        acknowledgeAdventurerOverride:
          type: boolean
          description: >-
            Acknowledge "Adventurer" override when starting outside registered
            city radius (PRD §21.8).
        isResume:
          type: boolean
          description: >-
            Set true when resuming an interrupted race (post-crash /
            post-restart). Default false → fresh start; backend rejects with
            EC7_DUPLICATE_START if an in-progress race exists.
    CheckpointDto:
      type: object
      properties:
        t:
          type: string
        lat:
          type: number
        lng:
          type: number
        distanceM:
          type: number
      required:
        - t
        - lat
        - lng
    SubmitCheckpointsDto:
      type: object
      properties:
        checkpoints:
          type: array
          items:
            $ref: '#/components/schemas/CheckpointDto'
      required:
        - checkpoints
    LivePositionPointDto:
      type: object
      properties:
        lat:
          type: number
          description: WGS84 latitude
        lng:
          type: number
          description: WGS84 longitude
        ts:
          type: number
          description: Sample timestamp (UTC ms epoch)
        accuracy:
          type: number
          description: Horizontal accuracy radius (meters)
          minimum: 0
          maximum: 10000
      required:
        - lat
        - lng
        - ts
        - accuracy
    PushLivePositionDto:
      type: object
      properties:
        resultId:
          type: string
          description: Caller’s in-flight HybridRaceResult id
        points:
          description: Batch of GPS samples, max 60 per call (~30s of 1Hz capture).
          type: array
          items:
            $ref: '#/components/schemas/LivePositionPointDto'
        clientTelemetry:
          type: object
          additionalProperties: true
      required:
        - resultId
        - points
    FinishHybridRaceDto:
      type: object
      properties:
        distanceMeters:
          type: number
        durationSeconds:
          type: number
        elevationGainM:
          type: number
        activityId:
          type: string
        clientTelemetry:
          type: object
          description: >-
            Optional device telemetry for the §70.10 edge-case observation
            ledger.
      required:
        - distanceMeters
        - durationSeconds
    SuggestLocalRouteQueryDto:
      type: object
      properties:
        lat:
          type: number
        lng:
          type: number
    InitPhotoCheckQueryDto:
      type: object
      properties:
        photoCheckId:
          type: string
    SubmitPhotoCheckDto:
      type: object
      properties:
        capturedAt:
          type: string
        capturedLat:
          type: number
        capturedLng:
          type: number
        capturedAccuracyM:
          type: number
        imageS3Key:
          type: string
      required:
        - capturedAt
        - capturedLat
        - capturedLng
        - imageS3Key
    SkipPhotoCheckDto:
      type: object
      properties:
        acknowledgment:
          type: string
      required:
        - acknowledgment
    AppealPhotoCheckDto:
      type: object
      properties:
        capturedAt:
          type: string
        capturedLat:
          type: number
        capturedLng:
          type: number
        imageS3Key:
          type: string
        reason:
          type: string
        mlTrainingConsent:
          type: boolean
          default: false
      required:
        - capturedAt
        - capturedLat
        - capturedLng
        - imageS3Key
    HybridConfigInputDto:
      type: object
      properties:
        pricePct:
          type: number
          minimum: 0
          maximum: 200
        windowStart:
          type: string
          description: ISO-8601 timestamp — start of hybrid participation window
        windowEnd:
          type: string
          description: ISO-8601 timestamp — end of hybrid participation window
        raceStartTime:
          type: string
          description: Synchronised global race-start moment (ISO-8601 UTC)
        merchIncluded:
          type: boolean
          description: Whether hybrid registration includes merch.
        validationLevel:
          type: string
          enum:
            - standard
            - strict
            - elite
        leaderboardMode:
          type: string
          enum:
            - separate
            - unified
    UpdateHybridConfigDto:
      type: object
      properties:
        hybridEnabled:
          type: boolean
          description: Enable/disable hybrid race participation entirely.
        hybridConfig:
          description: Structured hybrid-race configuration block.
          allOf:
            - $ref: '#/components/schemas/HybridConfigInputDto'
        leaderboardPolicy:
          type: string
          enum:
            - RANKED
            - ALL_FINISHERS_MEDAL
            - DEGRADED_MEDAL
          description: >-
            Per-event leaderboard policy. RANKED keeps the classic competitive
            board.
    FlagResultForReviewDto:
      type: object
      properties:
        dqReasonCode:
          type: string
          enum: &ref_651
            - NO_ACTIVITY
            - GPS_GAP
            - ELEVATION_MISMATCH
            - DISTANCE_MISMATCH
            - EXTERNAL_SOURCE_DISALLOWED
            - DEVICE_UNVERIFIED
            - ANTI_CHEAT_FLAGGED
            - TIER_MISMATCH
            - MANUAL_ORGANIZER_REVIEW
            - NOT_VALID
        notes:
          type: string
    ResolveReviewDto:
      type: object
      properties:
        outcome:
          type: string
          enum:
            - VERIFIED
            - REJECTED
        dqReasonCode:
          type: string
          enum: *ref_651
        notes:
          type: string
      required:
        - outcome
    UploadPhysicalResultItem:
      type: object
      properties: {}
    UploadPhysicalResultsDto:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/UploadPhysicalResultItem'
      required:
        - results
    UpdateMerchShipmentDto:
      type: object
      properties:
        weight:
          type: number
          description: Package weight (≥ 0).
        weightUnit:
          type: string
          enum:
            - kg
            - g
            - lb
        length:
          type: number
          description: Length (≥ 0).
        width:
          type: number
          description: Width (≥ 0).
        height:
          type: number
          description: Height (≥ 0).
        dimensionUnit:
          type: string
          enum:
            - cm
            - in
        shipFromAddress:
          type: string
          description: Origin address the parcel ships from.
    CreateSigningSessionDto:
      type: object
      properties:
        eventId:
          type: string
          description: Hybrid race event id
        resultId:
          type: string
          description: In-flight HybridRaceResult id
        routeType:
          type: string
          enum:
            - HYBRID
            - RANKED_ACTIVITY
            - FREE_WORKOUT
          description: Route type the signing session will protect.
        appBuild:
          type: string
          description: >-
            Format `ios:1.4.0+482` or `android:1.4.0+482`. Used by the
            rollout-mode app-version gate.
        platform:
          type: string
          enum:
            - ios
            - android
        deviceMetadataSummary:
          type: object
          description: >-
            Privacy-safe device metadata summary (no IMEI / no advertising id /
            no installed-app list — see §70.4 / privacy minimization).
          additionalProperties: true
        attestationToken:
          type: string
          description: >-
            Optional Apple App Attest / Google Play Integrity token. When
            absent, Stage 6 device-integrity status records `unavailable`.
      required:
        - eventId
        - resultId
        - routeType
        - appBuild
        - platform
    DecideReportAppealDto:
      type: object
      properties:
        decision:
          type: string
          enum:
            - APPROVED
            - REJECTED
        decisionNotes:
          type: string
      required:
        - decision
    CreateReportDto:
      type: object
      properties:
        targetType:
          type: string
          enum:
            - ACTIVITY
            - CLUB
            - CLUB_POST
            - CLUB_DM_MESSAGE
            - CHALLENGE
            - EVENT
            - USER
            - FEED_COMMENT
            - CLUB_POST_COMMENT
            - ROUTE
            - USER_DM_MESSAGE
            - FEED_POST
            - STORY
        targetId:
          type: string
        reason:
          type: string
        notes:
          type: string
        evidenceUrls:
          type: array
          items:
            type: string
      required:
        - targetType
        - targetId
        - reason
    SubmitReportAppealDto:
      type: object
      properties:
        reason:
          type: string
      required:
        - reason
    DestructiveActionDto:
      type: object
      properties:
        reason:
          type: string
          description: >-
            Free-text justification for the destructive action. 10–500 chars
            after trim. Stored as audit metadata length only — the raw text is
            NEVER stored in the audit log.
          minLength: 10
          maxLength: 500
      required:
        - reason
    UpdateOrganizerEazrTagDto:
      type: object
      properties:
        enabled:
          type: boolean
          description: Whether Eazr API-key clients may access the event catalogue
      required:
        - enabled
    AddEvidenceDto:
      type: object
      properties: {}
    SaveDefenseDraftDto:
      type: object
      properties: {}
    TerminalReasonDto:
      type: object
      properties: {}
    UnblockIpDto:
      type: object
      properties: {}
    HealthActivityDeletionsDto:
      type: object
      properties:
        externalIds:
          description: Platform record UUIDs removed from the device health store
          type: array
          items:
            type: string
      required:
        - externalIds
    StartTrackingSessionDto:
      type: object
      properties: {}
    AppendTrackingPointsDto:
      type: object
      properties: {}
    FinishTrackingSessionDto:
      type: object
      properties: {}
    AbandonTrackingSessionDto:
      type: object
      properties: {}
    CreateLiveTrackingShareRecipientDto:
      type: object
      properties:
        kind:
          type: string
          enum:
            - PHONE
            - EMAIL
            - REPEAK_USER
          description: >-
            Identity type for this recipient. Exactly one of phone / email /
            userId must be provided, matching this enum value.
        phone:
          type: string
          description: Required when kind=PHONE. E.164 format recommended.
          maxLength: 20
        email:
          type: string
          description: Required when kind=EMAIL.
          maxLength: 255
        userId:
          type: string
          description: >-
            Required when kind=REPEAK_USER. UUID of the recipient Repeak
            account.
        name:
          type: string
          description: Display name shown to the athlete + on the recipient page.
          maxLength: 120
        relation:
          type: string
          description: >-
            Optional relation tag (e.g. "Spouse" / "Parent" / "Coach" /
            "Friend"). Mirrors EventParticipant.emergencyContact.relation.
          maxLength: 40
      required:
        - kind
        - name
    CreateLiveTrackingShareDto:
      type: object
      properties:
        recipients:
          description: >-
            Recipients for this live-tracking share. 1–5 entries; each carries
            exactly one identity (phone / email / userId).
          minItems: 1
          maxItems: 5
          type: array
          items:
            $ref: '#/components/schemas/CreateLiveTrackingShareRecipientDto'
        ttlHours:
          type: number
          description: >-
            Time-to-live for this share, in hours. Default 4. Hard maximum 12
            (server clamps).
          minimum: 1
          maximum: 12
          default: 4
      required:
        - recipients
    CancelLiveTrackingShareDto:
      type: object
      properties:
        reason:
          type: string
          description: Free-text reason for cancellation. Stored in audit trail.
          maxLength: 500
    SendMessageDto:
      type: object
      properties:
        body:
          type: string
          description: Message text body (max 4000 chars)
        mediaUrl:
          type: string
          description: GCS public URL of attached media
        mediaType:
          type: string
          description: 'Media type: IMAGE | VIDEO | AUDIO'
          enum:
            - IMAGE
            - VIDEO
            - AUDIO
        messageType:
          type: string
          description: Special message type — "event_share" to share an event card
          enum:
            - event_share
        eventId:
          type: string
          description: Event id or slug — required when messageType is "event_share"
    MediaUploadDto:
      type: object
      properties:
        mimeType:
          type: string
          description: MIME type of the file to upload (e.g. image/jpeg, video/mp4)
      required:
        - mimeType
    CreateLinkDto:
      type: object
      properties:
        targetPath:
          type: string
          description: >-
            Canonical PATH on the public web domain (leading slash). e.g.
            /events/mumbai-marathon-2026, /@salman, /r/CODE. Never a full URL.
          example: /events/mumbai-marathon-2026
        campaign:
          type: string
        utmSource:
          type: string
        utmMedium:
          type: string
        utmCampaign:
          type: string
        expiresAt:
          type: string
          description: ISO8601 expiry. After this, the link resolves as expired.
      required:
        - targetPath
    SelectTierBody:
      type: object
      properties: {}
    CreatePricingTierBody:
      type: object
      properties: {}
    UpdatePricingTierBody:
      type: object
      properties: {}
    CreateMarketplaceEconomicsBody:
      type: object
      properties: {}
    UpdateMarketplaceEconomicsBody:
      type: object
      properties: {}
    ShareEventDto:
      type: object
      properties:
        surface:
          type: string
          enum: &ref_652
            - HYBRID_RACE_RESULT
            - ACTIVITY
            - YEAR_IN_SPORT
            - REPEAK_ID
            - FEED_EVENT
            - EVENT
            - CHALLENGE
            - ROUTE
            - POST
            - EDITION
            - CLUB
            - BRAND
            - REFERRAL
        subjectId:
          type: string
        channel:
          type: string
          enum:
            - NATIVE_SHEET
            - WHATSAPP
            - INSTAGRAM
            - COPY_LINK
            - UNKNOWN
        utm:
          type: object
          description: utm tags; server normalises source/medium/campaign
          example:
            source: repeak_share
            medium: mobile
            campaign: race
      required:
        - surface
        - subjectId
    ShareLinkOpenedDto:
      type: object
      properties:
        surface:
          type: string
          enum: *ref_652
        subjectId:
          type: string
        utmSource:
          type: string
        utmMedium:
          type: string
        utmCampaign:
          type: string
      required:
        - surface
        - subjectId
    InstallAttributedDto:
      type: object
      properties:
        surface:
          type: string
          enum: *ref_652
        utmSource:
          type: string
        utmMedium:
          type: string
        utmCampaign:
          type: string
    CreateAdaptivePlanDto:
      type: object
      properties:
        targetDistance:
          type: string
          enum:
            - TEN_K
            - HALF
        targetEventId:
          type: string
        goalTimeSeconds:
          type: number
          description: Goal finish time in seconds
        startDate:
          type: string
          description: ISO date
        targetDate:
          type: string
          description: ISO date; must be after startDate
        weeklyRunDays:
          type: number
          description: Weekly run days 3..6
        baselineWeeklyKm:
          type: number
          description: Athlete's honest recent weekly km
        baselineActivityId:
          type: string
      required:
        - targetDistance
        - startDate
        - targetDate
        - weeklyRunDays
    LaunchSessionDto:
      type: object
      properties:
        executionSource:
          type: string
          enum: &ref_653
            - APPLE_WATCH
            - PHONE_GUIDED
            - MANUAL
      required:
        - executionSource
    CompleteSessionDto:
      type: object
      properties:
        completedActivityId:
          type: string
        notes:
          type: string
        executionSource:
          type: string
          enum: *ref_653
        actualDurationSeconds:
          type: number
        actualDistanceMeters:
          type: number
        avgPaceSecPerKm:
          type: number
        avgHeartRateBpm:
          type: number
    AbandonSessionDto:
      type: object
      properties:
        reason:
          type: string
        executionSource:
          type: string
          enum: *ref_653
        completedIntervalCount:
          type: number
    CreateRouteDto:
      type: object
      properties:
        name:
          type: string
        city:
          type: string
        country:
          type: string
          default: IN
        distanceMeters:
          type: number
        distanceBucket:
          type: string
          enum: &ref_654
            - 5K
            - 10K
            - 15K
            - HALF
        elevationGainMeters:
          type: number
        surface:
          type: string
          enum: &ref_655
            - ROAD
          default: ROAD
        terrain:
          type: string
          enum: &ref_656
            - FLAT
            - ROLLING
            - HILLY
          default: FLAT
        startLat:
          type: number
        startLng:
          type: number
        polyline:
          type: string
          description: JSON-encoded array of [lat,lng] pairs.
        notes:
          type: string
        source:
          type: string
          enum: &ref_657
            - CURATED_V1
            - COMMUNITY
          default: CURATED_V1
        sport:
          type: string
          enum: &ref_658
            - RUN
            - CYCLE
            - WALK
            - HIKE
          default: RUN
          description: >-
            Sport this route is designed for. Wire codes: RUN | CYCLE | WALK |
            HIKE.
      required:
        - name
        - city
        - distanceMeters
        - distanceBucket
        - startLat
        - startLng
        - polyline
    UpdateRouteDto:
      type: object
      properties:
        name:
          type: string
        city:
          type: string
        country:
          type: string
          default: IN
        distanceMeters:
          type: number
        distanceBucket:
          type: string
          enum: *ref_654
        elevationGainMeters:
          type: number
        surface:
          type: string
          enum: *ref_655
          default: ROAD
        terrain:
          type: string
          enum: *ref_656
          default: FLAT
        startLat:
          type: number
        startLng:
          type: number
        polyline:
          type: string
          description: JSON-encoded array of [lat,lng] pairs.
        notes:
          type: string
        source:
          type: string
          enum: *ref_657
          default: CURATED_V1
        sport:
          type: string
          enum: *ref_658
          default: RUN
          description: >-
            Sport this route is designed for. Wire codes: RUN | CYCLE | WALK |
            HIKE.
    SubmitVirtualRunDto:
      type: object
      properties: {}
    SetSingleConsentDto:
      type: object
      properties: {}
    SetBulkConsentDto:
      type: object
      properties: {}
    DataErasureRequestDto:
      type: object
      properties: {}
    DataErasureCancelDto:
      type: object
      properties: {}
    AdminErasureRejectDto:
      type: object
      properties: {}
    CreatePrizeTaxDto:
      type: object
      properties: {}
    AggregateForm16ADto:
      type: object
      properties: {}
    GenerateForm16ADto:
      type: object
      properties: {}
    PreviewMergeDto:
      type: object
      properties: {}
    ProposeMergeDto:
      type: object
      properties: {}
    CancelMergeDto:
      type: object
      properties: {}
    NotifyWinnerDto:
      type: object
      properties: {}
    RevealSafetyProfileDto:
      type: object
      properties:
        justification:
          type: string
          description: >-
            Required justification for the medical-info reveal. Examples: "bib
            42 — heat exhaustion suspected", "incident #42 paramedic on scene".
            Stored on the medical_info_access_logs row.
        emergency:
          type: boolean
          description: >-
            Set true when the reveal is in active emergency context (paramedic
            on scene, athlete unresponsive). Switches the access log reason to
            EMERGENCY_REVEAL.
          default: false
      required:
        - justification
    CreateMedicalIncidentDto:
      type: object
      properties:
        incidentType:
          type: string
          enum:
            - DEHYDRATION
            - CRAMPING
            - CHEST_PAIN
            - ALLERGIC_REACTION
            - COLLAPSE
            - INJURY
            - HEAT_EXHAUSTION
            - GI_DISTRESS
            - OTHER
        severity:
          type: string
          enum: &ref_659
            - MILD
            - MODERATE
            - SEVERE
            - CRITICAL
        description:
          type: string
          description: What happened, interventions taken so far.
        athleteResponsive:
          type: boolean
          default: true
        ambulanceDispatched:
          type: boolean
          default: false
        hospitalTransferred:
          type: boolean
          default: false
        location:
          type: string
          description: On-course location / checkpoint.
      required:
        - incidentType
        - severity
        - description
    UpdateMedicalIncidentDto:
      type: object
      properties:
        status:
          type: string
          enum:
            - OPEN
            - UNDER_OBSERVATION
            - ESCALATED
            - TRANSFERRED
            - CLOSED
        severity:
          type: string
          enum: *ref_659
        description:
          type: string
        athleteResponsive:
          type: boolean
        ambulanceDispatched:
          type: boolean
        hospitalTransferred:
          type: boolean
        location:
          type: string
        resolutionNotes:
          type: string
          description: Notes for the incident timeline.
        hospitalName:
          type: string
          description: >-
            Destination hospital name. Required when status transitions to
            TRANSFERRED (server enforces).
        ambulanceReference:
          type: string
          description: >-
            Ambulance dispatch / transport reference number. Required when
            status transitions to TRANSFERRED.
    CloseMedicalIncidentDto:
      type: object
      properties:
        resolutionNotes:
          type: string
          description: Required closing note for audit trail.
      required:
        - resolutionNotes
    RiskActionDto:
      type: object
      properties:
        note:
          type: string
          description: Optional admin note attached to the audit log row. Max 1000 chars.
    QuoteSubscriptionDto:
      type: object
      properties:
        planPriceId:
          type: string
          description: Chosen plan price row id
        couponCode:
          type: string
          description: Coupon code as typed by the user
        countryCode:
          type: string
          description: ISO-3166 alpha-2, e.g. IN
        providerKey:
          type: string
          enum:
            - CASHFREE
            - RAZORPAY
            - STRIPE
      required:
        - planPriceId
    CreatePlanDto:
      type: object
      properties:
        code:
          type: string
          example: ATHLETE_PASSPORT
        audience:
          type: string
          enum: &ref_662
            - ATHLETE
            - ORGANIZER
            - BRAND
            - CLUB
        name:
          type: string
        displayName:
          type: string
        description:
          type: string
        tagline:
          type: string
        badgeText:
          type: string
          example: Most Popular
        themeColor:
          type: string
          example: '#0C656D'
        iconUrl:
          type: string
        bannerUrl:
          type: string
        sortOrder:
          type: number
          default: 0
        priority:
          type: number
          default: 0
          description: Tier rank; higher = better. Infers upgrade/downgrade direction.
        isRecommended:
          type: boolean
          default: false
        isDefaultPlan:
          type: boolean
          default: false
          description: The plan free users resolve to. Exactly one per audience.
        visibility:
          type: string
          enum: &ref_660
            - PUBLISHED
            - HIDDEN
            - DRAFT
            - INVITE_ONLY
            - INTERNAL
            - BETA
            - ARCHIVED
        status:
          type: string
          enum: &ref_661
            - ACTIVE
            - DRAFT
            - DISABLED
            - ARCHIVED
            - SCHEDULED
        visibilityFlagKey:
          type: string
          description: >-
            Delegates BETA / INVITE_ONLY visibility to the existing feature-flag
            engine
      required:
        - code
        - audience
        - name
    UpdatePlanDto:
      type: object
      properties:
        name:
          type: string
        displayName:
          type: string
        description:
          type: string
        tagline:
          type: string
        badgeText:
          type: string
        themeColor:
          type: string
        iconUrl:
          type: string
        bannerUrl:
          type: string
        sortOrder:
          type: number
        priority:
          type: number
        isRecommended:
          type: boolean
        isDefaultPlan:
          type: boolean
        visibility:
          type: string
          enum: *ref_660
        status:
          type: string
          enum: *ref_661
        visibilityFlagKey:
          type: string
    MintVersionDto:
      type: object
      properties:
        changeNote:
          type: string
          description: Why this version exists — shows in the diff view
      required:
        - changeNote
    UpdateVersionDto:
      type: object
      properties:
        trialEnabled:
          type: boolean
        trialDays:
          type: number
        trialPolicy:
          type: string
          enum:
            - NONE
            - ONE_TIME_PER_USER
            - ONE_TIME_PER_PLAN
            - REPEATABLE
        paymentMethodRequired:
          type: boolean
        autoRenewDefault:
          type: boolean
        taxCategoryId:
          type: string
        effectiveFrom:
          format: date-time
          type: string
        effectiveTo:
          format: date-time
          type: string
        changeNote:
          type: string
    UpsertPriceDto:
      type: object
      properties:
        billingCycle:
          type: string
          enum:
            - MONTHLY
            - QUARTERLY
            - HALF_YEARLY
            - YEARLY
            - LIFETIME
            - CUSTOM_DAYS
            - PER_EVENT
        currency:
          type: string
          example: INR
        amountMinor:
          type: number
          example: 19900
          description: Minor units (paise)
        customDays:
          type: number
        countryCode:
          type: string
          description: ISO-3166 alpha-2. Mutually exclusive with regionCode.
        regionCode:
          type: string
          description: Mutually exclusive with countryCode.
        compareAtAmountMinor:
          type: number
          description: Strike-through anchor, minor units
        taxBehavior:
          type: string
          enum:
            - INCLUSIVE
            - EXCLUSIVE
          default: EXCLUSIVE
      required:
        - billingCycle
        - currency
        - amountMinor
    PublishVersionDto:
      type: object
      properties:
        allowUnsyncedProvider:
          type: boolean
          default: false
          description: >-
            Publish for display/entitlement before a payment provider is wired.
            Checkout still refuses to sell it.
    CreateFeatureDto:
      type: object
      properties:
        code:
          type: string
          example: ai_queries
        name:
          type: string
        description:
          type: string
        categoryCode:
          type: string
        parentFeatureCode:
          type: string
        defaultLimitUnit:
          type: string
          example: QUERIES
        isVisible:
          type: boolean
          default: true
          description: false = backend-only gate
        sortOrder:
          type: number
      required:
        - code
        - name
    SetPlanFeatureDto:
      type: object
      properties:
        featureCode:
          type: string
          example: ai_queries
        enabled:
          type: boolean
        limitValue:
          type: number
          description: null / omitted = unlimited
        limitUnit:
          type: string
        limitPeriod:
          type: string
          enum:
            - DAY
            - WEEK
            - MONTH
            - BILLING_PERIOD
            - LIFETIME
        resetPolicy:
          type: string
          enum:
            - CALENDAR
            - ROLLING
            - BILLING_ANCHOR
          default: CALENDAR
        graceValue:
          type: number
          description: Soft overage before a hard block
        overagePolicy:
          type: string
          enum:
            - BLOCK
            - WARN
            - ALLOW_BILLABLE
          default: BLOCK
        metadata:
          type: object
          description: 'Feature-scoped config, e.g. {"historyDays": 90}'
      required:
        - featureCode
        - enabled
    SimulateEntitlementsDto:
      type: object
      properties:
        userId:
          type: string
        audience:
          type: string
          enum: *ref_662
        planVersionId:
          type: string
        planPriceId:
          type: string
        couponCode:
          type: string
        countryCode:
          type: string
    CouponScopeDto:
      type: object
      properties:
        scopeType:
          type: string
          enum:
            - PLAN
            - PLAN_VERSION
            - BILLING_CYCLE
            - COUNTRY
            - CURRENCY
            - PROVIDER
            - AUDIENCE
            - USER_SEGMENT
        scopeValue:
          type: string
        isExclusion:
          type: boolean
          default: false
      required:
        - scopeType
        - scopeValue
    BulkCouponTemplateDto:
      type: object
      properties:
        discountType:
          type: string
          enum: *ref_663
        percentValue:
          type: number
          description: PERCENT only — whole percent 1–100
        flatAmountMinor:
          type: number
          description: FLAT only — minor units
        currency:
          type: string
          description: Required for FLAT
        maxDiscountMinor:
          type: number
          description: PERCENT cap, minor units
        minPurchaseMinor:
          type: number
          description: Minimum order, minor units
        freePeriodCount:
          type: number
          description: FREE_PERIOD only — cycles free
        trialExtensionDays:
          type: number
          description: TRIAL_EXTENSION only — extra days
        appliesToRenewals:
          type: boolean
          default: true
          description: >-
            false = first cycle only. Requires a provider that supports a first
            charge differing from the mandate amount, or the discount silently
            repeats on every renewal.
        newSubscribersOnly:
          type: boolean
          default: false
        maxRedemptions:
          type: number
          description: Total redemptions; null = unlimited
        maxRedemptionsPerUser:
          type: number
          description: Per-user redemptions; null = unlimited
        stackable:
          type: boolean
          default: false
        startsAt:
          format: date-time
          type: string
        endsAt:
          format: date-time
          type: string
        publicDescription:
          type: string
          description: Shown to the user when the code is rejected
        internalNote:
          type: string
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/CouponScopeDto'
        name:
          type: string
          description: Label applied to every coupon in the batch
          example: Ambassador programme
      required:
        - discountType
    BulkGenerateCouponsDto:
      type: object
      properties:
        prefix:
          type: string
          example: AMBASSADOR
        count:
          type: number
          example: 50
        batchTag:
          type: string
        template:
          $ref: '#/components/schemas/BulkCouponTemplateDto'
      required:
        - prefix
        - count
        - batchTag
        - template
    PreviewCouponDto:
      type: object
      properties:
        planPriceId:
          type: string
        countryCode:
          type: string
        userId:
          type: string
          description: Simulate for a specific user
        providerKey:
          type: string
          enum:
            - CASHFREE
            - RAZORPAY
            - STRIPE
        isRenewal:
          type: boolean
          default: false
      required:
        - planPriceId
    UpsertRegionDto:
      type: object
      properties:
        code:
          type: string
          example: EU
        name:
          type: string
          example: Europe
        countryCodes:
          example:
            - DE
            - FR
            - ES
          description: ISO-3166 alpha-2. A country may belong to only one region.
          type: array
          items:
            type: string
        defaultCurrency:
          type: string
          example: EUR
      required:
        - code
        - name
        - countryCodes
        - defaultCurrency
    UpsertTaxCategoryDto:
      type: object
      properties:
        code:
          type: string
          example: GST_18
        name:
          type: string
          example: India GST 18%
        computation:
          type: string
          enum:
            - PERCENT
            - NONE
            - COMPOUND
      required:
        - code
        - name
    AddTaxRateDto:
      type: object
      properties:
        taxCategoryId:
          type: string
        percentBasis:
          type: number
          example: 1800
          description: BASIS POINTS — 1800 means 18%. Never a decimal percentage.
        countryCode:
          type: string
          description: ISO alpha-2; omit for a global rate
        stateCode:
          type: string
          description: Sub-national code, e.g. an Indian state
        hsnSacCode:
          type: string
        effectiveFrom:
          format: date-time
          type: string
          description: Defaults to now. Supersedes the open rate for this scope.
      required:
        - taxCategoryId
        - percentBasis
    UpsertProviderDto:
      type: object
      properties:
        providerKey:
          type: string
          example: CASHFREE
        displayName:
          type: string
          example: Cashfree Payments
        enabled:
          type: boolean
          default: false
          description: Rejected unless an adapter for this key is compiled in.
        supportsRecurring:
          type: boolean
        supportsMandates:
          type: boolean
        supportsRefunds:
          type: boolean
        supportsFirstChargeOverride:
          type: boolean
          description: >-
            Whether a first charge may differ from the mandate amount. FALSE
            means first-cycle-only coupons are impossible on this provider — the
            discount would repeat on every renewal.
        supportedCurrencies:
          type: array
          items:
            type: string
        supportedCountries:
          type: array
          items:
            type: string
        priority:
          type: number
      required:
        - providerKey
        - displayName
    UpsertProviderRefDto:
      type: object
      properties:
        planPriceId:
          type: string
        providerKey:
          type: string
          enum:
            - CASHFREE
            - RAZORPAY
            - STRIPE
        providerPlanId:
          type: string
          description: The provider-side plan identifier
        syncStatus:
          type: string
          enum:
            - PENDING
            - SYNCED
            - FAILED
          description: A paid price cannot be published until this is SYNCED.
        lastError:
          type: string
      required:
        - planPriceId
        - providerKey
    AddFeatureDependencyDto:
      type: object
      properties:
        featureCode:
          type: string
          example: ai_queries
        requiresFeatureCode:
          type: string
          example: ai
          description: Must be enabled wherever `featureCode` is enabled
      required:
        - featureCode
        - requiresFeatureCode
    SubmitPurchaseDto:
      type: object
      properties:
        store:
          type: string
          description: Which store the purchase happened on.
          enum:
            - APP_STORE
            - PLAY_STORE
        purchaseToken:
          type: string
          description: >-
            Apple: originalTransactionId. Google: the purchase token. Both are
            the store's stable lineage key.
        transactionId:
          type: string
          description: This period's transaction id, when the client has it.
        productId:
          type: string
          description: Store product id, used only for logging when lookup fails.
      required:
        - store
        - purchaseToken
    UpdateSubscriptionSettingsDto:
      type: object
      properties:
        subscriptionsEnabled:
          type: boolean
          description: >-
            Master switch. False hides the paywall everywhere, refuses quotes,
            and makes all feature gates inert. Never revokes existing
            subscribers.
        enforcementEnabled:
          type: boolean
          description: >-
            Whether feature gates actually deny. False = shadow mode (log only).
            Forced false while subscriptionsEnabled is false.
        iapEnabled:
          type: boolean
          description: Offer store purchases in the mobile app.
        webCheckoutEnabled:
          type: boolean
          description: Offer web checkout on web surfaces.
        renewalToleranceHours:
          type: number
          description: >-
            Hours past a period end before a missing renewal is treated as
            lapsed. Covers store notification latency — too low revokes access
            from paying subscribers over a queue delay, too high leaks free
            access. 0–720.
          minimum: 0
          maximum: 720
          example: 48
        dunningGraceDays:
          type: number
          description: >-
            Days a lapsed subscriber keeps access while the store retries the
            charge. Applies to FAILED RENEWALS only — a deliberate cancellation
            never receives grace. 0 disables dunning. 0–90.
          minimum: 0
          maximum: 90
          example: 3
        note:
          type: string
          description: >-
            Operator note explaining the current posture. Shown beside the
            switch.
    ExtendSubscriptionDto:
      type: object
      properties:
        days:
          type: number
          description: >-
            Days to add. Additive only — the period end moves forward and is
            never shortened.
          minimum: 1
          maximum: 3650
          example: 30
        reason:
          type: string
          description: Why. Shown in the audit trail; a support ticket reference is ideal.
          example: 'Ticket #4821 — charged but entitlement never applied'
      required:
        - days
        - reason
    RevokeSubscriptionDto:
      type: object
      properties:
        reason:
          type: string
          description: >-
            Why access is being withdrawn. Recorded on the subscription and in
            the audit log.
          example: Chargeback received from issuing bank
      required:
        - reason
    UpsertStoreProductRefDto:
      type: object
      properties:
        planPriceId:
          type: string
          description: Plan price row this store product bills
        storeKey:
          type: string
          enum:
            - APP_STORE
            - PLAY_STORE
        storeProductId:
          type: string
          description: >-
            Apple product identifier, or Google subscription product id. Must be
            unique per store.
        storeBasePlanId:
          type: string
          description: Google only — base plan id within the subscription product.
        storeOfferId:
          type: string
          description: Intro / promotional offer id.
        storeAmountMinor:
          type: number
          description: >-
            Price the STORE charges, in minor units. Recorded to detect drift
            against our catalog price.
        storeCurrency:
          type: string
          description: ISO-4217, e.g. INR
        markSynced:
          type: boolean
          description: >-
            Assert the product exists and is live in the store console. Required
            before the price becomes purchasable on mobile.
      required:
        - planPriceId
        - storeKey
        - storeProductId
    MintCohortLinkDto:
      type: object
      properties: {}
    VerifyCohortLinkDto:
      type: object
      properties: {}
    CreateTrainingProgramDto:
      type: object
      properties:
        name:
          type: string
          maxLength: 200
        description:
          type: string
        sport:
          type: string
          description: Sport key (e.g., "running", "cycling").
          maxLength: 40
        totalDurationWeeks:
          type: number
          minimum: 1
          maximum: 52
        eventId:
          type: string
          description: >-
            Optional event scope — when set, anchors the template to a specific
            event the organizer owns.
      required:
        - name
        - sport
        - totalDurationWeeks
    UpdateTrainingProgramDto:
      type: object
      properties:
        name:
          type: string
          maxLength: 200
        description:
          type: string
        sport:
          type: string
          description: Sport key (e.g., "running", "cycling").
          maxLength: 40
        totalDurationWeeks:
          type: number
          minimum: 1
          maximum: 52
        eventId:
          type: string
          description: >-
            Optional event scope — when set, anchors the template to a specific
            event the organizer owns.
        status:
          type: string
          enum:
            - DRAFT
            - PUBLISHED
            - ARCHIVED
    AddWorkoutDto:
      type: object
      properties:
        weekNumber:
          type: number
          minimum: 1
          maximum: 52
        dayNumber:
          type: number
          minimum: 1
          maximum: 7
        workoutType:
          type: string
          enum:
            - EASY
            - TEMPO
            - INTERVALS
            - HILL_REPEATS
            - LONG
            - RECOVERY
            - CROSS_TRAIN
            - REST
        distanceMeters:
          type: number
        durationMinutes:
          type: number
        intensityZone:
          type: string
          maxLength: 40
        description:
          type: string
        audioCuesConfig:
          type: object
        sourceLibraryWorkoutId:
          type: string
      required:
        - weekNumber
        - dayNumber
        - workoutType
    UpdateWorkoutDto:
      type: object
      properties:
        completionStatus:
          type: string
          description: Workout completion status
          enum:
            - pending
            - completed
            - partial
            - missed
            - exceeded
          example: completed
        actualActivityId:
          type: string
          description: Actual activity ID if linked to an activity
        actualDistanceKm:
          type: number
          description: Actual distance completed in kilometers
          example: 5.5
        actualDurationMinutes:
          type: number
          description: Actual duration in minutes
          example: 35
        actualPace:
          type: string
          description: Actual pace achieved
          example: 6:30 min/km
        performanceNotes:
          type: string
          description: Performance notes or comments
          example: Felt great, maintained consistent pace
    CustomizeFromLibraryDto:
      type: object
      properties:
        libraryWorkoutId:
          type: string
          description: Library workout id (e.g., "lib-easy-30min-z2").
        weekNumber:
          type: number
          minimum: 1
          maximum: 52
        dayNumber:
          type: number
          minimum: 1
          maximum: 7
      required:
        - libraryWorkoutId
        - weekNumber
        - dayNumber
    AssignProgramDto:
      type: object
      properties:
        eventId:
          type: string
        athleteUserId:
          type: string
        notes:
          type: string
      required:
        - eventId
        - athleteUserId
    BulkAssignProgramDto:
      type: object
      properties:
        eventId:
          type: string
        athleteUserIds:
          type: array
          items:
            type: string
      required:
        - eventId
        - athleteUserIds
    SaveOnboardingInterestsDto:
      type: object
      properties:
        sportIds:
          minItems: 1
          maxItems: 8
          type: array
          items:
            type: string
        topicIds:
          maxItems: 40
          type: array
          items:
            type: string
        subtopicIds:
          maxItems: 80
          type: array
          items:
            type: string
      required:
        - sportIds
        - topicIds
        - subtopicIds
    CreateUserAlbumDto:
      type: object
      properties:
        name:
          type: string
          description: Album name
        description:
          type: string
        type:
          type: string
          enum:
            - RACE_DAY
            - TRAINING
            - CLUB
            - CUSTOM
          description: >-
            Album type — defaults to CUSTOM. RACE_DAY requires eventId; CLUB
            requires clubId.
        eventId:
          type: string
        clubId:
          type: string
      required:
        - name
    UpdateUserAlbumDto:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        coverPhotoId:
          type: string
    CreateUserPhotoDto:
      type: object
      properties:
        fileUrl:
          type: string
          description: S3 URL of the uploaded photo
        caption:
          type: string
        albumId:
          type: string
        activityId:
          type: string
        eventId:
          type: string
        widthPx:
          type: number
        heightPx:
          type: number
        privacy:
          type: string
          description: 'Privacy scope: public | followers | private'
      required:
        - fileUrl
    UpdateUserPhotoDto:
      type: object
      properties:
        caption:
          type: string
        albumId:
          type: string
          description: Move photo to a different album
        privacy:
          type: string
    UpdateEditionDto:
      type: object
      properties:
        minimumDistanceKm:
          type: number
          description: >-
            Minimum GPS distance (km) an athlete must cover to receive a
            finisher certificate. Stored as proofRules.minimumDistance in
            meters.
          example: 5
        certificateTemplateUrl:
          type: string
          description: URL of the finisher certificate template issued for this edition.
          example: https://cdn.repeak.co/certificates/marathon-2026.png
    BulkEventActionDto:
      type: object
      properties: {}
    MoveParticipationToWaveDto:
      type: object
      properties: {}
    SeedWavesDto:
      type: object
      properties: {}
    UpdateSelfServiceConfigDto:
      type: object
      properties: {}
    AcceptEventGoodieDto:
      type: object
      properties:
        segmentId:
          type: string
        rankStart:
          type: number
          example: 1
        rankEnd:
          type: number
          example: 1
    EventRankWinnerDto:
      type: object
      properties:
        rank:
          type: number
          example: 1
          description: Finishing rank (1 = winner).
        userId:
          type: string
          description: >-
            The announced participant (userId) — the payable account credited on
            distribution.
        participantId:
          type: string
          description: >-
            The specific EventParticipant the organizer picked as this rank's
            winner — for a group booking, the actual finisher may differ from
            the paying account (userId). Omit for a solo booking where the
            account holder is themself the finisher.
      required:
        - rank
        - userId
    EventSegmentResultsDto:
      type: object
      properties:
        segmentId:
          type: string
          description: Prize leaderboard (segment) id.
        winners:
          type: array
          items:
            $ref: '#/components/schemas/EventRankWinnerDto'
      required:
        - segmentId
        - winners
    AnnounceEventResultsDto:
      type: object
      properties:
        segments:
          type: array
          items:
            $ref: '#/components/schemas/EventSegmentResultsDto'
      required:
        - segments
    ProposeEventGoodieDto:
      type: object
      properties:
        segmentId:
          type: string
          description: Target segment (leaderboard) id; omit to let the organizer route it.
        rankStart:
          type: number
          example: 1
        rankEnd:
          type: number
          example: 3
        goodieName:
          type: string
          example: Branded hydration pack
        goodieDescription:
          type: string
        imageUrl:
          type: string
          description: Goodie image URL.
        quantity:
          type: number
          example: 1
      required:
        - goodieName
    CreateEventBadgeDto:
      type: object
      properties: {}
    EventGeographicRestrictionsDto:
      type: object
      properties: {}
    CouponApplicableTicketDto:
      type: object
      properties:
        couponId:
          type: string
          description: Coupon ID
          example: 123e4567-e89b-12d3-a456-426614174000
        ticketIds:
          description: Array of ticket IDs that this coupon applies to
          example:
            - 123e4567-e89b-12d3-a456-426614174001
            - 123e4567-e89b-12d3-a456-426614174002
          type: array
          items:
            type: string
      required:
        - couponId
        - ticketIds
    GeoJsonPointDto:
      type: object
      properties:
        type:
          type: string
          description: The type of geometry
          example: Point
          enum:
            - Point
        coordinates:
          example:
            - 72.8777
            - 19.076
          type: array
          items:
            type: string
      required:
        - type
        - coordinates
    CreateEventLocationDto:
      type: object
      properties:
        id:
          type: string
          description: Event Location Id
          example: 123e4567-e89b-12d3-a456-426614174000
        city:
          type: string
          description: The city of the event location
          example: Mumbai
        state:
          type: string
          description: The state of the event location
          example: Maharashtra
        address:
          type: string
          description: The address of the event location
          example: 123 Main Street, City, Country
        coordinate:
          description: The geographical coordinates of the event location
          allOf:
            - $ref: '#/components/schemas/GeoJsonPointDto'
        platform:
          type: string
          description: Virtual event platform name
          example: Zoom
        link:
          type: string
          description: Virtual event meeting link
          example: https://zoom.us/j/1234567890
        password:
          type: string
          description: Virtual event meeting password
          example: password123
        additionalInstructions:
          type: string
          description: Virtual event meeting password
          example: password123
        isActive:
          type: boolean
          description: The is active of the event location
          example: true
        isProvisional:
          type: boolean
          description: >-
            TRUE when the address/coordinate are an auto-filled placeholder
            (e.g. a city centroid) rather than a confirmed venue. Template flow
            sends true; send false once the organizer confirms a real venue.
          example: false
      required:
        - id
    CreateEventTicketDto:
      type: object
      properties:
        id:
          type: string
          description: Event Ticket Id
          example: 123e4567-e89b-12d3-a456-426614174000
        name:
          type: string
          description: Name of the ticket
        description:
          type: string
          description: Description of the ticket
        saleStartDateTime:
          type: string
          description: Start date and time of the event
          example: '2024-12-25T09:00:00.000Z'
        saleEndDateTime:
          type: string
          description: End date and time of the event
          example: '2024-12-25T17:00:00.000Z'
        type:
          type: string
          enum:
            - free
            - paid
            - donation
          default: paid
          description: Type of ticket
        ticketCategory:
          type: string
          enum:
            - individual
            - group
          default: individual
          description: 'Ticket category: individual or group'
        groupSize:
          type: number
          description: Number of participants per ticket (applicable for group tickets)
          default: 1
          minimum: 1
        minAge:
          type: number
          description: Minimum age required for this ticket
          minimum: 0
        maxAge:
          type: number
          description: Maximum age allowed for this ticket
          minimum: 0
        minPerBooking:
          type: number
          description: Minimum tickets per booking
          default: 1
        maxPerBooking:
          type: number
          description: Maximum tickets per booking
          default: 10
        price:
          type: number
          description: Price required for this ticket
          minimum: 0
        discountedPrice:
          type: number
          description: Optional discounted price. Empty, null, and zero mean no discount.
          minimum: 0
          nullable: true
        quantity:
          type: number
          description: Quantity required for this ticket
          minimum: 0
        isActive:
          type: boolean
          description: Whether the event ticket is active
          example: true
          default: true
      required:
        - id
        - name
        - saleStartDateTime
        - saleEndDateTime
        - type
        - minPerBooking
        - maxPerBooking
    CreateEventSlotDto:
      type: object
      properties:
        id:
          type: string
          description: Event Slot Id
          example: 123e4567-e89b-12d3-a456-426614174000
        name:
          type: string
          description: Name of the event slot
          example: Morning slot
        startDateTime:
          type: string
          description: Start time of the event slot in HH:mm format
          example: '09:00'
        endDateTime:
          type: string
          description: End time of the event slot in HH:mm format
          example: '17:00'
        eventTickets:
          description: Event tickets for this slot
          type: array
          items:
            $ref: '#/components/schemas/CreateEventTicketDto'
        isActive:
          type: boolean
          description: Whether the event slot is active
          example: true
          default: true
      required:
        - id
        - name
        - startDateTime
        - endDateTime
        - eventTickets
    CreateEventAddOnDto:
      type: object
      properties:
        id:
          type: string
          description: Event Add On Id
          example: 123e4567-e89b-12d3-a456-426614174000
        productId:
          type: string
          description: Product ID for the add-on
          example: 123e4567-e89b-12d3-a456-426614174000
        quantity:
          type: number
          description: Quantity available for this add-on
          example: 100
          minimum: 0
          default: 0
        isActive:
          type: boolean
          description: Whether the add-on is active
          example: true
          default: true
      required:
        - id
        - productId
    CreateEventDto:
      type: object
      properties:
        ownerOrganizerId:
          type: string
          description: >-
            Admin-only target organizer. Ignored for non-admin callers and
            validated server-side.
        desktopVideoUploadKey:
          type: string
          description: >-
            Temporary owned object key returned by POST /v2/events/video-uploads
            for the desktop cover video.
        desktopVideoCrop:
          type: string
          description: JSON crop/trim settings for the 16:9 desktop cover video.
        promoVideoUploadKey:
          type: string
          description: >-
            Temporary owned object key returned by POST /v2/events/video-uploads
            for the mobile cover video.
        promoVideoCrop:
          type: string
          description: JSON crop/trim settings for the 4:5 mobile cover video.
        removeDesktopVideo:
          type: boolean
          description: Remove the saved desktop cover video.
        removePromoVideo:
          type: boolean
          description: Remove the saved mobile cover video.
        galleryVideoCrop:
          type: string
          description: JSON crop/trim settings for the optional 4:5 gallery video.
        removeGalleryVideo:
          type: boolean
          description: Remove the currently saved gallery video.
        listingMode:
          type: string
          enum: &ref_664
            - REPEAK_TICKETING
            - INFORMATION_ONLY
          default: REPEAK_TICKETING
          description: >-
            Organizer event publishing model. INFORMATION_ONLY requires an
            active Organizer Official Partner agreement.
        premiumPageEnabled:
          type: boolean
          default: true
        raceInformation:
          type: object
          description: Race guide and event-day logistics shown on the premium event page.
        eventBadge:
          description: Optional participation badge submitted with the event.
          allOf:
            - $ref: '#/components/schemas/CreateEventBadgeDto'
        brandPartners:
          description: Optional partners shown on an information-only event page.
          type: array
          items:
            type: string
        title:
          type: string
          description: Title of the event
          example: Annual Marathon 2024
          maxLength: 250
        description:
          type: string
          description: Description of the event
          example: >-
            Join us for the most exciting marathon event of the year with
            amazing prizes and challenges.
        startDateTime:
          type: string
          description: Start date and time of the event
          example: '2024-12-25T09:00:00.000Z'
        endDateTime:
          type: string
          description: End date and time of the event
          example: '2024-12-25T17:00:00.000Z'
        registrationOpensAt:
          type: string
          description: >-
            When public registration opens. Omit for "open immediately", which
            is how every event behaves by default. Subscribers whose plan
            includes early access may register a configured number of hours
            before this time.
          example: '2024-11-01T10:00:00.000Z'
        type:
          type: string
          description: Type of the event
          enum: &ref_665
            - virtual
            - in_person
            - hybrid
          example: in_person
        themeColor:
          type: string
          description: >-
            Per-event override for theme color (#RRGGBB). When omitted, cascades
            from organizer brand-page default. PRD §44.2.
          example: '#FF6B35'
        currency:
          type: string
          description: >-
            ISO 4217 currency code for ticket prices. Defaults to INR. Cascades
            from organizer brand-page default at creation.
          example: INR
        organizerLogoUrl:
          type: string
          description: >-
            Per-event override for organizer logo URL. When omitted, cascades
            from organizer brand-page default. PRD §44.2.
          example: https://cdn.acme.com/logo.png
        standardFieldsConfig:
          type: object
          description: >-
            Per-event override for standard-fields config blob. When omitted,
            cascades from organizer brand-page default. PRD §44.2.
        clubId:
          type: string
          description: >-
            When set, the event is floated on behalf of this club instead of the
            calling organizer. The organizer must own the club. Vision §1 —
            clubs are first-class event creators.
          example: 123e4567-e89b-12d3-a456-426614174000
        sponsorId:
          type: string
          description: >-
            When set, the event is floated on behalf of this sponsor brand. The
            calling user must have an ACTIVE SponsorAccount for the brand.
            Vision §1 — sponsors are first-class event hosts.
          example: 123e4567-e89b-12d3-a456-426614174000
        eventGeographicRestrictions:
          description: >-
            Limit who can register by country / city. When openGlobally is true
            the lists are ignored. Mostly used for hybrid races.
          allOf:
            - $ref: '#/components/schemas/EventGeographicRestrictionsDto'
        couponApplicableTicket:
          description: >-
            Array of coupon-ticket mappings specifying which coupons apply to
            which tickets
          example: &ref_666
            - couponId: 123e4567-e89b-12d3-a456-426614174000
              ticketIds:
                - 123e4567-e89b-12d3-a456-426614174001
                - 123e4567-e89b-12d3-a456-426614174002
          type: array
          items:
            $ref: '#/components/schemas/CouponApplicableTicketDto'
        location:
          description: Location details of the event
          allOf:
            - $ref: '#/components/schemas/CreateEventLocationDto'
        couponIds:
          description: Array of coupon IDs for event discounts
          example: &ref_667
            - 123e4567-e89b-12d3-a456-426614174000
            - 987fcdeb-51a2-43d1-b456-426614174000
          type: array
          items:
            type: string
        coinsDiscountPercentage:
          type: number
          description: Coins discount percentage (0-100 with 2 decimal places)
          example: 15.25
          minimum: 0
          maximum: 100
        slots:
          description: Event slots with their tickets
          type: array
          items:
            $ref: '#/components/schemas/CreateEventSlotDto'
        addOns:
          description: Array of add-on products with quantities
          example: &ref_668
            - productId: 123e4567-e89b-12d3-a456-426614174000
              quantity: 50
              isActive: true
          type: array
          items:
            $ref: '#/components/schemas/CreateEventAddOnDto'
        frequentlyAskedQuestionsIds:
          description: Array of frequently asked questions IDs
          example: &ref_669
            - 123e4567-e89b-12d3-a456-426614174000
          type: array
          items:
            type: string
        termsAndConditionsId:
          type: string
          description: Terms and conditions ID
          example: 123e4567-e89b-12d3-a456-426614174000
        privacyPolicyId:
          type: string
          description: Privacy policy ID
          example: 123e4567-e89b-12d3-a456-426614174000
        isActive:
          type: boolean
          description: Whether the event is active
          example: true
          default: true
        hybridEnabled:
          type: boolean
          description: Whether hybrid race participation is enabled for this event.
          default: false
        hybridConfig:
          type: object
          description: Structured hybrid-race configuration.
        leaderboardPolicy:
          type: string
          description: >-
            Per-event leaderboard policy: RANKED | ALL_FINISHERS_MEDAL |
            DEGRADED_MEDAL.
          enum: &ref_670
            - RANKED
            - ALL_FINISHERS_MEDAL
            - DEGRADED_MEDAL
        medalPolicy:
          type: object
          description: >-
            Medal artwork policy. `useSystemDefault=true` (default) uses the
            platform template; Pro-tier partners can set false and supply custom
            image URLs.
        bibIssueWindow:
          type: string
          description: >-
            Pre-event window in which digital bibs are auto-issued: TEN_DAYS |
            SEVEN_DAYS | TWO_DAYS | CUSTOM.
          enum: &ref_671
            - TEN_DAYS
            - SEVEN_DAYS
            - TWO_DAYS
            - CUSTOM
        bibIssueWindowCustomDays:
          type: number
          description: Custom pre-event window in days when bibIssueWindow=CUSTOM.
        courseGpxUrl:
          type: string
          description: URL of uploaded GPX course file (S3).
        elevationProfile:
          type: object
          description: >-
            Elevation profile derived from the course GPX (distance → elevation
            sample series).
        totalElevationGainM:
          type: number
          description: Total elevation gain (meters) of the course.
        courseDistanceM:
          type: number
          description: >-
            Target distance in metres for virtual/hybrid events. Used by the
            athlete app to compute progress percentage. For hybrid events this
            is auto-populated when a GPX is uploaded; set it manually here when
            there is no GPX. For virtual events this is the distance athletes
            must cover to complete the event.
          example: 10000
        refundPolicy:
          description: >-
            Structured refund policy tiers (ordered). Existing
            `settings.refundPolicy` free-text field is retained.
          example: &ref_672
            - daysBefore: 30
              refundPct: 100
            - daysBefore: 7
              refundPct: 50
          type: array
          items:
            type: string
        sportId:
          type: string
          description: >-
            Primary sport for this event (FK admins_v2.sports.id). Required
            going forward for explore/filter/analytics; nullable for backwards
            compatibility with pre-49 drafts.
          example: 123e4567-e89b-12d3-a456-426614174000
        sportIds:
          description: >-
            Full sport set for multi-discipline events (triathlon, duathlon,
            aquabike). For a single-sport event, omit or repeat `sportId`.
          example: &ref_673
            - 123e4567-e89b-12d3-a456-426614174000
            - 123e4567-e89b-12d3-a456-426614174001
          type: array
          items:
            type: string
        allowedParticipationModes:
          type: array
          description: >-
            Participation modes this event sells simultaneously. One event can
            sell PHYSICAL + HYBRID + VIRTUAL at once (vision §1). If omitted,
            the server infers from the legacy `type` scalar for backwards
            compatibility.
          example: &ref_674
            - PHYSICAL
            - VIRTUAL
          items: &ref_675
            type: string
            enum:
              - PHYSICAL
              - HYBRID
              - VIRTUAL
              - BOTH
        virtualWindowStart:
          type: string
          description: >-
            When the virtual-run submission window opens. Required if
            `allowedParticipationModes` includes VIRTUAL. Before this moment
            virtual activity submissions are rejected with 400.
          example: '2026-05-01T00:00:00Z'
        virtualWindowEnd:
          type: string
          description: >-
            Soft close of the virtual-run window. New registrations for VIRTUAL
            mode are rejected after this instant; already-registered users can
            still submit up to `virtualSubmissionDeadline`.
          example: '2026-05-07T23:59:59Z'
        virtualSubmissionDeadline:
          type: string
          description: >-
            Hard deadline past which the server rejects any virtual activity
            submission. Defaults to `virtualWindowEnd` when omitted. Use a later
            value to extend a grace window.
          example: '2026-05-08T23:59:59Z'
        isTestMode:
          type: boolean
          description: >-
            Mark the event as TEST MODE — visible inside the org, surfaces a
            TEST MODE badge across operator surfaces. (Sandbox payment routing
            is a separate Cashfree-credentials follow-up.)
          example: false
        certificateEnabled:
          type: boolean
          description: >-
            Enable finisher certificates for this event. Gates the Certificates
            page (design + publish) — actual issuance still only fires manually,
            after the event is COMPLETED.
          example: false
        certificateMode:
          type: string
          description: >-
            Certificate rendering mode. COMMON distributes the same artwork;
            DYNAMIC personalizes the certificate with participant and result
            variables.
          enum: &ref_676
            - COMMON
            - DYNAMIC
          default: DYNAMIC
        scheduledPublishAt:
          type: string
          description: >-
            Schedule auto-publish: when set in the future and status is DRAFT,
            the EventScheduler cron promotes status → PUBLISHED at this instant.
            ISO 8601.
          example: '2026-06-01T08:00:00Z'
        parentEventId:
          type: string
          description: >-
            Optional parent event ID for series / multi-day umbrella linkage.
            Each event still owns its own ticketing / refunds — the link only
            renders the "part of" badge + the parent's "Linked events" panel.
          example: 01957001-0001-4000-8000-000000000020
        marketingTags:
          type: object
          description: >-
            Marketing tags / pixels: { metaPixelId, gaMeasurementId,
            gtmContainerId, utmDefaults: { source, medium, campaign } }.
      required:
        - title
        - description
        - startDateTime
        - endDateTime
        - type
        - location
        - coinsDiscountPercentage
        - slots
        - frequentlyAskedQuestionsIds
        - termsAndConditionsId
        - privacyPolicyId
    UpdateFeaturedEventsDto:
      type: object
      properties:
        eventIds:
          description: Array of event IDs to update featured status
          example:
            - 019985cc-10e2-75f8-cea4-181c6e558eab
            - 019985cc-10e2-75f8-cea4-181c6e558eac
          type: array
          items:
            type: string
        isFeatured:
          type: boolean
          description: Set featured status (true to feature, false to unfeature)
          default: true
      required:
        - eventIds
    UpdateEventDto:
      type: object
      properties:
        ownerOrganizerId:
          type: string
          description: >-
            Admin-only target organizer. Ignored for non-admin callers and
            validated server-side.
        desktopVideoUploadKey:
          type: string
          description: >-
            Temporary owned object key returned by POST /v2/events/video-uploads
            for the desktop cover video.
        desktopVideoCrop:
          type: string
          description: JSON crop/trim settings for the 16:9 desktop cover video.
        promoVideoUploadKey:
          type: string
          description: >-
            Temporary owned object key returned by POST /v2/events/video-uploads
            for the mobile cover video.
        promoVideoCrop:
          type: string
          description: JSON crop/trim settings for the 4:5 mobile cover video.
        removeDesktopVideo:
          type: boolean
          description: Remove the saved desktop cover video.
        removePromoVideo:
          type: boolean
          description: Remove the saved mobile cover video.
        galleryVideoCrop:
          type: string
          description: JSON crop/trim settings for the optional 4:5 gallery video.
        removeGalleryVideo:
          type: boolean
          description: Remove the currently saved gallery video.
        listingMode:
          type: string
          enum: *ref_664
          default: REPEAK_TICKETING
          description: >-
            Organizer event publishing model. INFORMATION_ONLY requires an
            active Organizer Official Partner agreement.
        premiumPageEnabled:
          type: boolean
          default: true
        raceInformation:
          type: object
          description: Race guide and event-day logistics shown on the premium event page.
        eventBadge:
          description: Optional participation badge submitted with the event.
          allOf:
            - $ref: '#/components/schemas/CreateEventBadgeDto'
        brandPartners:
          description: Optional partners shown on an information-only event page.
          type: array
          items:
            type: string
        title:
          type: string
          description: Title of the event
          example: Annual Marathon 2024
          maxLength: 250
        description:
          type: string
          description: Description of the event
          example: >-
            Join us for the most exciting marathon event of the year with
            amazing prizes and challenges.
        startDateTime:
          type: string
          description: Start date and time of the event
          example: '2024-12-25T09:00:00.000Z'
        endDateTime:
          type: string
          description: End date and time of the event
          example: '2024-12-25T17:00:00.000Z'
        registrationOpensAt:
          type: string
          description: >-
            When public registration opens. Omit for "open immediately", which
            is how every event behaves by default. Subscribers whose plan
            includes early access may register a configured number of hours
            before this time.
          example: '2024-11-01T10:00:00.000Z'
        type:
          type: string
          description: Type of the event
          enum: *ref_665
          example: in_person
        themeColor:
          type: string
          description: >-
            Per-event override for theme color (#RRGGBB). When omitted, cascades
            from organizer brand-page default. PRD §44.2.
          example: '#FF6B35'
        currency:
          type: string
          description: >-
            ISO 4217 currency code for ticket prices. Defaults to INR. Cascades
            from organizer brand-page default at creation.
          example: INR
        organizerLogoUrl:
          type: string
          description: >-
            Per-event override for organizer logo URL. When omitted, cascades
            from organizer brand-page default. PRD §44.2.
          example: https://cdn.acme.com/logo.png
        standardFieldsConfig:
          type: object
          description: >-
            Per-event override for standard-fields config blob. When omitted,
            cascades from organizer brand-page default. PRD §44.2.
        clubId:
          type: string
          description: >-
            When set, the event is floated on behalf of this club instead of the
            calling organizer. The organizer must own the club. Vision §1 —
            clubs are first-class event creators.
          example: 123e4567-e89b-12d3-a456-426614174000
        sponsorId:
          type: string
          description: >-
            When set, the event is floated on behalf of this sponsor brand. The
            calling user must have an ACTIVE SponsorAccount for the brand.
            Vision §1 — sponsors are first-class event hosts.
          example: 123e4567-e89b-12d3-a456-426614174000
        eventGeographicRestrictions:
          description: >-
            Limit who can register by country / city. When openGlobally is true
            the lists are ignored. Mostly used for hybrid races.
          allOf:
            - $ref: '#/components/schemas/EventGeographicRestrictionsDto'
        couponApplicableTicket:
          description: >-
            Array of coupon-ticket mappings specifying which coupons apply to
            which tickets
          example: *ref_666
          type: array
          items:
            $ref: '#/components/schemas/CouponApplicableTicketDto'
        location:
          description: Location details of the event
          allOf:
            - $ref: '#/components/schemas/CreateEventLocationDto'
        couponIds:
          description: Array of coupon IDs for event discounts
          example: *ref_667
          type: array
          items:
            type: string
        coinsDiscountPercentage:
          type: number
          description: Coins discount percentage (0-100 with 2 decimal places)
          example: 15.25
          minimum: 0
          maximum: 100
        slots:
          description: Event slots with their tickets
          type: array
          items:
            $ref: '#/components/schemas/CreateEventSlotDto'
        addOns:
          description: Array of add-on products with quantities
          example: *ref_668
          type: array
          items:
            $ref: '#/components/schemas/CreateEventAddOnDto'
        frequentlyAskedQuestionsIds:
          description: Array of frequently asked questions IDs
          example: *ref_669
          type: array
          items:
            type: string
        termsAndConditionsId:
          type: string
          description: Terms and conditions ID
          example: 123e4567-e89b-12d3-a456-426614174000
        privacyPolicyId:
          type: string
          description: Privacy policy ID
          example: 123e4567-e89b-12d3-a456-426614174000
        isActive:
          type: boolean
          description: Whether the event is active
          example: true
          default: true
        hybridEnabled:
          type: boolean
          description: Whether hybrid race participation is enabled for this event.
          default: false
        hybridConfig:
          type: object
          description: Structured hybrid-race configuration.
        leaderboardPolicy:
          type: string
          description: >-
            Per-event leaderboard policy: RANKED | ALL_FINISHERS_MEDAL |
            DEGRADED_MEDAL.
          enum: *ref_670
        medalPolicy:
          type: object
          description: >-
            Medal artwork policy. `useSystemDefault=true` (default) uses the
            platform template; Pro-tier partners can set false and supply custom
            image URLs.
        bibIssueWindow:
          type: string
          description: >-
            Pre-event window in which digital bibs are auto-issued: TEN_DAYS |
            SEVEN_DAYS | TWO_DAYS | CUSTOM.
          enum: *ref_671
        bibIssueWindowCustomDays:
          type: number
          description: Custom pre-event window in days when bibIssueWindow=CUSTOM.
        courseGpxUrl:
          type: string
          description: URL of uploaded GPX course file (S3).
        elevationProfile:
          type: object
          description: >-
            Elevation profile derived from the course GPX (distance → elevation
            sample series).
        totalElevationGainM:
          type: number
          description: Total elevation gain (meters) of the course.
        courseDistanceM:
          type: number
          description: >-
            Target distance in metres for virtual/hybrid events. Used by the
            athlete app to compute progress percentage. For hybrid events this
            is auto-populated when a GPX is uploaded; set it manually here when
            there is no GPX. For virtual events this is the distance athletes
            must cover to complete the event.
          example: 10000
        refundPolicy:
          description: >-
            Structured refund policy tiers (ordered). Existing
            `settings.refundPolicy` free-text field is retained.
          example: *ref_672
          type: array
          items:
            type: string
        sportId:
          type: string
          description: >-
            Primary sport for this event (FK admins_v2.sports.id). Required
            going forward for explore/filter/analytics; nullable for backwards
            compatibility with pre-49 drafts.
          example: 123e4567-e89b-12d3-a456-426614174000
        sportIds:
          description: >-
            Full sport set for multi-discipline events (triathlon, duathlon,
            aquabike). For a single-sport event, omit or repeat `sportId`.
          example: *ref_673
          type: array
          items:
            type: string
        allowedParticipationModes:
          type: array
          description: >-
            Participation modes this event sells simultaneously. One event can
            sell PHYSICAL + HYBRID + VIRTUAL at once (vision §1). If omitted,
            the server infers from the legacy `type` scalar for backwards
            compatibility.
          example: *ref_674
          items: *ref_675
        virtualWindowStart:
          type: string
          description: >-
            When the virtual-run submission window opens. Required if
            `allowedParticipationModes` includes VIRTUAL. Before this moment
            virtual activity submissions are rejected with 400.
          example: '2026-05-01T00:00:00Z'
        virtualWindowEnd:
          type: string
          description: >-
            Soft close of the virtual-run window. New registrations for VIRTUAL
            mode are rejected after this instant; already-registered users can
            still submit up to `virtualSubmissionDeadline`.
          example: '2026-05-07T23:59:59Z'
        virtualSubmissionDeadline:
          type: string
          description: >-
            Hard deadline past which the server rejects any virtual activity
            submission. Defaults to `virtualWindowEnd` when omitted. Use a later
            value to extend a grace window.
          example: '2026-05-08T23:59:59Z'
        isTestMode:
          type: boolean
          description: >-
            Mark the event as TEST MODE — visible inside the org, surfaces a
            TEST MODE badge across operator surfaces. (Sandbox payment routing
            is a separate Cashfree-credentials follow-up.)
          example: false
        certificateEnabled:
          type: boolean
          description: >-
            Enable finisher certificates for this event. Gates the Certificates
            page (design + publish) — actual issuance still only fires manually,
            after the event is COMPLETED.
          example: false
        certificateMode:
          type: string
          description: >-
            Certificate rendering mode. COMMON distributes the same artwork;
            DYNAMIC personalizes the certificate with participant and result
            variables.
          enum: *ref_676
          default: DYNAMIC
        scheduledPublishAt:
          type: string
          description: >-
            Schedule auto-publish: when set in the future and status is DRAFT,
            the EventScheduler cron promotes status → PUBLISHED at this instant.
            ISO 8601.
          example: '2026-06-01T08:00:00Z'
        parentEventId:
          type: string
          description: >-
            Optional parent event ID for series / multi-day umbrella linkage.
            Each event still owns its own ticketing / refunds — the link only
            renders the "part of" badge + the parent's "Linked events" panel.
          example: 01957001-0001-4000-8000-000000000020
        marketingTags:
          type: object
          description: >-
            Marketing tags / pixels: { metaPixelId, gaMeasurementId,
            gtmContainerId, utmDefaults: { source, medium, campaign } }.
    SendEventAnnouncementDto:
      type: object
      properties:
        title:
          type: string
          description: Title of the announcement
          example: 'Event Update: New Schedule'
          maxLength: 128
        content:
          type: string
          description: Content/body of the announcement
          example: >-
            Dear participants, we have updated the event schedule. Please check
            the new timings.
          maxLength: 1024
      required:
        - title
        - content
    CancelEventDto:
      type: object
      properties:
        customReason:
          type: string
          description: >-
            Custom reason for cancelling the event (sent to participants in
            notification)
          example: Event cancelled due to unforeseen circumstances
          maxLength: 500
    CreateSlotDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the event slot
          example: Morning slot
        startDateTime:
          type: string
          description: Start date time of the event slot in ISO format
          example: '2024-12-25T09:00:00.000Z'
        endDateTime:
          type: string
          description: End date time of the event slot in ISO format
          example: '2024-12-25T17:00:00.000Z'
        eventTickets:
          description: Event tickets for this slot (optional)
          type: array
          items:
            $ref: '#/components/schemas/CreateEventTicketDto'
        isActive:
          type: boolean
          description: Whether the event slot is active
          example: true
          default: true
      required:
        - name
        - startDateTime
        - endDateTime
    UpdateSlotDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the event slot
          example: Morning slot
        startDateTime:
          type: string
          description: Start date time of the event slot in ISO format
          example: '2024-12-25T09:00:00.000Z'
        endDateTime:
          type: string
          description: End date time of the event slot in ISO format
          example: '2024-12-25T17:00:00.000Z'
        isActive:
          type: boolean
          description: Whether the event slot is active
          example: true
        eventTickets:
          description: >-
            Event tickets for this slot (accepted but managed via the tickets
            endpoints)
          type: array
          items:
            $ref: '#/components/schemas/CreateEventTicketDto'
    CreateTicketDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the ticket
        description:
          type: string
          description: Description of the ticket
        saleStartDateTime:
          type: string
          description: Sale start date and time
          example: '2024-12-25T09:00:00.000Z'
        saleEndDateTime:
          type: string
          description: Sale end date and time
          example: '2024-12-25T17:00:00.000Z'
        type:
          type: string
          enum:
            - free
            - paid
            - donation
          default: paid
          description: Type of ticket
        ticketCategory:
          type: string
          enum:
            - individual
            - group
          default: individual
          description: 'Ticket category: individual or group'
        groupSize:
          type: number
          description: Number of participants per ticket (applicable for group tickets)
          default: 1
          minimum: 1
        minAge:
          type: number
          description: Minimum age required for this ticket
          minimum: 0
        maxAge:
          type: number
          description: Maximum age allowed for this ticket
          minimum: 0
        minPerBooking:
          type: number
          description: Minimum tickets per booking
          default: 1
        maxPerBooking:
          type: number
          description: Maximum tickets per booking
          default: 10
        price:
          type: number
          description: Price of the ticket
          minimum: 0
        discountedPrice:
          type: number
          description: Optional discounted price. Empty, null, and zero mean no discount.
          minimum: 0
          nullable: true
        quantity:
          type: number
          description: Total quantity of tickets available
          minimum: 1
        isActive:
          type: boolean
          description: Whether the ticket is active
          example: true
          default: true
      required:
        - name
        - saleStartDateTime
        - saleEndDateTime
        - type
        - price
        - quantity
    UpdateTicketDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the ticket
        description:
          type: string
          description: Description of the ticket
        saleStartDateTime:
          type: string
          description: Sale start date and time
          example: '2024-12-25T09:00:00.000Z'
        saleEndDateTime:
          type: string
          description: Sale end date and time
          example: '2024-12-25T17:00:00.000Z'
        type:
          type: string
          enum:
            - free
            - paid
            - donation
          description: Type of ticket
        ticketCategory:
          type: string
          enum:
            - individual
            - group
          description: 'Ticket category: individual or group'
        groupSize:
          type: number
          description: Number of participants per ticket (applicable for group tickets)
          minimum: 1
        minAge:
          type: number
          description: Minimum age required for this ticket
        maxAge:
          type: number
          description: Maximum age allowed for this ticket
        minPerBooking:
          type: number
          description: Minimum tickets per booking
        maxPerBooking:
          type: number
          description: Maximum tickets per booking
        price:
          type: number
          description: Price of the ticket
        discountedPrice:
          type: number
          description: Optional discounted price. Send null or zero to clear a discount.
          nullable: true
        quantity:
          type: number
          description: Total quantity of tickets available
        isActive:
          type: boolean
          description: Whether the ticket is active
    FormFieldDto:
      type: object
      properties: {}
    CreateFormDto:
      type: object
      properties:
        formType:
          type: string
          description: Type of form
          example: registration
          enum:
            - registration
            - feedback
            - survey
        showTiming:
          type: string
          description: When to show the form
          enum:
            - before_event
            - during_event
            - after_event
          example: before_event
        fields:
          description: Form fields
          type: array
          items:
            $ref: '#/components/schemas/FormFieldDto'
        isActive:
          type: boolean
          description: Whether the form is active
          example: true
          default: true
      required:
        - formType
        - showTiming
        - fields
    UpdateFormDto:
      type: object
      properties:
        formType:
          type: string
          description: Type of form
          example: registration
          enum:
            - registration
            - feedback
            - survey
        showTiming:
          type: string
          description: When to show the form
          enum:
            - before_event
            - during_event
            - after_event
        fields:
          description: Form fields
          type: array
          items:
            $ref: '#/components/schemas/FormFieldDto'
        isActive:
          type: boolean
          description: Whether the form is active
    CreateEventWaiverDto:
      type: object
      properties:
        name:
          type: string
          description: Waiver name
          example: Liability Waiver
        htmlContent:
          type: string
          description: >-
            HTML with {{key}} placeholders. Every {{key}} must be a registration
            form field name (see GET .../waiver/available-variables).
        headerLogo:
          type: string
          description: Header logo URL for the rendered PDF
        footerText:
          type: string
          description: Footer text for the rendered PDF
        cssStyles:
          type: string
          description: CSS applied to the waiver HTML
        requireAcceptance:
          type: boolean
          description: Block registration until the participant accepts.
          default: true
        acceptanceLabel:
          type: string
          description: Acceptance checkbox label shown at registration.
          example: I have read and accept the liability waiver
      required:
        - name
        - htmlContent
    UpdateEventWaiverDto:
      type: object
      properties:
        name:
          type: string
          description: Waiver name
          example: Liability Waiver
        htmlContent:
          type: string
          description: >-
            HTML with {{key}} placeholders. Every {{key}} must be a registration
            form field name (see GET .../waiver/available-variables).
        headerLogo:
          type: string
          description: Header logo URL for the rendered PDF
        footerText:
          type: string
          description: Footer text for the rendered PDF
        cssStyles:
          type: string
          description: CSS applied to the waiver HTML
        requireAcceptance:
          type: boolean
          description: Block registration until the participant accepts.
          default: true
        acceptanceLabel:
          type: string
          description: Acceptance checkbox label shown at registration.
          example: I have read and accept the liability waiver
    CreateEventCertificateDto:
      type: object
      properties:
        name:
          type: string
          description: Certificate name
          example: Finisher Certificate
        htmlContent:
          type: string
          description: >-
            HTML with {{key}} placeholders. Every {{key}} must be an available
            variable (see GET .../certificates/variables).
        headerLogo:
          type: string
          description: Header logo URL for the rendered PDF
        footerText:
          type: string
          description: Footer text for the rendered PDF
        cssStyles:
          type: string
          description: CSS applied to the certificate HTML
        backgroundImageUrl:
          type: string
          description: >-
            Full-bleed background design (the organizer-designed certificate
            art) the dynamic text fields render on top of.
        orientation:
          type: string
          description: Page orientation for the rendered PDF.
          enum: &ref_677
            - portrait
            - landscape
          default: landscape
      required:
        - name
        - htmlContent
    UpdateEventCertificateDto:
      type: object
      properties:
        name:
          type: string
          description: Certificate name
          example: Finisher Certificate
        htmlContent:
          type: string
          description: >-
            HTML with {{key}} placeholders. Every {{key}} must be an available
            variable (see GET .../certificates/variables).
        headerLogo:
          type: string
          description: Header logo URL for the rendered PDF
        footerText:
          type: string
          description: Footer text for the rendered PDF
        cssStyles:
          type: string
          description: CSS applied to the certificate HTML
        backgroundImageUrl:
          type: string
          description: >-
            Full-bleed background design (the organizer-designed certificate
            art) the dynamic text fields render on top of.
        orientation:
          type: string
          description: Page orientation for the rendered PDF.
          enum: *ref_677
          default: landscape
    CreateAddOnDto:
      type: object
      properties:
        productId:
          type: string
          description: Product ID for the add-on
          example: 123e4567-e89b-12d3-a456-426614174000
        quantity:
          type: number
          description: Quantity available for this add-on
          example: 100
          minimum: 0
          default: 0
        isActive:
          type: boolean
          description: Whether the add-on is active
          example: true
          default: true
      required:
        - productId
    UpdateAddOnDto:
      type: object
      properties:
        quantity:
          type: number
          description: Quantity available for this add-on
          example: 100
          minimum: 0
        isActive:
          type: boolean
          description: Whether the add-on is active
          example: true
    AttachCouponDto:
      type: object
      properties:
        couponId:
          type: string
          description: Coupon ID to attach to the event
          example: 123e4567-e89b-12d3-a456-426614174000
        ticketIds:
          description: >-
            List of ticket IDs this coupon applies to. If not provided, coupon
            applies to all tickets.
          example:
            - 123e4567-e89b-12d3-a456-426614174000
          type: array
          items:
            type: string
      required:
        - couponId
    UpdateCouponTicketsDto:
      type: object
      properties:
        ticketIds:
          description: List of ticket IDs this coupon applies to
          example:
            - 123e4567-e89b-12d3-a456-426614174000
          type: array
          items:
            type: string
      required:
        - ticketIds
    AttachFaqDto:
      type: object
      properties:
        faqId:
          type: string
          description: FAQ ID to attach to the event
          example: 123e4567-e89b-12d3-a456-426614174000
      required:
        - faqId
    AttachMultipleFaqsDto:
      type: object
      properties:
        faqIds:
          description: List of FAQ IDs to attach to the event
          example:
            - 123e4567-e89b-12d3-a456-426614174000
          type: array
          items:
            type: string
      required:
        - faqIds
    CancelWholeBookingDto:
      type: object
      properties:
        reason:
          type: string
          description: Reason for canceling the entire booking
          enum:
            - ORGANIZER_CANCELLATION
            - EVENT_CANCELLED
            - SLOT_CANCELLED
            - TICKET_CANCELLED
            - CAPACITY_REDUCED
            - PARTICIPANT_MISCONDUCT
            - DUPLICATE_BOOKING
            - PAYMENT_ISSUE
            - ORGANIZER_OTHER
          example: ORGANIZER_CANCELLATION
        customReason:
          type: string
          description: >-
            Custom reason for cancellation (required if reason is
            ORGANIZER_OTHER)
          example: Event has been rescheduled
          maxLength: 500
      required:
        - reason
    BulkCancelParticipantsDto:
      type: object
      properties:
        participationIds:
          description: Array of participation (booking) IDs to cancel.
          example:
            - uuid-1
            - uuid-2
          type: array
          items:
            type: string
        reason:
          type: string
          description: >-
            Shared reason that auto-fills every cancellation. Per-row overrides
            via `overrides` take precedence.
          enum:
            - ORGANIZER_CANCELLATION
            - EVENT_CANCELLED
            - SLOT_CANCELLED
            - TICKET_CANCELLED
            - CAPACITY_REDUCED
            - PARTICIPANT_MISCONDUCT
            - DUPLICATE_BOOKING
            - PAYMENT_ISSUE
            - ORGANIZER_OTHER
          example: ORGANIZER_CANCELLATION
        customReason:
          type: string
          description: >-
            Custom reason that accompanies the shared reason. Visible to
            athletes.
          maxLength: 500
        overrides:
          type: object
          description: >-
            Per-participation reason overrides. Keys are participation IDs;
            values mirror {reason, customReason}.
          example:
            uuid-1:
              reason: PARTICIPANT_MISCONDUCT
              customReason: DQ ruling on hybrid leg
      required:
        - participationIds
        - reason
    CancelParticipantDto:
      type: object
      properties:
        reason:
          type: string
          description: Reason for canceling the participant booking
          enum:
            - ORGANIZER_CANCELLATION
            - TICKET_CANCELLED
            - CAPACITY_REDUCED
            - PARTICIPANT_MISCONDUCT
            - DUPLICATE_BOOKING
            - PAYMENT_ISSUE
            - ORGANIZER_OTHER
          example: ORGANIZER_CANCELLATION
        customReason:
          type: string
          description: >-
            Custom reason for cancellation (required if reason is
            ORGANIZER_OTHER)
          example: Participant violated event guidelines
          maxLength: 500
      required:
        - reason
    UpdateParticipantDetailsDto:
      type: object
      properties:
        formFields:
          type: string
          description: Updated form fields JSON for the participant
          example: >-
            [{"label":"Full
            Name","name":"full_name","type":"text","values":"John Doe"}]
        bibNumber:
          type: string
          description: >-
            Bib number for this participant. Pass an empty string or null to
            clear.
          example: A101
          maxLength: 50
          nullable: true
    ToggleBookingCheckInDto:
      type: object
      properties:
        isCheckedIn:
          type: boolean
          description: Target check-in state for every active participant in the booking.
          example: true
      required:
        - isCheckedIn
    CreateCourseWaypointDto:
      type: object
      properties:
        type:
          type: string
          enum: &ref_678
            - START
            - FINISH
            - WATER_STOP
            - AID_STATION
            - TOILET
            - VIEWING_AREA
            - LANDMARK
          description: PRD §33.1 step 5 waypoint taxonomy.
        name:
          type: string
          maxLength: 120
        latitude:
          type: number
          description: WGS-84 latitude.
        longitude:
          type: number
          description: WGS-84 longitude.
        distanceFromStartM:
          type: number
          description: Cumulative metres along the GPX track from start.
        sequenceIndex:
          type: number
          description: Render order on the partner UI. Defaults to 0.
        notes:
          type: string
      required:
        - type
        - latitude
        - longitude
    UpdateCourseWaypointDto:
      type: object
      properties:
        type:
          type: string
          enum: *ref_678
          description: PRD §33.1 step 5 waypoint taxonomy.
        name:
          type: string
          maxLength: 120
        latitude:
          type: number
          description: WGS-84 latitude.
        longitude:
          type: number
          description: WGS-84 longitude.
        distanceFromStartM:
          type: number
          description: Cumulative metres along the GPX track from start.
        sequenceIndex:
          type: number
          description: Render order on the partner UI. Defaults to 0.
        notes:
          type: string
    CreateEventCommunicationTemplateDto:
      type: object
      properties:
        trigger:
          type: string
          enum: &ref_679
            - REGISTRATION_CONFIRMATION
            - REMINDER_T_MINUS_7_DAYS
            - REMINDER_T_MINUS_3_DAYS
            - REMINDER_T_MINUS_1_DAY
            - RACE_DAY
            - POST_RACE_THANK_YOU
            - POST_RACE_RESULTS
            - POST_RACE_PHOTOS
            - POST_RACE_SURVEY
          description: Lifecycle moment that fires this template.
        channel:
          type: string
          enum: &ref_680
            - EMAIL
            - SMS
            - PUSH
          description: Channel — EMAIL / SMS / PUSH.
        subject:
          type: string
          maxLength: 200
          description: Required for EMAIL, ignored for SMS/PUSH.
        body:
          type: string
          description: >-
            Template body. Use {{variable}} placeholders (athleteName,
            eventTitle, startDate, bibNumber, ...).
        scheduleOffsetMinutes:
          type: number
          description: >-
            Minutes relative to trigger anchor (negative = before, positive =
            after). Ignored for REGISTRATION_CONFIRMATION.
        enabled:
          type: boolean
      required:
        - trigger
        - channel
        - body
    UpdateEventCommunicationTemplateDto:
      type: object
      properties:
        trigger:
          type: string
          enum: *ref_679
          description: Lifecycle moment that fires this template.
        channel:
          type: string
          enum: *ref_680
          description: Channel — EMAIL / SMS / PUSH.
        subject:
          type: string
          maxLength: 200
          description: Required for EMAIL, ignored for SMS/PUSH.
        body:
          type: string
          description: >-
            Template body. Use {{variable}} placeholders (athleteName,
            eventTitle, startDate, bibNumber, ...).
        scheduleOffsetMinutes:
          type: number
          description: >-
            Minutes relative to trigger anchor (negative = before, positive =
            after). Ignored for REGISTRATION_CONFIRMATION.
        enabled:
          type: boolean
    PreviewCommunicationTemplateDto:
      type: object
      properties:
        context:
          type: object
          description: >-
            Optional template-render context. Variables not present here resolve
            to empty string.
    CreateBundleFromEventDto:
      type: object
      properties: {}
    ApplyBundleDto:
      type: object
      properties: {}
    PremiumEventImportPreviewDto:
      type: object
      properties: {}
    PremiumEventImportCommitDto:
      type: object
      properties: {}
    UpdateAppVersionPolicyDto:
      type: object
      properties:
        minSupportedVersion:
          type: string
          example: 1.2.0
          description: Floor; below this = force.
        latestVersion:
          type: string
          example: 1.4.0
          description: Latest shipping version.
        storeUrl:
          type: string
          description: Per-platform store URL. Null/empty clears it.
        releaseNotes:
          type: string
          description: Soft-prompt release notes.
        forceMessage:
          type: string
          description: Hard-block copy override.
        maintenanceEnabled:
          type: boolean
          description: Temporarily block this platform.
        maintenanceMessage:
          type: string
          description: Copy shown while maintenance is active.
      required:
        - minSupportedVersion
        - latestVersion
    UpdateProfileDto:
      type: object
      properties:
        name:
          type: string
        email:
          type: string
        tshirtSize:
          type: string
        skills:
          type: array
          items:
            type: string
    RespondDto:
      type: object
      properties:
        accept:
          type: boolean
        reason:
          type: string
      required:
        - accept
    CreateVolunteerDto:
      type: object
      properties:
        name:
          type: string
        phone:
          type: string
        email:
          type: string
        role:
          type: string
        headId:
          type: string
        tshirtSize:
          type: string
      required:
        - phone
        - role
    InviteMemberDto:
      type: object
      properties:
        name:
          type: string
        phone:
          type: string
        email:
          type: string
        role:
          type: string
        tshirtSize:
          type: string
      required:
        - role
    RateDto:
      type: object
      properties:
        stars:
          type: number
        tags:
          type: array
          items:
            type: string
      required:
        - stars
    CrewLifecycleReasonDto:
      type: object
      properties:
        reason:
          type: string
          maxLength: 500
    CreateVolunteerHeadDto:
      type: object
      properties:
        name:
          type: string
        phone:
          type: string
        email:
          type: string
        tshirtSize:
          type: string
      required:
        - phone
    SetHeadDto:
      type: object
      properties:
        headId:
          type: string
          nullable: true
    CreateAssignmentDto:
      type: object
      properties:
        volunteerId:
          type: string
        crewMemberId:
          type: string
        roleForEvent:
          type: string
        shiftId:
          type: string
        mode:
          type: string
          enum:
            - invite
            - direct
      required:
        - roleForEvent
    AttendanceCheckInDto:
      type: object
      properties:
        eventId:
          type: string
        lat:
          type: number
        lng:
          type: number
        clientActionId:
          type: string
        localTimestamp:
          type: string
        selfieBase64:
          type: string
      required:
        - eventId
        - clientActionId
    AttendanceCheckOutDto:
      type: object
      properties:
        sessionId:
          type: string
        lat:
          type: number
        lng:
          type: number
        clientActionId:
          type: string
        localTimestamp:
          type: string
      required:
        - sessionId
    SyncBatchDto:
      type: object
      properties:
        actions:
          type: array
          items:
            type: object
      required:
        - actions
    CreateItemTypeDto:
      type: object
      properties:
        name:
          type: string
        category:
          type: string
        requiresSize:
          type: boolean
        tracksInventory:
          type: boolean
        totalStock:
          type: number
        window:
          type: string
      required:
        - name
    HandoutDto:
      type: object
      properties:
        itemTypeId:
          type: string
        eventParticipantId:
          type: string
        quantity:
          type: number
        sizeGiven:
          type: string
        clientActionId:
          type: string
      required:
        - itemTypeId
        - eventParticipantId
        - clientActionId
    CrewSendOtpDto:
      type: object
      properties:
        phoneNumber:
          type: string
      required:
        - phoneNumber
    CrewVerifyOtpDto:
      type: object
      properties:
        phoneNumber:
          type: string
        otp:
          type: string
      required:
        - phoneNumber
        - otp
    SendCrewEmailOtpDto:
      type: object
      properties:
        email:
          type: string
          description: Email address to send the 4-digit crew login code to.
      required:
        - email
    VerifyCrewEmailOtpDto:
      type: object
      properties:
        email:
          type: string
          description: Email address to send the 4-digit crew login code to.
        otp:
          type: string
          description: The 4-digit code emailed to the address.
      required:
        - email
        - otp
    RegisterPushTokenDto:
      type: object
      properties: {}
    TestPushDto:
      type: object
      properties: {}
    CreateCrewJoinCodeDto:
      type: object
      properties: {}
    UpdateCrewJoinCodeDto:
      type: object
      properties: {}
    CrewJoinCodeInputDto:
      type: object
      properties: {}
    UpdateBadgeDto:
      type: object
      properties:
        name:
          type: string
          description: Badge name
          example: First Finish
        description:
          type: string
          description: Badge description
          example: Attend your first event
        iconUrl:
          type: string
          description: Icon URL
        color:
          type: string
          description: Hex color
          example: '#FF5733'
        sourceSystem:
          type: string
          description: Source system
          enum: *ref_681
          example: event
        activityTypeFilter:
          type: string
          description: Activity type filter
          enum: *ref_682
        rarity:
          type: string
          description: Rarity tier
          enum: *ref_683
          example: bronze
        points:
          type: number
          description: Points value
          example: 50
        conditions:
          description: Conditions array
          type: array
          items:
            $ref: '#/components/schemas/BadgeConditionDto'
        conditionLogic:
          type: string
          description: Condition logic (AND/OR)
          enum: *ref_684
          default: AND
        isHidden:
          type: boolean
          description: Hidden until earned?
          default: false
        isRepeatable:
          type: boolean
          description: Can badge be earned multiple times?
          default: false
        repeatCooldownDays:
          type: number
          description: Cooldown days for repeatable badges
        isTimeLimited:
          type: boolean
          description: Is time-limited?
          default: false
        availableFrom:
          format: date-time
          type: string
          description: Available from date
        availableUntil:
          format: date-time
          type: string
          description: Available until date
        mappedChallengeId:
          type: string
          description: Mapped challenge ID
        isActive:
          type: boolean
          description: Is badge active?
          default: true
    CreateGearDto:
      type: object
      properties:
        userId:
          type: string
          description: ID of the user who has the gear
          example: 23rdwd-23ews3-3wrds-4ewdsf
        typeId:
          type: string
          description: ID of the type of gear
          example: 23ews3-3wrds-4ewdsf-23rdwd
        sportId:
          type: string
          description: ID of the default sport for the Gear
          example: 4ewdsf-23rdwd-23ews3-3wrds
        brand:
          type: string
          description: Brand of the Gear
          example: Adidas
        model:
          type: string
          description: Model of the Gear
          example: Adidas Ultraboost
        weight:
          type: number
          description: Weight of the Gear
          example: 180
        isActive:
          type: boolean
          description: Indicates if the gear is active or not!
          example: true
      required:
        - userId
        - typeId
        - sportId
        - brand
        - model
        - weight
    UpdateGearDto:
      type: object
      properties:
        userId:
          type: string
          description: ID of the user who has the gear
          example: 23rdwd-23ews3-3wrds-4ewdsf
        typeId:
          type: string
          description: ID of the type of gear
          example: 23ews3-3wrds-4ewdsf-23rdwd
        sportId:
          type: string
          description: ID of the default sport for the Gear
          example: 4ewdsf-23rdwd-23ews3-3wrds
        brand:
          type: string
          description: Brand of the Gear
          example: Adidas
        model:
          type: string
          description: Model of the Gear
          example: Adidas Ultraboost
        weight:
          type: number
          description: Weight of the Gear
          example: 180
        isActive:
          type: boolean
          description: Indicates if the gear is active or not!
          example: true
    CreateScheduleDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the schedule
          maxLength: 100
        sportId:
          type: string
          description: UUID of the sport
        scheduledAt:
          type: string
          description: Scheduled date and time in ISO format
        isCompleted:
          type: boolean
          description: Status indicating if the schedule is completed
        userId:
          type: string
          description: UUID of the user
        isActive:
          type: boolean
          description: Status indicating if the schedule is active
      required:
        - name
        - sportId
        - scheduledAt
        - userId
    UpdateScheduleDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the schedule
          maxLength: 100
        sportId:
          type: string
          description: UUID of the sport
        scheduledAt:
          type: string
          description: Scheduled date and time in ISO format
        isCompleted:
          type: boolean
          description: Status indicating if the schedule is completed
        userId:
          type: string
          description: UUID of the user
        isActive:
          type: boolean
          description: Status indicating if the schedule is active
    CreateActivityDto:
      type: object
      properties:
        userId:
          type: string
          description: ID of the user associated with the activity
        polyline:
          type: string
          description: Encoded Polyline Algorithm Format
          example: _p~iF~ps|U_ulLnnqC_mqNvxq`@
        sportId:
          type: string
          description: ID of the sport associated with the activity
        completedAt:
          type: object
          description: Date and time when the activity was completed
          example: '2024-02-10T10:00:00'
        distanceInMeters:
          type: number
          description: Distance covered in meters
          example: 5250
        durationInSeconds:
          type: number
          description: Duration of the activity in seconds
          example: 3600
        stepsCount:
          type: number
          description: Number of steps taken during the activity
          example: 8000
        statistics:
          type: string
          description: Activity statistics in JSON format
          example: '{"calories": 500, "avgPace": 6.2}'
        name:
          type: string
          description: Name of the activity
          example: Morning Run
        description:
          type: string
          description: Description of the activity
          example: A refreshing morning jog
        mapType:
          type: string
          description: Type of map used
          enum: &ref_685
            - standard
            - satelite
            - hybrid
          example: standard
        gearId:
          type: string
          description: ID of the gear associated with the activity
        hideStatistics:
          type: string
          description: Whether statistics should be hidden like calories or avgPace
          example: calories
        exertion:
          type: string
          description: Exertion level of the activity
          enum: &ref_686
            - easy
            - moderate
            - max_effort
          example: moderate
        elevationGain:
          type: number
          description: Cumulative uphill elevation climbed in meters
          example: 312
        elevationLoss:
          type: number
          description: Cumulative downhill elevation descended in meters
          example: 298
        isActive:
          type: boolean
          description: Indicates if the activity is active or not!
          example: true
        validationStatus:
          type: string
          description: Validation status (anti-cheat pipeline output).
          enum: &ref_687
            - VALID
            - PENDING
            - FLAGGED
            - REJECTED
        privacy:
          type: string
          description: Privacy scope for social surfaces.
          enum: &ref_688
            - PUBLIC
            - FOLLOWERS
            - PRIVATE
        splits:
          description: >-
            Per-km splits produced by the tracker. `elevationGainM` /
            `elevationLossM` are optional and omitted when the device reported
            no altitude.
          example: &ref_689
            - km: 1
              timeSeconds: 330
              paceSecPerKm: 330
              elevationGainM: 4.2
          type: array
          items:
            type: string
        source:
          type: string
          description: Source system that produced the activity.
          enum: &ref_690
            - REPEAK
            - EXTERNAL_SYNC
            - MANUAL
        deviceSource:
          type: string
          description: Device identifier / user-agent.
        externalId:
          type: string
          description: External system activity id (e.g. Strava activity id).
        challengeId:
          type: string
          description: Linked challenge id.
        eventRegistrationId:
          type: string
          description: Linked event registration id.
        hybridRaceResultId:
          type: string
          description: Linked hybrid race result id.
        validationMetadata:
          type: object
          description: Validation metadata (ML scores, reasons, etc.).
      required:
        - userId
        - polyline
        - sportId
        - completedAt
        - distanceInMeters
        - durationInSeconds
        - stepsCount
        - statistics
        - name
        - description
        - mapType
        - hideStatistics
        - exertion
    UpdateActivityDto:
      type: object
      properties:
        userId:
          type: string
          description: ID of the user associated with the activity
        polyline:
          type: string
          description: Encoded Polyline Algorithm Format
          example: _p~iF~ps|U_ulLnnqC_mqNvxq`@
        sportId:
          type: string
          description: ID of the sport associated with the activity
        completedAt:
          type: object
          description: Date and time when the activity was completed
          example: '2024-02-10T10:00:00'
        distanceInMeters:
          type: number
          description: Distance covered in meters
          example: 5250
        durationInSeconds:
          type: number
          description: Duration of the activity in seconds
          example: 3600
        stepsCount:
          type: number
          description: Number of steps taken during the activity
          example: 8000
        statistics:
          type: string
          description: Activity statistics in JSON format
          example: '{"calories": 500, "avgPace": 6.2}'
        name:
          type: string
          description: Name of the activity
          example: Morning Run
        description:
          type: string
          description: Description of the activity
          example: A refreshing morning jog
        mapType:
          type: string
          description: Type of map used
          enum: *ref_685
          example: standard
        gearId:
          type: string
          description: ID of the gear associated with the activity
        hideStatistics:
          type: string
          description: Whether statistics should be hidden like calories or avgPace
          example: calories
        exertion:
          type: string
          description: Exertion level of the activity
          enum: *ref_686
          example: moderate
        elevationGain:
          type: number
          description: Cumulative uphill elevation climbed in meters
          example: 312
        elevationLoss:
          type: number
          description: Cumulative downhill elevation descended in meters
          example: 298
        isActive:
          type: boolean
          description: Indicates if the activity is active or not!
          example: true
        validationStatus:
          type: string
          description: Validation status (anti-cheat pipeline output).
          enum: *ref_687
        privacy:
          type: string
          description: Privacy scope for social surfaces.
          enum: *ref_688
        splits:
          description: >-
            Per-km splits produced by the tracker. `elevationGainM` /
            `elevationLossM` are optional and omitted when the device reported
            no altitude.
          example: *ref_689
          type: array
          items:
            type: string
        source:
          type: string
          description: Source system that produced the activity.
          enum: *ref_690
        deviceSource:
          type: string
          description: Device identifier / user-agent.
        externalId:
          type: string
          description: External system activity id (e.g. Strava activity id).
        challengeId:
          type: string
          description: Linked challenge id.
        eventRegistrationId:
          type: string
          description: Linked event registration id.
        hybridRaceResultId:
          type: string
          description: Linked hybrid race result id.
        validationMetadata:
          type: object
          description: Validation metadata (ML scores, reasons, etc.).
    UserParticipateInChallengeDto:
      type: object
      properties:
        rcDiscount:
          type: number
          description: >-
            Repeak Coins to apply against the entry fee. Cannot exceed the entry
            fee. Cannot be applied to a free challenge.
          example: 50
          minimum: 0
    VerifyChallengePaymentDto:
      type: object
      properties:
        orderId:
          type: string
          description: >-
            The Cashfree order id returned to the app on join / echoed back by
            the SDK on payment success.
          example: order_104992653GnpgEiOCSgUBccUBR0IBCDczQQ
      required:
        - orderId
    CreateEventParticipantDto:
      type: object
      properties:
        ticketId:
          type: string
          description: Event Ticket ID
          example: 123e4567-e89b-12d3-a456-426614174000
        formId:
          type: string
          description: Form ID
          example: 123e4567-e89b-12d3-a456-426614174000
        formFields:
          type: string
          description: Form fields
          example: >-
            [{"label":"Name","name":"name","type":"text","multiple":false,"required":true,"values":"John
            Doe"},
            {"label":"Interests","name":"interests","type":"text","multiple":true,"required":true,"values":["Sports",
            "Reading", "Traveling"]}]
        bibNumber:
          type: string
          description: Bib number for this participant.
        tshirtSize:
          type: string
          description: T-shirt size for this participant.
          enum:
            - XS
            - S
            - M
            - L
            - XL
            - XXL
            - XXXL
        emergencyContact:
          type: object
          description: Emergency contact details.
          example:
            name: Jane Doe
            phone: '+919999999999'
            relation: Spouse
        medicalInfo:
          type: object
          description: >-
            Per-participant medical info. Encrypted at rest; public surfaces
            never echo it.
          example:
            medicalConditions:
              - Asthma
            allergies:
              - Peanuts
            bloodGroup: O+
            medications: Inhaler PRN
            notes: Carry inhaler in race-belt.
        waiverAccepted:
          type: boolean
          description: >-
            Participant has accepted the event waiver. Required when the event
            has a mandatory waiver.
          example: true
      required:
        - ticketId
        - formId
        - formFields
    PreviewEventParticipationDto:
      type: object
      properties:
        eventId:
          type: string
          description: Event ID
          example: 123e4567-e89b-12d3-a456-426614174000
        slotId:
          type: string
          description: Slot ID
          example: 123e4567-e89b-12d3-a456-426614174000
        participants:
          type: array
          items:
            $ref: '#/components/schemas/CreateEventParticipantDto'
          description: Array of event participants
        coinsUsed:
          type: number
          description: 'Coins used by the user (optional, default: 0)'
          example: 50
        couponIds:
          description: Array of coupon IDs applied by the user
          example:
            - 2f3e1b40-7fc3-4b0c-8f7a-b6bbee924e1f
            - 4c3fbb3e-ded0-4e0d-b420-e4185b2f8799
          type: array
          items:
            type: string
        addOns:
          description: Array of add-ons IDs applied by the user
          example:
            - addOnId: 2f3e1b40-7fc3-4b0c-8f7a-b6bbee924e1f
              quantity: 2
            - addOnId: 4c3fbb3e-ded0-4e0d-b420-e4185b2f8799
              quantity: 1
          type: array
          items:
            type: string
      required:
        - eventId
        - slotId
        - participants
    CreateEventParticipationDto:
      type: object
      properties:
        eventId:
          type: string
          description: Event ID
          example: 123e4567-e89b-12d3-a456-426614174000
        slotId:
          type: string
          description: Slot ID
          example: 123e4567-e89b-12d3-a456-426614174000
        participants:
          type: array
          items:
            $ref: '#/components/schemas/CreateEventParticipantDto'
          description: Array of event participants
        amountPaid:
          type: number
          description: Amount paid by the user (must match server-calculated total)
          example: 199.99
        coinsUsed:
          type: number
          description: 'Coins used by the user (optional, default: 0)'
          example: 50
        couponIds:
          description: Array of coupon IDs applied by the user
          example:
            - 2f3e1b40-7fc3-4b0c-8f7a-b6bbee924e1f
            - 4c3fbb3e-ded0-4e0d-b420-e4185b2f8799
          type: array
          items:
            type: string
        addOns:
          description: Array of add-ons IDs applied by the user
          example:
            - addOnId: 2f3e1b40-7fc3-4b0c-8f7a-b6bbee924e1f
              quantity: 2
            - addOnId: 4c3fbb3e-ded0-4e0d-b420-e4185b2f8799
              quantity: 1
          type: array
          items:
            type: string
        provider:
          type: string
          description: Payment Provider of the payment (e.g. cashfree, eazr)
          enum:
            - cashfree
            - eazr
            - no_provider
          default: cashfree
        registrationType:
          type: string
          description: >-
            Registration type (PHYSICAL, HYBRID, VIRTUAL, or BOTH). VIRTUAL is
            only selectable on events whose allowedParticipationModes include
            VIRTUAL; the server rejects with 400 otherwise.
          enum:
            - PHYSICAL
            - HYBRID
            - VIRTUAL
            - BOTH
          default: PHYSICAL
      required:
        - eventId
        - slotId
        - participants
        - amountPaid
        - provider
    UploadFormFileDto:
      type: object
      properties:
        fieldName:
          type: string
          description: >-
            The `name` of the file-type field on the registration form this
            upload answers (matches FormField.name).
          example: government_id_proof
        formId:
          type: string
          description: >-
            The registration form id. Optional — when omitted the active form
            with formType='registration' for the event is used.
          format: uuid
      required:
        - fieldName
    VerifyEventParticipationDto:
      type: object
      properties:
        requestId:
          type: string
          description: >-
            Id of the order in case of cashfree or Id of the payment in case of
            eazr pay later
        provider:
          type: string
          enum:
            - cashfree
            - eazr
            - no_provider
          description: Provider of the payment (e.g. cashfree, eazr)
      required:
        - requestId
        - provider
    CancelEventParticipationDto:
      type: object
      properties:
        reason:
          type: string
          description: Predefined reason for canceling the event participation
          enum:
            - USER_CANCELLATION
            - SCHEDULE_CONFLICT
            - PERSONAL_EMERGENCY
            - ILLNESS
            - TRAVEL_ISSUES
            - FINANCIAL_REASONS
            - NO_LONGER_INTERESTED
            - FOUND_ALTERNATIVE
            - WRONG_BOOKING
            - CHANGED_MIND
            - OTHER
            - ORGANIZER_CANCELLATION
            - EVENT_CANCELLED
            - TICKET_CANCELLED
            - SLOT_CANCELLED
            - CAPACITY_REDUCED
            - PARTICIPANT_MISCONDUCT
            - DUPLICATE_BOOKING
            - PAYMENT_ISSUE
            - ORGANIZER_OTHER
          example: CHANGED_MIND
        customReason:
          type: string
          description: Custom reason for canceling the event participation
          example: Unable to attend due to personal reasons
          maxLength: 500
    TestCheckInDto:
      type: object
      properties:
        participantIds:
          description: Array of participant IDs to check-in/check-out
          example:
            - 0199800c-02fa-61f3-3655-3c5299c10e87
            - 01998026-4d78-005c-4825-9884fb6d1183
          type: array
          items:
            type: string
        checkIn:
          type: boolean
          description: Check-in (true) or check-out (false)
          default: true
      required:
        - participantIds
    CreateReviewDto:
      type: object
      properties:
        reviewAbout:
          type: string
          description: What the review is about (challenge or event)
          enum: &ref_691
            - challenge
            - event
          example: challenge
        reviewAboutId:
          type: string
          description: ID of the challenge or event being reviewed
          example: 550e8400-e29b-41d4-a716-446655440000
        rating:
          type: number
          description: Rating from 1 to 5 stars
          example: 5
          minimum: 1
          maximum: 5
        comment:
          type: string
          description: Optional comment/feedback text
          example: Great challenge! Really enjoyed participating.
      required:
        - reviewAbout
        - reviewAboutId
        - rating
    UpdateReviewDto:
      type: object
      properties:
        reviewAbout:
          type: string
          description: What the review is about (challenge or event)
          enum: *ref_691
          example: challenge
        reviewAboutId:
          type: string
          description: ID of the challenge or event being reviewed
          example: 550e8400-e29b-41d4-a716-446655440000
        rating:
          type: number
          description: Rating from 1 to 5 stars
          example: 5
          minimum: 1
          maximum: 5
        comment:
          type: string
          description: Optional comment/feedback text
          example: Great challenge! Really enjoyed participating.
    GenerateTrainingPlanDto:
      type: object
      properties:
        eventId:
          type: string
          description: Event ID (if registering for RaceAbove event)
          example: 123e4567-e89b-12d3-a456-426614174000
        eventName:
          type: string
          description: Event name
          example: Mumbai Marathon 2025
        eventDescription:
          type: string
          description: Event description for better AI context
          example: Annual marathon event covering scenic routes through Mumbai
        eventDate:
          type: string
          description: Event date (YYYY-MM-DD)
          example: '2025-09-30'
        planStartDate:
          type: string
          description: >-
            Date when the training plan should start (YYYY-MM-DD). Defaults to
            today if not provided.
          example: '2025-09-01'
        sportType:
          type: string
          description: >-
            Sport type for the training plan (defaults to RUNNING if not
            provided)
          enum:
            - running
            - cycling
            - swimming
            - triathlon
            - hiking_trekking
          example: running
        eventSubType:
          type: string
          description: Specific event sub-type (e.g., marathon, road_cycling, sprint)
          example: half_marathon
        duration:
          type: string
          description: Training plan duration
          enum:
            - 2_weeks
            - 4_weeks
            - 8_weeks
          example: 4_weeks
        eventType:
          type: string
          description: '[DEPRECATED] Type of event - use sportType and eventSubType instead'
          enum:
            - 5K
            - 10K
            - Half Marathon
            - Marathon
          example: Half Marathon
          deprecated: true
        eventDistanceKm:
          type: number
          description: >-
            Event distance in kilometers (fetched from event details if not
            provided)
          example: 21.1
        terrain:
          type: string
          description: Event terrain type
          enum:
            - Road
            - Trail
            - Mixed
            - Mountain
            - Indoor
            - Open Water
            - Pool
          example: Road
        goalType:
          type: string
          description: Goal type for the event (defaults to FINISH if not provided)
          enum:
            - Finish
            - Time Goal
            - Personal Best
          example: Finish
        targetTime:
          type: string
          description: Target finish time (HH:MM:SS format)
          example: '02:30:00'
        preferredDays:
          type: string
          description: Preferred training days (comma-separated or "Flexible")
          example: Mon,Wed,Fri,Sat
        injuryHistory:
          type: string
          description: Injury history
          example: Knee pain in 2023
        foodPreference:
          type: string
          description: Food preference for nutrition plan (veg/non_veg/vegan)
          enum:
            - veg
            - non_veg
            - vegan
          example: veg
        workoutTimePreference:
          type: string
          description: Preferred workout time of day
          enum:
            - early_morning
            - morning
            - afternoon
            - evening
            - night
            - flexible
          example: morning
      required:
        - eventName
        - eventDate
        - duration
    WeeklySummaryDto:
      type: object
      properties:
        weekNumber:
          type: number
        weekStartDate:
          type: string
        weekEndDate:
          type: string
        totalDistanceKm:
          type: number
        totalRuns:
          type: number
        weekFocus:
          type: string
        isRecoveryWeek:
          type: boolean
      required:
        - weekNumber
        - weekStartDate
        - weekEndDate
        - totalDistanceKm
        - totalRuns
        - weekFocus
        - isRecoveryWeek
    CoachNotesDto:
      type: object
      properties:
        planOverview:
          type: string
        keyWorkouts:
          type: array
          items:
            type: string
        injuryPreventionTips:
          type: array
          items:
            type: string
        nutritionReminders:
          type: array
          items:
            type: string
        raceDayAdvice:
          type: string
      required:
        - planOverview
        - keyWorkouts
        - injuryPreventionTips
        - nutritionReminders
        - raceDayAdvice
    DailyWorkoutResponseDto:
      type: object
      properties:
        dayNumber:
          type: number
        date:
          type: string
        dayOfWeek:
          type: string
        weekNumber:
          type: number
        workoutType:
          type: string
        isRestDay:
          type: boolean
        distanceKm:
          type: number
        durationMinutes:
          type: number
        targetPace:
          type: string
        intensity:
          type: string
        heartRateZone:
          type: string
        workoutDescription:
          type: string
        warmup:
          type: string
        cooldown:
          type: string
        notes:
          type: string
        alternatives:
          type: string
        completionStatus:
          type: string
      required:
        - dayNumber
        - date
        - dayOfWeek
        - weekNumber
        - workoutType
        - isRestDay
        - distanceKm
        - durationMinutes
        - targetPace
        - intensity
        - heartRateZone
        - workoutDescription
        - warmup
        - cooldown
        - notes
        - alternatives
        - completionStatus
    TrainingPlanResponseDto:
      type: object
      properties:
        id:
          type: string
        userId:
          type: string
        eventName:
          type: string
        eventDate:
          type: string
        status:
          type: string
        totalDays:
          type: number
        totalWeeks:
          type: number
        difficultyLevel:
          type: string
        weeklyPeakKm:
          type: number
        taperStartsDay:
          type: number
        weeklySummary:
          type: array
          items:
            $ref: '#/components/schemas/WeeklySummaryDto'
        coachNotes:
          $ref: '#/components/schemas/CoachNotesDto'
        dailyWorkouts:
          type: array
          items:
            $ref: '#/components/schemas/DailyWorkoutResponseDto'
        createdAt:
          format: date-time
          type: string
        updatedAt:
          format: date-time
          type: string
      required:
        - id
        - userId
        - eventName
        - eventDate
        - status
        - totalDays
        - totalWeeks
        - difficultyLevel
        - weeklyPeakKm
        - taperStartsDay
        - weeklySummary
        - coachNotes
        - dailyWorkouts
        - createdAt
        - updatedAt
    MatchActivityDto:
      type: object
      properties:
        activityId:
          type: string
          description: Activity ID from the activities table
          example: 01JFXXX...
        activityDate:
          type: string
          description: Activity date (YYYY-MM-DD)
          example: '2025-07-09'
        activityType:
          type: string
          description: Type of activity
          example: Run
        distanceKm:
          type: number
          description: Distance in kilometers
          example: 5.2
        durationMinutes:
          type: number
          description: Duration in minutes
          example: 35
        avgPace:
          type: string
          description: Average pace (min/km format)
          example: 6:45 min/km
        avgHeartRate:
          type: number
          description: Average heart rate in BPM
          example: 145
        elevationGainM:
          type: number
          description: Elevation gain in meters
          example: 120
        userNotes:
          type: string
          description: User notes about the activity
          example: Felt great today, easy pace
      required:
        - activityId
        - activityDate
        - activityType
        - distanceKm
        - durationMinutes
        - avgPace
    MatchResultResponseDto:
      type: object
      properties:
        status:
          type: string
          description: Match status
          enum:
            - Completed
            - Partial
            - Exceeded
            - Missed
            - Wrong Workout Type
            - Rest Day Activity
          example: Completed
        matchConfidence:
          type: number
          description: Match confidence percentage (0-100)
          example: 95
        distanceCompletionPercentage:
          type: number
          description: Distance completion percentage
          example: 104
        paceVsTarget:
          type: string
          description: Pace compared to target
          enum:
            - Slower
            - On Target
            - Faster
            - N/A
          example: On Target
        intensityAssessment:
          type: string
          description: Intensity assessment
          enum:
            - Under
            - Appropriate
            - Over
            - N/A
          example: Appropriate
        feedbackForUser:
          type: string
          description: Personalized feedback message for the user
          example: >-
            Great job! You completed the planned workout perfectly. Your pace
            was spot-on!
        impactOnPlan:
          type: string
          description: Impact on training plan
          enum:
            - None
            - Minor Adjustment Recommended
            - Rest Recommended
          example: None
      required:
        - status
        - matchConfidence
        - distanceCompletionPercentage
        - paceVsTarget
        - intensityAssessment
        - feedbackForUser
        - impactOnPlan
    WorkoutMatchResponseDto:
      type: object
      properties:
        workout:
          type: object
          description: Updated workout details
        matchResult:
          description: Match analysis result
          allOf:
            - $ref: '#/components/schemas/MatchResultResponseDto'
      required:
        - workout
        - matchResult
    PlanProgressResponseDto:
      type: object
      properties:
        totalWorkouts:
          type: number
          description: Total non-rest workouts in plan
          example: 60
        completed:
          type: number
          description: Number of completed workouts
          example: 45
        partial:
          type: number
          description: Number of partially completed workouts
          example: 5
        missed:
          type: number
          description: Number of missed workouts
          example: 3
        pending:
          type: number
          description: Number of pending workouts
          example: 7
        completionRate:
          type: number
          description: Overall completion rate percentage
          example: 79
      required:
        - totalWorkouts
        - completed
        - partial
        - missed
        - pending
        - completionRate
    AdjustPlanDto:
      type: object
      properties:
        adjustmentType:
          type: string
          description: Type of adjustment needed
          enum:
            - missed_workouts
            - injury_prevention
            - schedule_conflict
            - performance_issue
            - increase_intensity
            - decrease_intensity
            - custom
          example: missed_workouts
        reason:
          type: string
          description: Detailed reason for adjustment request
          example: Missed 3 workouts last week due to work commitments
        injuryDetails:
          type: string
          description: Injury or pain details (required for injury_prevention type)
          example: Right knee pain during long runs
        preferredDays:
          description: Preferred training days (e.g., ["Monday", "Wednesday", "Friday"])
          example:
            - Monday
            - Wednesday
            - Friday
            - Saturday
          type: array
          items:
            type: string
        targetWeeklyDistance:
          type: number
          description: Target weekly distance in kilometers
          example: 30
      required:
        - adjustmentType
        - reason
    CurrentProgressDto:
      type: object
      properties:
        completionRate:
          type: number
          description: Overall completion rate percentage
          example: 65
        missedWorkouts:
          type: number
          description: Number of missed workouts
          example: 5
        recentPerformance:
          type: string
          description: Recent performance summary
          example: 3 completed, 2 missed (last 7 days)
        adherenceIssues:
          description: List of adherence issues detected
          example:
            - Multiple missed workouts in last 7 days
            - Low overall completion rate
          type: array
          items:
            type: string
      required:
        - completionRate
        - missedWorkouts
        - recentPerformance
        - adherenceIssues
    WorkoutModificationDto:
      type: object
      properties:
        dayNumber:
          type: number
          description: Day number in the plan
          example: 15
        currentWorkout:
          type: string
          description: Original workout description
          example: Easy Run - 8km
        proposedWorkout:
          type: string
          description: Modified workout description
          example: Easy Run - 5km
        reason:
          type: string
          description: Reason for modification
          example: Reduced from 8km due to missed workouts last week
      required:
        - dayNumber
        - currentWorkout
        - proposedWorkout
        - reason
    ScheduleAdjustmentDto:
      type: object
      properties:
        weekNumber:
          type: number
          description: Week number in the plan
          example: 3
        change:
          type: string
          description: Description of the change
          example: 25km - Rebuilding base after missed workouts
        reason:
          type: string
          description: Reason for the change
          example: Reducing volume to allow proper recovery
      required:
        - weekNumber
        - change
        - reason
    ProposedChangesDto:
      type: object
      properties:
        workoutModifications:
          description: List of workout modifications
          type: array
          items:
            $ref: '#/components/schemas/WorkoutModificationDto'
        scheduleAdjustments:
          description: Schedule adjustments by week
          type: array
          items:
            $ref: '#/components/schemas/ScheduleAdjustmentDto'
        intensityChanges:
          type: string
          description: Overall intensity changes
          example: Reduced weekly volume by 15% and added extra recovery day
      required:
        - workoutModifications
        - scheduleAdjustments
        - intensityChanges
    AdjustmentAnalysisDto:
      type: object
      properties:
        currentProgress:
          description: Current training progress analysis
          allOf:
            - $ref: '#/components/schemas/CurrentProgressDto'
        proposedChanges:
          description: Proposed changes to the plan
          allOf:
            - $ref: '#/components/schemas/ProposedChangesDto'
        adjustmentReason:
          type: string
          description: Primary reason for the adjustment
          example: Plan adjusted to account for missed workouts and prevent injury
        impactAssessment:
          type: string
          description: Expected impact of the changes
          example: >-
            Gradual rebuild of fitness base; reduced injury risk; improved
            adherence
      required:
        - currentProgress
        - proposedChanges
        - adjustmentReason
        - impactAssessment
    PlanAdjustmentResponseDto:
      type: object
      properties:
        plan:
          type: object
          description: Updated training plan
        analysis:
          description: Detailed adjustment analysis
          allOf:
            - $ref: '#/components/schemas/AdjustmentAnalysisDto'
      required:
        - plan
        - analysis
    AdjustmentSuggestionsResponseDto:
      type: object
      properties:
        suggestions:
          description: Automated adjustment suggestions (not applied)
          allOf:
            - $ref: '#/components/schemas/AdjustmentAnalysisDto'
      required:
        - suggestions
    ConsistencyMetricsDto:
      type: object
      properties:
        completionRate:
          type: number
          description: Overall completion rate percentage
          example: 85
        weeklyAdherence:
          type: number
          description: Weekly adherence percentage (last 4 weeks)
          example: 90
        longestStreak:
          type: number
          description: Longest workout completion streak
          example: 12
        currentStreak:
          type: number
          description: Current active streak
          example: 5
      required:
        - completionRate
        - weeklyAdherence
        - longestStreak
        - currentStreak
    ConsistencyScoreDto:
      type: object
      properties:
        score:
          type: number
          description: Consistency score (0-100)
          example: 88
        metrics:
          description: Detailed consistency metrics
          allOf:
            - $ref: '#/components/schemas/ConsistencyMetricsDto'
      required:
        - score
        - metrics
    VolumeMetricsDto:
      type: object
      properties:
        weeklyAverageKm:
          type: number
          description: Weekly average distance in km
          example: 35.5
        monthlyTotalKm:
          type: number
          description: Monthly total distance in km
          example: 142
        volumeTrend:
          type: string
          description: Volume trend
          enum:
            - increasing
            - stable
            - decreasing
          example: increasing
        comparedToGoal:
          type: number
          description: Percentage compared to goal volume
          example: 85
      required:
        - weeklyAverageKm
        - monthlyTotalKm
        - volumeTrend
        - comparedToGoal
    VolumeScoreDto:
      type: object
      properties:
        score:
          type: number
          description: Volume score (0-100)
          example: 82
        metrics:
          description: Detailed volume metrics
          allOf:
            - $ref: '#/components/schemas/VolumeMetricsDto'
      required:
        - score
        - metrics
    IntensityMetricsDto:
      type: object
      properties:
        hardWorkoutsPerWeek:
          type: number
          description: Hard workouts per week average
          example: 1.5
        easyHardRatio:
          type: number
          description: Easy to hard workout ratio
          example: 2.5
        recoveryAdequacy:
          type: string
          description: Recovery adequacy assessment
          enum:
            - good
            - fair
            - poor
          example: good
      required:
        - hardWorkoutsPerWeek
        - easyHardRatio
        - recoveryAdequacy
    IntensityScoreDto:
      type: object
      properties:
        score:
          type: number
          description: Intensity score (0-100)
          example: 75
        metrics:
          description: Detailed intensity metrics
          allOf:
            - $ref: '#/components/schemas/IntensityMetricsDto'
      required:
        - score
        - metrics
    ProgressionMetricsDto:
      type: object
      properties:
        weekOverWeekImprovement:
          type: number
          description: Week-over-week improvement percentage
          example: 8
        peakDistance:
          type: number
          description: Peak distance completed in km
          example: 18.5
        longestRunCompleted:
          type: number
          description: Longest run completed in km
          example: 18.5
      required:
        - weekOverWeekImprovement
        - peakDistance
        - longestRunCompleted
    ProgressionScoreDto:
      type: object
      properties:
        score:
          type: number
          description: Progression score (0-100)
          example: 80
        metrics:
          description: Detailed progression metrics
          allOf:
            - $ref: '#/components/schemas/ProgressionMetricsDto'
      required:
        - score
        - metrics
    FitnessComponentsDto:
      type: object
      properties:
        consistency:
          description: Consistency component
          allOf:
            - $ref: '#/components/schemas/ConsistencyScoreDto'
        volume:
          description: Volume component
          allOf:
            - $ref: '#/components/schemas/VolumeScoreDto'
        intensity:
          description: Intensity component
          allOf:
            - $ref: '#/components/schemas/IntensityScoreDto'
        progression:
          description: Progression component
          allOf:
            - $ref: '#/components/schemas/ProgressionScoreDto'
      required:
        - consistency
        - volume
        - intensity
        - progression
    ProjectedPerformanceDto:
      type: object
      properties:
        estimatedFinishTime:
          type: string
          description: Estimated finish time (HH:MM:SS)
          example: '02:15:30'
        confidenceLevel:
          type: string
          description: Confidence level in projection
          enum:
            - high
            - medium
            - low
          example: medium
        keyFactors:
          description: Key factors influencing projection
          example:
            - Strong training consistency
            - Solid long run base established
          type: array
          items:
            type: string
      required:
        - confidenceLevel
        - keyFactors
    FitnessScoreResponseDto:
      type: object
      properties:
        overall:
          type: number
          description: Overall fitness score (0-100)
          example: 82
        components:
          description: Detailed component scores
          allOf:
            - $ref: '#/components/schemas/FitnessComponentsDto'
        trend:
          type: string
          description: Fitness trend
          enum:
            - improving
            - stable
            - declining
          example: improving
        insights:
          description: Personalized insights
          example:
            - Excellent consistency! You've completed 85% of workouts.
            - >-
              Your training volume is increasing - currently averaging
              35.5km/week.
          type: array
          items:
            type: string
        recommendations:
          description: Actionable recommendations
          example:
            - >-
              Focus on completing workouts consistently. Aim for at least 80%
              completion rate.
            - >-
              Consider adding quality workouts (tempo, intervals) to improve
              race readiness.
          type: array
          items:
            type: string
        readinessScore:
          type: number
          description: Event readiness score (0-100)
          example: 85
        projectedPerformance:
          description: Projected event performance
          allOf:
            - $ref: '#/components/schemas/ProjectedPerformanceDto'
      required:
        - overall
        - components
        - trend
        - insights
        - recommendations
        - readinessScore
    HistoricalFitnessDataDto:
      type: object
      properties:
        date:
          type: string
          description: Date of the score
          example: '2025-07-15'
        overallScore:
          type: number
          description: Overall fitness score
          example: 78
        consistencyScore:
          type: number
          description: Consistency score
          example: 85
        volumeScore:
          type: number
          description: Volume score
          example: 75
        intensityScore:
          type: number
          description: Intensity score
          example: 72
        progressionScore:
          type: number
          description: Progression score
          example: 80
      required:
        - date
        - overallScore
        - consistencyScore
        - volumeScore
        - intensityScore
        - progressionScore
    FitnessHistoryResponseDto:
      type: object
      properties:
        history:
          description: Historical fitness scores over time
          type: array
          items:
            $ref: '#/components/schemas/HistoricalFitnessDataDto'
        weeks:
          type: number
          description: Number of weeks included
          example: 4
      required:
        - history
        - weeks
    SendChatMessageDto:
      type: object
      properties:
        message:
          type: string
          description: User message
          example: What should I eat before a long run?
          maxLength: 2000
        sessionId:
          type: string
          description: Session ID to continue a conversation
          example: uuid-session-id
      required:
        - message
    ChatMessageResponseDto:
      type: object
      properties:
        messageId:
          type: string
          description: Message ID (same as WebSocket messageId)
          example: e85ecc71-e755-44d9-9b40-610cf1c4c7e3
        sessionId:
          type: string
          description: Session ID
          example: 5c4b9ba9-2f1c-4199-962f-99d057d94b71
        role:
          type: string
          description: Role (user/assistant)
          example: assistant
        fullContent:
          type: string
          description: Full content including markdown formatted training plan
          example: That's impressive! To prepare for your event...
        category:
          type: string
          description: Message category
          example: event
        tokensUsed:
          type: number
          description: Tokens used for this message
          example: 0
        actionButton:
          type: object
          description: Action button for navigation (null if no action)
          nullable: true
          example:
            text: View Training Plan
            action: navigate
            screen: TrainingPlanDashboardScreen
            params:
              planId: uuid
      required:
        - messageId
        - sessionId
        - role
        - fullContent
        - category
        - tokensUsed
        - actionButton
    ChatSessionListDto:
      type: object
      properties:
        sessionId:
          type: string
          description: Session ID
        preview:
          type: string
          description: First message preview
        messageCount:
          type: number
          description: Message count
        lastMessageAt:
          format: date-time
          type: string
          description: Last message timestamp
        createdAt:
          format: date-time
          type: string
          description: Session created at
      required:
        - sessionId
        - preview
        - messageCount
        - lastMessageAt
        - createdAt
    ChatHistoryResponseDto:
      type: object
      properties:
        sessionId:
          type: string
          description: Session ID
        messages:
          description: Messages in the session
          type: array
          items:
            $ref: '#/components/schemas/ChatMessageResponseDto'
        totalMessages:
          type: number
          description: Total messages count
      required:
        - sessionId
        - messages
        - totalMessages
    PlanTierDto:
      type: object
      properties:
        price:
          type: number
          description: Price in INR
          example: 9
        isFree:
          type: boolean
          description: Whether this plan is free
          example: false
        features:
          description: List of features included
          example:
            - Personalized training schedule
            - Daily nutrition tips
          type: array
          items:
            type: string
        availableDurations:
          description: Available durations for this tier
          example:
            - 2_weeks
            - 4_weeks
            - 8_weeks
          type: array
          items:
            type: string
      required:
        - price
        - isFree
        - features
        - availableDurations
    TrainingPlanOfferResponseDto:
      type: object
      properties:
        eligible:
          type: boolean
          description: Whether user is eligible for training plan
          example: true
        reason:
          type: string
          description: Reason for eligibility or ineligibility
          example: Eligible for personalized training plan
        daysUntilEvent:
          type: number
          description: Days until the event
          example: 45
        minDaysRequired:
          type: number
          description: Minimum days required before event
          example: 15
        sportType:
          type: string
          description: Sport type for the event
          enum:
            - running
            - cycling
            - swimming
            - triathlon
            - hiking_trekking
          example: running
        eventSubType:
          type: string
          description: Event sub-type (marathon, road_cycling, etc.)
          example: marathon
        pricing:
          type: object
          description: Pricing details for all tiers
        activePlan:
          description: Active (Easy) plan - FREE tier
          allOf:
            - $ref: '#/components/schemas/PlanTierDto'
        athletePlan:
          description: Athlete (Medium) plan - Paid tier
          allOf:
            - $ref: '#/components/schemas/PlanTierDto'
        goatPlan:
          description: GOAT (Tough) plan - Premium tier with chatbot
          allOf:
            - $ref: '#/components/schemas/PlanTierDto'
        normalPlan:
          type: object
          description: '[DEPRECATED] Use pricing.activePrice/athletePrice instead'
          deprecated: true
        advancedPlan:
          type: object
          description: '[DEPRECATED] Use pricing.goatPrice instead'
          deprecated: true
      required:
        - eligible
        - reason
        - daysUntilEvent
        - minDaysRequired
        - sportType
        - pricing
        - activePlan
        - athletePlan
        - goatPlan
    InitiateTrainingPlanPurchaseDto:
      type: object
      properties:
        eventId:
          type: string
          description: Event ID for which training plan is being purchased
          example: 550e8400-e29b-41d4-a716-446655440000
        planStartDate:
          type: string
          description: >-
            Date when the user wants to start the training plan (ISO 8601
            format). Defaults to today if not provided.
          example: '2026-01-10'
        programLevel:
          type: string
          description: Program level to purchase
          enum:
            - active
            - athlete
            - goat
          example: athlete
        duration:
          type: string
          description: Duration of the training plan
          enum:
            - 2_weeks
            - 4_weeks
            - 8_weeks
          example: 4_weeks
        sportType:
          type: string
          description: Sport type (defaults to event sport type)
          enum:
            - running
            - cycling
            - swimming
            - triathlon
            - hiking_trekking
          example: running
        planType:
          type: string
          description: '[DEPRECATED] Use programLevel instead'
          enum:
            - normal
            - advanced
          deprecated: true
        goalType:
          type: string
          description: Goal type for the training plan
          example: finish
        targetTime:
          type: string
          description: Target time for the event
          example: '2:00:00'
        preferredDays:
          type: string
          description: Preferred training days
          example: weekdays
        injuryHistory:
          type: string
          description: Any injury history to consider
          example: knee pain
        foodPreference:
          type: string
          description: Food preference for nutrition plan (veg/non_veg/vegan)
          enum:
            - veg
            - non_veg
            - vegan
          example: veg
        workoutTimePreference:
          type: string
          description: Preferred workout time of day
          enum:
            - early_morning
            - morning
            - afternoon
            - evening
            - night
            - flexible
          example: morning
      required:
        - eventId
        - programLevel
        - duration
    VerifyTrainingPlanPurchaseDto:
      type: object
      properties:
        orderId:
          type: string
          description: Order ID from Cashfree
          example: order_123456
      required:
        - orderId
    VerifyPaymentDto:
      type: object
      properties:
        orderId:
          type: string
          description: Order ID from Cashfree
          example: order_123456
      required:
        - orderId
    VerifyPaymentResponseDto:
      type: object
      properties:
        success:
          type: boolean
          description: Whether payment verification was successful
          example: true
        message:
          type: string
          description: Message describing the payment status
          example: Payment verified successfully
        paymentStatus:
          type: string
          description: Payment status from Cashfree
          example: PAID
        orderAmount:
          type: number
          description: Order amount in INR
          example: 19
        programLevel:
          type: string
          description: Program level for the training plan
          enum:
            - active
            - athlete
            - goat
          example: athlete
        duration:
          type: string
          description: Duration of the training plan
          enum:
            - 2_weeks
            - 4_weeks
            - 8_weeks
          example: 4_weeks
        eventId:
          type: string
          description: Event ID associated with the order
          example: 550e8400-e29b-41d4-a716-446655440000
        eventName:
          type: string
          description: Event name associated with the order
          example: Mumbai Marathon 2026
        planAlreadyCreated:
          type: boolean
          description: Whether a training plan has already been created for this order
          example: false
        planId:
          type: string
          description: Plan ID if a plan has already been created
          example: 01HQXYZ123456789
      required:
        - success
        - message
        - paymentStatus
        - orderAmount
        - planAlreadyCreated
    GenerateTrainingPlanFromOrderDto:
      type: object
      properties:
        orderId:
          type: string
          description: Order ID from Cashfree (required for paid plans)
          example: order_123456
        eventId:
          type: string
          description: Event ID for which training plan is being generated
          example: 550e8400-e29b-41d4-a716-446655440000
        programLevel:
          type: string
          description: Program level for the training plan
          enum:
            - active
            - athlete
            - goat
          example: athlete
        duration:
          type: string
          description: Duration of the training plan
          enum:
            - 2_weeks
            - 4_weeks
            - 8_weeks
          example: 4_weeks
        sportType:
          type: string
          description: Sport type (defaults to RUNNING)
          enum:
            - running
            - cycling
            - swimming
            - triathlon
            - hiking_trekking
          example: running
        planStartDate:
          type: string
          description: >-
            Date when the user wants to start the training plan (ISO 8601
            format). Defaults to today if not provided.
          example: '2026-01-10'
        goalType:
          type: string
          description: Goal type for the training plan
          example: finish
        targetTime:
          type: string
          description: Target time for the event
          example: '2:00:00'
        preferredDays:
          type: string
          description: Preferred training days
          example: weekdays
        injuryHistory:
          type: string
          description: Any injury history to consider
          example: knee pain
        foodPreference:
          type: string
          description: Food preference for nutrition plan (veg/non_veg/vegan)
          enum:
            - veg
            - non_veg
            - vegan
          example: veg
        workoutTimePreference:
          type: string
          description: Preferred workout time of day
          enum:
            - early_morning
            - morning
            - afternoon
            - evening
            - night
            - flexible
          example: morning
      required:
        - eventId
        - programLevel
        - duration
    GenerateTrainingPlanResponseDto:
      type: object
      properties:
        success:
          type: boolean
          description: Whether plan generation was successful
          example: true
        message:
          type: string
          description: Message describing the result
          example: Training plan created successfully
        planId:
          type: string
          description: Generated training plan ID
          example: 01HQXYZ123456789
        chatbotEnabled:
          type: boolean
          description: Whether AI chatbot is enabled for this plan (GOAT only)
          example: false
        programLevel:
          type: string
          description: Program level of the created plan
          enum:
            - active
            - athlete
            - goat
          example: athlete
        isFree:
          type: boolean
          description: Whether this was a free plan
          example: false
      required:
        - success
        - message
        - isFree
    CalendarEventDto:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier
        type:
          type: string
          enum:
            - training_workout
            - event_participation
            - challenge_participation
            - custom_workout
          description: Type of calendar event
        title:
          type: string
          description: Event title/name
        description:
          type: string
          description: Event description
        startDate:
          format: date-time
          type: string
          description: Start date/time
        endDate:
          format: date-time
          type: string
          description: End date/time
        allDay:
          type: boolean
          description: Is this an all-day event
        color:
          type: string
          description: Color code for UI
        metadata:
          type: object
          description: Additional metadata
      required:
        - id
        - type
        - title
        - startDate
        - allDay
    CalendarMonthResponseDto:
      type: object
      properties:
        year:
          type: number
          description: Year
        month:
          type: number
          description: Month (1-12)
        events:
          description: Events for the month
          type: array
          items:
            $ref: '#/components/schemas/CalendarEventDto'
        totalEvents:
          type: number
          description: Total count of events
      required:
        - year
        - month
        - events
        - totalEvents
    CalendarRangeResponseDto:
      type: object
      properties:
        startDate:
          type: string
          description: Start date of range
        endDate:
          type: string
          description: End date of range
        events:
          description: Events in the range
          type: array
          items:
            $ref: '#/components/schemas/CalendarEventDto'
        totalEvents:
          type: number
          description: Total count of events
      required:
        - startDate
        - endDate
        - events
        - totalEvents
    CreateUserWorkoutDto:
      type: object
      properties:
        date:
          type: string
          description: Workout date
          example: '2025-01-15'
        title:
          type: string
          description: Workout title
          example: Morning Run
          maxLength: 255
        description:
          type: string
          description: Workout description
          example: Easy 5km run in the park
        workoutType:
          type: string
          enum: &ref_692
            - run
            - walk
            - cycling
            - swimming
            - gym
            - yoga
            - stretching
            - cross_training
            - rest
            - other
          description: Type of workout
          example: run
        intensity:
          type: string
          enum: &ref_693
            - none
            - low
            - moderate
            - high
          description: Workout intensity level
          example: moderate
        distanceKm:
          type: number
          description: Distance in kilometers
          example: 5
        durationMinutes:
          type: number
          description: Duration in minutes
          example: 30
        targetPace:
          type: string
          description: Target pace (min/km)
          example: '6:00'
        calories:
          type: number
          description: Estimated calories to burn
          example: 300
        startTime:
          type: string
          description: Start time (HH:MM)
          example: '06:30'
        endTime:
          type: string
          description: End time (HH:MM)
          example: '07:00'
        location:
          type: string
          description: Workout location
          example: Central Park
        notes:
          type: string
          description: Additional notes
          example: Remember to stretch before and after
        color:
          type: string
          description: Color code for calendar display
          example: '#4CAF50'
        isRecurring:
          type: boolean
          description: Is this a recurring workout
          example: false
        recurringPattern:
          type: string
          description: Recurring pattern (daily, weekly, monthly)
          example: weekly
        nutritionPlan:
          type: object
          description: Nutrition plan for this workout
          example: &ref_694
            waterIntakeLiters: 2.5
            preWorkoutMeal: Banana and oats
            postWorkoutMeal: Protein shake
            notes: Stay hydrated
      required:
        - date
        - title
    UpdateUserWorkoutDto:
      type: object
      properties:
        date:
          type: string
          description: Workout date
          example: '2025-01-15'
        title:
          type: string
          description: Workout title
          example: Morning Run
          maxLength: 255
        description:
          type: string
          description: Workout description
          example: Easy 5km run in the park
        workoutType:
          type: string
          enum: *ref_692
          description: Type of workout
          example: run
        intensity:
          type: string
          enum: *ref_693
          description: Workout intensity level
          example: moderate
        distanceKm:
          type: number
          description: Distance in kilometers
          example: 5
        durationMinutes:
          type: number
          description: Duration in minutes
          example: 30
        targetPace:
          type: string
          description: Target pace (min/km)
          example: '6:00'
        calories:
          type: number
          description: Estimated calories to burn
          example: 300
        startTime:
          type: string
          description: Start time (HH:MM)
          example: '06:30'
        endTime:
          type: string
          description: End time (HH:MM)
          example: '07:00'
        location:
          type: string
          description: Workout location
          example: Central Park
        notes:
          type: string
          description: Additional notes
          example: Remember to stretch before and after
        color:
          type: string
          description: Color code for calendar display
          example: '#4CAF50'
        isRecurring:
          type: boolean
          description: Is this a recurring workout
          example: false
        recurringPattern:
          type: string
          description: Recurring pattern (daily, weekly, monthly)
          example: weekly
        nutritionPlan:
          type: object
          description: Nutrition plan for this workout
          example: *ref_694
        isCompleted:
          type: boolean
          description: Mark workout as completed
          example: true
    ChallengeProofRulesDto:
      type: object
      properties:
        gps_required:
          type: boolean
          description: Whether GPS tracking is required to record the activity
          example: true
        minimum_distance:
          type: number
          description: >-
            Minimum distance (in the challenge targetUnit) an activity must
            cover to qualify. Null means no minimum.
          example: 1
          nullable: true
        route_match:
          type: boolean
          description: Whether the activity must follow a predefined route
          example: false
        photo_proof:
          type: boolean
          description: Whether a photo is required as proof of completion
          example: false
        device_import:
          type: boolean
          description: >-
            Whether importing from a wearable / third-party device is allowed as
            proof
          example: true
        allowed_devices:
          description: >-
            Allowlist of device / platform identifiers (e.g. "garmin", "strava",
            "apple_health"). Empty array means any device is allowed.
          example:
            - garmin
            - strava
          type: array
          items:
            type: string
    PrizeCashDto:
      type: object
      properties:
        amount:
          type: number
          example: 10000
    PrizeCoinDto:
      type: object
      properties:
        coinAmount:
          type: number
          example: 2000
    PrizeProductDto:
      type: object
      properties:
        productName:
          type: string
          example: Nike Shoes
        productDescription:
          type: string
          example: Nike Air Zoom Pegasus
        quantity:
          type: number
          example: 1
    PrizeSlabDto:
      type: object
      properties:
        rankStart:
          type: number
          example: 1
        rankEnd:
          type: number
          example: 1
        cash:
          $ref: '#/components/schemas/PrizeCashDto'
        rcCoin:
          $ref: '#/components/schemas/PrizeCoinDto'
        product:
          $ref: '#/components/schemas/PrizeProductDto'
    ParticipationRewardDto:
      type: object
      properties:
        coinAmount:
          type: number
          example: 10
          description: RC Coins each completer earns.
        maxRewardedParticipants:
          type: number
          example: 500
          description: >-
            How many completers the reward is funded for. coinAmount × this is
            reserved from the creator wallet.
    CreateChallengeDto:
      type: object
      properties:
        ownerOrganizerId:
          type: string
          description: >-
            Admin-only target organizer. Ignored for non-admin callers and
            validated server-side.
        desktopVideoUploadKey:
          type: string
          description: >-
            Temporary owned GCS object key returned by POST
            /v2/challenges/video-uploads for a desktop video uploaded directly
            by the browser.
        desktopVideoCrop:
          type: string
          description: >-
            JSON crop/trim settings for the required 16:9 desktop video
            alternative.
        promoVideoUploadKey:
          type: string
          description: >-
            Temporary owned GCS object key returned by POST
            /v2/challenges/video-uploads for a mobile video uploaded directly by
            the browser.
        removeDesktopVideo:
          type: boolean
          description: Remove the currently saved desktop video.
        promoVideoCrop:
          type: string
          description: >-
            JSON crop/trim settings for the required 4:5 mobile video
            alternative.
        removePromoVideo:
          type: boolean
          description: Remove the currently saved promotional video.
        title:
          type: string
          description: Title of the challenge
          maxLength: 256
          example: January Running Challenge
        challengeType:
          type: string
          description: Type of the challenge (collective or daily)
          enum: &ref_695
            - collective
            - daily
            - distance
            - streak
            - single_effort
            - elevation
            - multi_sport
            - team
            - speed_pace
            - frequency
          example: collective
        startDate:
          format: date-time
          type: string
          description: Start date of the challenge (YYYY-MM-DD)
          example: '2025-01-01'
        endDate:
          format: date-time
          type: string
          description: End date of the challenge (YYYY-MM-DD)
          example: '2025-01-31'
        totalDays:
          type: number
          description: >-
            Total duration in days. Optional — the backend always computes the
            canonical value from startDate/endDate; if provided, it must match
            or the request is rejected. Frontend-supplied values are for UX
            display only, never trusted as-is.
          example: 30
        targetValue:
          type: number
          description: >-
            Target value of the challenge (total for COLLECTIVE, daily for
            DAILY). For DAILY challenges this is server-computed
            (dailyTargetValue × minActiveDays) and any client-supplied value is
            ignored.
          example: 5000
        dailyTargetValue:
          type: number
          description: Daily target value (required for DAILY challenges)
          example: 1000
        minActiveDays:
          type: number
          description: Minimum active days required to complete DAILY challenges
          example: 5
        dailyCompletionThreshold:
          type: number
          description: >-
            Percentage of dailyTargetValue required for a day to count as
            completed. This is a percentage, not a distance/steps amount
            (default 90).
          example: 90
        requireConsecutiveDays:
          type: boolean
          description: Whether daily challenges require consecutive days (default true)
          example: true
        targetUnit:
          type: string
          description: Target unit of the challenge (steps/km)
          enum: &ref_696
            - steps
            - km
            - calories
          example: steps
        targetDescription:
          type: string
          description: Target description of the challenge
          example: Complete to 5000 km in a month
        badgeDescription:
          type: string
          description: Description shown below the selected challenge badge
          example: Complete this challenge to earn your finisher badge.
        rewardCoinsInterval:
          type: number
          description: >-
            Legacy: activity interval at which coins are rewarded (in target
            unit). No longer used by any current UI.
          example: 10000
        rewardCoinsPerInterval:
          type: number
          description: >-
            Legacy: number of coins awarded per interval completion. No longer
            used by any current UI.
          example: 20
        rewardCoinsMultiplier:
          type: number
          description: >-
            Legacy: multiplier for reward coins. No longer used by any current
            UI.
          example: 1.5
        reward:
          type: string
          description: >-
            Legacy: free-text reward summary. No longer collected by any current
            UI.
          example: Digital badge, $100, Merchant Discount
        description:
          type: string
          description: Description of the challenge
          example: >-
            Fitgo partners with Brodks and challenges you to take part in a 5K.
            Find strength in every step you take, feel positive energy.
        qualifyingSports:
          description: Qualifying activities of the challenge
          example: &ref_697
            - ca462431-34da-42a7-9b7f-70e9fbcff541
            - ca462431-34da-42a7-9k3h-70e9fbcff541
            - ca462431-34da-42a7-9u8f-70e9fbcff541
          type: array
          items:
            type: string
        isActive:
          type: boolean
          description: Indicates if the challenge is active or not
          example: true
        clubId:
          type: string
          description: >-
            When set, the challenge is floated on behalf of this club instead of
            the calling organizer. The organizer must own the club. Vision §1 —
            clubs are first-class challenge creators.
          example: 123e4567-e89b-12d3-a456-426614174000
        sponsorId:
          type: string
          description: >-
            When set, the challenge is floated on behalf of this sponsor brand.
            The calling user must have an ACTIVE SponsorAccount for the brand.
            Vision §1 — sponsors are first-class challenge hosts.
          example: 123e4567-e89b-12d3-a456-426614174000
        proofRules:
          description: >-
            Activity verification rules for this challenge. Controls GPS,
            distance, route, photo proof, and device import requirements.
          allOf:
            - $ref: '#/components/schemas/ChallengeProofRulesDto'
        accessType:
          type: string
          description: Whether the challenge is free to join or requires an entry fee.
          enum: &ref_698
            - free
            - paid
          example: free
          default: free
        paymentMethod:
          type: string
          description: >-
            Required when accessType=PAID. RC_COIN charges the RC wallet; MONEY
            routes through the existing payment gateway flow.
          enum: &ref_699
            - rc_coin
            - money
          example: money
        entryFeeCoins:
          type: number
          description: Entry fee in RC Coins. Required when paymentMethod=RC_COIN.
          example: 500
        leaveCutoffDaysBeforeStart:
          type: number
          description: >-
            Refund/leave window for PAID challenges: participants may leave and
            be refunded only until this many days before startDate. 0 (default)
            = allowed right up to the start date. Ignored for FREE challenges
            (always leavable, no refund).
          example: 0
        entryFee:
          type: number
          description: >-
            Entry fee in the challenge currency (INR). Required when
            paymentMethod=MONEY.
          example: 499
        badgeId:
          type: string
          description: >-
            ID of an existing ACTIVE Badge (from the admin-curated badge
            library) to award on challenge completion. Replaces the old
            per-challenge badge image upload. Leave unset and provide
            badgeRequestName/... to raise a draft badge request instead.
        prizeSlabs:
          description: >-
            Rank-wise prize configuration. Unlimited slabs; each rank or rank
            range may carry Cash, RC Coin, and/or Product prizes simultaneously.
            RC Coin prizes are reserved from the creator’s wallet immediately on
            save.
          type: array
          items:
            $ref: '#/components/schemas/PrizeSlabDto'
        participationReward:
          description: >-
            Inclusive participation reward — every athlete who COMPLETES the
            challenge earns `coinAmount` RC Coins (paid on completion). Funded +
            reserved up front for `maxRewardedParticipants` completers.
            `maxRewardCoins` is derived from `coinAmount` (0 when unset).
          allOf:
            - $ref: '#/components/schemas/ParticipationRewardDto'
      required:
        - title
        - challengeType
        - startDate
        - endDate
        - targetValue
        - targetUnit
        - targetDescription
        - description
        - qualifyingSports
        - accessType
    UpdateChallengeDto:
      type: object
      properties:
        ownerOrganizerId:
          type: string
          description: >-
            Admin-only target organizer. Ignored for non-admin callers and
            validated server-side.
        desktopVideoUploadKey:
          type: string
          description: >-
            Temporary owned GCS object key returned by POST
            /v2/challenges/video-uploads for a desktop video uploaded directly
            by the browser.
        desktopVideoCrop:
          type: string
          description: >-
            JSON crop/trim settings for the required 16:9 desktop video
            alternative.
        promoVideoUploadKey:
          type: string
          description: >-
            Temporary owned GCS object key returned by POST
            /v2/challenges/video-uploads for a mobile video uploaded directly by
            the browser.
        removeDesktopVideo:
          type: boolean
          description: Remove the currently saved desktop video.
        promoVideoCrop:
          type: string
          description: >-
            JSON crop/trim settings for the required 4:5 mobile video
            alternative.
        removePromoVideo:
          type: boolean
          description: Remove the currently saved promotional video.
        title:
          type: string
          description: Title of the challenge
          maxLength: 256
          example: January Running Challenge
        challengeType:
          type: string
          description: Type of the challenge (collective or daily)
          enum: *ref_695
          example: collective
        startDate:
          format: date-time
          type: string
          description: Start date of the challenge (YYYY-MM-DD)
          example: '2025-01-01'
        endDate:
          format: date-time
          type: string
          description: End date of the challenge (YYYY-MM-DD)
          example: '2025-01-31'
        totalDays:
          type: number
          description: >-
            Total duration in days. Optional — the backend always computes the
            canonical value from startDate/endDate; if provided, it must match
            or the request is rejected. Frontend-supplied values are for UX
            display only, never trusted as-is.
          example: 30
        targetValue:
          type: number
          description: >-
            Target value of the challenge (total for COLLECTIVE, daily for
            DAILY). For DAILY challenges this is server-computed
            (dailyTargetValue × minActiveDays) and any client-supplied value is
            ignored.
          example: 5000
        dailyTargetValue:
          type: number
          description: Daily target value (required for DAILY challenges)
          example: 1000
        minActiveDays:
          type: number
          description: Minimum active days required to complete DAILY challenges
          example: 5
        dailyCompletionThreshold:
          type: number
          description: >-
            Percentage of dailyTargetValue required for a day to count as
            completed. This is a percentage, not a distance/steps amount
            (default 90).
          example: 90
        requireConsecutiveDays:
          type: boolean
          description: Whether daily challenges require consecutive days (default true)
          example: true
        targetUnit:
          type: string
          description: Target unit of the challenge (steps/km)
          enum: *ref_696
          example: steps
        targetDescription:
          type: string
          description: Target description of the challenge
          example: Complete to 5000 km in a month
        badgeDescription:
          type: string
          description: Description shown below the selected challenge badge
          example: Complete this challenge to earn your finisher badge.
        rewardCoinsInterval:
          type: number
          description: >-
            Legacy: activity interval at which coins are rewarded (in target
            unit). No longer used by any current UI.
          example: 10000
        rewardCoinsPerInterval:
          type: number
          description: >-
            Legacy: number of coins awarded per interval completion. No longer
            used by any current UI.
          example: 20
        rewardCoinsMultiplier:
          type: number
          description: >-
            Legacy: multiplier for reward coins. No longer used by any current
            UI.
          example: 1.5
        reward:
          type: string
          description: >-
            Legacy: free-text reward summary. No longer collected by any current
            UI.
          example: Digital badge, $100, Merchant Discount
        description:
          type: string
          description: Description of the challenge
          example: >-
            Fitgo partners with Brodks and challenges you to take part in a 5K.
            Find strength in every step you take, feel positive energy.
        qualifyingSports:
          description: Qualifying activities of the challenge
          example: *ref_697
          type: array
          items:
            type: string
        isActive:
          type: boolean
          description: Indicates if the challenge is active or not
          example: true
        clubId:
          type: string
          description: >-
            When set, the challenge is floated on behalf of this club instead of
            the calling organizer. The organizer must own the club. Vision §1 —
            clubs are first-class challenge creators.
          example: 123e4567-e89b-12d3-a456-426614174000
        sponsorId:
          type: string
          description: >-
            When set, the challenge is floated on behalf of this sponsor brand.
            The calling user must have an ACTIVE SponsorAccount for the brand.
            Vision §1 — sponsors are first-class challenge hosts.
          example: 123e4567-e89b-12d3-a456-426614174000
        proofRules:
          description: >-
            Activity verification rules for this challenge. Controls GPS,
            distance, route, photo proof, and device import requirements.
          allOf:
            - $ref: '#/components/schemas/ChallengeProofRulesDto'
        accessType:
          type: string
          description: Whether the challenge is free to join or requires an entry fee.
          enum: *ref_698
          example: free
          default: free
        paymentMethod:
          type: string
          description: >-
            Required when accessType=PAID. RC_COIN charges the RC wallet; MONEY
            routes through the existing payment gateway flow.
          enum: *ref_699
          example: money
        entryFeeCoins:
          type: number
          description: Entry fee in RC Coins. Required when paymentMethod=RC_COIN.
          example: 500
        leaveCutoffDaysBeforeStart:
          type: number
          description: >-
            Refund/leave window for PAID challenges: participants may leave and
            be refunded only until this many days before startDate. 0 (default)
            = allowed right up to the start date. Ignored for FREE challenges
            (always leavable, no refund).
          example: 0
        entryFee:
          type: number
          description: >-
            Entry fee in the challenge currency (INR). Required when
            paymentMethod=MONEY.
          example: 499
        badgeId:
          type: string
          description: >-
            ID of an existing ACTIVE Badge (from the admin-curated badge
            library) to award on challenge completion. Replaces the old
            per-challenge badge image upload. Leave unset and provide
            badgeRequestName/... to raise a draft badge request instead.
        prizeSlabs:
          description: >-
            Rank-wise prize configuration. Unlimited slabs; each rank or rank
            range may carry Cash, RC Coin, and/or Product prizes simultaneously.
            RC Coin prizes are reserved from the creator’s wallet immediately on
            save.
          type: array
          items:
            $ref: '#/components/schemas/PrizeSlabDto'
        participationReward:
          description: >-
            Inclusive participation reward — every athlete who COMPLETES the
            challenge earns `coinAmount` RC Coins (paid on completion). Funded +
            reserved up front for `maxRewardedParticipants` completers.
            `maxRewardCoins` is derived from `coinAmount` (0 when unset).
          allOf:
            - $ref: '#/components/schemas/ParticipationRewardDto'
        isFeatured:
          type: boolean
          description: Admin-only featured flag. Multipart string booleans are normalized.
    SubmitDirectProposalDto:
      type: object
      properties:
        targetType:
          type: string
          enum:
            - EVENT
            - CHALLENGE
          description: >-
            What is being pitched at. CLUB is not addressable this way — a club
            is not a dated competition with a leaderboard to put goodies on.
        targetId:
          type: string
          description: Id of the event or challenge. Must not have ended.
        proposedValue:
          type: number
          example: 25000
        currency:
          type: string
          example: INR
          default: INR
        message:
          type: string
          description: What the brand is offering, in its own words.
        placements:
          type: array
          items:
            type: object
        goodiesSummary:
          type: string
          maxLength: 2000
      required:
        - targetType
        - targetId
        - proposedValue
        - message
    UpdateActivityTrackingPreferencesDto:
      type: object
      properties: {}
    CreateSettingDto:
      type: object
      properties:
        clubDeactivationRefundGraceDays:
          type: number
          description: >-
            Days between Club deactivation and automatic paid-member refunds.
            Applies to future deactivations; active grace windows keep their
            snapshotted deadline.
          example: 15
          minimum: 1
          maximum: 90
        clubCreationTermsContent:
          type: string
          description: >-
            Platform-authored terms a Club owner must accept before creating a
            Club. Updating the content publishes a new version automatically.
        clubOwnershipTransferConsentDays:
          type: number
          description: Days User B has to accept a Club ownership-transfer request.
          minimum: 1
          maximum: 30
          default: 7
        platformFee:
          type: number
          description: Platform fee amount
          example: 2.5
          minimum: 0
        paymentGatewayFee:
          type: number
          description: Payment gateway fee amount
          example: 1.5
          minimum: 0
        platformFeeType:
          type: string
          description: Type of platform fee (PERCENTAGE or FIXED)
          enum: &ref_700
            - percentage
            - fixed
          example: percentage
        CGST:
          type: number
          description: Central Goods and Services Tax (CGST) percentage
          example: 9
          minimum: 0
        SGST:
          type: number
          description: State Goods and Services Tax (SGST) percentage
          example: 9
          minimum: 0
        UTGST:
          type: number
          description: Union Territory Goods and Services Tax (UTGST) percentage
          example: 9
          minimum: 0
        IGST:
          type: number
          description: Integrated Goods and Services Tax (IGST) percentage
          example: 18
          minimum: 0
        coinValueInFiat:
          type: number
          description: The real-life value of 1 coin in fiat currency (e.g. INR)
          example: 5
          minimum: 0
        trainingPlanNormalPrice:
          type: number
          description: '[DEPRECATED] Price for Normal training plan in INR'
          example: 9
          minimum: 0
          deprecated: true
        trainingPlanAdvancedPrice:
          type: number
          description: '[DEPRECATED] Price for Advanced training plan in INR'
          example: 15
          minimum: 0
          deprecated: true
        trainingPlanActivePrice:
          type: number
          description: Price for Active (Easy) training plan in INR (0 for free)
          example: 0
          minimum: 0
        trainingPlanAthletePrice:
          type: number
          description: Price for Athlete (Medium) training plan in INR
          example: 9
          minimum: 0
        trainingPlanGoatPrice:
          type: number
          description: Price for GOAT (Tough) training plan in INR (includes chatbot)
          example: 15
          minimum: 0
        trainingPlan2WeeksActivePrice:
          type: number
          description: Price for Active plan - 2 weeks duration (INR)
          example: 0
          minimum: 0
        trainingPlan2WeeksAthletePrice:
          type: number
          description: Price for Athlete plan - 2 weeks duration (INR)
          example: 9
          minimum: 0
        trainingPlan2WeeksGoatPrice:
          type: number
          description: Price for GOAT plan - 2 weeks duration (INR)
          example: 15
          minimum: 0
        trainingPlan4WeeksActivePrice:
          type: number
          description: Price for Active plan - 4 weeks duration (INR)
          example: 4
          minimum: 0
        trainingPlan4WeeksAthletePrice:
          type: number
          description: Price for Athlete plan - 4 weeks duration (INR)
          example: 19
          minimum: 0
        trainingPlan4WeeksGoatPrice:
          type: number
          description: Price for GOAT plan - 4 weeks duration (INR)
          example: 29
          minimum: 0
        trainingPlan8WeeksActivePrice:
          type: number
          description: Price for Active plan - 8 weeks duration (INR)
          example: 9
          minimum: 0
        trainingPlan8WeeksAthletePrice:
          type: number
          description: Price for Athlete plan - 8 weeks duration (INR)
          example: 39
          minimum: 0
        trainingPlan8WeeksGoatPrice:
          type: number
          description: Price for GOAT plan - 8 weeks duration (INR)
          example: 59
          minimum: 0
        trainingPlanMinDaysBeforeEvent:
          type: number
          description: Minimum days before event to be eligible for training plan
          example: 15
          minimum: 1
        cloudStorageGracePeriodDays:
          type: number
          description: Days after subscription expiry before cloud data deletion
          example: 3
          minimum: 1
        cloudStorageDataRestoreEnabled:
          type: boolean
          description: Allow organizers to restore data after soft-deletion
          example: true
        cloudStorageSettlementHours:
          type: number
          description: >-
            Hours after event completion before image earnings are settled to
            organizer
          example: 24
          minimum: 1
        challengeUpdateMode:
          type: string
          description: >-
            Challenge update mode: "single" updates only nearest-expiry
            challenge, "multiple" updates all eligible challenges
          enum: &ref_701
            - single
            - multiple
          example: multiple
        moderationWarningTier2RestrictedFeatures:
          description: RestrictableFeature keys applied at warning-ladder tier 2
          example: &ref_702
            - CREATE_CLUB_POST
          type: array
          items:
            type: string
        moderationWarningTier3SuspensionDays:
          type: number
          description: Suspension length (days) applied at warning-ladder tier 3
          example: 7
          minimum: 1
        moderationWarningTier4Permanent:
          type: boolean
          description: >-
            Whether warning-ladder tier 4 is a permanent ban (true) or another
            temporary suspension (false)
          example: true
        moderationFalseReportStrikeThreshold:
          type: number
          description: False-report strikes before reporting is temporarily disabled
          example: 3
          minimum: 1
        moderationFalseReportDisableDays:
          type: number
          description: Days reporting stays disabled once the strike threshold is hit
          example: 30
          minimum: 1
        moderationClubInvestigationWindowDays:
          type: number
          description: >-
            Rolling window (days) used for club auto-investigation report
            counting
          example: 30
          minimum: 1
        moderationClubInvestigationThresholdPercent:
          type: number
          description: >-
            Share of ACTIVE members (%) that must uniquely report a club within
            the window to auto-trigger UNDER_REVIEW
          example: 25
          minimum: 1
        clubTierCommissionPct:
          type: number
          description: >-
            Global default platform commission (%) taken on paid club tier
            subscriptions (CLUB stream). Per-club and per-tier overrides take
            precedence over this value.
          example: 3
          minimum: 0
          maximum: 30
        sponsorshipGstPct:
          type: number
          description: >-
            GST (%) added on top of the sponsorship amount and charged to the
            brand at checkout. Collected and remitted by Repeak; not passed
            through to the payee.
          example: 18
          minimum: 0
          maximum: 100
        sponsorshipCommissionPct:
          type: number
          description: >-
            Platform commission (%) retained from a sponsorship before settling
            the organizer or club (SPONSORSHIP stream).
          example: 15
          minimum: 0
          maximum: 100
        sponsorshipSettlementDelayHours:
          type: number
          description: >-
            Hours Repeak holds a sponsorship payment before its settlement
            matures to ELIGIBLE. Commercial promise is 48. Capped at 30 days.
          example: 48
          minimum: 0
          maximum: 720
      required:
        - platformFee
        - paymentGatewayFee
    UpdateSettingDto:
      type: object
      properties:
        clubDeactivationRefundGraceDays:
          type: number
          description: >-
            Days between Club deactivation and automatic paid-member refunds.
            Applies to future deactivations; active grace windows keep their
            snapshotted deadline.
          example: 15
          minimum: 1
          maximum: 90
        clubCreationTermsContent:
          type: string
          description: >-
            Platform-authored terms a Club owner must accept before creating a
            Club. Updating the content publishes a new version automatically.
        clubOwnershipTransferConsentDays:
          type: number
          description: Days User B has to accept a Club ownership-transfer request.
          minimum: 1
          maximum: 30
          default: 7
        platformFee:
          type: number
          description: Platform fee amount
          example: 2.5
          minimum: 0
        paymentGatewayFee:
          type: number
          description: Payment gateway fee amount
          example: 1.5
          minimum: 0
        platformFeeType:
          type: string
          description: Type of platform fee (PERCENTAGE or FIXED)
          enum: *ref_700
          example: percentage
        CGST:
          type: number
          description: Central Goods and Services Tax (CGST) percentage
          example: 9
          minimum: 0
        SGST:
          type: number
          description: State Goods and Services Tax (SGST) percentage
          example: 9
          minimum: 0
        UTGST:
          type: number
          description: Union Territory Goods and Services Tax (UTGST) percentage
          example: 9
          minimum: 0
        IGST:
          type: number
          description: Integrated Goods and Services Tax (IGST) percentage
          example: 18
          minimum: 0
        coinValueInFiat:
          type: number
          description: The real-life value of 1 coin in fiat currency (e.g. INR)
          example: 5
          minimum: 0
        trainingPlanNormalPrice:
          type: number
          description: '[DEPRECATED] Price for Normal training plan in INR'
          example: 9
          minimum: 0
          deprecated: true
        trainingPlanAdvancedPrice:
          type: number
          description: '[DEPRECATED] Price for Advanced training plan in INR'
          example: 15
          minimum: 0
          deprecated: true
        trainingPlanActivePrice:
          type: number
          description: Price for Active (Easy) training plan in INR (0 for free)
          example: 0
          minimum: 0
        trainingPlanAthletePrice:
          type: number
          description: Price for Athlete (Medium) training plan in INR
          example: 9
          minimum: 0
        trainingPlanGoatPrice:
          type: number
          description: Price for GOAT (Tough) training plan in INR (includes chatbot)
          example: 15
          minimum: 0
        trainingPlan2WeeksActivePrice:
          type: number
          description: Price for Active plan - 2 weeks duration (INR)
          example: 0
          minimum: 0
        trainingPlan2WeeksAthletePrice:
          type: number
          description: Price for Athlete plan - 2 weeks duration (INR)
          example: 9
          minimum: 0
        trainingPlan2WeeksGoatPrice:
          type: number
          description: Price for GOAT plan - 2 weeks duration (INR)
          example: 15
          minimum: 0
        trainingPlan4WeeksActivePrice:
          type: number
          description: Price for Active plan - 4 weeks duration (INR)
          example: 4
          minimum: 0
        trainingPlan4WeeksAthletePrice:
          type: number
          description: Price for Athlete plan - 4 weeks duration (INR)
          example: 19
          minimum: 0
        trainingPlan4WeeksGoatPrice:
          type: number
          description: Price for GOAT plan - 4 weeks duration (INR)
          example: 29
          minimum: 0
        trainingPlan8WeeksActivePrice:
          type: number
          description: Price for Active plan - 8 weeks duration (INR)
          example: 9
          minimum: 0
        trainingPlan8WeeksAthletePrice:
          type: number
          description: Price for Athlete plan - 8 weeks duration (INR)
          example: 39
          minimum: 0
        trainingPlan8WeeksGoatPrice:
          type: number
          description: Price for GOAT plan - 8 weeks duration (INR)
          example: 59
          minimum: 0
        trainingPlanMinDaysBeforeEvent:
          type: number
          description: Minimum days before event to be eligible for training plan
          example: 15
          minimum: 1
        cloudStorageGracePeriodDays:
          type: number
          description: Days after subscription expiry before cloud data deletion
          example: 3
          minimum: 1
        cloudStorageDataRestoreEnabled:
          type: boolean
          description: Allow organizers to restore data after soft-deletion
          example: true
        cloudStorageSettlementHours:
          type: number
          description: >-
            Hours after event completion before image earnings are settled to
            organizer
          example: 24
          minimum: 1
        challengeUpdateMode:
          type: string
          description: >-
            Challenge update mode: "single" updates only nearest-expiry
            challenge, "multiple" updates all eligible challenges
          enum: *ref_701
          example: multiple
        moderationWarningTier2RestrictedFeatures:
          description: RestrictableFeature keys applied at warning-ladder tier 2
          example: *ref_702
          type: array
          items:
            type: string
        moderationWarningTier3SuspensionDays:
          type: number
          description: Suspension length (days) applied at warning-ladder tier 3
          example: 7
          minimum: 1
        moderationWarningTier4Permanent:
          type: boolean
          description: >-
            Whether warning-ladder tier 4 is a permanent ban (true) or another
            temporary suspension (false)
          example: true
        moderationFalseReportStrikeThreshold:
          type: number
          description: False-report strikes before reporting is temporarily disabled
          example: 3
          minimum: 1
        moderationFalseReportDisableDays:
          type: number
          description: Days reporting stays disabled once the strike threshold is hit
          example: 30
          minimum: 1
        moderationClubInvestigationWindowDays:
          type: number
          description: >-
            Rolling window (days) used for club auto-investigation report
            counting
          example: 30
          minimum: 1
        moderationClubInvestigationThresholdPercent:
          type: number
          description: >-
            Share of ACTIVE members (%) that must uniquely report a club within
            the window to auto-trigger UNDER_REVIEW
          example: 25
          minimum: 1
        clubTierCommissionPct:
          type: number
          description: >-
            Global default platform commission (%) taken on paid club tier
            subscriptions (CLUB stream). Per-club and per-tier overrides take
            precedence over this value.
          example: 3
          minimum: 0
          maximum: 30
        sponsorshipGstPct:
          type: number
          description: >-
            GST (%) added on top of the sponsorship amount and charged to the
            brand at checkout. Collected and remitted by Repeak; not passed
            through to the payee.
          example: 18
          minimum: 0
          maximum: 100
        sponsorshipCommissionPct:
          type: number
          description: >-
            Platform commission (%) retained from a sponsorship before settling
            the organizer or club (SPONSORSHIP stream).
          example: 15
          minimum: 0
          maximum: 100
        sponsorshipSettlementDelayHours:
          type: number
          description: >-
            Hours Repeak holds a sponsorship payment before its settlement
            matures to ELIGIBLE. Commercial promise is 48. Capped at 30 days.
          example: 48
          minimum: 0
          maximum: 720
    SettlementDto:
      type: object
      properties:
        id:
          type: string
          description: Settlement ID
        settlementType:
          type: string
          description: Settlement type
          enum:
            - event
            - challenge
            - photo
            - club
            - hybrid_race
            - sponsorship
            - training_program
            - brand_challenge
        settlementStatus:
          type: string
          description: Settlement status
          enum:
            - pending
            - eligible
            - processing
            - completed
            - failed
            - on_hold
        grossAmount:
          type: number
          description: Gross amount (total revenue)
        ticketRevenue:
          type: number
          description: Revenue from ticket sales
        addOnsRevenue:
          type: number
          description: Revenue from add-ons
        platformFee:
          type: number
          description: Platform fee
        gatewayFee:
          type: number
          description: Gateway fee
        gstAmount:
          type: number
          description: GST amount
        platformFeeGst:
          type: number
          description: GST on platform fee
        netAmount:
          type: number
          description: Net amount to be paid
        participantsCount:
          type: number
          description: Number of participants
        successfulPaymentsCount:
          type: number
          description: Number of successful payments
        completedAt:
          format: date-time
          type: string
          description: Event/challenge completion date
        eligibleAt:
          format: date-time
          type: string
          description: Date when settlement becomes eligible
        processedAt:
          format: date-time
          type: string
          description: Date when payout was processed
        transactionId:
          type: string
          description: Bank transaction ID
        transactionDetails:
          type: string
          description: Transaction details
        failureReason:
          type: string
          description: Failure reason
        holdReason:
          type: string
          description: Hold reason
        remarks:
          type: string
          description: Admin remarks
        commissionPercentage:
          type: number
          description: Commission percentage used
        kycStatus:
          type: string
          description: KYC status at settlement time
          enum:
            - pending
            - approved
            - rejected
            - suspended
        bankDetailsAvailable:
          type: boolean
          description: Bank details available at settlement time
        settlementBlockedReason:
          type: string
          description: Reason if settlement is blocked
        isProcessable:
          type: boolean
          description: Is settlement processable
        settlementMessage:
          type: string
          description: Settlement message for organizer
        createdAt:
          format: date-time
          type: string
          description: Created at
        event:
          type: object
          description: Event details
        challenge:
          type: object
          description: Challenge details
        organizer:
          type: object
          description: Organizer details
      required:
        - id
        - settlementType
        - settlementStatus
        - grossAmount
        - ticketRevenue
        - addOnsRevenue
        - platformFee
        - gatewayFee
        - gstAmount
        - platformFeeGst
        - netAmount
        - participantsCount
        - successfulPaymentsCount
        - commissionPercentage
        - bankDetailsAvailable
        - isProcessable
        - createdAt
    SettlementSummaryDto:
      type: object
      properties:
        totalEarnings:
          type: number
          description: Total earnings (gross amount)
        ticketEarnings:
          type: number
          description: Earnings from ticket sales
        addOnsEarnings:
          type: number
          description: Earnings from add-ons sales
        platformFee:
          type: number
          description: Platform fee deduction
        gstOnPlatformFee:
          type: number
          description: GST on platform fee (18%)
        totalDeductions:
          type: number
          description: Total deductions
        netSettlementAmount:
          type: number
          description: Net settlement amount to be paid
        totalParticipants:
          type: number
          description: Total number of participants
        totalPayments:
          type: number
          description: Total number of successful payments
      required:
        - totalEarnings
        - ticketEarnings
        - addOnsEarnings
        - platformFee
        - gstOnPlatformFee
        - totalDeductions
        - netSettlementAmount
        - totalParticipants
        - totalPayments
    AddOnBreakdownDto:
      type: object
      properties:
        name:
          type: string
          description: Add-on name
        quantity:
          type: number
          description: Quantity purchased
        unitPrice:
          type: number
          description: Unit price
        totalPrice:
          type: number
          description: Total price
      required:
        - name
        - quantity
        - unitPrice
        - totalPrice
    TicketBreakdownDto:
      type: object
      properties:
        ticketName:
          type: string
          description: Ticket name
        ticketPrice:
          type: number
          description: Ticket price
        participantName:
          type: string
          description: Participant name
      required:
        - ticketName
        - ticketPrice
    SettlementPaymentDetailDto:
      type: object
      properties:
        id:
          type: string
          description: Payment detail ID
        userId:
          type: string
          description: User ID
        userName:
          type: string
          description: User name
        userPhone:
          type: string
          description: User phone number
        ticketCount:
          type: number
          description: Number of tickets
        ticketAmount:
          type: number
          description: Ticket amount
        addOnsCount:
          type: number
          description: Number of add-ons
        addOnsAmount:
          type: number
          description: Add-ons amount
        totalAmount:
          type: number
          description: Total amount paid
        paymentId:
          type: string
          description: Payment reference ID
        paymentDate:
          format: date-time
          type: string
          description: Payment date
        addOnsBreakdown:
          description: Add-ons breakdown
          type: array
          items:
            $ref: '#/components/schemas/AddOnBreakdownDto'
        ticketsBreakdown:
          description: Tickets breakdown
          type: array
          items:
            $ref: '#/components/schemas/TicketBreakdownDto'
      required:
        - id
        - userId
        - userName
        - ticketCount
        - ticketAmount
        - addOnsCount
        - addOnsAmount
        - totalAmount
    KycStatusDto:
      type: object
      properties:
        isKycApproved:
          type: boolean
          description: Is KYC approved
        isBankDetailsAvailable:
          type: boolean
          description: Are bank details available
        canProcess:
          type: boolean
          description: Can the settlement be processed
        blockedReason:
          type: string
          description: Reason if settlement is blocked
        message:
          type: string
          description: Status message for organizer
      required:
        - isKycApproved
        - isBankDetailsAvailable
        - canProcess
        - message
    SettlementDetailResponseDto:
      type: object
      properties:
        settlement:
          description: Settlement data
          allOf:
            - $ref: '#/components/schemas/SettlementDto'
        summary:
          description: Settlement summary
          allOf:
            - $ref: '#/components/schemas/SettlementSummaryDto'
        paymentsList:
          description: List of payment details per user
          type: array
          items:
            $ref: '#/components/schemas/SettlementPaymentDetailDto'
        kycStatus:
          description: KYC status
          allOf:
            - $ref: '#/components/schemas/KycStatusDto'
      required:
        - settlement
        - summary
        - paymentsList
        - kycStatus
    UpdateSettlementDto:
      type: object
      properties:
        settlementStatus:
          type: string
          description: Settlement status
          enum:
            - pending
            - eligible
            - processing
            - completed
            - failed
            - on_hold
        transactionId:
          type: string
          description: Transaction ID from bank transfer
        transactionDetails:
          type: string
          description: Transaction details (JSON string)
        failureReason:
          type: string
          description: Reason for failure (if status is FAILED)
        holdReason:
          type: string
          description: Reason for hold (if status is ON_HOLD)
        remarks:
          type: string
          description: Admin remarks/notes
    ProcessSettlementDto:
      type: object
      properties:
        transactionId:
          type: string
          description: Transaction ID from bank transfer
          example: TXN123456789
        transactionDetails:
          type: string
          description: Transaction details (additional info about the transfer)
          example: Bank transfer via NEFT
      required:
        - transactionId
    HoldSettlementDto:
      type: object
      properties:
        holdReason:
          type: string
          description: Reason for putting settlement on hold
          example: Pending KYC verification
      required:
        - holdReason
    BaselineDriftDto:
      type: object
      properties:
        confirm:
          type: boolean
          example: true
        expectedCount:
          type: number
          example: 42
          minimum: 0
      required:
        - confirm
        - expectedCount
    AcceptDriftDto:
      type: object
      properties:
        reason:
          type: string
          description: Optional human-readable reason
    CreateClubOrganizerAccountDto:
      type: object
      properties:
        club:
          $ref: '#/components/schemas/CreateClubDto'
        organizer:
          $ref: '#/components/schemas/CreateOrganizerIfNotExistsDto'
      required:
        - club
        - organizer
    RepairClubOrganizerAccountDto:
      type: object
      properties:
        sourceType:
          type: string
          enum:
            - CLUB
            - ORGANIZER
        sourceId:
          type: string
          format: uuid
      required:
        - sourceType
        - sourceId
    AIConfigResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Configuration ID
        feature:
          type: string
          enum:
            - training_plan
            - chatbot
            - plan_adjustment
          description: AI feature type
        primaryProvider:
          type: string
          enum:
            - openai
            - gemini
          description: Primary AI provider
        fallbackProvider:
          type: string
          enum:
            - openai
            - gemini
          description: Fallback AI provider
        useFallback:
          type: boolean
          description: Whether fallback is enabled
        modelName:
          type: string
          description: Model name
        temperature:
          type: number
          description: Temperature setting
        maxTokens:
          type: number
          description: Max tokens
        description:
          type: string
          description: Configuration description
        additionalConfig:
          type: object
          description: Additional config
        createdAt:
          format: date-time
          type: string
          description: Created at
        updatedAt:
          format: date-time
          type: string
          description: Updated at
      required:
        - id
        - feature
        - primaryProvider
        - useFallback
        - temperature
        - createdAt
        - updatedAt
    UpdateAIConfigDto:
      type: object
      properties:
        primaryProvider:
          type: string
          enum:
            - openai
            - gemini
          description: Primary AI provider to use
          example: openai
        fallbackProvider:
          type: string
          enum:
            - openai
            - gemini
          description: Fallback AI provider if primary fails
          example: gemini
        useFallback:
          type: boolean
          description: Whether to use fallback provider on failure
          example: true
        modelName:
          type: string
          description: Specific model name to use (e.g., gpt-4o, gemini-1.5-pro)
          example: gpt-4o
        temperature:
          type: number
          description: Temperature for AI responses (0.0 - 1.0)
          example: 0.7
        maxTokens:
          type: number
          description: Maximum tokens for response
          example: 8192
        description:
          type: string
          description: Description of this configuration
          example: Use OpenAI for training plan generation
        additionalConfig:
          type: object
          description: Additional configuration options
          example:
            responseFormat: json
      required:
        - primaryProvider
    CreateChallengePromoStoryDto:
      type: object
      properties:
        imageUrl:
          type: string
          description: Public URL of the challenge cover / poster image.
          example: https://assets.repeak.app/challenges/banner.jpg
        ctaUrl:
          type: string
          description: >-
            Deep-link CTA URL — typically the athlete-app challenge page. Shown
            as a tap-through on the story card.
          example: >-
            https://app.repeak.app/challenges/019ed50b-0b21-285b-ef28-db5c616c8c37
        caption:
          type: string
          description: >-
            Short caption rendered on the story card (max 500 chars). Defaults
            to the challenge title if omitted.
          example: Join 100 Steps Distance Month and win!
        ttlHours:
          type: number
          description: >-
            How long (hours) this promo story stays live. Defaults to 24 h; max
            72 h.
          default: 24
          minimum: 1
          maximum: 72
      required:
        - imageUrl
    AcceptChallengeGoodieDto:
      type: object
      properties:
        rankStart:
          type: number
          example: 1
        rankEnd:
          type: number
          example: 1
    RejectChallengeGoodieDto:
      type: object
      properties:
        reason:
          type: string
          example: Rank 1 is already sponsored
    ProposeChallengeGoodieDto:
      type: object
      properties:
        rankStart:
          type: number
          example: 1
        rankEnd:
          type: number
          example: 3
        goodieName:
          type: string
          example: Branded hydration pack
        goodieDescription:
          type: string
        imageUrl:
          type: string
          description: Goodie image URL.
        quantity:
          type: number
          example: 1
      required:
        - goodieName
    CreateTicketTypeDto:
      type: object
      properties:
        title:
          type: string
          description: The title of the ticket type
          example: VIP Pass
          maxLength: 255
        description:
          type: string
          description: The description of the ticket type
          example: Access to VIP area with complimentary drinks
        isActive:
          type: boolean
          description: Whether the ticket type is active
          example: true
          default: true
      required:
        - title
    UpdateTicketTypeDto:
      type: object
      properties: {}
    CreateTicketTemplateDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the ticket template
        description:
          type: string
          description: Description of the ticket template
        type:
          type: string
          enum:
            - free
            - paid
            - donation
          default: paid
          description: Type of ticket
        minAge:
          type: number
          description: Minimum age required for this ticket
          minimum: 0
        maxAge:
          type: number
          description: Maximum age allowed for this ticket
          minimum: 0
        minPerBooking:
          type: number
          description: Minimum tickets per booking
          default: 1
        maxPerBooking:
          type: number
          description: Maximum tickets per booking
          default: 1
        isActive:
          type: boolean
          description: Is ticket template active?
          default: true
      required:
        - name
        - type
        - minPerBooking
        - maxPerBooking
    UpdateTicketTemplateDto:
      type: object
      properties: {}
    CreateFaqDto:
      type: object
      properties:
        question:
          type: string
          description: The question
          example: What is the event start time?
        answer:
          type: string
          description: The answer
          example: The event starts at 9 AM.
        isActive:
          type: boolean
          description: Whether the FAQ is active
          example: true
      required:
        - question
        - answer
    UpdateFaqDto:
      type: object
      properties: {}
    CreateTermsAndConditionDto:
      type: object
      properties:
        content:
          type: string
          description: Terms and Conditions content
          example: All participants must...
        isActive:
          type: boolean
          description: Is active
          example: true
      required:
        - content
    UpdateTermsAndConditionDto:
      type: object
      properties: {}
    CreatePrivacyPolicyDto:
      type: object
      properties:
        content:
          type: string
          description: Privacy Policy content
          example: Your data will be protected...
        isActive:
          type: boolean
          description: Is active
          example: true
      required:
        - content
    UpdatePrivacyPolicyDto:
      type: object
      properties: {}
    CrossEventBulkNotifyDto:
      type: object
      properties: {}
    CreatePodcastDto:
      type: object
      properties:
        title:
          type: string
          example: Tech Talks
          description: Title of the podcast
        description:
          type: string
          example: Discussion about the latest tech trends
          description: Podcast description
        speaker:
          type: string
          example: John Doe
          description: Speaker of the podcast
        url:
          type: string
          example: https://example.com/podcast.mp3
          description: Podcast URL
        isLive:
          type: boolean
          example: false
          description: Is the podcast live?
          default: false
        scheduleTime:
          format: date-time
          type: string
          example: '2025-03-08T12:00:00Z'
          description: Scheduled time for the podcast
        isActive:
          type: boolean
          example: true
          description: Is the podcast active?
          default: true
      required:
        - title
        - speaker
        - isLive
        - isActive
    UpdatePodcastDto:
      type: object
      properties:
        title:
          type: string
          example: Tech Talks
          description: Title of the podcast
        description:
          type: string
          example: Discussion about the latest tech trends
          description: Podcast description
        speaker:
          type: string
          example: John Doe
          description: Speaker of the podcast
        url:
          type: string
          example: https://example.com/podcast.mp3
          description: Podcast URL
        isLive:
          type: boolean
          example: false
          description: Is the podcast live?
          default: false
        scheduleTime:
          format: date-time
          type: string
          example: '2025-03-08T12:00:00Z'
          description: Scheduled time for the podcast
        isActive:
          type: boolean
          example: true
          description: Is the podcast active?
          default: true
    CreateChallengeTemplateDto:
      type: object
      properties:
        name:
          type: string
          description: Template name shown in the picker.
        description:
          type: string
          description: Optional short description.
        config:
          type: object
          description: >-
            Reusable challenge config snapshot (title/type/target/reward/etc.).
            Applied client-side on the create form.
          additionalProperties: true
      required:
        - name
        - config
    FormFieldCreateDto:
      type: object
      properties:
        label:
          type: string
          description: Label for UI display
        type:
          type: string
          description: Input type
          enum:
            - text
            - number
            - email
            - select
            - multi_select
            - radio
            - checkbox
            - date
            - file
            - textarea
            - password
            - url
            - phone
        options:
          description: Options for select, radio, etc.
          type: array
          items:
            type: string
        required:
          type: boolean
          description: Is this field required?
        multiple:
          type: boolean
          description: Allow multiple values?
        defaultValue:
          type: string
          description: Default value if not filled
        placeholder:
          type: string
          description: Placeholder shown in UI
        helpText:
          type: string
          description: Help/hint text for UI
        maxLength:
          type: number
          description: Input max length for strings
        min:
          type: number
          description: Min value for number/date
        max:
          type: number
          description: Max value for number/date
        step:
          type: number
          description: Step for number/date fields
        maxSizeMB:
          type: number
          description: Max upload size (MB) for files
        accept:
          description: Accepted MIME types (for files)
          type: array
          items:
            type: string
        readOnly:
          type: boolean
          description: Make field readonly
        disabled:
          type: boolean
          description: Disable field in UI
        validation:
          type: object
          description: Validation rules
      required:
        - label
        - type
    ReviewApprovalDto:
      type: object
      properties:
        approvalStatus:
          type: string
          description: Approval status
          enum:
            - approved
            - rejected
        reviewReason:
          type: string
          description: Reason for approval/rejection (required for rejection)
      required:
        - approvalStatus
    ReviewKycDto:
      type: object
      properties:
        approvalStatus:
          type: string
          description: Approval status
          enum:
            - approved
            - rejected
        reviewReason:
          type: string
          description: Reason for approval/rejection (required for rejection)
      required:
        - approvalStatus
    CreateDeclarationFormTemplateDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the declaration form template
          example: Standard Declaration Form
        description:
          type: string
          description: Description of the template
          example: Declaration form for organizers without GST registration
        htmlTemplate:
          type: string
          description: >-
            HTML template with variables. Use {{variable_name}} format for
            placeholders.
          example: >-
            <h1>Declaration Form</h1><p>I, {{organizer_name}}, declare
            that...</p>
        requiredFields:
          description: List of required fields that organizer must fill before downloading
          example: &ref_703
            - pan_number
            - address
            - business_registration_number
          type: array
          items:
            type: string
        headerLogo:
          type: string
          description: URL of logo to display in header
          example: https://example.com/logo.png
        footerText:
          type: string
          description: Text to display in footer
          example: RaceAbove - Your Sports Event Partner
        isActive:
          type: boolean
          description: Whether this template is active
          example: true
      required:
        - name
        - htmlTemplate
        - requiredFields
    UpdateDeclarationFormTemplateDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the declaration form template
          example: Standard Declaration Form
        description:
          type: string
          description: Description of the template
          example: Declaration form for organizers without GST registration
        htmlTemplate:
          type: string
          description: >-
            HTML template with variables. Use {{variable_name}} format for
            placeholders.
          example: >-
            <h1>Declaration Form</h1><p>I, {{organizer_name}}, declare
            that...</p>
        requiredFields:
          description: List of required fields that organizer must fill before downloading
          example: *ref_703
          type: array
          items:
            type: string
        headerLogo:
          type: string
          description: URL of logo to display in header
          example: https://example.com/logo.png
        footerText:
          type: string
          description: Text to display in footer
          example: RaceAbove - Your Sports Event Partner
        isActive:
          type: boolean
          description: Whether this template is active
          example: true
    UpdatePayoutScheduleDto:
      type: object
      properties:
        schedule:
          type: string
          enum:
            - WEEKLY
            - BIWEEKLY
            - MONTHLY
            - CUSTOM
          description: >-
            New payout cadence. CUSTOM signals a non-standard cadence — the
            settlement scheduler skips CUSTOM organizers and ops handles them
            via the manual-process path (PRD §42.4).
      required:
        - schedule
    RespondToChargebackDto:
      type: object
      properties:
        responseText:
          type: string
          description: >-
            Free-text response narrative. Max 5000 chars; min 10 when
            submitting.
          minLength: 0
          maxLength: 5000
        evidenceUrls:
          description: External URLs pointing at evidence artifacts. Max 10.
          type: array
          items:
            type: string
        submit:
          type: boolean
          description: Submit (DEFENDED) vs save-as-draft.
          default: false
      required:
        - responseText
    PostThreadMessageDto:
      type: object
      properties: {}
    CreateSportDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the sport
          maxLength: 100
          example: Running
        isActive:
          type: boolean
          description: Indicates if the sport is active or not
          example: true
          nullable: true
      required:
        - name
    ReorderSportTaxonomyDto:
      type: object
      properties:
        ids:
          description: Complete ordered sibling IDs
          type: array
          items:
            type: string
      required:
        - ids
    CreateSportTopicDto:
      type: object
      properties:
        name:
          type: string
          example: Trail running
          maxLength: 80
        description:
          type: string
          maxLength: 180
        orderIndex:
          type: number
          default: 0
          minimum: 0
          maximum: 999
        isActive:
          type: boolean
          default: true
      required:
        - name
    UpdateSportTopicDto:
      type: object
      properties:
        name:
          type: string
          example: Trail running
          maxLength: 80
        description:
          type: string
          maxLength: 180
        orderIndex:
          type: number
          default: 0
          minimum: 0
          maximum: 999
        isActive:
          type: boolean
          default: true
    CreateSportSubtopicDto:
      type: object
      properties:
        name:
          type: string
          example: 5K
          maxLength: 80
        description:
          type: string
          maxLength: 180
        orderIndex:
          type: number
          default: 0
          minimum: 0
          maximum: 999
        isActive:
          type: boolean
          default: true
      required:
        - name
    UpdateSportSubtopicDto:
      type: object
      properties:
        name:
          type: string
          example: 5K
          maxLength: 80
        description:
          type: string
          maxLength: 180
        orderIndex:
          type: number
          default: 0
          minimum: 0
          maximum: 999
        isActive:
          type: boolean
          default: true
    UpdateSportDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the sport
          maxLength: 100
          example: Running
        isActive:
          type: boolean
          description: Indicates if the sport is active or not
          example: true
          nullable: true
    CreateGearTypeDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the gear type
          example: Bikes
        isActive:
          type: boolean
          description: Indicates if the gear type is active or not
          example: true
      required:
        - name
    UpdateGearTypeDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the gear type
          example: Bikes
        isActive:
          type: boolean
          description: Indicates if the gear type is active or not
          example: true
    CreateProductDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the product
          example: Premium Popcorn
          maxLength: 255
        description:
          type: string
          description: Description of the product
          example: Delicious buttered popcorn with extra seasoning
          maxLength: 255
        price:
          type: number
          description: Price of the product
          example: 150.5
        categoryId:
          type: string
          description: Category ID that this product belongs to
          example: 123e4567-e89b-12d3-a456-426614174000
        isActive:
          type: boolean
          description: Whether the product is active
          example: true
          default: true
      required:
        - name
        - description
        - price
        - categoryId
    UpdateProductDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the product
          example: Premium Popcorn
          maxLength: 255
        description:
          type: string
          description: Description of the product
          example: Delicious buttered popcorn with extra seasoning
          maxLength: 255
        price:
          type: number
          description: Price of the product
          example: 150.5
        categoryId:
          type: string
          description: Category ID that this product belongs to
          example: 123e4567-e89b-12d3-a456-426614174000
        isActive:
          type: boolean
          description: Whether the product is active
          example: true
          default: true
    CreateProductCategoryDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the product category
          example: Food & Beverages
          maxLength: 255
        description:
          type: string
          description: Description of the product category
          example: Food and beverage items for the event
          maxLength: 500
        isActive:
          type: boolean
          description: Whether the category is active
          example: true
          default: true
      required:
        - name
    UpdateProductCategoryDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the product category
          example: Food & Beverages
          maxLength: 255
        description:
          type: string
          description: Description of the product category
          example: Food and beverage items for the event
          maxLength: 500
        isActive:
          type: boolean
          description: Whether the category is active
          example: true
          default: true
    CreateFormFieldDto:
      type: object
      properties:
        label:
          type: string
          description: Label for UI display
        type:
          type: string
          description: Input type
          enum:
            - text
            - number
            - email
            - select
            - multi_select
            - radio
            - checkbox
            - date
            - file
            - textarea
            - password
            - url
            - phone
        options:
          description: Options for select, radio, etc.
          type: array
          items:
            type: string
        required:
          type: boolean
          description: Is this field required?
        multiple:
          type: boolean
          description: Allow multiple values?
        defaultValue:
          type: string
          description: Default value if not filled
        placeholder:
          type: string
          description: Placeholder shown in UI
        helpText:
          type: string
          description: Help/hint text for UI
        maxLength:
          type: number
          description: Input max length for strings
        min:
          type: number
          description: Min value for number/date
        max:
          type: number
          description: Max value for number/date
        step:
          type: number
          description: Step for number/date fields
        maxSizeMB:
          type: number
          description: Max upload size (MB) for files
        accept:
          description: Accepted MIME types (for files)
          type: array
          items:
            type: string
        readOnly:
          type: boolean
          description: Make field readonly
        disabled:
          type: boolean
          description: Disable field in UI
        validation:
          type: object
          description: Validation rules
      required:
        - label
        - type
    UpdateFormFieldDto:
      type: object
      properties: {}
    CreateEventCategoriesDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the event category
        description:
          type: string
          description: Optional description
        isActive:
          type: boolean
          description: Is category active?
      required:
        - name
    UpdateEventCategoriesDto:
      type: object
      properties: {}
    CreateFrequentlyAskedQuestionDto:
      type: object
      properties:
        question:
          type: string
          description: The question
          example: What is the event start time?
        answer:
          type: string
          description: The answer
          example: The event starts at 9 AM.
      required:
        - question
        - answer
    UpdateFrequentlyAskedQuestionDto:
      type: object
      properties:
        question:
          type: string
          description: The question
          example: What is the event start time?
        answer:
          type: string
          description: The answer
          example: The event starts at 9 AM.
    TrainingPlanOverviewStatsDto:
      type: object
      properties:
        totalPlans:
          type: number
          description: Total number of training plans generated
          example: 1500
        freePlans:
          type: number
          description: Total number of free plans
          example: 1000
        paidPlans:
          type: number
          description: Total number of paid plans
          example: 500
        totalRevenue:
          type: number
          description: Total revenue from training plans in INR
          example: 25000
        activePlans:
          type: number
          description: Active training plans count
          example: 300
        completedPlans:
          type: number
          description: Completed training plans count
          example: 1100
        cancelledPlans:
          type: number
          description: Cancelled training plans count
          example: 100
      required:
        - totalPlans
        - freePlans
        - paidPlans
        - totalRevenue
        - activePlans
        - completedPlans
        - cancelledPlans
    ProgramLevelStatsDto:
      type: object
      properties:
        programLevel:
          type: string
          description: Program level
          enum:
            - active
            - athlete
            - goat
          example: athlete
        count:
          type: number
          description: Number of plans at this level
          example: 400
        revenue:
          type: number
          description: Revenue from this program level in INR
          example: 7600
        percentage:
          type: number
          description: Percentage of total plans
          example: 26.67
      required:
        - programLevel
        - count
        - revenue
        - percentage
    SportTypeStatsDto:
      type: object
      properties:
        sportType:
          type: string
          description: Sport type
          enum:
            - running
            - cycling
            - swimming
            - triathlon
            - hiking_trekking
          example: running
        count:
          type: number
          description: Number of plans for this sport
          example: 1200
        revenue:
          type: number
          description: Revenue from this sport type in INR
          example: 20000
        percentage:
          type: number
          description: Percentage of total plans
          example: 80
      required:
        - sportType
        - count
        - revenue
        - percentage
    DurationStatsDto:
      type: object
      properties:
        duration:
          type: string
          description: Plan duration
          enum:
            - 2_weeks
            - 4_weeks
            - 8_weeks
          example: 4_weeks
        count:
          type: number
          description: Number of plans with this duration
          example: 800
        revenue:
          type: number
          description: Revenue from this duration in INR
          example: 15200
        percentage:
          type: number
          description: Percentage of total plans
          example: 53.33
      required:
        - duration
        - count
        - revenue
        - percentage
    MonthlyRevenueDto:
      type: object
      properties:
        month:
          type: string
          description: Month (YYYY-MM format)
          example: 2026-01
        plansCount:
          type: number
          description: Total plans generated in this month
          example: 150
        revenue:
          type: number
          description: Revenue for this month in INR
          example: 2850
        freePlans:
          type: number
          description: Free plans count
          example: 100
        paidPlans:
          type: number
          description: Paid plans count
          example: 50
      required:
        - month
        - plansCount
        - revenue
        - freePlans
        - paidPlans
    TrainingPlanStatsResponseDto:
      type: object
      properties:
        overview:
          description: Overview statistics
          allOf:
            - $ref: '#/components/schemas/TrainingPlanOverviewStatsDto'
        byProgramLevel:
          description: Stats by program level
          type: array
          items:
            $ref: '#/components/schemas/ProgramLevelStatsDto'
        bySportType:
          description: Stats by sport type
          type: array
          items:
            $ref: '#/components/schemas/SportTypeStatsDto'
        byDuration:
          description: Stats by duration
          type: array
          items:
            $ref: '#/components/schemas/DurationStatsDto'
        monthlyRevenue:
          description: Monthly revenue breakdown
          type: array
          items:
            $ref: '#/components/schemas/MonthlyRevenueDto'
      required:
        - overview
        - byProgramLevel
        - bySportType
        - byDuration
        - monthlyRevenue
    UserTrainingPlanStatsDto:
      type: object
      properties:
        userId:
          type: string
          description: User ID
          example: 01HQXYZ123456789
        userName:
          type: string
          description: User name
          example: John Doe
        phoneNumber:
          type: string
          description: User phone number
          example: '+919876543210'
        email:
          type: string
          description: User email
          example: john@example.com
        totalPlans:
          type: number
          description: Total training plans by this user
          example: 5
        freePlans:
          type: number
          description: Free plans count
          example: 2
        paidPlans:
          type: number
          description: Paid plans count
          example: 3
        totalRevenue:
          type: number
          description: Total revenue from this user in INR
          example: 57
        activePlans:
          type: number
          description: Active plans count
          example: 1
        lastPlanDate:
          format: date-time
          type: string
          description: Last plan created date
          example: '2026-01-05T10:30:00Z'
      required:
        - userId
        - userName
        - phoneNumber
        - totalPlans
        - freePlans
        - paidPlans
        - totalRevenue
        - activePlans
        - lastPlanDate
    UserTrainingPlanListResponseDto:
      type: object
      properties:
        users:
          description: List of user training plan stats
          type: array
          items:
            $ref: '#/components/schemas/UserTrainingPlanStatsDto'
        totalUsers:
          type: number
          description: Total number of users with training plans
          example: 500
        page:
          type: number
          description: Current page number
          example: 1
        limit:
          type: number
          description: Items per page
          example: 20
        totalPages:
          type: number
          description: Total pages
          example: 25
      required:
        - users
        - totalUsers
        - page
        - limit
        - totalPages
    TrainingPlanDetailDto:
      type: object
      properties:
        id:
          type: string
          description: Training plan ID
          example: 01HQXYZ123456789
        userId:
          type: string
          description: User ID
          example: 01HQABC987654321
        userName:
          type: string
          description: User name
          example: John Doe
        userPhone:
          type: string
          description: User phone number
          example: '+919876543210'
        eventName:
          type: string
          description: Event name
          example: Mumbai Marathon 2026
        eventId:
          type: string
          description: Event ID
          example: 01HQEVT123456789
        eventDate:
          format: date-time
          type: string
          description: Event date
          example: '2026-02-15'
        status:
          type: string
          description: Plan status
          enum:
            - active
            - completed
            - cancelled
            - expired
          example: active
        programLevel:
          type: string
          description: Program level
          enum:
            - active
            - athlete
            - goat
          example: athlete
        duration:
          type: string
          description: Plan duration
          enum:
            - 2_weeks
            - 4_weeks
            - 8_weeks
          example: 4_weeks
        sportType:
          type: string
          description: Sport type
          enum:
            - running
            - cycling
            - swimming
            - triathlon
            - hiking_trekking
          example: running
        pricePaid:
          type: number
          description: Price paid in INR
          example: 19
        isPaid:
          type: boolean
          description: Whether plan is paid
          example: true
        paymentId:
          type: string
          description: Payment ID
          example: order_123456
        transactionId:
          type: string
          description: Transaction ID
          example: txn_123456
        totalDays:
          type: number
          description: Total days in plan
          example: 28
        totalWeeks:
          type: number
          description: Total weeks in plan
          example: 4
        createdAt:
          format: date-time
          type: string
          description: Plan created date
          example: '2026-01-05T10:30:00Z'
      required:
        - id
        - userId
        - userName
        - userPhone
        - eventName
        - eventDate
        - status
        - programLevel
        - duration
        - sportType
        - isPaid
        - totalDays
        - totalWeeks
        - createdAt
    TrainingPlanListResponseDto:
      type: object
      properties:
        plans:
          description: List of training plans
          type: array
          items:
            $ref: '#/components/schemas/TrainingPlanDetailDto'
        total:
          type: number
          description: Total number of training plans
          example: 1500
        page:
          type: number
          description: Current page number
          example: 1
        limit:
          type: number
          description: Items per page
          example: 20
        totalPages:
          type: number
          description: Total pages
          example: 75
      required:
        - plans
        - total
        - page
        - limit
        - totalPages
    ModerationActionDto:
      type: object
      properties:
        reason:
          type: string
          description: Reason for the action (audit trail).
    UpdateEventStatusDto:
      type: object
      properties:
        status:
          type: string
          enum:
            - draft
            - pending_review
            - published
            - open
            - closing_soon
            - closed
            - in_progress
            - live
            - completed
            - cancelled
            - postponed
            - suspended
          description: >-
            New event status. Admin may set: published, suspended, cancelled,
            postponed, draft, pending_review.
        reason:
          type: string
          description: Reason for the override (for the audit trail).
      required:
        - status
    RestoreCancelledEventDto:
      type: object
      properties:
        reason:
          type: string
          description: Why the cancelled event is being restored to published.
          minLength: 3
          maxLength: 500
      required:
        - reason
    ReplaceEventUuidDto:
      type: object
      properties:
        newEventId:
          type: string
          description: The new UUID to assign to the event.
        confirmCurrentEventId:
          type: string
          description: Current event UUID, entered again as explicit confirmation.
        reason:
          type: string
          description: Operational reason for replacing the UUID.
          minLength: 10
          maxLength: 500
      required:
        - newEventId
        - confirmCurrentEventId
        - reason
    SuspendEventDto:
      type: object
      properties:
        reason:
          type: string
          description: Why the event is being suspended (required).
          minLength: 3
          maxLength: 1000
      required:
        - reason
    UpdateEditionStatusDto:
      type: object
      properties:
        status:
          type: string
          enum:
            - draft
            - published
            - live
            - completed
            - cancelled
          description: New edition status.
        reason:
          type: string
          description: Reason for the override (audit trail).
      required:
        - status
    CreateBadgeRequestDto:
      type: object
      properties:
        badgeName:
          type: string
          example: Half Marathon Hero
        description:
          type: string
          example: Awarded for completing a half marathon distance.
        criteria:
          type: string
          example: Complete 21.1km cumulative distance within the challenge window.
        category:
          type: string
          example: Distance
        challengeId:
          type: string
          description: Challenge this request was raised from, if any.
      required:
        - badgeName
        - description
        - criteria
