{"openapi":"3.1.0","info":{"title":"Torneio Rafa API","version":"1.0.0","description":"Read-only API for the BigBet Torneio Rafa affiliate tournament. Daily LotusXpert data is ingested every 6h into Postgres; this API exposes the leaderboard, scoring config, and supporting endpoints.\n\nDates are `YYYY-MM-DD`. Timestamps are ISO 8601, tenant timezone is `America/Sao_Paulo` (UTC-3)."},"servers":[{"url":"https://torneio.bigbetbr.com.br","description":"Production"},{"url":"http://localhost:3000","description":"Local"}],"tags":[{"name":"tournament","description":"Leaderboard + scoring config"},{"name":"players","description":"Per-player rollups"},{"name":"registrations","description":"Daily FTD lists"},{"name":"meta","description":"Liveness, OpenAPI spec"}],"paths":{"/":{"get":{"tags":["meta"],"summary":"Tournament dashboard (HTML)","description":"Branded VS Code-themed HTML leaderboard. Accepts `?preset=today|yesterday|7d|30d|all|custom` plus `?from=&to=` when `preset=custom`. JSON consumers should hit `/rankings` instead.","responses":{"200":{"description":"HTML"}}}},"/health":{"get":{"tags":["meta"],"summary":"Liveness probe","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"},"examples":{"ok":{"value":{"ok":true}}}}}}}}},"/api/docs.json":{"get":{"tags":["meta"],"summary":"This OpenAPI 3.1 specification","responses":{"200":{"description":"OpenAPI 3.1 document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/rankings":{"get":{"tags":["tournament"],"summary":"Tournament leaderboard","description":"Returns players ranked by total tournament points over a date window. Points come from base scoring (1 BRL deposited = N pts, 1 BRL wagered = M pts) plus daily mission bonuses, all configured in `tournament_config` and tunable via `/admin`.\n\nWithout `from`/`to`, defaults to the last 7 days in tenant TZ.","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date"},"example":"2026-05-01"},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date"},"example":"2026-05-07"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Ranked players","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rankings"},"examples":{"example":{"value":{"window":{"from":"2026-05-01","to":"2026-05-07"},"page":{"limit":100,"offset":0,"total":168},"config":{"scoring":{"pointsPerBrlDeposited":10,"pointsPerBrlWagered":0.1},"missions":[],"tiers":[],"rewards":{"weekly":[],"monthly":[]}},"players":[{"rank":1,"playerId":"907072987","tier":"gold","tierLabel":"Gold","totalPoints":24160,"depositPoints":200,"wagerPoints":24.16,"missionPoints":1000,"deposits":20,"wagering":241.6,"points":24160,"breakdown":{"deposits":20,"wagering":241.6,"basePoints":{"fromDeposits":200,"fromWagering":24.16},"missions":{"deposit_50":{"points":0,"daysCompleted":0},"wager_500":{"points":0,"daysCompleted":0},"play_3_slots":{"points":200,"daysCompleted":1}}}}]}}}}}}}}},"/tournament/config":{"get":{"tags":["tournament"],"summary":"Tournament configuration (scoring, missions, tiers, rewards)","description":"Public read of the JSON config that drives `/rankings` and `/`. Edited via the password-gated `/admin` page.","responses":{"200":{"description":"Config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TournamentConfig"}}}}}}},"/players/{playerId}":{"get":{"tags":["players"],"summary":"Per-player rollup: FTD, totals, games","description":"Master FTD record (independent of window) plus aggregate totals (deposit/GGR/wager) and per-game characteristics summed over the requested window. Omit `from`/`to` to span all ingested days.","parameters":[{"name":"playerId","in":"path","required":true,"schema":{"type":"string"},"example":"907072987"},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Player rollup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerRollup"}}}},"404":{"description":"Player not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/registrations/{date}":{"get":{"tags":["registrations"],"summary":"Players who FTD'd on a given day","parameters":[{"name":"date","in":"path","required":true,"schema":{"type":"string","format":"date"},"example":"2026-05-07"}],"responses":{"200":{"description":"Daily list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationList"}}}}}}}},"components":{"schemas":{"Health":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]},"Error":{"type":"object","properties":{"error":{"type":"string"},"detail":{"type":"string"}},"required":["error"]},"ScoringConfig":{"type":"object","properties":{"pointsPerBrlDeposited":{"type":"number","example":10,"description":"Points per BRL deposited (e.g. 10 = R$1 -> 10pts)"},"pointsPerBrlWagered":{"type":"number","example":0.1,"description":"Points per BRL wagered (e.g. 0.1 = R$10 -> 1pt)"}},"required":["pointsPerBrlDeposited","pointsPerBrlWagered"]},"Mission":{"type":"object","properties":{"key":{"type":"string","example":"deposit_50"},"label":{"type":"string","example":"Deposite R$ 50,00"},"type":{"type":"string","enum":["deposit","wager","distinct_games"]},"threshold":{"type":"number","example":50,"description":"Numeric threshold for completion (BRL for deposit/wager, count for distinct_games)"},"points":{"type":"integer","example":500,"description":"Points awarded for each day the mission is completed"}},"required":["key","type","threshold","points"]},"Tier":{"type":"object","properties":{"key":{"type":"string","enum":["bronze","silver","gold"]},"label":{"type":"string","example":"Gold"},"minPoints":{"type":"integer","example":20000,"description":"Minimum totalPoints to qualify for this tier"}},"required":["key","label","minPoints"]},"Reward":{"type":"object","properties":{"rank":{"type":"integer","example":1},"prize":{"type":"string","example":"R$ 1.000,00"}},"required":["rank","prize"]},"TournamentConfig":{"type":"object","properties":{"scoring":{"$ref":"#/components/schemas/ScoringConfig"},"missions":{"type":"array","items":{"$ref":"#/components/schemas/Mission"}},"tiers":{"type":"array","items":{"$ref":"#/components/schemas/Tier"}},"rewards":{"type":"object","properties":{"weekly":{"type":"array","items":{"$ref":"#/components/schemas/Reward"}},"monthly":{"type":"array","items":{"$ref":"#/components/schemas/Reward"}}}},"updatedAt":{"type":"string","format":"date-time"}},"required":["scoring","missions","tiers"]},"RankedPlayer":{"type":"object","description":"A leaderboard row. Top-level point fields are the canonical values for UI rendering; `breakdown` is provided for analysts/debugging.","properties":{"rank":{"type":"integer","example":1},"playerId":{"type":"string","example":"907072987"},"tier":{"type":"string","nullable":true,"example":"gold"},"tierLabel":{"type":"string","nullable":true,"example":"Gold"},"totalPoints":{"type":"number","example":24160,"description":"Sum of depositPoints + wagerPoints + missionPoints"},"depositPoints":{"type":"number","example":200,"description":"Base points from deposits = SUM(deposits) * pointsPerBrlDeposited"},"wagerPoints":{"type":"number","example":24.16,"description":"Base points from wager = SUM(wagering) * pointsPerBrlWagered"},"missionPoints":{"type":"number","example":1000,"description":"Sum of every mission completion in the window"},"deposits":{"type":"number","example":20,"description":"Total deposits in the window (BRL)"},"wagering":{"type":"number","example":241.6,"description":"Total wagered in the window (BRL)"},"points":{"type":"number","example":24160,"description":"Alias of totalPoints (kept for backwards compatibility)"},"breakdown":{"type":"object","properties":{"deposits":{"type":"number"},"wagering":{"type":"number"},"basePoints":{"type":"object","properties":{"fromDeposits":{"type":"number"},"fromWagering":{"type":"number"}}},"missions":{"type":"object","description":"Per-mission contribution. Keys match Mission.key.","additionalProperties":{"type":"object","properties":{"points":{"type":"number"},"daysCompleted":{"type":"integer"}}}}}}},"required":["rank","playerId","totalPoints","depositPoints","wagerPoints","missionPoints","deposits","wagering"]},"Rankings":{"type":"object","properties":{"window":{"type":"object","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"}},"required":["from","to"]},"page":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}},"required":["limit","offset","total"]},"config":{"type":"object","properties":{"scoring":{"$ref":"#/components/schemas/ScoringConfig"},"missions":{"type":"array","items":{"$ref":"#/components/schemas/Mission"}},"tiers":{"type":"array","items":{"$ref":"#/components/schemas/Tier"}},"rewards":{"type":"object","properties":{"weekly":{"type":"array","items":{"$ref":"#/components/schemas/Reward"}},"monthly":{"type":"array","items":{"$ref":"#/components/schemas/Reward"}}}}}},"players":{"type":"array","items":{"$ref":"#/components/schemas/RankedPlayer"}}},"required":["window","page","players"]},"Ftd":{"type":"object","description":"First Time Deposit master record.","properties":{"amount":{"type":"number","nullable":true,"example":20},"date":{"type":"string","format":"date-time","nullable":true}}},"Game":{"type":"object","properties":{"gameName":{"type":"string","example":"Tigre Sortudo Dourado"},"providerName":{"type":"string","example":"Pragmatic"},"bets":{"type":"integer","example":40},"payIn":{"type":"number","example":82},"payOut":{"type":"number","example":10.8},"ggr":{"type":"number","example":71.2},"retentionAvg":{"type":"number","example":86.83},"firstPlayed":{"type":"string","format":"date"},"lastPlayed":{"type":"string","format":"date"}}},"PlayerRollup":{"type":"object","properties":{"playerId":{"type":"string"},"affiliateId":{"type":"integer"},"currency":{"type":"string","example":"BRL"},"firstSeenDate":{"type":"string","format":"date"},"ftd":{"$ref":"#/components/schemas/Ftd"},"window":{"type":"object","properties":{"from":{"type":"string","format":"date","nullable":true},"to":{"type":"string","format":"date","nullable":true}}},"totals":{"type":"object","properties":{"deposit":{"type":"number"},"ggr":{"type":"number"},"wager":{"type":"number"},"depositCount":{"type":"integer"}}},"games":{"type":"array","items":{"$ref":"#/components/schemas/Game"}}}},"RegistrationList":{"type":"object","properties":{"date":{"type":"string","format":"date"},"count":{"type":"integer"},"players":{"type":"array","items":{"type":"object","properties":{"player_id":{"type":"string"},"first_deposit":{"type":"number"},"first_deposit_at":{"type":"string","format":"date-time"},"deposits":{"type":"number"},"ggr":{"type":"number"},"wagering":{"type":"number"}}}}}}}}}