{"openapi":"3.0.0","paths":{"/api/notifications":{"get":{"operationId":"NotificationsController_list","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["notifications"]}},"/api/notifications/unread-count":{"get":{"operationId":"NotificationsController_unread","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["notifications"]}},"/api/notifications/read-all":{"post":{"operationId":"NotificationsController_markAllRead","parameters":[],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["notifications"]}},"/api/notifications/push-sub":{"post":{"operationId":"NotificationsController_subscribe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["notifications"]},"delete":{"operationId":"NotificationsController_unsubscribe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["notifications"]}},"/api/notifications/preferences":{"get":{"operationId":"NotificationsController_getPreferences","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["notifications"]},"patch":{"operationId":"NotificationsController_updatePreferences","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotifPrefsDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["notifications"]}},"/api/notifications/stream":{"get":{"operationId":"NotificationsController_stream","parameters":[],"responses":{"200":{"description":""}},"tags":["notifications"]}},"/api/webhook/whatsapp":{"get":{"operationId":"WhatsAppController_verifyWebhook","parameters":[{"name":"hub.mode","required":true,"in":"query","schema":{"type":"string"}},{"name":"hub.verify_token","required":true,"in":"query","schema":{"type":"string"}},{"name":"hub.challenge","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["whatsapp"]},"post":{"operationId":"WhatsAppController_receiveWebhook","parameters":[{"name":"x-hub-signature-256","required":true,"in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["whatsapp"]}},"/api/whatsapp/opt-in":{"post":{"operationId":"WhatsAppController_optIn","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptInDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["whatsapp"]},"delete":{"operationId":"WhatsAppController_optOut","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["whatsapp"]}},"/api/whatsapp/status":{"get":{"operationId":"WhatsAppController_getStatus","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["whatsapp"]}},"/api/health":{"get":{"description":"Returns 200 + service + version + timestamp. No external dependencies are touched. Use as the Kubernetes / DigitalOcean liveness probe path.","operationId":"HealthController_liveness","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"service":{"type":"string","example":"api-gateway"},"version":{"type":"string","example":"0.0.1"},"timestamp":{"type":"string","format":"date-time"}}}}}}},"summary":"Liveness probe","tags":["health"]}},"/api/health/ready":{"get":{"description":"Pings PostgreSQL with a 1.5s timeout. Use as the readiness probe — returns 503 when the DB is unreachable so the load balancer drops the instance from rotation.","operationId":"HealthController_readiness","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":{"database":{"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":{"database":{"status":"up"}},"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":{"database":{"status":"up"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"error":{"type":"object","example":{"redis":{"status":"down","message":"Could not connect"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true},"nullable":true},"details":{"type":"object","example":{"database":{"status":"up"},"redis":{"status":"down","message":"Could not connect"}},"additionalProperties":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}},"additionalProperties":true}}}}}}}},"summary":"Readiness probe","tags":["health"]}},"/api/auth/sign-up":{"post":{"description":"Creates a fan account by default. Returns the access + refresh tokens; the access token is the bearer token for subsequent calls. Rate-limited to 3/min and 20/hour per IP.","operationId":"AuthController_signUp","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignUpDto"}}}},"responses":{"201":{"description":"Account created — tokens returned."},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Create an account","tags":["auth"]}},"/api/auth/sign-in":{"post":{"description":"Verifies credentials, returns a JWT access token (30d) plus a refresh token. If 2FA is enabled, returns a `twoFactorRequired: true` response and a short-lived 2FA token instead — re-call with the TOTP code attached.","operationId":"AuthController_signIn","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInDto"}}}},"responses":{"200":{"description":"Tokens issued."},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Sign in (email + password)","tags":["auth"]}},"/api/auth/oauth-provision":{"post":{"description":"Called by the web app after a Google/Apple/Facebook sign-in. Idempotent — first call creates a Sportsplex user; subsequent calls return the existing one. Returns the same shape as `/sign-in`.","operationId":"AuthController_oauthProvision","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthProvisionDto"}}}},"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Provision a Sportsplex identity from an OAuth profile","tags":["auth"]}},"/api/auth/refresh":{"post":{"description":"Refresh tokens are single-use; the response includes a new pair. Rotation is enforced server-side, so replays of an old refresh token fail with 401 and revoke the entire session family.","operationId":"AuthController_refresh","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenDto"}}}},"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Exchange a refresh token for a fresh access token","tags":["auth"]}},"/api/auth/logout":{"post":{"description":"Revokes the supplied refresh token. The access token continues to work until its 30d expiry — call `logout-all` to revoke everywhere.","operationId":"AuthController_logout","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenDto"}}}},"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Sign out the current session","tags":["auth"]}},"/api/auth/logout-all":{"post":{"description":"Sets `Session.revokedAt` on all of the caller's sessions so any access token signed against them is rejected on the next request.","operationId":"AuthController_logoutAll","parameters":[],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Revoke every active session for the user","tags":["auth"]}},"/api/auth/forgot-password":{"post":{"operationId":"AuthController_forgotPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordDto"}}}},"responses":{"202":{"description":""}},"tags":["auth"]}},"/api/auth/reset-password":{"post":{"operationId":"AuthController_resetPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"200":{"description":""}},"tags":["auth"]}},"/api/auth/change-password":{"post":{"operationId":"AuthController_changePassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/auth/verify-email":{"post":{"operationId":"AuthController_verifyEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailDto"}}}},"responses":{"200":{"description":""}},"tags":["auth"]}},"/api/auth/resend-verification":{"post":{"operationId":"AuthController_resendVerification","parameters":[],"responses":{"202":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/auth/sessions":{"get":{"operationId":"AuthController_listSessions","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/auth/sessions/{id}":{"delete":{"operationId":"AuthController_revokeSession","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/auth/2fa/enrol":{"post":{"operationId":"AuthController_beginEnrol","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/auth/2fa/confirm":{"post":{"operationId":"AuthController_confirmEnrol","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TotpCodeDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/auth/2fa/disable":{"post":{"operationId":"AuthController_disableTwoFactor","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableTwoFactorDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/auth/2fa/recovery-codes":{"post":{"operationId":"AuthController_regenerateRecovery","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["auth"]}},"/api/users/me":{"get":{"description":"Returns the caller's public profile + role set + counters. Same shape as `GET /users/:username` but always for `req.user`.","operationId":"UsersController_me","parameters":[],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Get the authenticated user","tags":["users"]},"patch":{"description":"Patch the caller's profile — `displayName`, `bio`, `country`, `pinnedPostId`, `sportInterests`, `dob`, etc. Only the supplied fields change. Use `pinnedPostUnset: true` to clear the pinned post.","operationId":"UsersController_updateMe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Update the authenticated user","tags":["users"]},"delete":{"operationId":"UsersController_closeAccount","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["users"]}},"/api/users/me/completion":{"get":{"operationId":"UsersController_completion","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["users"]}},"/api/users/me/suggestions":{"get":{"operationId":"UsersController_suggestions","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["users"]}},"/api/users/me/following-fixtures":{"get":{"operationId":"UsersController_followingFixtures","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["users"]}},"/api/users/me/bank":{"post":{"operationId":"UsersController_setBank","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankDetailsDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["users"]},"get":{"operationId":"UsersController_getBank","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["users"]}},"/api/users/{username}":{"get":{"description":"Returns a user's public profile. With a bearer token attached, the response also carries `isFollowing` and `isSelf` so the client doesn't need a second round-trip to decide which CTA to render.","operationId":"UsersController_byUsername","parameters":[{"name":"username","required":true,"in":"path","schema":{"example":"kaizer-chiefs","type":"string"}}],"responses":{"404":{"description":"No user with this username.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Public profile by username","tags":["users"]}},"/api/users/{username}/posts":{"get":{"operationId":"UsersController_postsByAuthor","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["users"]}},"/api/users/{username}/follow":{"post":{"description":"Idempotent — re-following an already-followed user is a no-op. Increments both follower counters denormalized on the row; the reconciler corrects drift.","operationId":"UsersController_follow","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Follow a user","tags":["users"]},"delete":{"operationId":"UsersController_unfollow","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["users"]}},"/api/users/{username}/followers":{"get":{"operationId":"UsersController_followers","parameters":[{"name":"username","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":["users"]}},"/api/users/{username}/following":{"get":{"operationId":"UsersController_following","parameters":[{"name":"username","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":["users"]}},"/api/feed":{"get":{"description":"Returns the caller's ranked timeline. Ranking weights are recency (35%) + affinity (25%) + engagement velocity (20%) + AI score (15%) + sponsored boost (5%). Anonymous callers get a popularity-only fallback ranking.","operationId":"FeedController_list","parameters":[{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"`{ items: FeedItem[] }`. Items are already author-hydrated."},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Ranked timeline","tags":["feed"]},"post":{"description":"Publishes a post (text + up to 10 media items) for the authenticated user. Optionally tags a fixture (`matchId`). Optionally cross-posts to social platforms the user has linked under `/integrations` — pass platform codes in `platforms`.","operationId":"FeedController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePostDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Publish a post","tags":["feed"]}},"/api/posts/trending":{"get":{"operationId":"FeedController_trending","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["feed"]}},"/api/posts/{id}":{"get":{"operationId":"FeedController_byId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["feed"]},"delete":{"operationId":"FeedController_destroy","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]}},"/api/posts/{id}/like":{"post":{"operationId":"FeedController_toggleLike","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]}},"/api/posts/{id}/comments":{"post":{"operationId":"FeedController_comment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]}},"/api/posts/{id}/pin":{"post":{"operationId":"FeedController_pin","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]},"delete":{"operationId":"FeedController_unpin","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]}},"/api/posts/{id}/repost":{"post":{"operationId":"FeedController_repost","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]},"delete":{"operationId":"FeedController_unrepost","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]}},"/api/reports":{"post":{"operationId":"FeedController_report","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["feed"]}},"/api/loyalty/me":{"get":{"operationId":"LoyaltyController_me","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["loyalty"]}},"/api/loyalty/{userId}":{"get":{"operationId":"LoyaltyController_profile","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["loyalty"]}},"/api/integrations/social":{"get":{"operationId":"IntegrationsController_list","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List connected social integrations","tags":["integrations"]}},"/api/integrations/social/initiate/{platform}":{"get":{"operationId":"IntegrationsController_initiate","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Initiate OAuth for a social platform","tags":["integrations"]}},"/api/integrations/social/callback/{platform}":{"post":{"operationId":"IntegrationsController_callback","parameters":[{"name":"platform","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"}}],"responses":{"201":{"description":""}},"summary":"Handle OAuth callback from social platform","tags":["integrations"]}},"/api/integrations/social/{id}":{"delete":{"operationId":"IntegrationsController_revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Disconnect a social integration","tags":["integrations"]}},"/api/integrations/social/{id}/test":{"post":{"operationId":"IntegrationsController_test","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Test a social integration connection","tags":["integrations"]}},"/api/matches":{"get":{"description":"Returns fixtures for `date` (YYYY-MM-DD, default today), optionally filtered by `league` (provider-namespaced slug, e.g. `PL`) or `sport`. With no `sport`, returns a multi-sport rollup. Provider attribution is in the response `provider` field.","operationId":"MatchesController_list","parameters":[{"name":"date","required":false,"in":"query","description":"ISO date.","schema":{"example":"2026-05-10","type":"string"}},{"name":"league","required":false,"in":"query","description":"League slug.","schema":{"example":"PL","type":"string"}},{"name":"sport","required":false,"in":"query","schema":{"example":"football","type":"string"}}],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"List fixtures","tags":["matches"]}},"/api/matches/{id}":{"get":{"description":"Looks up the live provider; falls back to the Postgres mirror when the provider is rate-limited or the fixture has rolled off the free-tier window. Returns 404 only when neither path knows the id.","operationId":"MatchesController_byId","parameters":[{"name":"id","required":true,"in":"path","description":"Provider-namespaced ID, e.g. `fd:538140`.","schema":{"type":"string"}}],"responses":{"404":{"description":"No provider knows this fixture id and no cached row exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Fetch a fixture by id","tags":["matches"]}},"/api/matches/{id}/events":{"get":{"operationId":"MatchesController_events","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]},"post":{"description":"Used by the data-provider worker (or live-ops console) to push goals, cards, etc. `GOAL` events fan out to the auto-Moment Reel generator so highlight clips appear in the Live tab feed within seconds.","operationId":"MatchesController_ingestEvent","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestEventDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"403":{"description":"Authenticated, but the role required for this operation is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Ingest a match timeline event (admin)","tags":["matches"]}},"/api/matches/{id}/events/stream":{"get":{"operationId":"MatchesController_eventsStream","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/matches/{id}/lineups":{"get":{"operationId":"MatchesController_lineups","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/matches/{id}/stats":{"get":{"operationId":"MatchesController_stats","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/matches/{id}/prediction":{"get":{"operationId":"MatchesController_prediction","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/matches/{id}/highlights":{"get":{"operationId":"MatchesController_matchHighlights","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/matches/{id}/videos":{"get":{"operationId":"MatchesController_matchVideos","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/matches/{id}/stadium":{"get":{"operationId":"MatchesController_stadium","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/videos/trending":{"get":{"operationId":"MatchesController_videosTrending","parameters":[{"name":"sport","required":true,"in":"query","schema":{"type":"string"}},{"name":"kind","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/leagues":{"get":{"operationId":"MatchesController_leagues","parameters":[{"name":"sport","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/standings/{leagueId}":{"get":{"operationId":"MatchesController_standings","parameters":[{"name":"leagueId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/sports":{"get":{"operationId":"MatchesController_sports_index","parameters":[],"responses":{"200":{"description":""}},"tags":["matches"]}},"/api/matches/{matchId}/messages":{"get":{"operationId":"MessagesController_list","parameters":[{"name":"matchId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["messages"]},"post":{"operationId":"MessagesController_create","parameters":[{"name":"matchId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMessageDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["messages"]}},"/api/search":{"get":{"operationId":"SearchController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["search"]}},"/api/athletes/{username}/tiers":{"get":{"operationId":"SubscriptionsController_tiers","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["subscriptions"]}},"/api/subscriptions":{"post":{"operationId":"SubscriptionsController_subscribe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["subscriptions"]}},"/api/subscriptions/me":{"get":{"operationId":"SubscriptionsController_mySubscriptions","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["subscriptions"]}},"/api/subscriptions/{id}":{"delete":{"operationId":"SubscriptionsController_cancel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["subscriptions"]}},"/api/bookings/me":{"get":{"description":"Returns the caller's bookings + the linked service. Status flow: PENDING → IN_ESCROW → COMPLETED, or DISPUTED → CANCELED on dispute resolution.","operationId":"MarketplaceController_myBookings","parameters":[],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"My bookings","tags":["marketplace"]}},"/api/services":{"get":{"description":"Filter by `providerUsername`, `providerId`, `category` (`COACHING` / `PHYSIO` / `NUTRITION` / `GEAR` / `STADIUM` / `OTHER` / `MEET_AND_GREET`), and `activeOnly`.","operationId":"MarketplaceController_list","parameters":[],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"List marketplace services","tags":["marketplace"]},"post":{"operationId":"MarketplaceController_createService","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["marketplace"]}},"/api/services/{id}":{"get":{"operationId":"MarketplaceController_byId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["marketplace"]}},"/api/services/{id}/bookings":{"post":{"description":"Captures payment via Paystack/Stripe Connect, opens an escrow hold, and creates a booking in PENDING. Returns the gateway authorization URL — redirect the user to it. The webhook flips the booking to IN_ESCROW on capture.","operationId":"MarketplaceController_book","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"404":{"description":"Service not found, or not currently active.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Book a service (escrow)","tags":["marketplace"]}},"/api/bookings/{id}/dispute":{"post":{"operationId":"MarketplaceController_dispute","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisputeBookingDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["marketplace"]}},"/api/sponsor/dashboard":{"get":{"description":"Live campaign rollup. SPONSOR sees only their own; ADMIN/SUPER_ADMIN see platform-wide. Reach and engagement are aggregated from the Activation table on every request — beacon increments land there, so numbers move in real time.","operationId":"SponsorController_dashboard","parameters":[],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"403":{"description":"Authenticated, but the role required for this operation is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Sponsor dashboard","tags":["sponsor"]}},"/api/sponsor/activations/{id}/beacon":{"post":{"operationId":"SponsorController_beacon","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImpressionDto"}}}},"responses":{"204":{"description":""}},"tags":["sponsor"]}},"/api/sponsor/activations/{id}/qr":{"post":{"operationId":"SponsorController_generateQr","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["sponsor"]}},"/api/sponsor/activations/live":{"get":{"operationId":"SponsorController_liveActivations","parameters":[],"responses":{"200":{"description":""}},"tags":["sponsor"]}},"/api/qr/{token}":{"get":{"operationId":"QrRedirectController_scan","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["QrRedirect"]}},"/api/ads/serve":{"get":{"description":"Returns either a first-party SmartAds creative (when one fits the targeting + budget guard) or a GAM fallback config. Public — anonymous + authed callers both get a response. Targeting accepts country, sport, fixtureId, gender, and women's-sport flag.","operationId":"SmartAdsController_serve","parameters":[{"name":"zone","required":true,"in":"query","schema":{"enum":["FEED","RIGHT_PANEL","LIVE_MATCH_BANNER","REELS_INTERSTITIAL","NEWS_SIDEBAR","NOTIFICATIONS_TOP"],"type":"string"}}],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Serve an ad for a zone","tags":["smartads"]}},"/api/ads/view":{"post":{"operationId":"SmartAdsController_view","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewDto"}}}},"responses":{"204":{"description":""}},"tags":["smartads"]}},"/api/ads/click":{"post":{"operationId":"SmartAdsController_click","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClickDto"}}}},"responses":{"204":{"description":""}},"tags":["smartads"]}},"/api/ads/analytics":{"get":{"description":"Impressions, clicks, CTR, and estimated revenue by zone over the last `days` (default 7). SPONSOR sees only their own campaigns; ADMIN/SUPER_ADMIN see platform-wide.","operationId":"SmartAdsController_analytics","parameters":[{"name":"days","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"SmartAds analytics rollup","tags":["smartads"]}},"/api/ads/units":{"post":{"operationId":"SmartAdsController_createUnit","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAdUnitDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["smartads"]}},"/api/ads/slots":{"get":{"operationId":"SmartAdsController_listSlots","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["smartads"]}},"/api/clubs/{username}/drops":{"get":{"description":"Public list of drops issued by the club, newest-first (capped at 12). Used by the About tab on the club profile.","operationId":"ClubController_clubDrops","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"404":{"description":"No club with this username.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"List a club's drops","tags":["club"]}},"/api/clubs/{username}/upcoming":{"get":{"operationId":"ClubController_clubUpcoming","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["club"]}},"/api/club/dashboard":{"get":{"description":"Live operational view for club staff: ticket sell-through, hospitality occupancy, member growth/churn, recent drops, upcoming fixtures. ADMIN/SUPER_ADMIN see any club; club roles see their own only.","operationId":"ClubController_dashboard","parameters":[],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"403":{"description":"Authenticated, but the role required for this operation is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Club operations dashboard","tags":["club"]}},"/api/admin/moderation":{"get":{"operationId":"AdminController_reports","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/moderation/{id}/resolve":{"post":{"operationId":"AdminController_resolve","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveReportDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/users/{id}/verify":{"post":{"operationId":"AdminController_verifyUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]},"delete":{"operationId":"AdminController_unverifyUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/bookings/disputed":{"get":{"operationId":"AdminController_listDisputed","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/bookings/{id}/resolve":{"post":{"operationId":"AdminController_resolveBooking","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/payouts":{"get":{"operationId":"AdminController_listPayouts","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/payouts/{id}/mark-paid":{"post":{"operationId":"AdminController_markPayoutPaid","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/payouts/{id}/mark-failed":{"post":{"operationId":"AdminController_markPayoutFailed","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/commissions":{"get":{"operationId":"AdminController_listCommissions","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/commissions/{id}/mark-paid":{"post":{"operationId":"AdminController_markCommissionPaid","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/commissions/{id}/reverse":{"post":{"operationId":"AdminController_reverseCommission","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/drift-alert":{"get":{"operationId":"AdminController_driftAlert","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/teams/cleanup-stats":{"get":{"operationId":"AdminController_teamCleanupStats","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/users":{"get":{"operationId":"AdminController_users","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/users/{id}/suspend":{"post":{"operationId":"AdminController_suspendUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/users/{id}/activate":{"post":{"operationId":"AdminController_activateUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["admin"]}},"/api/admin/tenants":{"get":{"operationId":"SuperAdminController_listTenants","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["super-admin"]},"post":{"operationId":"SuperAdminController_createTenant","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTenantDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["super-admin"]}},"/api/admin/tenants/{id}":{"patch":{"operationId":"SuperAdminController_updateTenant","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTenantDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["super-admin"]}},"/api/admin/staff":{"get":{"operationId":"SuperAdminController_listStaff","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["super-admin"]}},"/api/admin/staff/{userId}/grant":{"post":{"operationId":"SuperAdminController_grantStaff","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffGrantDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["super-admin"]}},"/api/admin/staff/{userId}/role/{role}":{"delete":{"operationId":"SuperAdminController_revokeStaff","parameters":[{"name":"userId","required":true,"in":"path","schema":{"type":"string"}},{"name":"role","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["super-admin"]}},"/api/admin/audit-log":{"get":{"operationId":"SuperAdminController_listAudit","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"action","required":true,"in":"query","schema":{"type":"string"}},{"name":"entity","required":true,"in":"query","schema":{"type":"string"}},{"name":"userId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["super-admin"]}},"/api/discover":{"get":{"operationId":"DiscoverController_recommend","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["discover"]}},"/api/tickets":{"get":{"description":"All tickets for upcoming fixtures, optionally narrowed to one fixture via `?fixtureId=<id>`.","operationId":"TicketsController_list","parameters":[{"name":"fixtureId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"List tickets","tags":["tickets"]}},"/api/tickets/me":{"get":{"operationId":"TicketsController_myHolds","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tickets"]}},"/api/tickets/{id}":{"get":{"operationId":"TicketsController_byId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["tickets"]}},"/api/tickets/holds":{"post":{"operationId":"TicketsController_hold","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoldTicketDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["tickets"]}},"/api/tickets/checkout":{"post":{"description":"Opens a Paystack/Stripe transaction for the held seat and returns `{ authorizationUrl }`. The client redirects the user there. Webhook + `/payments/verify` flips the hold to PURCHASED on capture.","operationId":"TicketsController_checkout","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutHoldDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Begin checkout for a held seat","tags":["tickets"]}},"/api/drops":{"get":{"description":"All drops the platform is currently showing on the public Drops surface — both club and athlete drops, sorted by `startsAt`. Reveal time is enforced by the read filter; future drops carry an embargo flag the UI shows as a countdown.","operationId":"DropsController_list","parameters":[],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"List public drops","tags":["drops"]},"post":{"operationId":"DropsController_createDrop","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDropDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["drops"]}},"/api/drops/{id}":{"get":{"description":"Returns the drop + the club/athlete that issued it. Inventory + price are surfaced as integer minor units (use `currency` for display).","operationId":"DropsController_byId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"404":{"description":"No drop with this id, or it has been retired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Get a single drop","tags":["drops"]}},"/api/drops/athlete/{athleteId}":{"get":{"operationId":"DropsController_athleteDrops","parameters":[{"name":"athleteId","required":true,"in":"path","schema":{"type":"string"}},{"name":"subscriber","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["drops"]}},"/api/drops/club/{clubId}":{"get":{"operationId":"DropsController_clubDrops","parameters":[{"name":"clubId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["drops"]}},"/api/drops/{id}/autographs":{"get":{"operationId":"DropsController_listAutographs","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["drops"]}},"/api/drops/autographs/mine":{"get":{"operationId":"DropsController_myAutographs","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["drops"]}},"/api/drops/autographs/{certId}":{"get":{"operationId":"DropsController_getAutograph","parameters":[{"name":"certId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["drops"]}},"/api/drops/{id}/autographs/issue":{"post":{"operationId":"DropsController_issueAutograph","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueAutographDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["drops"]}},"/api/drops/{id}/checkout":{"post":{"operationId":"DropsController_checkout","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutDropDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["drops"]}},"/api/media/upload/{key}":{"post":{"operationId":"MediaController_devUpload","parameters":[{"name":"key","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["media"]}},"/api/media/cdn/*":{"get":{"operationId":"MediaController_devDownload","parameters":[],"responses":{"200":{"description":""}},"tags":["media"]}},"/api/media/profile":{"post":{"operationId":"MediaController_uploadProfileMedia","parameters":[{"name":"kind","required":true,"in":"query","schema":{"type":"string"}},{"name":"ext","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/profile/presign":{"post":{"operationId":"MediaController_presignProfileUpload","parameters":[{"name":"kind","required":true,"in":"query","schema":{"type":"string"}},{"name":"ext","required":true,"in":"query","schema":{"type":"string"}},{"name":"contentType","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/podcast/presign":{"post":{"operationId":"MediaController_presignPodcastUpload","parameters":[{"name":"kind","required":true,"in":"query","schema":{"type":"string"}},{"name":"ext","required":true,"in":"query","schema":{"type":"string"}},{"name":"contentType","required":true,"in":"query","schema":{"type":"string"}},{"name":"podcastId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/profile/multipart/init":{"post":{"operationId":"MediaController_multipartInit","parameters":[{"name":"kind","required":true,"in":"query","schema":{"type":"string"}},{"name":"ext","required":true,"in":"query","schema":{"type":"string"}},{"name":"contentType","required":true,"in":"query","schema":{"type":"string"}},{"name":"parts","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/profile/multipart/complete":{"post":{"operationId":"MediaController_multipartComplete","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultipartCompleteDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/profile/multipart/abort":{"post":{"operationId":"MediaController_multipartAbort","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultipartAbortDto"}}}},"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/post":{"post":{"operationId":"MediaController_uploadPostMedia","parameters":[{"name":"kind","required":true,"in":"query","schema":{"type":"string"}},{"name":"ext","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/post/presign":{"post":{"operationId":"MediaController_presignPostUpload","parameters":[{"name":"kind","required":true,"in":"query","schema":{"type":"string"}},{"name":"ext","required":true,"in":"query","schema":{"type":"string"}},{"name":"contentType","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["media"]}},"/api/media/transcode-callback":{"post":{"operationId":"MediaController_transcodeCallback","parameters":[],"responses":{"204":{"description":""}},"tags":["media"]}},"/api/reels/upload-init":{"post":{"description":"Reserves a `reelId` and returns a signed upload target. In production: a one-shot Backblaze B2 PUT URL. In dev (no cloud creds): a `/media/upload/:key` URL on this gateway. The client uploads bytes there directly, then calls `/reels/:id/finalize`.","operationId":"ReelsController_initUpload","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadInitDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Begin a reel upload","tags":["reels"]}},"/api/reels/{id}/finalize":{"post":{"description":"Attaches caption, dimensions, hashtags, match tag, sound, challenge, visibility, etc. Kicks off the transcoder. Reel transitions UPLOADING → TRANSCODING; flips to READY when the worker callback fires.","operationId":"ReelsController_finalize","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinalizeReelDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"404":{"description":"No reel with this id, or it belongs to another user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Finalize a reel after upload","tags":["reels"]}},"/api/reels/{id}":{"delete":{"operationId":"ReelsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]},"get":{"description":"Returns the reel + viewer-specific flags (`liked`, `saved`, `followed`) when called with a bearer token. Anonymous callers get the reel only.","operationId":"ReelsController_byId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"404":{"description":"No reel with this id, or it has been removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Get a single reel","tags":["reels"]}},"/api/reels/feed/foryou":{"get":{"description":"Sports-aware ranked feed. Score = recency × affinity × velocity × completion-rate × match-context × diversity. Cursor-paginated; pass `?cursor=<token>` for the next page.","operationId":"ReelsController_forYou","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"For-You reel feed","tags":["reels"]}},"/api/reels/feed/following":{"get":{"description":"Chronological feed of reels from the caller's follow graph. Cursor-paginated.","operationId":"ReelsController_following","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Reels from people you follow","tags":["reels"]}},"/api/reels/feed/match/{matchId}":{"get":{"operationId":"ReelsController_matchFeed","parameters":[{"name":"matchId","required":true,"in":"path","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":["reels"]}},"/api/users/{username}/reels":{"get":{"operationId":"ReelsController_byAuthor","parameters":[{"name":"username","required":true,"in":"path","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":["reels"]}},"/api/hashtags/{tag}/reels":{"get":{"operationId":"ReelsController_byHashtag","parameters":[{"name":"tag","required":true,"in":"path","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":["reels"]}},"/api/matches/{id}/reels":{"get":{"operationId":"ReelsController_matchReels","parameters":[{"name":"id","required":true,"in":"path","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":["reels"]}},"/api/matches/{id}/moments":{"get":{"operationId":"ReelsController_matchMoments","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/sounds/{id}/reels":{"get":{"operationId":"ReelsController_soundReels","parameters":[{"name":"id","required":true,"in":"path","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":["reels"]}},"/api/reels/{id}/like":{"post":{"description":"Idempotent toggle: returns `{ liked, likes }` reflecting the post-toggle state. Drops a `LIKE`/`UNLIKE` interaction so the ranker picks it up on the next pass.","operationId":"ReelsController_toggleLike","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Toggle like on a reel","tags":["reels"]}},"/api/reels/{id}/save":{"post":{"operationId":"ReelsController_toggleSave","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/reels/{id}/view":{"post":{"operationId":"ReelsController_logView","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReelViewDto"}}}},"responses":{"204":{"description":""}},"tags":["reels"]}},"/api/reels/{id}/interaction":{"post":{"operationId":"ReelsController_logInteraction","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReelInteractionDto"}}}},"responses":{"204":{"description":""}},"tags":["reels"]}},"/api/reels/{id}/not-interested":{"post":{"operationId":"ReelsController_notInterested","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/reels/{id}/comments":{"get":{"operationId":"ReelsController_listComments","parameters":[{"name":"id","required":true,"in":"path","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":["reels"]},"post":{"operationId":"ReelsController_createComment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReelCommentDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/comments/{id}/replies":{"get":{"operationId":"ReelsController_listReplies","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/comments/{id}":{"delete":{"operationId":"ReelsController_removeComment","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/sounds/trending":{"get":{"operationId":"ReelsController_trendingSounds","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/sounds/{id}":{"get":{"operationId":"ReelsController_soundById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/sounds/lift":{"post":{"operationId":"ReelsController_liftSound","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiftSoundDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/hashtags/trending":{"get":{"operationId":"ReelsController_trendingHashtags","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/hashtags/search":{"get":{"operationId":"ReelsController_searchHashtags","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/challenges":{"get":{"operationId":"ReelsController_listChallenges","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]},"post":{"operationId":"ReelsController_createChallenge","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChallengeDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/challenges/{slug}":{"get":{"operationId":"ReelsController_challengeBySlug","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/challenges/{slug}/reels":{"get":{"operationId":"ReelsController_challengeReels","parameters":[{"name":"slug","required":true,"in":"path","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":["reels"]}},"/api/reels/{id}/tip":{"post":{"operationId":"ReelsController_tip","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTipDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/users/{username}/pulse-score":{"get":{"operationId":"ReelsController_pulseFor","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["reels"]}},"/api/channels/{username}/subscribe":{"post":{"operationId":"ReelsController_subscribe","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]},"delete":{"operationId":"ReelsController_unsubscribe","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/channels/me/subscriptions":{"get":{"operationId":"ReelsController_mySubs","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["reels"]}},"/api/reels/{reelId}/reactions":{"post":{"operationId":"LiveReactionsController_publish","parameters":[{"name":"reelId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FloatingReactionDto"}}}},"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"tags":["live-reactions"]}},"/api/reels/{reelId}/reactions/stream":{"get":{"operationId":"LiveReactionsController_stream","parameters":[{"name":"reelId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["live-reactions"]}},"/api/matches/{matchId}/reactions":{"post":{"operationId":"MatchReactionsController_publish","parameters":[{"name":"matchId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchReactionDto"}}}},"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"tags":["match-reactions"]}},"/api/matches/{matchId}/reactions/stream":{"get":{"operationId":"MatchReactionsController_stream","parameters":[{"name":"matchId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["match-reactions"]}},"/api/matches/{matchId}/reactions/emojis":{"get":{"operationId":"MatchReactionsController_emojis","parameters":[],"responses":{"200":{"description":""}},"tags":["match-reactions"]}},"/api/co-watch/reels/{reelId}/rooms":{"post":{"operationId":"CoWatchController_create","parameters":[{"name":"reelId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}":{"get":{"operationId":"CoWatchController_byId","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["co-watch"]},"delete":{"operationId":"CoWatchController_end","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/join":{"post":{"operationId":"CoWatchController_join","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]},"delete":{"operationId":"CoWatchController_leave","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/control":{"post":{"operationId":"CoWatchController_control","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoWatchControlDto"}}}},"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/chat":{"post":{"operationId":"CoWatchController_chat","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoWatchChatDto"}}}},"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/reaction":{"post":{"operationId":"CoWatchController_reaction","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoWatchReactionDto"}}}},"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/stream":{"get":{"operationId":"CoWatchController_stream","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/questions":{"get":{"operationId":"CoWatchController_listQuestions","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["co-watch"]},"post":{"operationId":"CoWatchController_submitQuestion","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QAQuestionDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/questions/{qid}/upvote":{"post":{"operationId":"CoWatchController_upvoteQuestion","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}},{"name":"qid","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/co-watch/rooms/{roomId}/questions/{qid}/answer":{"post":{"operationId":"CoWatchController_markAnswered","parameters":[{"name":"roomId","required":true,"in":"path","schema":{"type":"string"}},{"name":"qid","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["co-watch"]}},"/api/news":{"get":{"description":"Aggregated headlines from RSS providers (Guardian, BBC, etc.). When called with a bearer token, articles matching the viewer's sport interests are boosted in the ranking — `personalised: true` in the response confirms it.","operationId":"NewsController_list","parameters":[{"name":"sport","required":false,"in":"query","schema":{"example":"football","type":"string"}},{"name":"q","required":false,"in":"query","description":"Keyword search override.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"type":"integer","minimum":1,"maximum":60}}],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Sports news feed","tags":["news"]}},"/api/news/sources":{"get":{"operationId":"NewsController_sources","parameters":[],"responses":{"200":{"description":""}},"tags":["news"]}},"/api/news/{id}":{"get":{"description":"Returns the full article + AI-generated 2-sentence brief (when ready). The brief is enriched asynchronously after first publish, so newly-ingested articles may return `aiSummary: null`.","operationId":"NewsController_byId","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"404":{"description":"No article with this id, or it has rolled off the feed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Read an article","tags":["news"]}},"/api/payments/verify":{"get":{"operationId":"PaymentsController_verify","parameters":[{"name":"reference","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["payments"]}},"/api/payments/{id}":{"get":{"operationId":"PaymentsController_status","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["payments"]}},"/api/payments/webhooks/paystack":{"post":{"operationId":"PaymentsController_paystackWebhook","parameters":[],"responses":{"200":{"description":""}},"tags":["payments"]}},"/api/brands":{"get":{"operationId":"BrandsController_listBrands","parameters":[],"responses":{"200":{"description":""}},"tags":["brands"]}},"/api/brands/{username}/products":{"get":{"operationId":"BrandsController_productsByBrand","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}},{"name":"category","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["brands"]}},"/api/products/{id}":{"get":{"operationId":"BrandsController_productById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["brands"]}},"/api/brands/me/products":{"post":{"operationId":"BrandsController_createProduct","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/brands/me/products/{id}":{"patch":{"operationId":"BrandsController_updateProduct","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]},"delete":{"operationId":"BrandsController_deleteProduct","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/brands/{username}/partnerships":{"get":{"operationId":"BrandsController_partnershipsByBrand","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["brands"]}},"/api/users/{username}/partnerships":{"get":{"operationId":"BrandsController_partnershipsByAthlete","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["brands"]}},"/api/brands/me/partnerships":{"post":{"operationId":"BrandsController_createPartnership","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePartnershipDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/products/{id}/checkout":{"post":{"operationId":"BrandsController_checkoutProduct","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutProductDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/orders/me":{"get":{"operationId":"BrandsController_myOrders","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/brands/me/orders":{"get":{"operationId":"BrandsController_myBrandOrders","parameters":[{"name":"status","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/brands/me/orders/{id}":{"patch":{"operationId":"BrandsController_updateOrderStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/brands/me/partnerships/{id}":{"delete":{"operationId":"BrandsController_endPartnership","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["brands"]}},"/api/affiliates/{code}":{"get":{"operationId":"AffiliatesController_lookup","parameters":[{"name":"code","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["affiliates"]}},"/api/affiliates/me/codes":{"get":{"operationId":"AffiliatesController_myCodes","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["affiliates"]},"post":{"operationId":"AffiliatesController_createCode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAffiliateCodeDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["affiliates"]}},"/api/affiliates/me/codes/{id}":{"patch":{"operationId":"AffiliatesController_updateCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAffiliateCodeDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["affiliates"]},"delete":{"operationId":"AffiliatesController_deactivate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["affiliates"]}},"/api/affiliates/me/commissions":{"get":{"operationId":"AffiliatesController_myCommissions","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["affiliates"]}},"/api/referrals/me":{"get":{"operationId":"ReferralsController_myStats","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["referrals"]}},"/api/referrals/leaderboard":{"get":{"operationId":"ReferralsController_leaderboard","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["referrals"]}},"/api/referrals/{code}/preview":{"get":{"operationId":"ReferralsController_preview","parameters":[{"name":"code","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["referrals"]}},"/api/matches/{id}/predict":{"post":{"operationId":"PredictionsController_submit","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitPredictionDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["predictions"]}},"/api/matches/{id}/predict/me":{"get":{"operationId":"PredictionsController_forMatch","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["predictions"]}},"/api/matches/{id}/predictions/leaderboard":{"get":{"operationId":"PredictionsController_fixtureLeaderboard","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["predictions"]}},"/api/predictions/me":{"get":{"operationId":"PredictionsController_mine","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["predictions"]}},"/api/predictions/leaderboard":{"get":{"operationId":"PredictionsController_leaderboard","parameters":[],"responses":{"200":{"description":""}},"tags":["predictions"]}},"/api/teams/by-country/{code}":{"get":{"operationId":"TeamsController_byCountry","parameters":[{"name":"code","required":true,"in":"path","schema":{"type":"string"}},{"name":"sport","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["teams"]}},"/api/teams/discover/trending":{"get":{"operationId":"TeamsController_trending","parameters":[{"name":"perCountry","required":true,"in":"query","schema":{"type":"string"}},{"name":"maxCountries","required":true,"in":"query","schema":{"type":"string"}},{"name":"sport","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/teams/{slug}":{"get":{"operationId":"TeamsController_detail","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["teams"]}},"/api/teams/{slug}/fixtures":{"get":{"operationId":"TeamsController_fixtures","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["teams"]}},"/api/users/me/teams":{"get":{"operationId":"TeamsController_myTeams","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/users/{username}/teams":{"get":{"operationId":"TeamsController_userTeams","parameters":[{"name":"username","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["teams"]}},"/api/teams/me/claim":{"post":{"operationId":"TeamsController_claim","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimTeamDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/teams/{slug}/follow":{"post":{"operationId":"TeamsController_followTeam","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]},"delete":{"operationId":"TeamsController_unfollowTeam","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/teams/{slug}/follow-status":{"get":{"operationId":"TeamsController_followStatus","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/admin/team-memberships/pending":{"get":{"operationId":"TeamsController_pending","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/admin/team-memberships/{id}/verify":{"post":{"operationId":"TeamsController_verify","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/admin/team-memberships/{id}":{"delete":{"operationId":"TeamsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["teams"]}},"/api/competitions":{"get":{"operationId":"CompetitionsController_list","parameters":[{"name":"isWomensSport","required":true,"in":"query","schema":{"type":"string"}},{"name":"sport","required":true,"in":"query","schema":{"type":"string"}},{"name":"countryCode","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":"cursor","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["competitions"]},"post":{"operationId":"CompetitionsController_create","parameters":[],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/competitions/mine":{"get":{"operationId":"CompetitionsController_mine","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/competitions/{slug}":{"get":{"operationId":"CompetitionsController_detail","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["competitions"]}},"/api/competitions/{slug}/fixtures":{"get":{"operationId":"CompetitionsController_fixtures","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["competitions"]},"post":{"operationId":"CompetitionsController_createFixture","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/competitions/{slug}/standings":{"get":{"operationId":"CompetitionsController_standings","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["competitions"]}},"/api/competitions/{slug}/follow":{"post":{"operationId":"CompetitionsController_follow","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]},"delete":{"operationId":"CompetitionsController_unfollow","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/competitions/{slug}/follow-status":{"get":{"operationId":"CompetitionsController_followStatus","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/competitions/{id}":{"patch":{"operationId":"CompetitionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/competitions/{slug}/fixtures/managed":{"get":{"operationId":"CompetitionsController_fixturesManaged","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/competitions/{slug}/fixtures/{fixtureId}":{"patch":{"operationId":"CompetitionsController_updateFixture","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}},{"name":"fixtureId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["competitions"]}},"/api/coach/dashboard":{"get":{"operationId":"CoachController_dashboard","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["coach"]}},"/api/scout/dashboard":{"get":{"operationId":"ScoutController_dashboard","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["scout"]}},"/api/service-provider/dashboard":{"get":{"operationId":"ServiceProviderController_dashboard","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["service-provider"]}},"/api/team-dashboard":{"get":{"operationId":"TeamDashboardController_dashboard","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["team-dashboard"]}},"/api/communities":{"get":{"description":"Paginated list, filterable by `kind`, `country`, or full-text `q`. With a bearer token, the response includes the caller's membership role for each community shown.","operationId":"CommunitiesController_list","parameters":[],"responses":{"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"List communities","tags":["communities"]},"post":{"description":"The caller becomes OWNER. Slug must be unique platform-wide; `kind` chooses the discovery surface (`OPEN` / `PRIVATE` / `PAID`).","operationId":"CommunitiesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommunityDto"}}}},"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Create a community","tags":["communities"]}},"/api/communities/mine":{"get":{"operationId":"CommunitiesController_mine","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["communities"]}},"/api/communities/{slug}":{"get":{"description":"Returns the community + the caller's membership role (`OWNER` / `MODERATOR` / `MEMBER` / null) when called with a bearer token.","operationId":"CommunitiesController_get","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"404":{"description":"No community with this slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"summary":"Community detail","tags":["communities"]}},"/api/communities/{id}":{"patch":{"operationId":"CommunitiesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommunityDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["communities"]},"delete":{"operationId":"CommunitiesController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["communities"]}},"/api/communities/{id}/join":{"post":{"description":"OPEN communities accept the join immediately. PRIVATE communities create a pending request the moderators must approve. PAID communities require a successful payment first.","operationId":"CommunitiesController_join","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"401":{"description":"Missing or invalid bearer token (or session no longer valid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"429":{"description":"Throttled — back off, then retry. See `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"500":{"description":"Unexpected server error. Quote `error.requestId` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}},"503":{"description":"Upstream provider unreachable or rate-limited. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelopeDto"}}}}},"security":[{"bearer":[]}],"summary":"Join a community","tags":["communities"]}},"/api/communities/{id}/leave":{"delete":{"operationId":"CommunitiesController_leave","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["communities"]}},"/api/communities/{id}/promote":{"post":{"operationId":"CommunitiesController_promote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteMemberDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["communities"]}},"/api/communities/{id}/members":{"get":{"operationId":"CommunitiesController_members","parameters":[{"name":"id","required":true,"in":"path","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":["communities"]}},"/api/communities/{id}/feed":{"get":{"operationId":"CommunitiesController_feed","parameters":[{"name":"id","required":true,"in":"path","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":["communities"]}},"/api/communities/{id}/posts":{"post":{"operationId":"CommunitiesController_createPost","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["communities"]}},"/api/communities/{id}/verify":{"post":{"operationId":"CommunitiesController_verify","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["communities"]}},"/api/matches/{id}/polls":{"get":{"operationId":"PollsController_list","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["polls"]},"post":{"operationId":"PollsController_create","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePollDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["polls"]}},"/api/polls/{id}/tally":{"get":{"operationId":"PollsController_tally","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["polls"]}},"/api/polls/{id}/vote":{"post":{"operationId":"PollsController_vote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoteDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["polls"]}},"/api/checkins/{fixtureId}":{"post":{"operationId":"CheckInsController_checkIn","parameters":[{"name":"fixtureId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckInDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["checkins"]},"delete":{"operationId":"CheckInsController_checkOut","parameters":[{"name":"fixtureId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["checkins"]}},"/api/checkins/{fixtureId}/me":{"get":{"operationId":"CheckInsController_me","parameters":[{"name":"fixtureId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["checkins"]}},"/api/checkins/{fixtureId}/nearby":{"get":{"operationId":"CheckInsController_nearby","parameters":[{"name":"fixtureId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["checkins"]}},"/api/tournaments":{"get":{"operationId":"TournamentsController_discover","parameters":[{"name":"sport","required":true,"in":"query","schema":{"type":"string"}},{"name":"countryCode","required":true,"in":"query","schema":{"type":"string"}},{"name":"city","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":["tournaments"]},"post":{"operationId":"TournamentsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTournamentDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/tournaments/mine":{"get":{"operationId":"TournamentsController_mine","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/tournaments/{slug}":{"get":{"operationId":"TournamentsController_detail","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["tournaments"]}},"/api/tournaments/{slug}/publish":{"post":{"operationId":"TournamentsController_publish","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/tournaments/{slug}/cancel":{"post":{"operationId":"TournamentsController_cancel","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/tournaments/{slug}/bracket":{"post":{"operationId":"TournamentsController_generateBracket","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/tournaments/{slug}/fixtures/{fid}/result":{"post":{"operationId":"TournamentsController_enterResult","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}},{"name":"fid","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterResultDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/tournaments/{slug}/revenue":{"get":{"operationId":"TournamentsController_revenue","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/tournaments/{slug}/register":{"post":{"operationId":"TournamentsController_register","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]},"delete":{"operationId":"TournamentsController_cancelRegistration","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["tournaments"]}},"/api/meetups/{fixtureId}":{"get":{"operationId":"MeetupsController_list","parameters":[{"name":"fixtureId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Meetups"]},"post":{"operationId":"MeetupsController_create","parameters":[{"name":"fixtureId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMeetupDto"}}}},"responses":{"201":{"description":""}},"tags":["Meetups"]}},"/api/meetups/detail/{meetupId}":{"get":{"operationId":"MeetupsController_getOne","parameters":[{"name":"meetupId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Meetups"]},"delete":{"operationId":"MeetupsController_delete","parameters":[{"name":"meetupId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Meetups"]}},"/api/meetups/detail/{meetupId}/rsvp":{"post":{"operationId":"MeetupsController_rsvp","parameters":[{"name":"meetupId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RsvpDto"}}}},"responses":{"201":{"description":""}},"tags":["Meetups"]}},"/api/podcasts":{"get":{"operationId":"PodcastsController_list","parameters":[{"name":"ownerUserId","required":true,"in":"query","schema":{"type":"string"}},{"name":"category","required":true,"in":"query","schema":{"type":"string"}},{"name":"sort","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Podcasts"]},"post":{"operationId":"PodcastsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePodcastDto"}}}},"responses":{"201":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/categories":{"get":{"operationId":"PodcastsController_categories","parameters":[],"responses":{"200":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/episodes/latest":{"get":{"operationId":"PodcastsController_latestEpisodes","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/subscribed":{"get":{"operationId":"PodcastsController_subscribed","parameters":[{"name":"page","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/{id}":{"get":{"operationId":"PodcastsController_getOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Podcasts"]},"patch":{"operationId":"PodcastsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePodcastDto"}}}},"responses":{"200":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/{id}/episodes":{"post":{"operationId":"PodcastsController_createEpisode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEpisodeDto"}}}},"responses":{"201":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/episodes/{episodeId}/publish":{"post":{"operationId":"PodcastsController_publishEpisode","parameters":[{"name":"episodeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/episodes/{episodeId}":{"delete":{"operationId":"PodcastsController_deleteEpisode","parameters":[{"name":"episodeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/{id}/subscribe":{"post":{"operationId":"PodcastsController_subscribe","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["Podcasts"]},"delete":{"operationId":"PodcastsController_unsubscribe","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Podcasts"]}},"/api/podcasts/episodes/{episodeId}/play":{"post":{"operationId":"PodcastsController_recordPlay","parameters":[{"name":"episodeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Podcasts"]}},"/api/dm":{"get":{"operationId":"DmController_inbox","parameters":[],"responses":{"200":{"description":""}},"tags":["Dm"]}},"/api/dm/unread":{"get":{"operationId":"DmController_unread","parameters":[],"responses":{"200":{"description":""}},"tags":["Dm"]}},"/api/dm/conversations":{"post":{"operationId":"DmController_start","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartConversationDto"}}}},"responses":{"201":{"description":""}},"tags":["Dm"]}},"/api/dm/conversations/{id}/messages":{"get":{"operationId":"DmController_messages","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Dm"]},"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":["Dm"]}},"/api/dm/messages/{messageId}":{"delete":{"operationId":"DmController_deleteMessage","parameters":[{"name":"messageId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Dm"]}},"/api/season-passes":{"get":{"operationId":"SeasonPassesController_list","parameters":[{"name":"clubUsername","required":true,"in":"query","schema":{"type":"string"}},{"name":"competitionId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["SeasonPasses"]},"post":{"operationId":"SeasonPassesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSeasonPassDto"}}}},"responses":{"201":{"description":""}},"tags":["SeasonPasses"]}},"/api/season-passes/mine":{"get":{"operationId":"SeasonPassesController_mine","parameters":[],"responses":{"200":{"description":""}},"tags":["SeasonPasses"]}},"/api/season-passes/{id}":{"get":{"operationId":"SeasonPassesController_getOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["SeasonPasses"]}},"/api/season-passes/{id}/purchase":{"post":{"operationId":"SeasonPassesController_purchase","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseDto"}}}},"responses":{"201":{"description":""}},"tags":["SeasonPasses"]}},"/api/voice-reactions":{"get":{"operationId":"VoiceReactionsController_list","parameters":[{"name":"matchId","required":true,"in":"query","schema":{"type":"string"}},{"name":"matchEventId","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["VoiceReactions"]},"post":{"operationId":"VoiceReactionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVoiceReactionDto"}}}},"responses":{"201":{"description":""}},"tags":["VoiceReactions"]}},"/api/voice-reactions/{id}/play":{"post":{"operationId":"VoiceReactionsController_play","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["VoiceReactions"]}},"/api/voice-reactions/{id}":{"delete":{"operationId":"VoiceReactionsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["VoiceReactions"]}},"/api/posts/{postId}/boost":{"post":{"operationId":"BoostsController_boost","parameters":[{"name":"postId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["boosts"]}},"/api/posts/{postId}/boosts":{"get":{"operationId":"BoostsController_list","parameters":[{"name":"postId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["boosts"]}},"/api/posts/{postId}/boosts/mine":{"get":{"operationId":"BoostsController_mine","parameters":[{"name":"postId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["boosts"]}},"/api/governance/orgs":{"get":{"operationId":"GovernanceController_listOrgs","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Governance"]}},"/api/governance/reports":{"post":{"operationId":"GovernanceController_submit","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportDto"}}}},"responses":{"201":{"description":""}},"tags":["Governance"]},"get":{"operationId":"GovernanceController_myReports","parameters":[],"responses":{"200":{"description":""}},"tags":["Governance"]}},"/api/governance/inbox":{"get":{"operationId":"GovernanceController_inbox","parameters":[{"name":"status","required":true,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Governance"]}},"/api/governance/reports/{id}/respond":{"patch":{"operationId":"GovernanceController_respond","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RespondDto"}}}},"responses":{"200":{"description":""}},"tags":["Governance"]}},"/api/events":{"get":{"operationId":"EventsController_list","parameters":[],"responses":{"200":{"description":""}},"tags":["events"]},"post":{"operationId":"EventsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["events"]}},"/api/events/me/upcoming":{"get":{"operationId":"EventsController_myUpcoming","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["events"]}},"/api/events/me/organised":{"get":{"operationId":"EventsController_myOrganised","parameters":[{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["events"]}},"/api/events/organiser/{userId}":{"get":{"operationId":"EventsController_getByOrganiser","parameters":[{"name":"userId","required":true,"in":"path","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":["events"]}},"/api/events/{slug}":{"get":{"operationId":"EventsController_getBySlug","parameters":[{"name":"slug","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["events"]}},"/api/events/{id}/join":{"post":{"operationId":"EventsController_join","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinEventDto"}}}},"responses":{"201":{"description":""}},"tags":["events"]},"delete":{"operationId":"EventsController_leave","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["events"]}},"/api/events/{id}/checkin":{"post":{"operationId":"EventsController_checkIn","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckInDto"}}}},"responses":{"201":{"description":""}},"tags":["events"]}},"/api/events/{id}/votes":{"post":{"operationId":"EventsController_vote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MotorsportVoteDto"}}}},"responses":{"201":{"description":""}},"tags":["events"]},"get":{"operationId":"EventsController_getVotes","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["events"]}},"/api/events/{id}/share":{"post":{"operationId":"EventsController_recordShare","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"channel","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["events"]}},"/api/events/{id}/view":{"post":{"operationId":"EventsController_recordView","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"ref","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["events"]}},"/api/events/{id}/analytics":{"get":{"operationId":"EventsController_getAnalytics","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["events"]}},"/api/otp/request":{"post":{"operationId":"OtpController_request","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestOtpDto"}}}},"responses":{"200":{"description":""}},"tags":["otp"]}},"/api/otp/verify":{"post":{"operationId":"OtpController_verify","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyOtpDto"}}}},"responses":{"200":{"description":""}},"tags":["otp"]}}},"info":{"title":"Sportsplex API","description":"REST API for the Sportsplex platform — social network, live sports layer,\nfan marketplace, athlete economy, sponsor intelligence.\n\n**Auth**: bearer JWT, issued by `POST /auth/sign-in`. Send as\n`Authorization: Bearer <token>`. Tokens expire in 30 days.\n\n**Errors**: every non-2xx response is a JSON envelope:\n`{ error: { code, message, requestId, details? } }`. The same\n`requestId` is also returned in the `x-request-id` response header,\nand is what support uses to correlate with server logs.\n\n**Idempotency**: state-changing operations accept `Idempotency-Key`\nheader (UUID v4 recommended) to make retries safe.\n\n**Pagination**: list endpoints use cursor pagination —\n`{ items, nextCursor }`. Pass `?cursor=<token>` to fetch the next page.","version":"0.1.0","contact":{"name":"Sportsplex","url":"https://sportsplex.app","email":"isaac@kavodtechnologies.com"},"license":{"name":"UNLICENSED","url":"https://sportsplex.app/terms"}},"tags":[{"name":"auth","description":"Sign-in, sign-up, OAuth provisioning, password reset."},{"name":"users","description":"Profile, follow graph, settings."},{"name":"feed","description":"Posts, comments, likes, the ranked timeline."},{"name":"reels","description":"Pulse Reels — short/long-form sports video."},{"name":"matches","description":"Fixtures, events, live data."},{"name":"messages","description":"Live match chat."},{"name":"notifications","description":"In-app notifications."},{"name":"marketplace","description":"Service listings, bookings, escrow."},{"name":"subscriptions","description":"Athlete subscription tiers."},{"name":"tickets","description":"Tickets and seat holds."},{"name":"drops","description":"Limited-release club merch + collectibles."},{"name":"sponsor","description":"Brand campaigns, activations, intelligence."},{"name":"club","description":"Club operations dashboard."},{"name":"admin","description":"Staff-only moderation + audit."},{"name":"health","description":"Liveness + readiness probes."},{"name":"media","description":"Upload pipeline + transcoder webhooks."},{"name":"co-watch","description":"Synchronized watch parties (SSE)."},{"name":"live-reactions","description":"Floating-emoji reactions over reels (SSE)."}],"servers":[{"url":"https://api.sportsplex.app","description":"Production"}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"Sportsplex JWT issued by /auth/sign-in."}},"schemas":{"PushSubDto":{"type":"object","properties":{}},"UnsubDto":{"type":"object","properties":{}},"NotifPrefsDto":{"type":"object","properties":{}},"OptInDto":{"type":"object","properties":{}},"ErrorBodyDto":{"type":"object","properties":{"code":{"type":"string","example":"NOT_FOUND","description":"Stable, machine-readable error code (e.g. NOT_FOUND, RATE_LIMITED)."},"message":{"type":"string","example":"Match not found","description":"Human-readable description, safe to show end-users."},"requestId":{"type":"object","example":"57ac14a4-32dd-4cb7-b32b-d40812703f21","description":"Per-request correlation id. Always returned in the `x-request-id` response header too.","nullable":true},"details":{"type":"object","description":"Optional structured detail (e.g. validation field errors). Only present for 400/422."}},"required":["code","message","requestId"]},"ErrorEnvelopeDto":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorBodyDto"}},"required":["error"]},"SignUpDto":{"type":"object","properties":{"email":{"type":"string","example":"fan@sportsplex.app"},"username":{"type":"string","example":"fan_user","pattern":"^[a-z0-9_]{3,30}$"},"displayName":{"type":"string","example":"Bukayo Saka"},"password":{"type":"string","example":"A-strong-password-here-1","description":"Min 12 chars; must include at least one lowercase, uppercase and digit."},"primaryRole":{"type":"string","enum":["FAN","ATHLETE","TEAM","CLUB","ACADEMY","FEDERATION","LEAGUE","EVENT_ORGANISER","RIGHTS_HOLDER","COACH","SCOUT","AGENT","SERVICE_PROVIDER","SPONSOR","MEDIA","STADIUM"],"default":"FAN"},"referralCode":{"type":"string","example":"SAKA-AFC"},"acceptedTermsAt":{"type":"string","example":"2026-05-10T12:00:00.000Z"},"orgMeta":{"type":"object"}},"required":["email","username","displayName","password","primaryRole"]},"SignInDto":{"type":"object","properties":{"email":{"type":"string","example":"fan@sportsplex.app"},"password":{"type":"string","example":"a-strong-password-here"},"totpCode":{"type":"string","description":"6-digit TOTP code or 11-char recovery code (e.g. abcde-fghij). Required when the account has 2FA enabled."}},"required":["email","password"]},"OAuthProvisionDto":{"type":"object","properties":{"email":{"type":"string","example":"fan@sportsplex.app"},"displayName":{"type":"string","example":"Bukayo Saka"},"provider":{"type":"string","enum":["GOOGLE","APPLE","FACEBOOK"]},"avatarUrl":{"type":"string"},"providerId":{"type":"string","description":"Provider-side stable user id"}},"required":["email","displayName","provider"]},"RefreshTokenDto":{"type":"object","properties":{"refreshToken":{"type":"string","description":"Opaque refresh token issued at sign-in."}},"required":["refreshToken"]},"ForgotPasswordDto":{"type":"object","properties":{"email":{"type":"string","example":"fan@sportsplex.app"}},"required":["email"]},"ResetPasswordDto":{"type":"object","properties":{"token":{"type":"string","description":"Single-use reset token emailed to the user."},"password":{"type":"string","example":"A-strong-password-here-1"}},"required":["token","password"]},"ChangePasswordDto":{"type":"object","properties":{"currentPassword":{"type":"string","description":"Current password (re-auth check)."},"newPassword":{"type":"string","example":"A-new-strong-password-1"}},"required":["currentPassword","newPassword"]},"VerifyEmailDto":{"type":"object","properties":{"token":{"type":"string","description":"Single-use token emailed at sign-up."}},"required":["token"]},"TotpCodeDto":{"type":"object","properties":{"code":{"type":"string","example":"123456"}},"required":["code"]},"DisableTwoFactorDto":{"type":"object","properties":{"password":{"type":"string","description":"Current password — re-auth gate."}},"required":["password"]},"UpdateMeDto":{"type":"object","properties":{}},"BankDetailsDto":{"type":"object","properties":{}},"CreatePostDto":{"type":"object","properties":{}},"CreateCommentDto":{"type":"object","properties":{}},"CreateReportDto":{"type":"object","properties":{}},"IngestEventDto":{"type":"object","properties":{}},"CreateMessageDto":{"type":"object","properties":{}},"SubscribeDto":{"type":"object","properties":{}},"CreateServiceDto":{"type":"object","properties":{}},"CreateBookingDto":{"type":"object","properties":{}},"DisputeBookingDto":{"type":"object","properties":{}},"ImpressionDto":{"type":"object","properties":{}},"ViewDto":{"type":"object","properties":{}},"ClickDto":{"type":"object","properties":{}},"CreateAdUnitDto":{"type":"object","properties":{}},"ResolveReportDto":{"type":"object","properties":{}},"CreateTenantDto":{"type":"object","properties":{}},"UpdateTenantDto":{"type":"object","properties":{}},"StaffGrantDto":{"type":"object","properties":{}},"HoldTicketDto":{"type":"object","properties":{}},"CheckoutHoldDto":{"type":"object","properties":{}},"CreateDropDto":{"type":"object","properties":{}},"IssueAutographDto":{"type":"object","properties":{}},"CheckoutDropDto":{"type":"object","properties":{}},"MultipartCompleteDto":{"type":"object","properties":{}},"MultipartAbortDto":{"type":"object","properties":{}},"UploadInitDto":{"type":"object","properties":{}},"FinalizeReelDto":{"type":"object","properties":{}},"ReelViewDto":{"type":"object","properties":{}},"ReelInteractionDto":{"type":"object","properties":{}},"CreateReelCommentDto":{"type":"object","properties":{}},"LiftSoundDto":{"type":"object","properties":{}},"CreateChallengeDto":{"type":"object","properties":{}},"CreateTipDto":{"type":"object","properties":{}},"FloatingReactionDto":{"type":"object","properties":{}},"MatchReactionDto":{"type":"object","properties":{}},"CoWatchControlDto":{"type":"object","properties":{}},"CoWatchChatDto":{"type":"object","properties":{}},"CoWatchReactionDto":{"type":"object","properties":{}},"QAQuestionDto":{"type":"object","properties":{}},"CreateProductDto":{"type":"object","properties":{}},"UpdateProductDto":{"type":"object","properties":{}},"CreatePartnershipDto":{"type":"object","properties":{}},"CheckoutProductDto":{"type":"object","properties":{}},"CreateAffiliateCodeDto":{"type":"object","properties":{}},"UpdateAffiliateCodeDto":{"type":"object","properties":{}},"SubmitPredictionDto":{"type":"object","properties":{}},"ClaimTeamDto":{"type":"object","properties":{}},"CreateCommunityDto":{"type":"object","properties":{}},"UpdateCommunityDto":{"type":"object","properties":{}},"PromoteMemberDto":{"type":"object","properties":{}},"CreatePollDto":{"type":"object","properties":{}},"VoteDto":{"type":"object","properties":{}},"CheckInDto":{"type":"object","properties":{}},"CreateTournamentDto":{"type":"object","properties":{}},"EnterResultDto":{"type":"object","properties":{}},"RegisterDto":{"type":"object","properties":{}},"CreateMeetupDto":{"type":"object","properties":{}},"RsvpDto":{"type":"object","properties":{}},"CreatePodcastDto":{"type":"object","properties":{}},"UpdatePodcastDto":{"type":"object","properties":{}},"CreateEpisodeDto":{"type":"object","properties":{}},"StartConversationDto":{"type":"object","properties":{}},"SendMessageDto":{"type":"object","properties":{}},"CreateSeasonPassDto":{"type":"object","properties":{}},"PurchaseDto":{"type":"object","properties":{}},"CreateVoiceReactionDto":{"type":"object","properties":{}},"RespondDto":{"type":"object","properties":{}},"CreateEventDto":{"type":"object","properties":{}},"JoinEventDto":{"type":"object","properties":{}},"MotorsportVoteDto":{"type":"object","properties":{}},"RequestOtpDto":{"type":"object","properties":{}},"VerifyOtpDto":{"type":"object","properties":{}}}}}