{"openapi":"3.1.0","info":{"title":"crowdsource API","description":"Prediction-market competition platform. Authenticate with a Supabase JWT (`Authorization: Bearer …`) or an API key (`X-API-Key: cs_…`). Public read endpoints (health, summary, economic config, listing competitions) need no auth.","license":{"name":"proprietary"},"version":"0.1.0"},"paths":{"/health":{"get":{"tags":["health"],"summary":"Liveness probe.","operationId":"health","responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{}}}}}}},"/v1/admin/audit":{"get":{"tags":["admin"],"operationId":"list_audit","parameters":[{"name":"actor","in":"path","required":true,"schema":{"type":["string","null"],"format":"uuid"}},{"name":"action","in":"path","required":true,"schema":{"type":["string","null"]}},{"name":"target_id","in":"path","required":true,"schema":{"type":["string","null"],"format":"uuid"}},{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Paginated admin audit log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditResponse"}}}},"401":{"description":"Missing or invalid credentials"},"403":{"description":"Caller is not an admin"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/authz":{"get":{"tags":["config"],"summary":"Lightweight staff gate used by the admin UI's forward-auth (nginx\n`auth_request` → admin app `/__authz` → here). 200 iff the caller is a staff\nmember (admin/support/support_plus/audit); the `StaffUser` extractor returns\n401/403 otherwise. Individual admin endpoints restrict further by level — see\nPERMISSIONS.md.","operationId":"admin_authz","responses":{"200":{"description":"Caller is staff"},"401":{"description":"Missing or invalid credentials"},"403":{"description":"Caller is not staff"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/badges":{"get":{"tags":["admin"],"summary":"The full badge catalog — for the admin award picker.","operationId":"list_badge_defs","responses":{"200":{"description":"Badge definitions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BadgeDefView"}}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions":{"get":{"tags":["admin"],"operationId":"list_competitions","parameters":[{"name":"status","in":"path","required":true,"schema":{"type":["string","null"]}},{"name":"org_id","in":"path","required":true,"schema":{"type":["string","null"],"format":"uuid"}},{"name":"tag","in":"path","required":true,"schema":{"type":["string","null"]}},{"name":"q","in":"path","required":true,"schema":{"type":["string","null"]}},{"name":"taxonomy","in":"path","description":"Filter to one exact taxonomy (e.g. `coingecko.crypto.spot`).","required":true,"schema":{"type":["string","null"]}},{"name":"source","in":"path","description":"Filter to one source = first taxonomy segment (e.g. `coingecko`).","required":true,"schema":{"type":["string","null"]}},{"name":"paused","in":"path","description":"Filter by paused state.","required":true,"schema":{"type":["boolean","null"]}},{"name":"failing","in":"path","description":"Only competitions with a non-zero resolution-failure streak.","required":true,"schema":{"type":["boolean","null"]}},{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Competitions page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions/summary":{"get":{"tags":["admin"],"operationId":"competitions_summary","parameters":[{"name":"group_by","in":"path","description":"One of: taxonomy (default), source, status.","required":true,"schema":{"type":["string","null"]}},{"name":"sort","in":"path","description":"Sort column: total (default), taxonomy, running, paused, failing, scored, failed.","required":true,"schema":{"type":["string","null"]}},{"name":"dir","in":"path","description":"Sort direction: desc (default) or asc.","required":true,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Grouped competition counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SummaryResponse"}}}},"400":{"description":"Bad group_by"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions/{id}":{"delete":{"tags":["admin"],"operationId":"delete_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Competition deleted","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]},"patch":{"tags":["admin"],"operationId":"edit_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditBody"}}},"required":true},"responses":{"200":{"description":"Competition updated","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions/{id}/close":{"post":{"tags":["admin"],"operationId":"close_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Competition closed","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions/{id}/pause":{"post":{"tags":["admin"],"operationId":"pause_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Recurring family paused","content":{"application/json":{"schema":{}}}},"400":{"description":"Not a recurring competition"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions/{id}/resume":{"post":{"tags":["admin"],"operationId":"resume_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Recurring family resumed (and activated if it was a seeded draft)","content":{"application/json":{"schema":{}}}},"400":{"description":"Not a recurring competition"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions/{id}/transfer":{"post":{"tags":["admin"],"operationId":"transfer_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferBody"}}},"required":true},"responses":{"200":{"description":"Competition transferred","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/competitions/{id}/void":{"post":{"tags":["admin"],"operationId":"void_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoidBody"}}},"required":true},"responses":{"200":{"description":"Competition voided and refunded","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/config/economics":{"put":{"tags":["config"],"operationId":"put_economics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EconomicConfig"}}},"required":true},"responses":{"200":{"description":"Published new economic config version","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigResponse"}}}},"401":{"description":"Missing or invalid credentials"},"403":{"description":"Caller is not an admin"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/config/economics/history":{"get":{"tags":["config"],"summary":"`GET /v1/admin/config/economics/history` — published config versions\n(newest first) with provenance, for the admin console's audit / rollback view.","operationId":"economics_history","responses":{"200":{"description":"Published config versions, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EconomicConfigVersion"}}}}},"401":{"description":"Missing or invalid credentials"},"403":{"description":"Caller is not an admin"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/data-sources":{"get":{"tags":["admin"],"operationId":"list_data_sources","responses":{"200":{"description":"Data sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminDataSource"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/data-sources/{id}/disable":{"post":{"tags":["admin"],"operationId":"disable_data_source","parameters":[{"name":"id","in":"path","description":"Data source id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Data source disabled","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/data-sources/{id}/enable":{"post":{"tags":["admin"],"operationId":"enable_data_source","parameters":[{"name":"id","in":"path","description":"Data source id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Data source enabled","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/events":{"get":{"tags":["admin"],"operationId":"list_events","parameters":[{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Un-anonymized activity feed","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminEvent"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/reports":{"get":{"tags":["admin"],"operationId":"list_reports","parameters":[{"name":"status","in":"path","required":true,"schema":{"type":["string","null"]}},{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Reports page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Staff only"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/reports/{id}":{"get":{"tags":["admin"],"operationId":"get_report","parameters":[{"name":"id","in":"path","description":"Report id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Report detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportRow"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Staff only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/reports/{id}/resolve":{"post":{"tags":["admin"],"operationId":"resolve_report","parameters":[{"name":"id","in":"path","description":"Report id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveBody"}}},"required":true},"responses":{"200":{"description":"Report resolved","content":{"application/json":{"schema":{}}}},"401":{"description":"Unauthorized"},"403":{"description":"Moderator only"},"404":{"description":"Not found"},"409":{"description":"Already resolved / not actionable"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/stats":{"get":{"tags":["admin"],"operationId":"get_stats","responses":{"200":{"description":"Dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminStats"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users":{"get":{"tags":["admin"],"operationId":"list_users","parameters":[{"name":"q","in":"path","required":true,"schema":{"type":["string","null"]}},{"name":"is_admin","in":"path","required":true,"schema":{"type":["boolean","null"]}},{"name":"rank_tier","in":"path","required":true,"schema":{"type":["string","null"]}},{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"List of users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserListResponse"}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}":{"get":{"tags":["admin"],"operationId":"get_user","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetail"}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]},"patch":{"tags":["admin"],"operationId":"update_user","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUser"}}},"required":true},"responses":{"200":{"description":"Updated user detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetail"}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}/badges":{"get":{"tags":["admin"],"summary":"A user's earned badges (all sources).","operationId":"list_user_badges","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Earned badges","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserBadgeView"}}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]},"post":{"tags":["admin"],"summary":"Manually award a badge to a user (idempotent; keeps an existing award).","operationId":"award_badge","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AwardBadge"}}},"required":true},"responses":{"200":{"description":"Updated badge list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserBadgeView"}}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"User or badge not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}/badges/{slug}":{"delete":{"tags":["admin"],"summary":"Revoke a badge from a user (idempotent).","operationId":"revoke_badge","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"slug","in":"path","description":"Badge slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated badge list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserBadgeView"}}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}/ban":{"post":{"tags":["admin"],"operationId":"ban_user","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanBody"}}},"required":true},"responses":{"200":{"description":"User suspended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetail"}}}},"401":{"description":"Authentication required"},"403":{"description":"Moderator only"},"409":{"description":"User not found, deleted, or an admin"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}/credits":{"post":{"tags":["admin"],"operationId":"adjust_credits","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditAdjust"}}},"required":true},"responses":{"200":{"description":"Updated balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceResponse"}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}/ledger":{"get":{"tags":["admin"],"operationId":"get_ledger","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Credit ledger","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LedgerResponse"}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}/rank":{"patch":{"tags":["admin"],"operationId":"update_rank","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RankUpdate"}}},"required":true},"responses":{"200":{"description":"Updated rank","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RankResponse"}}}},"401":{"description":"Authentication required"},"403":{"description":"Admin only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/admin/users/{id}/unban":{"post":{"tags":["admin"],"operationId":"unban_user","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Suspension lifted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserDetail"}}}},"401":{"description":"Authentication required"},"403":{"description":"Moderator only"},"409":{"description":"User is not suspended"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/api-keys":{"get":{"tags":["api-keys"],"operationId":"list_api_keys","responses":{"200":{"description":"List of API keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]},"post":{"tags":["api-keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKey"}}},"required":true},"responses":{"201":{"description":"API key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Validation failed"},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/api-keys/{id}":{"delete":{"tags":["api-keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"API key deleted"},"401":{"description":"Authentication required"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions":{"get":{"tags":["competitions"],"summary":"GET /v1/competitions — list competitions with optional filters.","operationId":"list_competitions","parameters":[{"name":"status","in":"path","required":true,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CompetitionStatus"}]}},{"name":"type","in":"path","required":true,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CompetitionType"}]}},{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"mine","in":"path","description":"`\"true\"` to filter to competitions the caller has submitted to.","required":true,"schema":{"type":["string","null"]}},{"name":"hosted","in":"path","description":"`\"true\"` to filter to competitions hosted by the caller's org.","required":true,"schema":{"type":["string","null"]}},{"name":"needs_resolution","in":"path","description":"`\"true\"` to filter to the caller's org's closed competitions still awaiting\na manual resolution (closed, no oracle URL, no ground truth yet).","required":true,"schema":{"type":["string","null"]}},{"name":"tag","in":"path","description":"Filter to competitions carrying this tag.","required":true,"schema":{"type":["string","null"]}},{"name":"sort","in":"path","description":"Sort order: `created` (default, newest first), `ending` (soonest end\nfirst), `fee` (lowest submission fee first), `bounty` (largest bounty first).","required":true,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Matching competitions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListResponse"}}}}}},"post":{"tags":["competitions"],"summary":"POST /v1/competitions — create a new competition.","operationId":"create_competition","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCompetition"}}},"required":true},"responses":{"201":{"description":"Competition created (draft)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitionResponse"}}}},"400":{"description":"Validation failed"},"401":{"description":"Authentication required"},"403":{"description":"Creating competitions is gated off"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/free":{"get":{"tags":["competitions"],"summary":"GET /v1/competitions/free — the competition that is free to enter this hour.","operationId":"free_competition","responses":{"200":{"description":"The current free-to-enter competition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitionResponse"}}}},"404":{"description":"No free competition is open right now"}}}},"/v1/competitions/{id}":{"get":{"tags":["competitions"],"summary":"GET /v1/competitions/:id — get competition detail.","operationId":"get_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Competition detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitionResponse"}}}},"404":{"description":"Competition not found"}}},"patch":{"tags":["competitions"],"summary":"PATCH /v1/competitions/:id — update a draft competition.","operationId":"update_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCompetition"}}},"required":true},"responses":{"200":{"description":"Updated competition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitionResponse"}}}},"400":{"description":"Only draft competitions can be edited"},"401":{"description":"Authentication required"},"403":{"description":"Not the owner"},"404":{"description":"Competition not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/access":{"get":{"tags":["competitions"],"operationId":"list_access","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Access requests + grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AccessRow"}}}}},"401":{"description":"Authentication required"},"403":{"description":"Host only"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]},"post":{"tags":["competitions"],"operationId":"manage_access","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManageAccess"}}},"required":true},"responses":{"200":{"description":"Access updated"},"400":{"description":"Bad action"},"401":{"description":"Authentication required"},"403":{"description":"Host only"},"404":{"description":"Competition or user not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/access/request":{"post":{"tags":["competitions"],"operationId":"request_access","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"Access requested (pending host approval)"},"401":{"description":"Authentication required"},"403":{"description":"You host this competition"},"404":{"description":"Not found"},"409":{"description":"This competition doesn't accept access requests"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/close":{"post":{"tags":["competitions"],"summary":"POST /v1/competitions/:id/close — close a competition early.","operationId":"close_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitionResponse"}}}},"400":{"description":"Only open competitions can be closed"},"401":{"description":"Authentication required"},"403":{"description":"Not the owner"},"404":{"description":"Competition not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/ground-truth":{"post":{"tags":["competitions"],"summary":"POST /v1/competitions/:id/ground-truth — creator pushes ground truth data.","operationId":"push_ground_truth","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundTruthRequest"}}},"required":true},"responses":{"200":{"description":"Ground truth accepted; scoring triggered"},"401":{"description":"Authentication required"},"403":{"description":"Not the owner"},"404":{"description":"Competition not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/history":{"get":{"tags":["competitions"],"summary":"GET /v1/competitions/:id/history — prior resolved results for this competition's\nrecurring family (by `seed_key`, else by owner+title), oldest→newest, as a time\nseries. Non-recurring competitions just return their single resolved point.","operationId":"get_history","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"path","description":"Max points (most recent), 1–365. Default 60.","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Resolved history (oldest→newest)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HistoryPoint"}}}}},"404":{"description":"Competition not found"}}}},"/v1/competitions/{id}/index":{"get":{"tags":["competitions"],"operationId":"get_index","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"format","in":"path","description":"`csv` returns a `key,value` template (blank values) instead of JSON.","required":true,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Submission index (row keys) + target shape","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexResponse"}}}},"400":{"description":"Competition has no dataset spec / source unreadable"},"404":{"description":"Competition not found"}}}},"/v1/competitions/{id}/input-source":{"get":{"tags":["competitions"],"summary":"GET /v1/competitions/:id/input-source — the competition's public input data\nsource (what participants predict on). Public; never exposes the resolution\n(answer) source or any auth header. 404 when the competition has no input\nsource (e.g. single-value competitions).","operationId":"get_input_source","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Public input data source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicDataSource"}}}},"404":{"description":"Competition has no input source"}}}},"/v1/competitions/{id}/instances":{"get":{"tags":["competitions"],"summary":"GET /v1/competitions/:id/instances — previous cycles of this competition's\nrecurring series (same `series_id`), newest→oldest. Non-recurring\ncompetitions (no series) return an empty list. Public.","operationId":"list_instances","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"path","description":"Page size, 1–100. Default 10.","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","description":"Rows to skip. Default 0.","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Previous instances (newest first)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstancesResponse"}}}},"404":{"description":"Competition not found"}}}},"/v1/competitions/{id}/leaderboard":{"get":{"tags":["submissions"],"summary":"Public leaderboard for a competition. Ranked best-first once scored; while\nopen it lists current participants (score/rank null), ordered by submission\ntime. The caller's own row is flagged `is_you` when authenticated.","operationId":"leaderboard","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Leaderboard (ranked once scored)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardResponse"}}}},"404":{"description":"Competition not found"}}}},"/v1/competitions/{id}/publish":{"post":{"tags":["competitions"],"summary":"POST /v1/competitions/:id/publish — transition draft → open.","operationId":"publish_competition","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Published (draft → open)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompetitionResponse"}}}},"400":{"description":"Not a draft, or end_date is in the past"},"401":{"description":"Authentication required"},"403":{"description":"Not the owner"},"404":{"description":"Competition not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/resolution-file":{"post":{"tags":["competitions"],"summary":"POST /v1/competitions/:id/resolution-file — manual resolution by uploading a\nresults file (CSV/Excel/Parquet/JSON). The file is parsed in-memory into a\n`{index: target}` ground-truth map and discarded — it is never stored. The\nindex/target columns default to the competition's dataset spec; `index_column`\n/ `target_column` form fields override them. Same effect as pushing JSON\nground truth: stores the map, scores, and resolves the competition.","operationId":"resolution_file","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"description":"`file` (required) plus optional `index_column` / `target_column` / `format`","content":{"multipart/form-data":{}}},"responses":{"200":{"description":"Resolved and scored"},"400":{"description":"Bad file or missing column mapping"},"401":{"description":"Authentication required"},"403":{"description":"Not the owner"},"404":{"description":"Competition not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/series":{"patch":{"tags":["competitions"],"summary":"PATCH /v1/competitions/:id/series — edit the recurring competition's series\n(definition). Unlike the draft-only instance PATCH, this works on a live\nseries and applies to FUTURE cycles (each next cycle is materialized from the\nseries). The current open cycle is unchanged. Owner or admin only.","operationId":"update_series","parameters":[{"name":"id","in":"path","description":"Any competition in the series","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCompetition"}}},"required":true},"responses":{"200":{"description":"Updated series (applies to future cycles)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeriesResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Authentication required"},"403":{"description":"Not the owner"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/submissions":{"get":{"tags":["submissions"],"operationId":"list_competition_submissions","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Submissions (host org sees all; others see their own)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SubmissionResponse"}}}}},"401":{"description":"Authentication required"},"404":{"description":"Competition not found"}},"security":[{"bearer":[]},{"api_key":[]}]},"post":{"tags":["submissions"],"operationId":"create_submission","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubmission"}}},"required":true},"responses":{"201":{"description":"Submission recorded (fee charged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionResponse"}}}},"400":{"description":"Missing payload/s3_key or invalid"},"401":{"description":"Authentication required"},"403":{"description":"Rank too low, or submissions gated off"},"404":{"description":"Competition not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/competitions/{id}/submissions/retract":{"post":{"tags":["submissions"],"operationId":"retract_submission","parameters":[{"name":"id","in":"path","description":"Competition id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Entry retracted and fee refunded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetractResponse"}}}},"401":{"description":"Authentication required"},"404":{"description":"No active submission to retract"},"409":{"description":"Competition is not open"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/config/economics":{"get":{"tags":["config"],"operationId":"get_economics","responses":{"200":{"description":"Active economic config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigResponse"}}}}}}},"/v1/credits/checkout":{"post":{"tags":["credits"],"operationId":"create_checkout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}},"required":true},"responses":{"201":{"description":"Stripe Checkout session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"400":{"description":"amount_cents did not match an active credit pack"},"401":{"description":"Missing or invalid authentication"},"403":{"description":"Buying credits not enabled"},"500":{"description":"Stripe request failed"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/credits/gift":{"post":{"tags":["credits"],"summary":"Gift credits to another user by handle. The sender is debited and the\nrecipient credited as **earned** (non-refundable — gifts can't be cashed out).","operationId":"gift_credits","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftRequest"}}},"required":true},"responses":{"201":{"description":"Credits gifted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GiftResponse"}}}},"400":{"description":"Bad amount, self-gift, or insufficient balance"},"401":{"description":"Authentication required"},"404":{"description":"Recipient not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/data-sources":{"get":{"tags":["data-sources"],"operationId":"list_data_sources","parameters":[{"name":"limit","in":"path","description":"Page size (1–200). Omit to return all of the user's sources (e.g. pickers).","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","description":"Offset for pagination (default 0).","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"List of the authenticated user's data sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DataSourceResponse"}}}}},"401":{"description":"Missing or invalid authentication"}},"security":[{"bearer":[]},{"api_key":[]}]},"post":{"tags":["data-sources"],"operationId":"create_data_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDataSource"}}},"required":true},"responses":{"201":{"description":"Data source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataSourceResponse"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid authentication"},"403":{"description":"Data source registration not enabled"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/data-sources/{id}":{"get":{"tags":["data-sources"],"operationId":"get_data_source","parameters":[{"name":"id","in":"path","description":"Data source id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The requested data source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataSourceResponse"}}}},"401":{"description":"Missing or invalid authentication"},"404":{"description":"Data source not found"}},"security":[{"bearer":[]},{"api_key":[]}]},"delete":{"tags":["data-sources"],"operationId":"delete_data_source","parameters":[{"name":"id","in":"path","description":"Data source id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Data source deleted"},"401":{"description":"Missing or invalid authentication"},"404":{"description":"Data source not found"}},"security":[{"bearer":[]},{"api_key":[]}]},"patch":{"tags":["data-sources"],"operationId":"update_data_source","parameters":[{"name":"id","in":"path","description":"Data source id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDataSource"}}},"required":true},"responses":{"200":{"description":"The updated data source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataSourceResponse"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Missing or invalid authentication"},"404":{"description":"Data source not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/datasets/infer-schema":{"post":{"tags":["datasets"],"operationId":"infer_schema","requestBody":{"description":"A `file` part (CSV/CSV.gz/Excel/Parquet/JSON), or `url` + optional `auth_header`/`format` fields.","content":{"multipart/form-data":{}}},"responses":{"200":{"description":"Inferred schema + proposed dataset_spec","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InferResponse"}}}},"400":{"description":"Missing/unreadable input or unsupported format"},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/demo/random":{"get":{"tags":["demo"],"summary":"Demo random-number oracle. Returns `{ \"value\": N }` with N a uniform integer\nin `[min, max]` (defaults 0..=100). Intended as a \"dumb\" resolution source\nfor tutorial / test competitions: set the competition's `oracle_url` to this\nendpoint and `resolution_path` to `value`. The sweep fetches it once when the\ncompetition closes, so every entry is scored against the same drawn number.","operationId":"random","parameters":[{"name":"min","in":"path","description":"Inclusive lower bound (default 0).","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"max","in":"path","description":"Inclusive upper bound (default 100).","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"A random integer in [min, max]","content":{"application/json":{"schema":{}}}}}}},"/v1/events":{"get":{"tags":["events"],"summary":"GET /v1/events — public activity feed, newest first.","operationId":"get_events","parameters":[{"name":"limit","in":"path","description":"Max events to return (1–50, default 20).","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Public activity feed, newest first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}}}}},"/v1/leaderboards/global":{"get":{"tags":["leaderboards"],"summary":"Global aggregate leaderboard across scored competitions. Public (the caller's\nown row is flagged `is_you` when authenticated). Ranked by total normalized\npoints, best first.","operationId":"global","parameters":[{"name":"window","in":"path","description":"`7d`, `30d`, or `all` (default `all`).","required":true,"schema":{"type":["string","null"]}},{"name":"tier","in":"path","description":"Restrict to a single rank tier (bronze..master).","required":true,"schema":{"type":["string","null"]}},{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Global leaderboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalResponse"}}}}}}},"/v1/leaderboards/me":{"get":{"tags":["leaderboards"],"summary":"The authenticated user's standing — global rank, tier rank, headline stats,\nand a few nearby rows — for the home ranking card. Unranked (no eligible\nscored competitions) returns zeros with null ranks and `ranked = false`.","operationId":"me","parameters":[{"name":"window","in":"path","required":true,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Your leaderboard standing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me":{"get":{"tags":["me"],"operationId":"get_me","responses":{"200":{"description":"Current user profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]},"delete":{"tags":["me"],"operationId":"delete_me","responses":{"204":{"description":"Account deleted (anonymized) and login disabled"},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]},"patch":{"tags":["me"],"operationId":"patch_me","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMe"}}},"required":true},"responses":{"200":{"description":"Updated user profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"400":{"description":"Validation failed"},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/app-grant":{"post":{"tags":["me"],"operationId":"claim_app_grant","responses":{"200":{"description":"Install-bonus state after the claim","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppGrantResponse"}}}},"401":{"description":"Authentication required"},"403":{"description":"Not called from the mobile app"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/badges":{"get":{"tags":["me"],"summary":"The caller's earned badges (active definitions), best/rarest first. Unlike the\npublic `/v1/users/{handle}` badge list this is private — the owner always sees\ntheir own badges regardless of profile visibility.","operationId":"get_my_badges","responses":{"200":{"description":"The caller's earned badges","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MyBadge"}}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/credits":{"get":{"tags":["me"],"operationId":"get_credits","responses":{"200":{"description":"Credit balance and accounting summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsResponse"}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/preferences":{"get":{"tags":["me"],"operationId":"get_preferences","responses":{"200":{"description":"User preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferencesResponse"}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]},"patch":{"tags":["me"],"operationId":"patch_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferences"}}},"required":true},"responses":{"200":{"description":"Updated user preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreferencesResponse"}}}},"400":{"description":"Validation failed"},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/rank/down":{"post":{"tags":["me"],"operationId":"rank_down","responses":{"200":{"description":"Rank decreased","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RankTransitionResponse"}}}},"400":{"description":"Validation failed"},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/rank/up":{"post":{"tags":["me"],"operationId":"rank_up","responses":{"200":{"description":"Rank increased","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RankTransitionResponse"}}}},"400":{"description":"Validation failed"},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/streaks/daily":{"get":{"tags":["me"],"summary":"The caller's daily participation streak. Reads the sweep-maintained\n`user_streaks` cache and optimistically folds in a qualifying submission made\ntoday (so the count updates before the next sweep). Returns zeros with\n`enabled: false` when the feature is gated off.","operationId":"get_daily_streak","responses":{"200":{"description":"Daily streak state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyStreak"}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/me/submissions":{"get":{"tags":["submissions"],"operationId":"list_my_submissions","parameters":[{"name":"limit","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"offset","in":"path","required":true,"schema":{"type":["integer","null"],"format":"int64"}}],"responses":{"200":{"description":"Your submissions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SubmissionResponse"}}}}},"401":{"description":"Authentication required"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/orgs/{org_id}":{"get":{"tags":["orgs"],"operationId":"get_org","parameters":[{"name":"org_id","in":"path","description":"Organization ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Organization details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"401":{"description":"Authentication required"},"404":{"description":"Not found"}},"security":[{"bearer":[]},{"api_key":[]}]}},"/v1/summary":{"get":{"tags":["summary"],"operationId":"get_summary","responses":{"200":{"description":"Aggregate platform headline numbers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SummaryResponse"}}}}}}},"/v1/users/{handle}":{"get":{"tags":["users"],"summary":"Public profile by handle. No auth required — public fields only.","operationId":"get_profile","parameters":[{"name":"handle","in":"path","description":"The user's public handle","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Public profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicProfile"}}}},"404":{"description":"No such profile"}}}},"/v1/version":{"get":{"tags":["health"],"summary":"Build/version and dependency connectivity.","operationId":"version","responses":{"200":{"description":"Version + dependency status","content":{"application/json":{"schema":{}}}}}}},"/webhooks/stripe":{"post":{"tags":["webhooks"],"operationId":"stripe_webhook","requestBody":{"description":"Raw Stripe event payload (HMAC-verified via Stripe-Signature header)","content":{"text/plain":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Acknowledged"},"400":{"description":"Invalid signature or payload"}}}}},"components":{"schemas":{"AccessMode":{"type":"string","description":"How users may join a competition. See migration 20260703000002.","enum":["public","restricted","invite"]},"AccessRow":{"type":"object","required":["user_id","status","created_at"],"properties":{"created_at":{"type":"string"},"display_name":{"type":["string","null"]},"handle":{"type":["string","null"]},"status":{"type":"string"},"user_id":{"type":"string"}}},"AdminCompetitionRow":{"type":"object","required":["id","org_id","title","status","competition_type","bounty_amount","submission_fee","owner_email","participant_count","end_date","created_at","paused","resolution_failures"],"properties":{"bounty_amount":{"type":"integer","format":"int64"},"competition_type":{"$ref":"#/components/schemas/CompetitionType"},"created_at":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"failure_reason":{"type":["string","null"]},"id":{"type":"string","format":"uuid"},"last_resolution_at":{"type":["string","null"],"format":"date-time"},"last_resolution_error":{"type":["string","null"]},"org_id":{"type":"string","format":"uuid"},"owner_email":{"type":"string"},"participant_count":{"type":"integer","format":"int64"},"paused":{"type":"boolean"},"recurring_interval":{"type":["string","null"]},"resolution_failures":{"type":"integer","format":"int32"},"seed_key":{"type":["string","null"]},"status":{"$ref":"#/components/schemas/CompetitionStatus"},"submission_fee":{"type":"integer","format":"int64"},"taxonomy":{"type":["string","null"]},"title":{"type":"string"}}},"AdminDataSource":{"type":"object","required":["id","name","url","http_method","enabled","org_id","owner_email","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"enabled":{"type":"boolean"},"http_method":{"type":"string"},"id":{"type":"string","format":"uuid"},"last_probe":{},"name":{"type":"string"},"org_id":{"type":"string","format":"uuid"},"owner_email":{"type":"string"},"url":{"type":"string"}}},"AdminEvent":{"type":"object","required":["kind","ts"],"properties":{"amount":{"type":["integer","null"],"format":"int64"},"competition_id":{"type":["string","null"],"format":"uuid"},"handle":{"type":["string","null"],"description":"Real email of the actor (un-anonymized), or null."},"kind":{"type":"string"},"title":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"AdminStats":{"type":"object","required":["users_total","competitions_total","competitions_draft","competitions_open","competitions_closed","competitions_scoring","competitions_scored","competitions_failed","active_bounties","escrow_held","submissions_today","submissions_total","predictors","credits_paid","revenue_cents","data_sources_total"],"properties":{"active_bounties":{"type":"integer","format":"int64"},"competitions_closed":{"type":"integer","format":"int64"},"competitions_draft":{"type":"integer","format":"int64"},"competitions_failed":{"type":"integer","format":"int64"},"competitions_open":{"type":"integer","format":"int64"},"competitions_scored":{"type":"integer","format":"int64"},"competitions_scoring":{"type":"integer","format":"int64"},"competitions_total":{"type":"integer","format":"int64"},"credits_paid":{"type":"integer","format":"int64"},"data_sources_total":{"type":"integer","format":"int64"},"escrow_held":{"type":"integer","format":"int64"},"predictors":{"type":"integer","format":"int64"},"revenue_cents":{"type":"integer","format":"int64"},"submissions_today":{"type":"integer","format":"int64"},"submissions_total":{"type":"integer","format":"int64"},"users_total":{"type":"integer","format":"int64"}}},"AdminUserDetail":{"type":"object","required":["id","email","org_id","org_name","user_level","is_admin","approved","rank_tier","rank_level","balance","competitions_hosted","submissions_made","created_at","updated_at"],"properties":{"allow_create_competition":{"type":["boolean","null"]},"allow_create_dataset":{"type":["boolean","null"]},"allow_submit":{"type":["boolean","null"]},"approved":{"type":"boolean"},"avatar_url":{"type":["string","null"]},"balance":{"type":"integer","format":"int64"},"ban_reason":{"type":["string","null"]},"banned_at":{"type":["string","null"],"format":"date-time","description":"Set when the account is suspended (banned)."},"competitions_hosted":{"type":"integer","format":"int64"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":["string","null"]},"email":{"type":"string"},"handle":{"type":["string","null"]},"id":{"type":"string","format":"uuid"},"is_admin":{"type":"boolean"},"org_id":{"type":"string","format":"uuid"},"org_name":{"type":"string"},"rank_level":{"type":"integer","format":"int32"},"rank_tier":{"$ref":"#/components/schemas/RankTier"},"submissions_made":{"type":"integer","format":"int64"},"updated_at":{"type":"string","format":"date-time"},"user_level":{"$ref":"#/components/schemas/UserLevel"}}},"AdminUserRow":{"type":"object","description":"A user row with its derived credit balance.","required":["id","email","org_id","user_level","is_admin","rank_tier","rank_level","created_at","balance"],"properties":{"balance":{"type":"integer","format":"int64"},"created_at":{"type":"string","format":"date-time"},"display_name":{"type":["string","null"]},"email":{"type":"string"},"id":{"type":"string","format":"uuid"},"is_admin":{"type":"boolean"},"org_id":{"type":"string","format":"uuid"},"rank_level":{"type":"integer","format":"int32"},"rank_tier":{"$ref":"#/components/schemas/RankTier"},"user_level":{"$ref":"#/components/schemas/UserLevel"}}},"ApiKeyResponse":{"type":"object","required":["id","name","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"last_used_at":{"type":["string","null"]},"name":{"type":"string"}}},"AppGrantResponse":{"type":"object","description":"Response to an install-bonus claim.","required":["granted","already_claimed","balance"],"properties":{"already_claimed":{"type":"boolean","description":"True when the user had already claimed the install bonus before this call."},"balance":{"type":"integer","format":"int64","description":"The user's credit balance after the call."},"granted":{"type":"integer","format":"int64","description":"Credits granted by *this* call (0 if already claimed, or the grant is off)."}}},"AuditEntry":{"type":"object","required":["id","actor_user_id","action","target_type","summary","created_at"],"properties":{"action":{"type":"string"},"actor_user_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"summary":{},"target_id":{"type":["string","null"],"format":"uuid"},"target_type":{"type":"string"}}},"AuditResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AuditEntry"}},"total":{"type":"integer","format":"int64"}}},"AwardBadge":{"type":"object","required":["slug"],"properties":{"note":{"type":["string","null"],"description":"Optional reason, stored on the award and in the audit log."},"slug":{"type":"string","description":"Badge slug from the catalog (`GET /v1/admin/badges`)."}}},"BadgeDefView":{"type":"object","required":["id","slug","name","description","icon","category","rarity","sort_order","active"],"properties":{"active":{"type":"boolean"},"category":{"type":"string"},"criteria":{"description":"Automatic-award rule; null = manual-only."},"description":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"rarity":{"type":"string"},"slug":{"type":"string"},"sort_order":{"type":"integer","format":"int32"}}},"BalanceResponse":{"type":"object","required":["balance","delta"],"properties":{"balance":{"type":"integer","format":"int64"},"delta":{"type":"integer","format":"int64"}}},"BanBody":{"type":"object","properties":{"reason":{"type":["string","null"],"description":"Optional reason, surfaced to the suspended user."}}},"BountyMode":{"type":"string","enum":["top_n_equal","top_n_weighted"]},"Capabilities":{"type":"object","description":"Effective (resolved) answers for each gated write, for the current user. The\nsite uses these to show/hide controls without re-deriving the rules. See\nPERMISSIONS.md.","required":["create_competition","create_dataset","submit","buy_credits"],"properties":{"buy_credits":{"type":"boolean"},"create_competition":{"type":"boolean"},"create_dataset":{"type":"boolean"},"submit":{"type":"boolean"}}},"CheckoutRequest":{"type":"object","required":["amount_cents"],"properties":{"amount_cents":{"type":"integer","format":"int64","description":"Price to charge in USD cents — must match one of the active credit packs."}}},"CheckoutResponse":{"type":"object","required":["checkout_url"],"properties":{"checkout_url":{"type":"string"}}},"ColumnInfo":{"type":"object","required":["name","type","nullable","unique","distinct"],"properties":{"distinct":{"type":"integer","minimum":0},"enum_values":{"type":["array","null"],"items":{"type":"string"},"description":"Present for `enum` columns — the observed value set."},"name":{"type":"string"},"nullable":{"type":"boolean"},"type":{"$ref":"#/components/schemas/ColumnType"},"unique":{"type":"boolean","description":"All non-null sampled values distinct (an index/key candidate)."}}},"ColumnType":{"type":"string","enum":["integer","number","boolean","enum","string"]},"CompetitionMetric":{"type":"string","enum":["accuracy","f1_macro","rmse","mae","r2"]},"CompetitionResponse":{"type":"object","required":["id","org_id","title","description","competition_type","metric","status","bounty_amount","bounty_mode","bounty_top_n","min_rank","submission_fee","end_date","show_host","access_mode","unlisted","close_window_seconds","created_at","updated_at"],"properties":{"access_mode":{"$ref":"#/components/schemas/AccessMode","description":"How users join: public, restricted (request+approve), or invite."},"bounty_amount":{"type":"integer","format":"int64"},"bounty_mode":{"$ref":"#/components/schemas/BountyMode"},"bounty_top_n":{"type":"integer","format":"int32"},"bounty_weights":{},"close_window_seconds":{"type":"integer","format":"int32","description":"Reject submissions within this many seconds of `end_date` (0 = none)."},"competition_type":{"$ref":"#/components/schemas/CompetitionType"},"created_at":{"type":"string"},"dataset_schema":{},"description":{"type":"string"},"end_date":{"type":"string"},"failure_reason":{"type":["string","null"],"description":"Why a `scoring_failed` competition was voided: `no_participation` |\n`threshold` | `oracle_error` | `market_closed`. Absent otherwise."},"host":{"type":["string","null"],"description":"The organizer's display name — present only when `show_host` is true."},"id":{"type":"string"},"input_source_id":{"type":["string","null"]},"metric":{"$ref":"#/components/schemas/CompetitionMetric"},"min_participants":{"type":["integer","null"],"format":"int32"},"min_rank":{"$ref":"#/components/schemas/RankTier"},"min_score":{"type":["number","null"],"format":"double"},"my_access":{"type":["string","null"],"description":"The caller's access relationship to a non-public competition:\n`owner` | `requested` | `approved` | `invited` | `denied` (absent = none)."},"org_id":{"type":"string"},"participant_count":{"type":["integer","null"],"format":"int32","description":"Scored participant count, stamped at resolution (present once resolved)."},"recurring_close_time":{"type":["string","null"]},"recurring_end_date":{"type":["string","null"]},"recurring_interval":{"type":["string","null"]},"recurring_start_date":{"type":["string","null"]},"recurring_timezone":{"type":["string","null"]},"resolution_offset_minutes":{"type":["integer","null"],"format":"int32"},"resolution_source_id":{"type":["string","null"]},"series_id":{"type":["string","null"],"description":"Stable id shared by all cycles of a recurring competition (absent for one-offs)."},"show_host":{"type":"boolean","description":"Whether to credit the organizer on the competition page."},"status":{"$ref":"#/components/schemas/CompetitionStatus"},"submission_fee":{"type":"integer","format":"int64"},"tags":{"type":"array","items":{"type":"string"}},"title":{"type":"string"},"unlisted":{"type":"boolean","description":"Hidden from browse / get-by-id for non-owner/non-invited."},"updated_at":{"type":"string"}}},"CompetitionStatus":{"type":"string","enum":["draft","open","closed","scoring","scored","scoring_failed"]},"CompetitionType":{"type":"string","enum":["classification","regression"]},"ConfigResponse":{"type":"object","required":["version","config"],"properties":{"config":{"$ref":"#/components/schemas/EconomicConfig"},"version":{"type":"integer","format":"int64"}}},"CreateApiKey":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","secret","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"secret":{"type":"string"}}},"CreateCompetition":{"type":"object","required":["title","competition_type","metric","bounty_amount","bounty_mode","bounty_top_n","end_date"],"properties":{"access_mode":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AccessMode","description":"Join mode: public (default), restricted (request+approve), or invite."}]},"bounty_amount":{"type":"integer","format":"int64"},"bounty_mode":{"$ref":"#/components/schemas/BountyMode"},"bounty_top_n":{"type":"integer","format":"int32"},"bounty_weights":{},"close_window_seconds":{"type":["integer","null"],"format":"int32","description":"Reject submissions within this many seconds of `end_date` (0 = none)."},"competition_type":{"$ref":"#/components/schemas/CompetitionType"},"dataset_schema":{},"description":{"type":["string","null"]},"end_date":{"type":"string","format":"date-time"},"input_source_id":{"type":["string","null"],"format":"uuid"},"metric":{"$ref":"#/components/schemas/CompetitionMetric"},"min_participants":{"type":["integer","null"],"format":"int32","description":"Creator-set void thresholds (optional). If unmet at scoring, the\ncompetition is voided and fully refunded."},"min_rank":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RankTier","description":"Minimum rank to participate; also selects submission fee + min bounty.\nDefaults to `bronze` (open to all). Master is not allowed."}]},"min_score":{"type":["number","null"],"format":"double"},"oracle_auth_header":{"type":["string","null"]},"oracle_body":{"type":["string","null"],"description":"POST body (form-urlencoded) when `oracle_method` is `POST`."},"oracle_method":{"type":["string","null"],"description":"Oracle HTTP method: `GET` (default) or `POST`."},"oracle_url":{"type":["string","null"]},"recurring_close_time":{"type":["string","null"]},"recurring_end_date":{"type":["string","null"],"format":"date-time"},"recurring_interval":{"type":["string","null"]},"recurring_start_date":{"type":["string","null"],"format":"date-time"},"recurring_timezone":{"type":["string","null"]},"resolution_offset_minutes":{"type":["integer","null"],"format":"int32"},"resolution_source_id":{"type":["string","null"],"format":"uuid"},"show_host":{"type":["boolean","null"],"description":"Show the organizer's display name on the competition page. Defaults false."},"tags":{"type":["array","null"],"items":{"type":"string"}},"title":{"type":"string"},"unlisted":{"type":["boolean","null"],"description":"Hide from browse / get-by-id (private). Only meaningful for non-public."}}},"CreateDataSource":{"type":"object","required":["name","url"],"properties":{"auth_header":{"type":["string","null"]},"compatible_types":{"type":["array","null"],"items":{"type":"string"}},"description":{"type":["string","null"]},"http_method":{"type":["string","null"]},"name":{"type":"string"},"openapi_path":{"type":["string","null"]},"roles":{"type":["array","null"],"items":{"type":"string"}},"schema_format":{"type":["string","null"]},"schema_text":{"type":["string","null"]},"url":{"type":"string"}}},"CreateSubmission":{"type":"object","properties":{"payload":{"description":"Inline prediction payload (a JSON object keyed by row id). The scorer\nreads this directly; no object storage needed."},"s3_key":{"type":["string","null"],"description":"Opaque storage key; caller uploads the payload out of band. Optional —\nprovide an inline `payload` instead for short/seeded competitions."}}},"CreationFees":{"type":"object","description":"Per-competition-type creation fees, in credits.","required":["classification","regression"],"properties":{"classification":{"type":"integer","format":"int64"},"regression":{"type":"integer","format":"int64"}}},"CreditAdjust":{"type":"object","required":["amount"],"properties":{"amount":{"type":"integer","format":"int64"},"note":{"type":["string","null"]}}},"CreditPack":{"type":"object","description":"A purchasable credit pack: pay `price_cents`, receive `credits_granted`\n(bonus baked in).","required":["price_cents","credits_granted"],"properties":{"credits_granted":{"type":"integer","format":"int64"},"price_cents":{"type":"integer","format":"int64"}}},"CreditsResponse":{"type":"object","required":["balance","purchased_total","earned_total","fees_paid","rank_spent","purchased_remaining","refundable_cents"],"properties":{"balance":{"type":"integer","format":"int64"},"earned_total":{"type":"integer","format":"int64"},"fees_paid":{"type":"integer","format":"int64","description":"Credits spent on platform fees: submission fees + hosting (creation) fees.\nExcludes escrowed bounty (held, not a fee) and rank spend."},"purchased_remaining":{"type":"integer","format":"int64","description":"Purchased credits not yet consumed (non-purchase credits spend first)."},"purchased_total":{"type":"integer","format":"int64"},"rank_spent":{"type":"integer","format":"int64","description":"Net credits invested in rank: rank-up spend minus rank-down refunds."},"refundable_cents":{"type":"integer","format":"int64","description":"Cash value of unused purchased credits, in USD cents (the refundable amount)."}}},"DailyStreak":{"type":"object","required":["enabled","current","longest","today_complete"],"properties":{"current":{"type":"integer","format":"int32","description":"Current consecutive-day streak (optimistically includes today)."},"enabled":{"type":"boolean","description":"Whether the streaks feature is enabled (`gates.streaks`)."},"last_qualified_date":{"type":["string","null"]},"longest":{"type":"integer","format":"int32","description":"Longest consecutive-day streak ever."},"next_milestone":{"type":["integer","null"],"format":"int32","description":"Next milestone day-count above `current` (from the config), if any."},"today_complete":{"type":"boolean","description":"True once today has a qualifying submission."}}},"DataSourceResponse":{"type":"object","required":["id","name","description","url","http_method","roles","compatible_types","created_at","updated_at"],"properties":{"auth_header":{"type":["string","null"]},"compatible_types":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string"},"description":{"type":"string"},"http_method":{"type":"string"},"id":{"type":"string"},"last_probe":{},"name":{"type":"string"},"openapi_path":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"schema_format":{"type":["string","null"]},"schema_text":{"type":["string","null"]},"updated_at":{"type":"string"},"url":{"type":"string"}}},"EconomicConfig":{"type":"object","required":["nominal_cents_per_credit","credit_packs","submission_fee_default","creation_fees","rank"],"properties":{"app_install_grant_credits":{"type":"integer","format":"int64","description":"One-time bonus for installing the mobile app (claimed via\n`POST /v1/me/app-grant`). 0 = no grant. Stacks on top of the signup grant."},"creation_fee_by_tier":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TierCreationFees","description":"Per-`min_rank` creation fee (each tier keeps the per-type split). When\npresent it takes precedence over `creation_fees`. `serde(default)` (None)\nso older rows fall back to `creation_fees`."}]},"creation_fees":{"$ref":"#/components/schemas/CreationFees","description":"Legacy/base per-type creation fee. Kept as the fallback for config rows\npublished before `creation_fee_by_tier` existed."},"credit_packs":{"type":"array","items":{"$ref":"#/components/schemas/CreditPack"}},"featured_tags":{"type":"array","items":{"type":"string"},"description":"Curated tags for the homepage \"Live Competitions\" filter tabs (the UI\nalways prepends \"ALL\"). Admin-editable; lowercase to match competition tags."},"gates":{"$ref":"#/components/schemas/Gates","description":"Per-capability rollout gates. `serde(default)` so older config rows load\nwith everything-on (shipped) / everything-off (to-do)."},"min_bounty_by_tier":{"$ref":"#/components/schemas/TierAmounts","description":"Per-`min_rank` minimum bounty enforced at competition creation."},"nominal_cents_per_credit":{"type":"integer","format":"int64","description":"Display-only nominal rate (e.g. 1 → \"$1 = 100 credits\"). Actual value is\nexpressed through `credit_packs`."},"rank":{"$ref":"#/components/schemas/RankEconomics"},"referral_grant_credits":{"type":"integer","format":"int64","description":"One-time referral bonus paid to BOTH the referrer and the new invitee when\na user signs up with a valid referral code. 0 = referrals off."},"require_purchased_credits_to_create":{"type":"boolean","description":"Require purchased credits (not earned/awarded) to create a competition."},"require_user_approval":{"type":"boolean","description":"Gate all non-admin participation writes on per-user `approved` (PERMISSIONS.md)."},"signup_grant_credits":{"type":"integer","format":"int64","description":"One-time welcome credits granted to a newly provisioned (verified) account.\n0 = no grant. Funds Phase 1–2 participation before buying is enabled."},"streaks":{"$ref":"#/components/schemas/StreaksConfig"},"submission_fee_by_tier":{"$ref":"#/components/schemas/TierAmounts","description":"Per-`min_rank` submission fee. `serde(default)` so older config rows\n(without this field) still load with sensible values."},"submission_fee_default":{"type":"integer","format":"int64","description":"Baseline submission fee (the bronze tier). Kept for generic display;\nactual competition fees come from `submission_fee_by_tier` via `min_rank`."},"tier_gates":{"$ref":"#/components/schemas/TierGates","description":"Minimum rank tiers for tier-gated features (the \"rank up to unlock\" nudge).\n`serde(default)` so older config rows load with the default thresholds."}}},"EconomicConfigVersion":{"type":"object","description":"One published economic-config version's provenance (no config body) — the\nadmin audit / rollback list.","required":["version","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"created_by":{"type":["string","null"],"format":"uuid"},"version":{"type":"integer","format":"int64"}}},"EditBody":{"type":"object","properties":{"bounty_amount":{"type":["integer","null"],"format":"int64"},"description":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"min_participants":{"type":["integer","null"],"format":"int32"},"min_score":{"type":["number","null"],"format":"double"},"submission_fee":{"type":["integer","null"],"format":"int64"},"tags":{"type":["array","null"],"items":{"type":"string"}},"title":{"type":["string","null"]}}},"Event":{"type":"object","required":["kind","ts"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Bounty (for `competition_opened`) or payout (for `win`), in credits."},"competition_id":{"type":["string","null"],"description":"Competition id, when applicable."},"handle":{"type":["string","null"],"description":"Anonymized actor handle, or null (e.g. for `competition_opened`)."},"kind":{"type":"string","description":"One of `competition_opened`, `win`, `rank_up`, `submission`."},"title":{"type":["string","null"],"description":"Competition title, when applicable."},"ts":{"type":"string","description":"Event timestamp (RFC 3339)."}}},"EventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}}},"Gates":{"type":"object","description":"Per-capability rollout gates (gated launch). Shipped capabilities default ON,\nso adding this block doesn't change today's open dev/prod; not-yet-shipped\nfeatures default OFF (gated until built). Admin-editable via the economic\nconfig; the four launch phases (readonly → submit → create → buy) are presets\nover these flags. Each is enforced server-side and reflected in the site UI.","properties":{"api_keys":{"type":"boolean","description":"Create API keys."},"buy_credits":{"type":"boolean","description":"Purchase credits (Stripe checkout)."},"competitions":{"type":"boolean","description":"Create competitions."},"data_sources":{"type":"boolean","description":"Register data sources (oracle URLs)."},"datasets":{"type":"boolean","description":"Static dataset (S3) uploads — not built yet."},"rank_up":{"type":"boolean","description":"Spend credits to rank up."},"registration":{"type":"boolean","description":"Auto-provision new accounts on first login."},"streaks":{"type":"boolean","description":"Daily participation streaks (home card + streak badges)."},"submissions":{"type":"boolean","description":"Submit predictions to competitions."},"two_factor":{"type":"boolean","description":"TOTP / two-factor auth enrollment — not built yet."}}},"GiftRequest":{"type":"object","required":["recipient_handle","amount"],"properties":{"amount":{"type":"integer","format":"int64","description":"Credits to send — must be > 0 and within your balance."},"message":{"type":["string","null"],"description":"Optional message shown to the recipient (≤ 280 characters)."},"recipient_handle":{"type":"string","description":"Recipient's public handle (with or without a leading `@`)."}}},"GiftResponse":{"type":"object","required":["recipient_handle","amount","balance"],"properties":{"amount":{"type":"integer","format":"int64"},"balance":{"type":"integer","format":"int64","description":"The sender's balance after the gift."},"recipient_handle":{"type":"string"}}},"GlobalEntry":{"type":"object","required":["rank","handle","tier","tier_level","points","scored_count","win_count","top3_count","avg_percentile","is_you","provisional"],"properties":{"avg_percentile":{"type":"number","format":"double","description":"Average normalized points per scored competition (0..100)."},"handle":{"type":"string","description":"Anonymized, stable per-user handle (derived from the user id)."},"is_you":{"type":"boolean","description":"True for the calling user's own row (when authenticated)."},"points":{"type":"number","format":"double","description":"Sum of normalized points across eligible scored competitions."},"provisional":{"type":"boolean","description":"True while the user has fewer than the eligibility threshold of scored\ncompetitions — ranked, but not yet established."},"rank":{"type":"integer","format":"int64","description":"1-based position in this leaderboard page."},"scored_count":{"type":"integer","format":"int64","description":"Number of eligible scored competitions the user appears in."},"tier":{"type":"string","description":"Current rank tier (bronze..master)."},"tier_level":{"type":"integer","format":"int32","description":"Sub-level within the tier (1 highest .. 4 lowest)."},"top3_count":{"type":"integer","format":"int64","description":"Top-3 finishes."},"win_count":{"type":"integer","format":"int64","description":"First-place finishes."}}},"GlobalResponse":{"type":"object","required":["window","total","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/GlobalEntry"}},"tier":{"type":["string","null"],"description":"Tier filter applied, if any."},"total":{"type":"integer","format":"int64","description":"Total ranked users in scope (for pagination)."},"window":{"type":"string","description":"Echoes the requested window (`7d`, `30d`, `all`)."}}},"GroundTruthRequest":{"type":"object","required":["data"],"properties":{"data":{}}},"HistoryPoint":{"type":"object","required":["end_date","value"],"properties":{"end_date":{"type":"string","format":"date-time"},"value":{"description":"The resolved ground-truth `value` for that cycle (the number forecast)."}}},"IndexResponse":{"type":"object","description":"The set of row keys a submission must predict, plus the target shape. For a\n`fixed` index these are the stored keys; for a `dynamic` index they're fetched\nlive from the input source and extracted from the index column. Never exposes\nthe resolution source or any answers.","required":["index_column","mode","target_kind","count","keys"],"properties":{"classes":{"type":["array","null"],"items":{"type":"string"}},"count":{"type":"integer","minimum":0},"index_column":{"type":"string"},"keys":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","description":"\"fixed\" or \"dynamic\"."},"target_kind":{"type":"string","description":"\"number\" (regression) or \"class\" (classification)."}}},"InferResponse":{"type":"object","required":["format","inferred","proposed_spec","index_keys"],"properties":{"format":{"$ref":"#/components/schemas/TabularFormat","description":"Detected (or supplied) source format."},"index_keys":{"type":"object","description":"Distinct values for each index-candidate column (capped) — lets the UI\nstore keys for a small \"fixed\" index without re-uploading."},"inferred":{"$ref":"#/components/schemas/Inferred","description":"Inferred columns, index/target candidates, sample, and row count."},"proposed_spec":{"type":"object","description":"A proposed `dataset_spec` (canonical schema) the creator can edit."}}},"Inferred":{"type":"object","required":["columns","index_candidates","target_candidates","row_count","sample"],"properties":{"columns":{"type":"array","items":{"$ref":"#/components/schemas/ColumnInfo"}},"index_candidates":{"type":"array","items":{"type":"string"},"description":"Unique key columns (string or integer) — submission keys."},"row_count":{"type":"integer","minimum":0},"sample":{"type":"array","items":{"type":"object"},"description":"First few rows as objects, for a UI preview."},"target_candidates":{"type":"array","items":{"type":"string"},"description":"Numeric (regression) or low-cardinality (classification) columns."}}},"InstanceRow":{"type":"object","required":["id","end_date","status","bounty_amount"],"properties":{"bounty_amount":{"type":"integer","format":"int64"},"end_date":{"type":"string"},"id":{"type":"string"},"participant_count":{"type":["integer","null"],"format":"int32","description":"Scored participant count (present once resolved)."},"status":{"$ref":"#/components/schemas/CompetitionStatus"}}},"InstancesResponse":{"type":"object","required":["instances","total","limit","offset"],"properties":{"instances":{"type":"array","items":{"$ref":"#/components/schemas/InstanceRow"}},"limit":{"type":"integer","format":"int64"},"offset":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"LeaderboardEntry":{"type":"object","required":["handle","is_you","submitted_at"],"properties":{"handle":{"type":"string","description":"Anonymized, stable per-user handle (derived from the user id)."},"is_you":{"type":"boolean","description":"True for the calling user's own row (when authenticated)."},"payout":{"type":["integer","null"],"format":"int64"},"rank":{"type":["integer","null"],"format":"int32","description":"1-based rank once scored; null while the competition is still open."},"score":{"type":["number","null"],"format":"double"},"submitted_at":{"type":"string"}}},"LeaderboardResponse":{"type":"object","required":["competition_id","status","total","entries"],"properties":{"competition_id":{"type":"string"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/LeaderboardEntry"}},"status":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"LedgerEntry":{"type":"object","required":["id","amount","source","reason","created_at"],"properties":{"amount":{"type":"integer","format":"int64"},"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"note":{"type":["string","null"]},"reason":{"type":"string"},"reference_id":{"type":["string","null"],"format":"uuid"},"source":{"type":"string"},"usd_cents":{"type":["integer","null"],"format":"int64"}}},"LedgerResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LedgerEntry"}},"total":{"type":"integer","format":"int64"}}},"LevelUpCost":{"type":"object","description":"Credits to move up one rung *within* the named source tier.","required":["bronze","silver","gold","platinum","diamond"],"properties":{"bronze":{"type":"integer","format":"int64"},"diamond":{"type":"integer","format":"int64"},"gold":{"type":"integer","format":"int64"},"platinum":{"type":"integer","format":"int64"},"silver":{"type":"integer","format":"int64"}}},"ListResponse":{"type":"object","required":["competitions","total"],"properties":{"competitions":{"type":"array","items":{"$ref":"#/components/schemas/CompetitionResponse"}},"total":{"type":"integer","format":"int64"}}},"ManageAccess":{"type":"object","required":["handle","action"],"properties":{"action":{"type":"string","description":"`invite` | `approve` | `deny`."},"handle":{"type":"string","description":"Target user's handle (with or without a leading `@`)."}}},"MeResponse":{"type":"object","required":["id","email","org_id","rank_tier","rank_level","is_admin","user_level","approved","capabilities","profile_public","suspended","created_at"],"properties":{"allow_create_competition":{"type":["boolean","null"]},"allow_create_dataset":{"type":["boolean","null"]},"allow_submit":{"type":["boolean","null"]},"approved":{"type":"boolean"},"avatar_url":{"type":["string","null"]},"capabilities":{"$ref":"#/components/schemas/Capabilities","description":"Resolved capabilities for this user under the live config."},"created_at":{"type":"string"},"display_name":{"type":["string","null"]},"email":{"type":"string"},"handle":{"type":["string","null"],"description":"Public, unique handle powering the shareable `/u/{handle}` profile."},"id":{"type":"string"},"is_admin":{"type":"boolean"},"org_id":{"type":"string"},"profile_public":{"type":"boolean","description":"Whether the account's public `/u/{handle}` profile is visible (all-or-nothing)."},"rank_level":{"type":"integer","format":"int32"},"rank_tier":{"type":"string"},"referral_code":{"type":["string","null"],"description":"The user's referral share code (for building an invite link). May be null\nfor accounts provisioned before referral codes existed."},"staff":{"type":["string","null"],"description":"`admin` / `staff` for platform operators (else null) — a public identity highlight."},"suspended":{"type":"boolean","description":"True when the account is suspended: only viewing this profile and deleting\nthe account are permitted; every other action is blocked."},"suspended_reason":{"type":["string","null"],"description":"Operator-supplied reason shown to a suspended user."},"user_level":{"$ref":"#/components/schemas/UserLevel"}}},"MeScope":{"type":"object","required":["total"],"properties":{"rank":{"type":["integer","null"],"format":"int64","description":"1-based rank in this scope; null when the user has no eligible scored\ncompetitions yet."},"total":{"type":"integer","format":"int64","description":"Total ranked users in this scope."}}},"MyBadge":{"type":"object","required":["slug","name","icon","category","rarity","awarded_at"],"properties":{"awarded_at":{"type":"string"},"category":{"type":"string"},"icon":{"type":"string"},"name":{"type":"string"},"rarity":{"type":"string"},"slug":{"type":"string"}}},"OrgResponse":{"type":"object","required":["id","name","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"PreferencesResponse":{"type":"object","required":["theme","notifications"],"properties":{"notifications":{},"theme":{"type":"string"}}},"ProfileBadge":{"type":"object","required":["slug","name","icon"],"properties":{"icon":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}}},"PublicDataSource":{"type":"object","description":"Public view of a data source — the fields safe to expose to anyone viewing a\ncompetition (no `auth_header`). Used only for a competition's INPUT source,\nwhich participants need; the resolution source is never exposed this way.","required":["id","name","description","url","http_method"],"properties":{"description":{"type":"string"},"http_method":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"schema_format":{"type":["string","null"]},"schema_text":{"type":["string","null"]},"url":{"type":"string"}}},"PublicLeaderboard":{"type":"object","required":["ranked","provisional","global_total","tier_total"],"properties":{"global_rank":{"type":["integer","null"],"format":"int64"},"global_total":{"type":"integer","format":"int64"},"provisional":{"type":"boolean","description":"Fewer scored competitions than the eligibility threshold."},"ranked":{"type":"boolean","description":"False when the user has no eligible scored competitions yet."},"tier_rank":{"type":["integer","null"],"format":"int64"},"tier_total":{"type":"integer","format":"int64"}}},"PublicProfile":{"type":"object","required":["id","handle","avatar_seed","rank_tier","rank_level","member_since","stats","leaderboard","badges"],"properties":{"avatar_seed":{"type":"string","description":"Seed for the deterministic generated avatar (resolved server-side to match\nthe owner's own view: the stored seed, or the id when none/an image URL)."},"badges":{"type":"array","items":{"$ref":"#/components/schemas/ProfileBadge"},"description":"Earned badges, best/rarest first (by definition sort_order)."},"display_name":{"type":["string","null"]},"handle":{"type":"string"},"id":{"type":"string","description":"User id — public; used e.g. as the target of a profile report."},"leaderboard":{"$ref":"#/components/schemas/PublicLeaderboard"},"member_since":{"type":"string","description":"Account creation time (RFC 3339)."},"rank_level":{"type":"integer","format":"int32"},"rank_tier":{"type":"string"},"staff":{"type":["string","null"],"description":"`admin` / `staff` when the account is a platform operator (else absent) —\na public \"special\" identity highlight."},"stats":{"$ref":"#/components/schemas/PublicStats"}}},"PublicStats":{"type":"object","required":["competitions_entered","competitions_hosted","earned_credits","scored_count","win_count","top3_count","points"],"properties":{"competitions_entered":{"type":"integer","format":"int64","description":"Distinct competitions the user has a live (non-retracted) submission in."},"competitions_hosted":{"type":"integer","format":"int64","description":"Competitions the user hosts and has chosen to disclose (show_host = true)."},"earned_credits":{"type":"integer","format":"int64","description":"Lifetime earned credits (winnings + grants; excludes rank-down refunds)."},"points":{"type":"number","format":"double","description":"Sum of normalized leaderboard points (0–100 per competition)."},"scored_count":{"type":"integer","format":"int64","description":"Eligible scored competitions counted toward the leaderboard."},"top3_count":{"type":"integer","format":"int64","description":"Top-3 finishes."},"win_count":{"type":"integer","format":"int64","description":"First-place finishes."}}},"RankEconomics":{"type":"object","required":["level_up_cost","tier_entry_cost","rank_down_refund_num","rank_down_refund_den"],"properties":{"level_up_cost":{"$ref":"#/components/schemas/LevelUpCost"},"rank_down_refund_den":{"type":"integer","format":"int64"},"rank_down_refund_num":{"type":"integer","format":"int64","description":"Refund on voluntary demotion = previous cost × num / den."},"tier_entry_cost":{"$ref":"#/components/schemas/TierEntryCost"}}},"RankResponse":{"type":"object","required":["rank_tier","rank_level"],"properties":{"rank_level":{"type":"integer","format":"int32"},"rank_tier":{"$ref":"#/components/schemas/RankTier"}}},"RankTier":{"type":"string","enum":["bronze","silver","gold","platinum","diamond","master"]},"RankTransitionResponse":{"type":"object","required":["rank_tier","rank_level","balance","delta"],"properties":{"balance":{"type":"integer","format":"int64"},"delta":{"type":"integer","format":"int64"},"rank_level":{"type":"integer","format":"int32"},"rank_tier":{"type":"string"}}},"RankUpdate":{"type":"object","required":["rank_tier","rank_level"],"properties":{"rank_level":{"type":"integer","format":"int32"},"rank_tier":{"type":"string"}}},"ReportRow":{"type":"object","required":["id","target_type","reporter_user_id","reason","status","created_at"],"properties":{"competition_id":{"type":["string","null"],"format":"uuid"},"created_at":{"type":"string","format":"date-time"},"details":{"type":["string","null"]},"id":{"type":"string","format":"uuid"},"reason":{"type":"string"},"reported_handle":{"type":["string","null"],"description":"Reported user's handle (for a profile link), when the target is a user."},"reporter_email":{"type":["string","null"]},"reporter_user_id":{"type":"string","format":"uuid"},"resolution":{"type":["string","null"]},"status":{"type":"string"},"submission_id":{"type":["string","null"],"format":"uuid"},"target_title":{"type":["string","null"],"description":"Human label: competition title, or the reported user's name/@handle."},"target_type":{"type":"string"},"user_id":{"type":["string","null"],"format":"uuid","description":"The reported user (for `target_type = 'user'`)."}}},"ResolveBody":{"type":"object","required":["action"],"properties":{"action":{"type":"string","description":"\"dismiss\" | \"void\" | \"delete\"."},"note":{"type":["string","null"]}}},"RetractResponse":{"type":"object","required":["submission_id","refunded","balance"],"properties":{"balance":{"type":"integer","format":"int64","description":"The caller's resulting credit balance."},"refunded":{"type":"integer","format":"int64","description":"Credits refunded (the per-submission fee)."},"submission_id":{"type":"string"}}},"SeriesResponse":{"type":"object","description":"The editable definition shared by all cycles of a recurring competition.","required":["id","title","description","metric","bounty_amount","bounty_mode","bounty_top_n","tags","updated_at"],"properties":{"bounty_amount":{"type":"integer","format":"int64"},"bounty_mode":{"$ref":"#/components/schemas/BountyMode"},"bounty_top_n":{"type":"integer","format":"int32"},"description":{"type":"string"},"id":{"type":"string"},"metric":{"$ref":"#/components/schemas/CompetitionMetric"},"min_participants":{"type":["integer","null"],"format":"int32"},"min_score":{"type":["number","null"],"format":"double"},"tags":{"type":"array","items":{"type":"string"}},"title":{"type":"string"},"updated_at":{"type":"string"}}},"StreakMilestone":{"type":"object","required":["days","badge_slug"],"properties":{"badge_slug":{"type":"string","description":"Badge slug awarded at this milestone (a `badge_definitions.slug`)."},"days":{"type":"integer","format":"int32","description":"Consecutive-day count that unlocks the badge."}}},"StreaksConfig":{"type":"object","description":"Daily-streak configuration (see TODO_STREAKS.md). `platform_timezone` sets the\nday boundary streaks are counted in; `milestones` maps a day count to the badge\nawarded at that streak length. Admin-editable + hot-reloaded like the rest of\nthe config; the feature itself is gated by `gates.streaks`.","properties":{"milestones":{"type":"array","items":{"$ref":"#/components/schemas/StreakMilestone"},"description":"Streak-length milestones and the badge each awards, ascending by `days`."},"platform_timezone":{"type":"string","description":"IANA zone the streak \"day\" is measured in (e.g. `America/New_York`)."}}},"SubmissionResponse":{"type":"object","required":["id","competition_id","user_id","s3_key","created_at"],"properties":{"competition_id":{"type":"string"},"created_at":{"type":"string"},"id":{"type":"string"},"payout":{"type":["integer","null"],"format":"int64"},"rank":{"type":["integer","null"],"format":"int32"},"retracted_at":{"type":["string","null"],"description":"Set when the entry was voluntarily withdrawn; such a submission is\nrefunded, excluded from scoring, and cannot be resubmitted."},"s3_key":{"type":"string"},"score":{"type":["number","null"],"format":"double"},"scored_at":{"type":["string","null"]},"user_id":{"type":"string"}}},"SummaryGroup":{"type":"object","required":["key","total","running","paused","failing","scored","scoring_failed"],"properties":{"failing":{"type":"integer","format":"int64"},"key":{"type":"string"},"paused":{"type":"integer","format":"int64"},"running":{"type":"integer","format":"int64"},"scored":{"type":"integer","format":"int64"},"scoring_failed":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"SummaryResponse":{"type":"object","required":["competitions_open","competitions_total","active_bounties","predictions_today","predictions_total","predictors","credits_paid"],"properties":{"active_bounties":{"type":"integer","format":"int64","description":"Sum of bounties on currently-open competitions."},"competitions_open":{"type":"integer","format":"int64","description":"Competitions currently open for submissions."},"competitions_total":{"type":"integer","format":"int64","description":"All published (non-draft) competitions, ever."},"credits_paid":{"type":"integer","format":"int64","description":"Credits distributed to winners across all scored competitions."},"predictions_today":{"type":"integer","format":"int64","description":"Predictions submitted since the start of the current UTC day."},"predictions_total":{"type":"integer","format":"int64","description":"Predictions submitted, ever."},"predictors":{"type":"integer","format":"int64","description":"Distinct users who have submitted at least one prediction."}}},"TabularFormat":{"type":"string","enum":["csv","csv_gz","xlsx","parquet","json"]},"TierAmounts":{"type":"object","description":"Per-tier amounts keyed by the selectable `min_rank` tiers (bronze..diamond).\nMaster is invite-only and not creatable as a competition `min_rank`.","required":["bronze","silver","gold","platinum","diamond"],"properties":{"bronze":{"type":"integer","format":"int64"},"diamond":{"type":"integer","format":"int64"},"gold":{"type":"integer","format":"int64"},"platinum":{"type":"integer","format":"int64"},"silver":{"type":"integer","format":"int64"}}},"TierCreationFees":{"type":"object","description":"Creation fees that scale by the competition's minimum participation tier\n(each tier still keeps the per-type split). Mirrors `submission_fee_by_tier`\nbut with a `{classification, regression}` pair per tier.","required":["bronze","silver","gold","platinum","diamond"],"properties":{"bronze":{"$ref":"#/components/schemas/CreationFees"},"diamond":{"$ref":"#/components/schemas/CreationFees"},"gold":{"$ref":"#/components/schemas/CreationFees"},"platinum":{"$ref":"#/components/schemas/CreationFees"},"silver":{"$ref":"#/components/schemas/CreationFees"}}},"TierEntryCost":{"type":"object","description":"Credits to cross into the named tier's floor (level 4).","required":["silver","gold","platinum","diamond","master"],"properties":{"diamond":{"type":"integer","format":"int64"},"gold":{"type":"integer","format":"int64"},"master":{"type":"integer","format":"int64"},"platinum":{"type":"integer","format":"int64"},"silver":{"type":"integer","format":"int64"}}},"TierGates":{"type":"object","description":"Minimum rank tier required to use a tier-gated feature — the \"rank up to\nunlock\" nudge that encourages participation. Each field defaults on its own so\nstored configs load, and new gated features can be added over time (upvote,\ncomment, etc.). Admin-tunable (hot-reloaded like the rest of the config).","properties":{"customize_handle":{"$ref":"#/components/schemas/RankTier","description":"Minimum tier to claim a custom `@handle` (below it, the auto-assigned\nhandle stands). Default silver — the first tier-up."}}},"TransferBody":{"type":"object","required":["org_id"],"properties":{"org_id":{"type":"string","format":"uuid"}}},"UpdateCompetition":{"type":"object","properties":{"bounty_amount":{"type":["integer","null"],"format":"int64"},"bounty_mode":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BountyMode"}]},"bounty_top_n":{"type":["integer","null"],"format":"int32"},"bounty_weights":{},"dataset_schema":{},"description":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"metric":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CompetitionMetric"}]},"min_participants":{"type":["integer","null"],"format":"int32"},"min_score":{"type":["number","null"],"format":"double"},"oracle_auth_header":{"type":["string","null"]},"oracle_url":{"type":["string","null"]},"tags":{"type":["array","null"],"items":{"type":"string"}},"title":{"type":["string","null"]}}},"UpdateDataSource":{"type":"object","properties":{"auth_header":{"type":["string","null"]},"compatible_types":{"type":["array","null"],"items":{"type":"string"}},"description":{"type":["string","null"]},"http_method":{"type":["string","null"]},"last_probe":{},"name":{"type":["string","null"]},"openapi_path":{"type":["string","null"]},"roles":{"type":["array","null"],"items":{"type":"string"}},"schema_format":{"type":["string","null"]},"schema_text":{"type":["string","null"]},"url":{"type":["string","null"]}}},"UpdateMe":{"type":"object","properties":{"avatar_url":{"type":["string","null"]},"display_name":{"type":["string","null"]},"handle":{"type":["string","null"],"description":"Claim a custom public handle. Requires reaching the tier in\n`economic_config.tier_gates.customize_handle` (admins bypass). Validated\n(3–24 chars of a-z0-9_-, not reserved) and unique."},"profile_public":{"type":["boolean","null"],"description":"Toggle the public profile on/off (all-or-nothing privacy)."}}},"UpdatePreferences":{"type":"object","properties":{"notifications":{},"theme":{"type":["string","null"]}}},"UpdateUser":{"type":"object","properties":{"allow_create_competition":{"type":["boolean","null"],"description":"Per-user capability overrides (true/false; null in JSON is treated as absent)."},"allow_create_dataset":{"type":["boolean","null"]},"allow_submit":{"type":["boolean","null"]},"approved":{"type":["boolean","null"],"description":"Per-user approval (consulted when require_user_approval is on)."},"display_name":{"type":["string","null"]},"handle":{"type":["string","null"],"description":"Force-set the public handle (moderation of an abusive handle). Validated +\nunique, same rules as the self-service change."},"is_admin":{"type":["boolean","null"],"description":"Legacy admin toggle — mapped to user_level admin/retail. Prefer `user_level`."},"user_level":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UserLevel","description":"Preferred: set the user's role. See PERMISSIONS.md."}]}}},"UserBadgeView":{"type":"object","required":["slug","name","icon","category","rarity","source","awarded_at"],"properties":{"awarded_at":{"type":"string"},"category":{"type":"string"},"icon":{"type":"string"},"name":{"type":"string"},"note":{"type":["string","null"]},"rarity":{"type":"string"},"slug":{"type":"string"},"source":{"type":"string","description":"`recompute` | `manual` | `event`."}}},"UserLevel":{"type":"string","description":"Per-account role. Replaces the old `is_admin` boolean; see\ncrowdsource-docs/PERMISSIONS.md for the canonical capability matrix.","enum":["admin","support","support_plus","audit","power","retail","preview"]},"UserListResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminUserRow"}},"total":{"type":"integer","format":"int64"}}},"VoidBody":{"type":"object","properties":{"reason":{"type":["string","null"]}}}},"securitySchemes":{"api_key":{"type":"apiKey","in":"header","name":"X-API-Key"},"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"tags":[{"name":"health","description":"Liveness, version, and the OpenAPI document."},{"name":"summary","description":"Public platform statistics."},{"name":"config","description":"Economic configuration (fees, packs, rank costs, gates)."},{"name":"competitions","description":"Create, browse, and manage competitions."},{"name":"submissions","description":"Submit predictions and read leaderboards."},{"name":"leaderboards","description":"Aggregate forecaster rankings across competitions."},{"name":"me","description":"The authenticated user: profile, credits, rank, preferences."},{"name":"api-keys","description":"Programmatic access keys."},{"name":"orgs","description":"Organizations."},{"name":"credits","description":"Credit purchase (Stripe checkout)."},{"name":"data-sources","description":"Registered oracle/data endpoints."},{"name":"datasets","description":"Dataset schema inference from files/URLs."},{"name":"events","description":"Public activity feed."},{"name":"admin","description":"Admin-only moderation and operations."},{"name":"webhooks","description":"Inbound provider webhooks."}]}