{"openapi":"3.1.0","info":{"title":"Nepal Domestic Cricket Stats API","version":"1.0.0","description":"Tournament statistics imported from Cricket Association of Nepal (CAN) stat sheets: series, divisions, teams, players, and batting / bowling / fielding figures.\n\n**Authentication.** Send your API key as `X-API-Key` (create one on your account page). Signed-in dashboard users send `Authorization: Bearer <accessToken>` from `POST /auth/login`. Admin endpoints need a user with the admin role.\n\n**Plans & quotas.** Each key draws on its owner's plan: responses carry `X-Plan`, `X-Quota-Limit`, `X-Quota-Remaining` and `X-Quota-Reset`. When the monthly quota is used up the API answers 429 `QUOTA_EXCEEDED` until the period resets or an admin grants a higher plan; the per-minute limit answers 429 with `Retry-After`.\n\n**Errors** always look like `{ \"error\": { \"code\", \"message\", \"details?\", \"requestId\" } }`.\n\n**Caching.** Reads carry `Cache-Control` and an `ETag`; send `If-None-Match` to get 304 when nothing changed.\n\n**Data quality.** Figures are stored as published. Lines whose published figures contradict each other carry `quality.status` = `open` / `acknowledged` / `corrected` (see the Quality schema)."},"servers":[{"url":"/api/v1","description":"This server"}],"tags":[{"name":"Meta"},{"name":"Auth"},{"name":"Users"},{"name":"Competitions"},{"name":"Players"},{"name":"Statistics"},{"name":"Plans & API keys"},{"name":"Admin: imports"},{"name":"Admin: API keys"},{"name":"Admin: players"},{"name":"Admin: data quality"},{"name":"Admin: plans"},{"name":"Internal: international"}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner app key (Admin → API keys), e.g. can_1a2b3c4d.…"},"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"accessToken from POST /auth/login (valid 15 minutes; refresh with POST /auth/refresh)"},"refreshCookie":{"type":"apiKey","in":"cookie","name":"rt","description":"httpOnly refresh-token cookie set at sign-in"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"VALIDATION_ERROR"},"message":{"type":"string"},"details":{"description":"Field errors ([{field, message}]) or row issues for imports"},"requestId":{"type":"string","description":"Also in the X-Request-Id header; quote it when reporting a problem"}},"required":["code","message"]}},"required":["error"]},"PageMeta":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasNext":{"type":"boolean"}}},"Message":{"type":"object","properties":{"message":{"type":"string"}}},"PlayerRef":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"},"disambiguation":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Admin label that tells namesakes apart, e.g. \"wicket-keeper\""}}},"TeamRef":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"}}},"DivisionRef":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"},"season":{"anyOf":[{"type":"integer"},{"type":"null"}]}}},"Ref":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"}}},"Quality":{"type":"object","properties":{"status":{"enum":["clean","open","acknowledged","corrected"],"description":"clean · open (discrepancy in the published figures) · acknowledged (admin confirmed as published) · corrected (admin fixed a value)"},"flags":{"type":"array","items":{"type":"object","properties":{"rule":{"type":"string","example":"boundaries-exceed-runs"},"level":{"enum":["warning","suspect"]},"field":{"type":"string"},"message":{"type":"string"}}}},"corrections":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"sourceValue":{},"value":{},"reason":{"type":"string"},"at":{"type":"string","format":"date-time"}}}}}},"BattingRow":{"type":"object","properties":{"position":{"type":"integer","description":"Rank in this result set"},"player":{"$ref":"#/components/schemas/PlayerRef"},"team":{"$ref":"#/components/schemas/TeamRef"},"tournament":{"$ref":"#/components/schemas/DivisionRef","description":"Present when combine=false (one row per division)"},"tournaments":{"type":"integer","description":"Divisions combined into this row (combine=true)"},"flaggedLines":{"type":"integer","description":"Divisions in this row whose source figures have an open or acknowledged discrepancy (combine=true)"},"group":{"anyOf":[{"type":"string"},{"type":"null"}]},"quality":{"$ref":"#/components/schemas/Quality","description":"Data-quality state of the line (combine=false)"},"matches":{"type":"integer","description":"Matches (source header e.g. \"Mat\")"},"innings":{"type":"integer","description":"Innings (source header e.g. \"Inns\")"},"notOuts":{"type":"integer","description":"Not outs (source header e.g. \"NO\")"},"runs":{"type":"integer","description":"Runs (source header e.g. \"Runs\")"},"balls":{"type":"integer","description":"Balls faced (source header e.g. \"Balls\")"},"fours":{"type":"integer","description":"Fours (source header e.g. \"4's\")"},"sixes":{"type":"integer","description":"Sixes (source header e.g. \"6's\")"},"fifties":{"type":"integer","description":"Fifties (source header e.g. \"50's\")"},"hundreds":{"type":"integer","description":"Hundreds (source header e.g. \"100's\")"},"highestScore":{"type":"integer","description":"Highest score (source header e.g. \"HS\")"},"highestScoreNotOut":{"type":"boolean","description":"true when the highest score was not out (e.g. 104*)"},"strikeRate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Strike rate (source header e.g. \"SR\"). Recomputed from raw counts"},"average":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Batting average (source header e.g. \"Avg\"). Recomputed from raw counts"},"points":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Points (MVP) (source header e.g. \"Points\"). null when the source sheet does not record it"},"thirties":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Thirties (source header e.g. \"30's\"). null when the source sheet does not record it"},"ducks":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Ducks (source header e.g. \"Ducks\"). null when the source sheet does not record it"},"dotBalls":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Dot balls faced (source header e.g. \"Dots\"). null when the source sheet does not record it"},"singles":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Singles (source header e.g. \"1's\"). null when the source sheet does not record it"},"twos":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Twos (source header e.g. \"2's\"). null when the source sheet does not record it"},"threes":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Threes (source header e.g. \"3's\"). null when the source sheet does not record it"},"retiredHurt":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Retired hurt (source header e.g. \"RH\"). null when the source sheet does not record it"},"boundaryPercent":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Runs from boundaries % (source header e.g. \"Bdry %\"). Recomputed from raw counts"},"ballsPerBoundary":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Balls per boundary (source header e.g. \"BpB\"). Recomputed from raw counts"},"dotPercent":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Dot-ball % (source header e.g. \"Dot %\"). null when the source sheet does not record it. Recomputed from raw counts"}},"description":"Batting figures of one player — for one division, or combined across divisions"},"BattingPage":{"type":"object","properties":{"kind":{"const":"batting"},"category":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"highlight":{"type":"string","description":"Column the category ranks by"}}},"combine":{"type":"boolean"},"qualifiers":{"type":"object","additionalProperties":{"type":"integer"},"description":"Minimums in effect (category defaults or overrides)"},"ranges":{"type":"object","additionalProperties":{"type":"object"},"description":"Range filters in effect, e.g. {\"runs\": {\"gte\": 200}}"},"filters":{"type":"object","description":"Echo of the tag / season / series / division / team filters"},"data":{"type":"array","items":{"$ref":"#/components/schemas/BattingRow"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"BowlingRow":{"type":"object","properties":{"position":{"type":"integer","description":"Rank in this result set"},"player":{"$ref":"#/components/schemas/PlayerRef"},"team":{"$ref":"#/components/schemas/TeamRef"},"tournament":{"$ref":"#/components/schemas/DivisionRef","description":"Present when combine=false (one row per division)"},"tournaments":{"type":"integer","description":"Divisions combined into this row (combine=true)"},"flaggedLines":{"type":"integer","description":"Divisions in this row whose source figures have an open or acknowledged discrepancy (combine=true)"},"group":{"anyOf":[{"type":"string"},{"type":"null"}]},"quality":{"$ref":"#/components/schemas/Quality","description":"Data-quality state of the line (combine=false)"},"matches":{"type":"integer","description":"Matches (source header e.g. \"Mat\")"},"innings":{"type":"integer","description":"Innings (source header e.g. \"Inns\")"},"overs":{"type":"string","example":"14.2","description":"Overs (source header e.g. \"Overs\"). Recomputed from raw counts"},"balls":{"type":"integer","description":"Balls bowled (source header e.g. \"Balls\")"},"maidens":{"type":"integer","description":"Maidens (source header e.g. \"Mdns\")"},"runsConceded":{"type":"integer","description":"Runs conceded (source header e.g. \"Runs\")"},"wickets":{"type":"integer","description":"Wickets (source header e.g. \"Wkts\")"},"bestWickets":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Best bowling figures (source header e.g. \"BBF\")"},"bestRuns":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Runs conceded in the best figures"},"economy":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Economy rate (source header e.g. \"Econ\"). Recomputed from raw counts"},"average":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Bowling average (source header e.g. \"Avg\"). Recomputed from raw counts"},"strikeRate":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Bowling strike rate (source header e.g. \"SR\"). Recomputed from raw counts"},"dots":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Dot balls (source header e.g. \"Dots\"). null when the source sheet does not record it"},"fourWickets":{"type":"integer","description":"4-wicket hauls (source header e.g. \"4W\")"},"fiveWickets":{"type":"integer","description":"5-wicket hauls (source header e.g. \"5W\")"},"hatTricks":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Hat-tricks (source header e.g. \"Hat-trick\"). null when the source sheet does not record it"},"points":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Points (MVP) (source header e.g. \"Points\"). null when the source sheet does not record it"},"threeWickets":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"3-wicket hauls (source header e.g. \"3W\"). null when the source sheet does not record it"},"foursConceded":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Fours conceded (source header e.g. \"4's\"). null when the source sheet does not record it"},"sixesConceded":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Sixes conceded (source header e.g. \"6's\"). null when the source sheet does not record it"},"wides":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Wides (source header e.g. \"Wd\"). null when the source sheet does not record it"},"noBalls":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"No-balls (source header e.g. \"Nb\"). null when the source sheet does not record it"},"extras":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Extras conceded (source header e.g. \"Extras\"). null when the source sheet does not record it"},"dotPercent":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Dot-ball % (source header e.g. \"Dot %\"). null when the source sheet does not record it. Recomputed from raw counts"}},"description":"Bowling figures of one player — for one division, or combined across divisions"},"BowlingPage":{"type":"object","properties":{"kind":{"const":"bowling"},"category":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"highlight":{"type":"string","description":"Column the category ranks by"}}},"combine":{"type":"boolean"},"qualifiers":{"type":"object","additionalProperties":{"type":"integer"},"description":"Minimums in effect (category defaults or overrides)"},"ranges":{"type":"object","additionalProperties":{"type":"object"},"description":"Range filters in effect, e.g. {\"runs\": {\"gte\": 200}}"},"filters":{"type":"object","description":"Echo of the tag / season / series / division / team filters"},"data":{"type":"array","items":{"$ref":"#/components/schemas/BowlingRow"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"FieldingRow":{"type":"object","properties":{"position":{"type":"integer","description":"Rank in this result set"},"player":{"$ref":"#/components/schemas/PlayerRef"},"team":{"$ref":"#/components/schemas/TeamRef"},"tournament":{"$ref":"#/components/schemas/DivisionRef","description":"Present when combine=false (one row per division)"},"tournaments":{"type":"integer","description":"Divisions combined into this row (combine=true)"},"flaggedLines":{"type":"integer","description":"Divisions in this row whose source figures have an open or acknowledged discrepancy (combine=true)"},"group":{"anyOf":[{"type":"string"},{"type":"null"}]},"quality":{"$ref":"#/components/schemas/Quality","description":"Data-quality state of the line (combine=false)"},"matches":{"type":"integer","description":"Matches (source header e.g. \"Mat\")"},"innings":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Innings (source header e.g. \"Inns\"). null when the source sheet does not record it"},"catches":{"type":"integer","description":"Catches (source header e.g. \"Ct\")"},"wkCatches":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Catches as wicket-keeper (source header e.g. \"Ct (WK)\"). null when the source sheet does not record it"},"stumpings":{"type":"integer","description":"Stumpings (source header e.g. \"St\")"},"runOuts":{"type":"integer","description":"Run outs (source header e.g. \"RO\")"},"directHits":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Direct-hit run outs (source header e.g. \"DH\"). null when the source sheet does not record it"},"droppedCatches":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Dropped catches (source header e.g. \"Drops\"). null when the source sheet does not record it"},"dismissals":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Total dismissals (source header e.g. \"Dis\"). Recomputed from raw counts"},"keeperDismissals":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Wicket-keeping dismissals (source header e.g. \"WK Dis\"). Recomputed from raw counts"},"points":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Points (MVP) (source header e.g. \"Points\"). null when the source sheet does not record it"}},"description":"Fielding figures of one player — for one division, or combined across divisions"},"FieldingPage":{"type":"object","properties":{"kind":{"const":"fielding"},"category":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"highlight":{"type":"string","description":"Column the category ranks by"}}},"combine":{"type":"boolean"},"qualifiers":{"type":"object","additionalProperties":{"type":"integer"},"description":"Minimums in effect (category defaults or overrides)"},"ranges":{"type":"object","additionalProperties":{"type":"object"},"description":"Range filters in effect, e.g. {\"runs\": {\"gte\": 200}}"},"filters":{"type":"object","description":"Echo of the tag / season / series / division / team filters"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FieldingRow"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"StatColumn":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"title":{"type":"string"},"type":{"enum":["count","decimal","score","overs","figures"]},"digits":{"anyOf":[{"type":"integer"},{"type":"null"}]},"primary":{"type":"boolean","description":"Shown by default (CricClubs layout)"},"optional":{"type":"boolean"},"derived":{"type":"boolean"},"sortKey":{"anyOf":[{"type":"string"},{"type":"null"}]},"filterable":{"type":"boolean","description":"Usable as a range filter: field[gte|gt|lte|lt|eq|ne]=number"}}},"Categories":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["batting","bowling","fielding"]},"label":{"type":"string"},"categories":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"highlight":{"type":"string"},"defaults":{"type":"object"}}}},"columns":{"type":"array","items":{"$ref":"#/components/schemas/StatColumn"}},"sortable":{"type":"array","items":{"type":"string"}}}}}}},"FilterOptions":{"type":"object","properties":{"data":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}},"years":{"type":"array","items":{"type":"integer"}},"series":{"type":"array","items":{"$ref":"#/components/schemas/TeamRef"}},"divisions":{"type":"array","items":{"$ref":"#/components/schemas/DivisionRef"}},"matchTypes":{"type":"array","items":{"type":"string"}},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamRef"}}}}}},"Leaderboard":{"type":"object","properties":{"kind":{"enum":["batting","bowling","fielding"]},"metric":{"type":"string"},"scope":{"enum":["tournament","season","all-time"]},"data":{"type":"array","items":{"type":"object"}}}},"Profile":{"type":"object","properties":{"photoUrl":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"role":{"anyOf":[{"enum":["batter","bowler","all-rounder","wicket-keeper","wicket-keeper-batter"]},{"type":"null"}]},"battingStyle":{"anyOf":[{"enum":["right-hand bat","left-hand bat"]},{"type":"null"}]},"bowlingStyle":{"anyOf":[{"enum":["right-arm fast","right-arm fast-medium","right-arm medium","right-arm off-spin","right-arm leg-spin","left-arm fast","left-arm fast-medium","left-arm medium","left-arm orthodox","left-arm wrist-spin"]},{"type":"null"}]},"dateOfBirth":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"age":{"anyOf":[{"type":"integer"},{"type":"null"}]},"district":{"anyOf":[{"type":"string"},{"type":"null"}]},"bio":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"PlayerListItem":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"},"ordinal":{"type":"integer","description":"Namesakes at one club: 1, 2, …"},"disambiguation":{"anyOf":[{"type":"string"},{"type":"null"}]},"team":{"$ref":"#/components/schemas/TeamRef"},"profile":{"type":"object"},"externalIds":{"type":"object"}}},"PlayerDetail":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"slug":{"type":"string"},"name":{"type":"string"},"displayName":{"type":"string","description":"Name plus namesake label, e.g. \"Bishal Thapa (wicket-keeper)\""},"disambiguation":{"anyOf":[{"type":"string"},{"type":"null"}]},"profile":{"$ref":"#/components/schemas/Profile"},"externalIds":{"type":"object","properties":{"chautari":{"anyOf":[{"type":"string"},{"type":"null"}]},"cricclubs":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"currentTeam":{"anyOf":[{"$ref":"#/components/schemas/Ref"},{"type":"null"}]},"teams":{"type":"array","items":{"type":"object","properties":{"team":{"$ref":"#/components/schemas/Ref"},"firstSeason":{"type":"integer"},"lastSeason":{"type":"integer"}}}},"formerRecords":{"type":"array","description":"Ids of records merged into this player — re-map stored references","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"slug":{"type":"string"},"team":{"$ref":"#/components/schemas/Ref"}}}}}},"career":{"type":"object","properties":{"batting":{"anyOf":[{"$ref":"#/components/schemas/BattingRow","description":"Totals; rates recomputed from summed counts"},{"type":"null"}]},"bowling":{"anyOf":[{"$ref":"#/components/schemas/BowlingRow","description":"Totals; rates recomputed from summed counts"},{"type":"null"}]},"fielding":{"anyOf":[{"$ref":"#/components/schemas/FieldingRow","description":"Totals; rates recomputed from summed counts"},{"type":"null"}]}}},"bySeason":{"type":"object","properties":{"batting":{"type":"array","items":{"type":"object","description":"{ season, divisions, …batting figures }"}},"bowling":{"type":"array","items":{"type":"object","description":"{ season, divisions, …bowling figures }"}},"fielding":{"type":"array","items":{"type":"object","description":"{ season, divisions, …fielding figures }"}}}},"bySeries":{"type":"object","properties":{"batting":{"type":"array","items":{"type":"object","description":"{ series, divisions, …batting figures }"}},"bowling":{"type":"array","items":{"type":"object","description":"{ series, divisions, …bowling figures }"}},"fielding":{"type":"array","items":{"type":"object","description":"{ series, divisions, …fielding figures }"}}}},"byTeam":{"type":"object","properties":{"batting":{"type":"array","items":{"type":"object","description":"{ team, divisions, …batting figures }"}},"bowling":{"type":"array","items":{"type":"object","description":"{ team, divisions, …bowling figures }"}},"fielding":{"type":"array","items":{"type":"object","description":"{ team, divisions, …fielding figures }"}}}},"divisions":{"type":"object","properties":{"batting":{"type":"array","items":{"type":"object","description":"One batting line per division, with division {id, name, slug, season, series}, team, quality and rank {by, position, of}"}},"bowling":{"type":"array","items":{"type":"object","description":"One bowling line per division, with division {id, name, slug, season, series}, team, quality and rank {by, position, of}"}},"fielding":{"type":"array","items":{"type":"object","description":"One fielding line per division, with division {id, name, slug, season, series}, team, quality and rank {by, position, of}"}}}}}},"Series":{"type":"object","description":"A competition run as several divisions","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"},"organizer":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"Tournament":{"type":"object","description":"One division of a series","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"},"series":{},"season":{"type":"integer"},"district":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"datasets":{"type":"array","items":{"enum":["batting","bowling","fielding"]}},"participants":{"type":"array","items":{"type":"object","properties":{"team":{},"group":{"type":"string"}}}}}},"Team":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"}}},"User":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"enum":["user","admin"]},"isActive":{"type":"boolean"},"lastLoginAt":{"type":"string","format":"date-time"}}},"Session":{"type":"object","properties":{"accessToken":{"type":"string","description":"JWT; send as Authorization: Bearer <token>"},"tokenType":{"const":"Bearer"},"expiresIn":{"type":"string","example":"15m"},"user":{"$ref":"#/components/schemas/User"}},"description":"Also sets the httpOnly refresh-token cookie `rt` (path /api/v1/auth)"},"ImportPreview":{"type":"object","properties":{"format":{"enum":["pdf","csv","xlsx","xls","json"]},"kind":{"enum":["batting","bowling","fielding"]},"title":{"type":"string"},"suggestedTournament":{"type":"object","description":"Division name, season, district, organizer, series and tags derived from the sheet title"},"headers":{"type":"array","items":{"type":"string"}},"columnMap":{"type":"array","items":{"type":"object","properties":{"header":{"type":"string"},"field":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"totalRows":{"type":"integer"},"validRows":{"type":"integer"},"issues":{"type":"array","items":{"type":"object"},"description":"Row errors (the file cannot be imported as is)"},"warnings":{"type":"array","items":{"type":"object"},"description":"Suspected mistakes; rows import as published and are flagged"},"notes":{"type":"array","items":{"type":"string"},"description":"How ambiguous columns were read, e.g. BBF as runs/wickets"},"sample":{"type":"array","items":{"type":"object"}},"fileHash":{"type":"string"}}},"ImportResult":{"type":"object","properties":{"job":{"type":"object"},"tournament":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"slug":{"type":"string"},"created":{"type":"boolean"}}},"series":{"anyOf":[{"$ref":"#/components/schemas/Ref"},{"type":"null"}]},"summary":{"type":"object","properties":{"rows":{"type":"integer"},"imported":{"type":"integer"},"inserted":{"type":"integer"},"updated":{"type":"integer"},"deleted":{"type":"integer"},"skipped":{"type":"integer"},"teamsCreated":{"type":"integer"},"playersCreated":{"type":"integer"}}},"quality":{"type":"object","properties":{"flaggedLines":{"type":"integer"},"suspectLines":{"type":"integer"},"regressions":{"type":"integer"},"correctionsReapplied":{"type":"integer"},"correctionsSuperseded":{"type":"integer"},"acknowledgementsKept":{"type":"integer"}}},"warnings":{"type":"array","items":{"type":"object"}}}},"ApiClient":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string"},"prefix":{"type":"string","description":"Public part of the key (can_<prefix>.…)"},"rateLimitPerMinute":{"type":"integer"},"isActive":{"type":"boolean"},"internal":{"type":"boolean","description":"May call /internal endpoints"},"requestCount":{"type":"integer"},"lastUsedAt":{"type":"string","format":"date-time"}}},"InternationalSeries":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"name":{"type":"string","example":"ICC Cricket World Cup 2027"},"shortName":{"type":"string"},"slug":{"type":"string","example":"icc-cricket-world-cup-2027"},"format":{"enum":["ODI","T20I","Test"]},"gender":{"enum":["Men","Women"]},"season":{"type":"integer"},"hosts":{"type":"array","items":{"type":"string"}},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"source":{"type":"object","properties":{"system":{"const":"icc"},"seriesId":{"type":"string","example":"15463"},"tourId":{"type":"string"}}},"syncedAt":{"type":"string","format":"date-time","description":"Last pull from the ICC feed"}}},"InternationalSeriesDetail":{"allOf":[{"$ref":"#/components/schemas/InternationalSeries"},{"type":"object","properties":{"matchCount":{"type":"integer"},"stages":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"matches":{"type":"integer"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"}}}},"groups":{"type":"array","items":{"type":"object","properties":{"stage":{"type":"string"},"name":{"type":"string"},"teams":{"type":"array","items":{"$ref":"#/components/schemas/InternationalSide"}}}}},"teams":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"shortName":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceId":{"type":"string"},"group":{"anyOf":[{"type":"string"},{"type":"null"}]}}}},"venues":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"matches":{"type":"integer"}}}}}}]},"InternationalSide":{"type":"object","properties":{"name":{"type":"string","example":"India"},"shortName":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"placeholder":{"type":"boolean","description":"A slot to be filled (qualifier, group position, knockout winner), e.g. \"A1\", \"Q-A\", \"T.B.C.\""}}},"InternationalMatch":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"ordinal":{"type":"integer","description":"Running order across the event"},"title":{"type":"string","example":"Match 6"},"stage":{"type":"string","example":"Group"},"group":{"anyOf":[{"type":"string"},{"type":"null"}]},"format":{"type":"string","example":"ODI"},"teamA":{"$ref":"#/components/schemas/InternationalSide"},"teamB":{"$ref":"#/components/schemas/InternationalSide"},"venue":{"type":"object","properties":{"name":{"type":"string"},"city":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"sourceId":{"anyOf":[{"type":"string"},{"type":"null"}]}}},"startTime":{"type":"string","format":"date-time","description":"UTC"},"localStartTime":{"anyOf":[{"type":"string","example":"2027-10-10T10:00:00+02:00"},{"type":"null"}]},"dayNight":{"type":"boolean"},"provisional":{"type":"boolean","description":"Date or time not confirmed"},"status":{"enum":["upcoming","live","completed","abandoned"]},"statusText":{"anyOf":[{"type":"string"},{"type":"null"}]},"result":{"anyOf":[{"type":"string"},{"type":"null"}]},"winner":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"object","properties":{"system":{"const":"icc"},"matchId":{"type":"string","example":"275309"}}}}},"Match":{"type":"object","properties":{"_id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"ordinal":{"type":"integer","description":"Running order in the division, 1 = first match played"},"title":{"type":"string","example":"Qualifier 1"},"stage":{"type":"string","example":"League"},"date":{"type":"string","format":"date","example":"2025-12-13"},"teamA":{"$ref":"#/components/schemas/TeamRef"},"teamB":{"$ref":"#/components/schemas/TeamRef"},"innings":{"type":"array","description":"In batting order","items":{"type":"object","properties":{"team":{"$ref":"#/components/schemas/TeamRef"},"score":{"type":"string","example":"86/4"},"runs":{"type":"integer"},"wickets":{"anyOf":[{"type":"integer"},{"type":"null"}]},"overs":{"type":"string","example":"19.4"},"balls":{"type":"integer"}}}},"oversPerSide":{"anyOf":[{"type":"integer","example":20},{"type":"null"}]},"status":{"enum":["upcoming","completed","abandoned"]},"outcome":{"anyOf":[{"enum":["win","tie","no-result"]},{"type":"null"}]},"result":{"anyOf":[{"type":"string","example":"LUMBINI LIONS won by 6 Wickets","description":"As published"},{"type":"null"}]},"winner":{"anyOf":[{"$ref":"#/components/schemas/TeamRef"},{"type":"null"}]},"margin":{"anyOf":[{"type":"object","properties":{"value":{"type":"integer"},"unit":{"enum":["runs","wickets"]}}},{"type":"null"}]},"source":{"type":"object","properties":{"system":{"const":"cricclubs"},"key":{"type":"string","description":"Date and teams; the export has no match id"},"sno":{"anyOf":[{"type":"integer"},{"type":"null"}]}}}}},"Standings":{"type":"object","properties":{"data":{"type":"object","properties":{"stage":{"anyOf":[{"type":"string","example":"League"},{"type":"null"}]},"points":{"type":"object","properties":{"win":{"type":"integer"},"tie":{"type":"integer"},"noResult":{"type":"integer"},"loss":{"type":"integer"}}},"table":{"type":"array","items":{"type":"object","properties":{"position":{"type":"integer"},"team":{"$ref":"#/components/schemas/TeamRef"},"played":{"type":"integer"},"won":{"type":"integer"},"lost":{"type":"integer"},"tied":{"type":"integer"},"noResult":{"type":"integer"},"points":{"type":"integer"},"nrr":{"anyOf":[{"type":"number","example":0.812,"description":"Net run rate, 3 decimals"},{"type":"null"}]},"runsFor":{"type":"integer"},"oversFor":{"type":"string"},"runsAgainst":{"type":"integer"},"oversAgainst":{"type":"string"},"form":{"type":"string","example":"WWLWL","description":"Last five results, most recent first (W, L, T, N = no result)"}}}},"playoffs":{"type":"array","items":{"$ref":"#/components/schemas/Match"}},"champion":{"anyOf":[{"$ref":"#/components/schemas/TeamRef"},{"type":"null"}]},"runnerUp":{"anyOf":[{"$ref":"#/components/schemas/TeamRef"},{"type":"null"}]}}},"tournament":{"$ref":"#/components/schemas/DivisionRef"}}},"ApiClientWithKey":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ApiClient"},"apiKey":{"type":"string","example":"can_1a2b3c4d.xxxxxxxx","description":"Shown once; store it now"},"notice":{"type":"string"}}},"Plan":{"type":"object","properties":{"key":{"type":"string","example":"pro"},"name":{"type":"string"},"description":{"type":"string"},"periodDays":{"type":"integer"},"monthlyQuota":{"type":"integer","description":"API requests per period"},"rateLimitPerMinute":{"type":"integer"},"maxApiKeys":{"type":"integer"},"csvExport":{"type":"boolean"},"features":{"type":"array","items":{"type":"string"}}}},"Plans":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}}}},"AccountStatus":{"type":"object","properties":{"data":{"type":"object","properties":{"current":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","description":"MongoDB ObjectId"},"plan":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"}}},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"quota":{"type":"integer"},"used":{"type":"integer"},"remaining":{"type":"integer"},"rateLimitPerMinute":{"type":"integer"},"maxApiKeys":{"type":"integer"},"csvExport":{"type":"boolean"},"source":{"enum":["free","admin-grant"]}}},{"type":"null"}]},"upcoming":{"type":"array","items":{"type":"object"},"description":"Granted periods starting when the current one ends"},"apiKeys":{"type":"integer"}}}}},"QualityLine":{"type":"object","description":"A stat line in the review queue: kind, player, team, tournament, quality and the correctable figures"},"QualitySummary":{"type":"object","properties":{"data":{"type":"object","properties":{"open":{"type":"integer"},"acknowledged":{"type":"integer"},"corrected":{"type":"integer"},"byRule":{"type":"array","items":{"type":"object"}}}}}},"StatLine":{"type":"object","description":"A stored stat line after the change (figures, recomputed rates and quality)"},"IdentityColumns":{"type":"object","description":"Identity columns recognised in uploads: #, Player, Team, Group, Player ID, Chautari ID"}}},"paths":{"/":{"get":{"tags":["Meta"],"summary":"API index","operationId":"get","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/register":{"post":{"tags":["Auth"],"summary":"Create an account","description":"Creates an inactive account and emails an activation link. If the email cannot be sent the account is rolled back (502).","operationId":"postAuthRegister","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":80},"email":{"type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"password":{"type":"string","minLength":8,"maxLength":72,"allOf":[{"pattern":"[a-z]"},{"pattern":"[A-Z]"},{"pattern":"\\d"}]}},"required":["name","email","password"]}}}},"security":[],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"user":{"$ref":"#/components/schemas/User"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/activate/{token}":{"post":{"tags":["Auth"],"summary":"Activate an account","description":"One-time token from the activation email.","operationId":"postAuthActivateByToken","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","minLength":20,"maxLength":100}}],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/login":{"post":{"tags":["Auth"],"summary":"Sign in","description":"Returns an access token (JWT, 15 min) and sets the refresh-token cookie `rt`. Five failed attempts lock the account for 15 minutes (423).","operationId":"postAuthLogin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"password":{"type":"string","minLength":1,"maxLength":200}},"required":["email","password"]}}}},"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/refresh":{"post":{"tags":["Auth"],"summary":"Get a new access token","description":"Rotates the refresh token (cookie `rt`, or `refreshToken` in the body). Replaying an already-used token revokes the whole session family.","operationId":"postAuthRefresh","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","maxLength":200}}}}}},"security":[{"refreshCookie":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/logout":{"post":{"tags":["Auth"],"summary":"Sign out","description":"Revokes the refresh token and clears the cookie.","operationId":"postAuthLogout","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","maxLength":200}}}}}},"security":[{"refreshCookie":[]}],"responses":{"204":{"description":"No content"},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/logout-all":{"post":{"tags":["Auth"],"summary":"Sign out everywhere","description":"Revokes every refresh token and invalidates outstanding access tokens.","operationId":"postAuthLogoutAll","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/password/forgot":{"post":{"tags":["Auth"],"summary":"Request a password reset email","description":"Same response whether or not the email exists.","operationId":"postAuthPasswordForgot","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["email"]}}}},"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/password/reset":{"post":{"tags":["Auth"],"summary":"Set a new password","description":"One-time token from the reset email (valid 1 hour). Signs out every session.","operationId":"postAuthPasswordReset","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":20,"maxLength":100},"password":{"type":"string","minLength":8,"maxLength":72,"allOf":[{"pattern":"[a-z]"},{"pattern":"[A-Z]"},{"pattern":"\\d"}]}},"required":["token","password"]}}}},"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/me":{"get":{"tags":["Auth"],"summary":"Current user","operationId":"getAuthMe","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/users":{"get":{"tags":["Users"],"summary":"List users","description":"**Requires role:** admin.","operationId":"getUsers","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"role","in":"query","required":false,"schema":{"type":"string","enum":["user","admin"]}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update my name","operationId":"patchUsersMe","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":80}},"required":["name"],"additionalProperties":false}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/User"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Users"],"summary":"Delete my account","operationId":"deleteUsersMe","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/users/me/password":{"patch":{"tags":["Users"],"summary":"Change my password","description":"Signs out other sessions.","operationId":"patchUsersMePassword","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"currentPassword":{"type":"string","minLength":1,"maxLength":200},"newPassword":{"type":"string","minLength":8,"maxLength":72,"allOf":[{"pattern":"[a-z]"},{"pattern":"[A-Z]"},{"pattern":"\\d"}]}},"required":["currentPassword","newPassword"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/users/{id}":{"get":{"tags":["Users"],"summary":"Get a user","description":"Admins, or the user themselves.","operationId":"getUsersById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/User"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Users"],"summary":"Delete a user","description":"**Requires role:** admin.","operationId":"deleteUsersById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/users/{id}/role":{"patch":{"tags":["Users"],"summary":"Change a user's role","description":"**Requires role:** admin.","operationId":"patchUsersByIdRole","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["user","admin"]}},"required":["role"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/User"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/series":{"get":{"tags":["Competitions"],"summary":"List series","description":"With division counts and seasons.","operationId":"getSeries","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"tag","in":"query","required":false,"schema":{"type":"string","maxLength":40}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Series"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Competitions"],"summary":"Create a series","description":"**Requires role:** admin.","operationId":"postSeries","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":200},"organizer":{"type":"string","maxLength":150},"tags":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}}},"required":["name"]}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/series/{series}":{"get":{"tags":["Competitions"],"summary":"Get a series and its divisions","operationId":"getSeriesBySeries","parameters":[{"name":"series","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"},"divisions":{"type":"array","items":{"$ref":"#/components/schemas/Tournament"}}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Competitions"],"summary":"Update a series","description":"**Requires role:** admin.","operationId":"patchSeriesBySeries","parameters":[{"name":"series","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":160}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":200},"organizer":{"type":"string","maxLength":150},"tags":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}}},"additionalProperties":false}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Series"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Competitions"],"summary":"Delete an empty series","description":"409 while it still has divisions.\n\n**Requires role:** admin.","operationId":"deleteSeriesBySeries","parameters":[{"name":"series","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments":{"get":{"tags":["Competitions"],"summary":"List divisions","operationId":"getTournaments","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"season","in":"query","required":false,"schema":{"type":"integer","minimum":1900,"maximum":2200}},{"name":"district","in":"query","required":false,"schema":{"type":"string","maxLength":80}},{"name":"series","in":"query","required":false,"schema":{"type":"string","maxLength":160}},{"name":"matchType","in":"query","required":false,"schema":{"type":"string","maxLength":30}},{"name":"tag","in":"query","required":false,"schema":{"type":"string","maxLength":40}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["upcoming","ongoing","completed"]}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","maxLength":60}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tournament"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Competitions"],"summary":"Create a division","description":"**Requires role:** admin.","operationId":"postTournaments","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":200},"slug":{"type":"string","maxLength":160,"pattern":"^[a-z0-9-]+$"},"season":{"type":"integer","minimum":1900,"maximum":2200},"district":{"type":"string","maxLength":80},"organizer":{"type":"string","maxLength":150},"series":{"type":"string","maxLength":160},"matchType":{"type":"string","maxLength":30},"tags":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"status":{"type":"string","enum":["upcoming","ongoing","completed"]}},"required":["name"]}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tournament"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}":{"get":{"tags":["Competitions"],"summary":"Get a division","description":"By id or slug, with participating teams and groups.","operationId":"getTournamentsByTournament","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tournament"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Competitions"],"summary":"Update a division","description":"**Requires role:** admin.","operationId":"patchTournamentsByTournament","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":200},"season":{"type":"integer","minimum":1900,"maximum":2200},"district":{"type":"string","maxLength":80},"organizer":{"type":"string","maxLength":150},"series":{"type":"string","maxLength":160},"matchType":{"type":"string","maxLength":30},"tags":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"status":{"type":"string","enum":["upcoming","ongoing","completed"]}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tournament"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Competitions"],"summary":"Delete a division and all its figures","description":"**Requires role:** admin.","operationId":"deleteTournamentsByTournament","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/summary":{"get":{"tags":["Competitions"],"summary":"Division headline numbers and top performers","operationId":"getTournamentsByTournamentSummary","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/teams":{"get":{"tags":["Competitions"],"summary":"Per-team aggregates in a division","operationId":"getTournamentsByTournamentTeams","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/matches":{"get":{"tags":["Competitions"],"summary":"Match results and fixtures of a division","description":"In playing order (`ordinal`). Filter by stage, team (id, slug or name), status, outcome or date range. Each innings has runs, wickets, overs and balls; `margin` is `{ value, unit: runs|wickets }`. Imported from CricClubs results exports.","operationId":"getTournamentsByTournamentMatches","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":100,"type":"integer","minimum":1,"maximum":100}},{"name":"stage","in":"query","required":false,"description":"League, Qualifier, Eliminator, Final, …","schema":{"type":"string","minLength":1,"maxLength":40}},{"name":"team","in":"query","required":false,"description":"Team id, slug or name","schema":{"type":"string","minLength":1,"maxLength":150}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["upcoming","completed","abandoned"]}},{"name":"outcome","in":"query","required":false,"schema":{"type":"string","enum":["win","tie","no-result"]}},{"name":"from","in":"query","required":false,"description":"Played on or after this date","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Played on or before this date","schema":{"type":"string","format":"date"}},{"name":"sort","in":"query","required":false,"description":"ordinal (default) or date; prefix - for descending","schema":{"type":"string","maxLength":40}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Match"}},"meta":{"$ref":"#/components/schemas/PageMeta"},"tournament":{"$ref":"#/components/schemas/DivisionRef"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/matches/{match}":{"get":{"tags":["Competitions"],"summary":"One match","description":"By id, or by its number in the division (1 = first match played).","operationId":"getTournamentsByTournamentMatchesByMatch","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"match","in":"path","required":true,"description":"Match id, or its number in the division (1 = first match played)","schema":{"type":"string","pattern":"^([a-f0-9]{24}|\\d{1,4})$"}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Match"},"tournament":{"$ref":"#/components/schemas/DivisionRef"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/standings":{"get":{"tags":["Competitions"],"summary":"Points table, playoffs and champion","description":"Table of the league / group stage (the stage with the most matches unless `stage` is given): played, won, lost, tied, no result, points (win 2, tie or no result 1), net run rate and last-five form. A side bowled out is charged its full overs quota for NRR. Matches of other stages are listed under `playoffs`.","operationId":"getTournamentsByTournamentStandings","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"stage","in":"query","required":false,"description":"Stage to tabulate; defaults to the one with the most matches (League)","schema":{"type":"string","minLength":1,"maxLength":40}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Standings"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/batting":{"get":{"tags":["Competitions"],"summary":"Batting table for one division","description":"Sort with `sort` or rank by `category`. Any numeric column can also be range-filtered with `field[gte|gt|lte|lt|eq|ne]=number` (e.g. `runs[gte]=200&strikeRate[gte]=120`). With combine=true the filter applies to combined totals.","operationId":"getTournamentsByTournamentBatting","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"category","in":"query","required":false,"description":"Leaderboard to rank by, e.g. most-runs, best-economy, most-catches (see GET /stats/categories)","schema":{"type":"string","maxLength":40}},{"name":"sort","in":"query","required":false,"description":"Explicit order instead of the category, e.g. \"-sixes,runs\" (prefix - for descending)","schema":{"type":"string","maxLength":100}},{"name":"team","in":"query","required":false,"description":"Team slug or id","schema":{"type":"string","maxLength":160}},{"name":"group","in":"query","required":false,"description":"Group within a division, e.g. A","schema":{"type":"string","maxLength":20}},{"name":"q","in":"query","required":false,"description":"Player name search","schema":{"type":"string","maxLength":80}},{"name":"minInnings","in":"query","required":false,"description":"Minimum innings (overrides the category default; 0 disables)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minBalls","in":"query","required":false,"description":"Minimum balls faced / bowled","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minWickets","in":"query","required":false,"description":"Minimum wickets (bowling)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"format","in":"query","required":false,"description":"csv downloads the same view as a CricClubs-style sheet","schema":{"default":"json","type":"string","enum":["json","csv"]}},{"name":"columns","in":"query","required":false,"description":"CSV columns: CricClubs layout, or every recorded column","schema":{"default":"primary","type":"string","enum":["primary","all"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated columns to return, e.g. runs,sixes","schema":{"type":"string","maxLength":500}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BattingPage"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/bowling":{"get":{"tags":["Competitions"],"summary":"Bowling table for one division","description":"Sort with `sort` or rank by `category`. Any numeric column can also be range-filtered with `field[gte|gt|lte|lt|eq|ne]=number` (e.g. `runs[gte]=200&strikeRate[gte]=120`). With combine=true the filter applies to combined totals.","operationId":"getTournamentsByTournamentBowling","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"category","in":"query","required":false,"description":"Leaderboard to rank by, e.g. most-runs, best-economy, most-catches (see GET /stats/categories)","schema":{"type":"string","maxLength":40}},{"name":"sort","in":"query","required":false,"description":"Explicit order instead of the category, e.g. \"-sixes,runs\" (prefix - for descending)","schema":{"type":"string","maxLength":100}},{"name":"team","in":"query","required":false,"description":"Team slug or id","schema":{"type":"string","maxLength":160}},{"name":"group","in":"query","required":false,"description":"Group within a division, e.g. A","schema":{"type":"string","maxLength":20}},{"name":"q","in":"query","required":false,"description":"Player name search","schema":{"type":"string","maxLength":80}},{"name":"minInnings","in":"query","required":false,"description":"Minimum innings (overrides the category default; 0 disables)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minBalls","in":"query","required":false,"description":"Minimum balls faced / bowled","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minWickets","in":"query","required":false,"description":"Minimum wickets (bowling)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"format","in":"query","required":false,"description":"csv downloads the same view as a CricClubs-style sheet","schema":{"default":"json","type":"string","enum":["json","csv"]}},{"name":"columns","in":"query","required":false,"description":"CSV columns: CricClubs layout, or every recorded column","schema":{"default":"primary","type":"string","enum":["primary","all"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated columns to return, e.g. runs,sixes","schema":{"type":"string","maxLength":500}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BowlingPage"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tournaments/{tournament}/fielding":{"get":{"tags":["Competitions"],"summary":"Fielding table for one division","description":"Sort with `sort` or rank by `category`. Any numeric column can also be range-filtered with `field[gte|gt|lte|lt|eq|ne]=number` (e.g. `runs[gte]=200&strikeRate[gte]=120`). With combine=true the filter applies to combined totals.","operationId":"getTournamentsByTournamentFielding","parameters":[{"name":"tournament","in":"path","required":true,"description":"Division id or slug","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"category","in":"query","required":false,"description":"Leaderboard to rank by, e.g. most-runs, best-economy, most-catches (see GET /stats/categories)","schema":{"type":"string","maxLength":40}},{"name":"sort","in":"query","required":false,"description":"Explicit order instead of the category, e.g. \"-sixes,runs\" (prefix - for descending)","schema":{"type":"string","maxLength":100}},{"name":"team","in":"query","required":false,"description":"Team slug or id","schema":{"type":"string","maxLength":160}},{"name":"group","in":"query","required":false,"description":"Group within a division, e.g. A","schema":{"type":"string","maxLength":20}},{"name":"q","in":"query","required":false,"description":"Player name search","schema":{"type":"string","maxLength":80}},{"name":"minInnings","in":"query","required":false,"description":"Minimum innings (overrides the category default; 0 disables)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minBalls","in":"query","required":false,"description":"Minimum balls faced / bowled","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minWickets","in":"query","required":false,"description":"Minimum wickets (bowling)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"format","in":"query","required":false,"description":"csv downloads the same view as a CricClubs-style sheet","schema":{"default":"json","type":"string","enum":["json","csv"]}},{"name":"columns","in":"query","required":false,"description":"CSV columns: CricClubs layout, or every recorded column","schema":{"default":"primary","type":"string","enum":["primary","all"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated columns to return, e.g. runs,sixes","schema":{"type":"string","maxLength":500}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FieldingPage"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/teams":{"get":{"tags":["Competitions"],"summary":"List teams","operationId":"getTeams","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":80}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Team"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/teams/{team}":{"get":{"tags":["Competitions"],"summary":"Get a team with its squad and divisions","operationId":"getTeamsByTeam","parameters":[{"name":"team","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/players":{"get":{"tags":["Players"],"summary":"Search players","description":"Matches names and merged-in spellings. Merged duplicate records are hidden.","operationId":"getPlayers","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":80}},{"name":"team","in":"query","required":false,"schema":{"type":"string","maxLength":160}},{"name":"role","in":"query","required":false,"schema":{"type":"string","enum":["batter","bowler","all-rounder","wicket-keeper","wicket-keeper-batter"]}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlayerListItem"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/players/external/{system}/{externalId}":{"get":{"tags":["Players"],"summary":"Player detail by partner id","description":"Look a player up by your own id (e.g. Cricket Chautari's). Same response as /players/{player}.","operationId":"getPlayersExternalBySystemByExternalId","parameters":[{"name":"system","in":"path","required":true,"schema":{"type":"string","enum":["chautari","cricclubs"]}},{"name":"externalId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":100}},{"name":"tag","in":"query","required":false,"description":"Narrow every figure to part of the career. Comma-separated for several, e.g. Men","schema":{"type":"string","maxLength":500}},{"name":"season","in":"query","required":false,"description":"Narrow every figure to part of the career. Comma-separated for several, e.g. 2025,2026","schema":{"type":"string","maxLength":500}},{"name":"series","in":"query","required":false,"description":"Narrow every figure to part of the career. Comma-separated for several, e.g. mens-prime-minister-cup-district-selection","schema":{"type":"string","maxLength":500}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerDetail"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/players/{player}":{"get":{"tags":["Players"],"summary":"Player detail","description":"Profile, career totals, breakdowns by season / series / team, and every division line with the player's rank in it. A merged record's id or slug answers **301** with the kept player's URL: follow it and update stored references.","operationId":"getPlayersByPlayer","parameters":[{"name":"player","in":"path","required":true,"description":"Player id or slug","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"tag","in":"query","required":false,"description":"Narrow every figure to part of the career. Comma-separated for several, e.g. Men","schema":{"type":"string","maxLength":500}},{"name":"season","in":"query","required":false,"description":"Narrow every figure to part of the career. Comma-separated for several, e.g. 2025,2026","schema":{"type":"string","maxLength":500}},{"name":"series","in":"query","required":false,"description":"Narrow every figure to part of the career. Comma-separated for several, e.g. mens-prime-minister-cup-district-selection","schema":{"type":"string","maxLength":500}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerDetail"}}}},"301":{"description":"This record was merged; Location points at the kept player"},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Players"],"summary":"Edit profile, namesake label and partner ids","description":"`null` clears a field. Photo URLs must be https.\n\n**Requires role:** admin.","operationId":"patchPlayersByPlayer","parameters":[{"name":"player","in":"path","required":true,"description":"Player id or slug","schema":{"type":"string","minLength":1,"maxLength":200}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"disambiguation":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"profile":{"type":"object","properties":{"photoUrl":{"anyOf":[{"type":"string","maxLength":500,"format":"uri"},{"type":"null"}]},"role":{"anyOf":[{"type":"string","enum":["batter","bowler","all-rounder","wicket-keeper","wicket-keeper-batter"]},{"type":"null"}]},"battingStyle":{"anyOf":[{"type":"string","enum":["right-hand bat","left-hand bat"]},{"type":"null"}]},"bowlingStyle":{"anyOf":[{"type":"string","enum":["right-arm fast","right-arm fast-medium","right-arm medium","right-arm off-spin","right-arm leg-spin","left-arm fast","left-arm fast-medium","left-arm medium","left-arm orthodox","left-arm wrist-spin"]},{"type":"null"}]},"dateOfBirth":{"anyOf":[{"type":"string","format":"date","example":"2004-05-01"},{"type":"null"}]},"district":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"bio":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false},"externalIds":{"type":"object","properties":{"chautari":{"anyOf":[{"type":"string","minLength":1,"maxLength":100},{"type":"null"}]},"cricclubs":{"anyOf":[{"type":"string","minLength":1,"maxLength":100},{"type":"null"}]}},"additionalProperties":false}},"additionalProperties":false}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stats/categories":{"get":{"tags":["Statistics"],"summary":"Categories and column metadata","description":"The category menu for each dataset and the column metadata (labels, types, which columns are primary / filterable). Build tables and filter pickers from this instead of hard-coding columns.","operationId":"getStatsCategories","security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Categories"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stats/filters":{"get":{"tags":["Statistics"],"summary":"Options for the filter dropdowns","description":"Cascading: each list is narrowed by the filters above it (Tag → Year → Series → Division → Teams).","operationId":"getStatsFilters","parameters":[{"name":"tag","in":"query","required":false,"description":"Comma-separated for several, e.g. Men,U-19","schema":{"type":"string","maxLength":500}},{"name":"season","in":"query","required":false,"description":"Comma-separated for several, e.g. 2025,2026","schema":{"type":"string","maxLength":500}},{"name":"series","in":"query","required":false,"description":"Comma-separated for several, e.g. mens-prime-minister-cup-district-selection","schema":{"type":"string","maxLength":500}},{"name":"tournament","in":"query","required":false,"description":"Comma-separated for several, e.g. a division slug or id","schema":{"type":"string","maxLength":500}},{"name":"matchType","in":"query","required":false,"description":"Comma-separated for several, e.g. T20","schema":{"type":"string","maxLength":500}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FilterOptions"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stats/batting":{"get":{"tags":["Statistics"],"summary":"Batting statistics explorer","description":"CricClubs-style leaderboard. Categories: `most-runs`, `highest-scores`, `best-average`, `best-strike-rate`, `most-centuries`, `most-fifties`, `most-sixes`, `most-fours`. Filter by tag / season / series / division (`tournament`) / team / player (`q`). combine=true (default) sums each player across the selected divisions; combine=false gives one row per division. Any numeric column can also be range-filtered with `field[gte|gt|lte|lt|eq|ne]=number` (e.g. `runs[gte]=200&strikeRate[gte]=120`). With combine=true the filter applies to combined totals. `format=csv` exports the view.","operationId":"getStatsBatting","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"category","in":"query","required":false,"description":"Leaderboard to rank by, e.g. most-runs, best-economy, most-catches (see GET /stats/categories)","schema":{"type":"string","maxLength":40}},{"name":"sort","in":"query","required":false,"description":"Explicit order instead of the category, e.g. \"-sixes,runs\" (prefix - for descending)","schema":{"type":"string","maxLength":100}},{"name":"team","in":"query","required":false,"description":"Team slug or id","schema":{"type":"string","maxLength":160}},{"name":"group","in":"query","required":false,"description":"Group within a division, e.g. A","schema":{"type":"string","maxLength":20}},{"name":"q","in":"query","required":false,"description":"Player name search","schema":{"type":"string","maxLength":80}},{"name":"minInnings","in":"query","required":false,"description":"Minimum innings (overrides the category default; 0 disables)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minBalls","in":"query","required":false,"description":"Minimum balls faced / bowled","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minWickets","in":"query","required":false,"description":"Minimum wickets (bowling)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"format","in":"query","required":false,"description":"csv downloads the same view as a CricClubs-style sheet","schema":{"default":"json","type":"string","enum":["json","csv"]}},{"name":"columns","in":"query","required":false,"description":"CSV columns: CricClubs layout, or every recorded column","schema":{"default":"primary","type":"string","enum":["primary","all"]}},{"name":"tag","in":"query","required":false,"description":"Comma-separated for several, e.g. Men,U-19","schema":{"type":"string","maxLength":500}},{"name":"season","in":"query","required":false,"description":"Comma-separated for several, e.g. 2025,2026","schema":{"type":"string","maxLength":500}},{"name":"series","in":"query","required":false,"description":"Comma-separated for several, e.g. mens-prime-minister-cup-district-selection","schema":{"type":"string","maxLength":500}},{"name":"tournament","in":"query","required":false,"description":"Comma-separated for several, e.g. a division slug or id","schema":{"type":"string","maxLength":500}},{"name":"matchType","in":"query","required":false,"description":"Comma-separated for several, e.g. T20","schema":{"type":"string","maxLength":500}},{"name":"combine","in":"query","required":false,"description":"true: one row per player, summed across the selected divisions (rates recomputed). false: one row per player per division","schema":{"default":"true","type":"string","enum":["0","1","true","false"]}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BattingPage"}},"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stats/bowling":{"get":{"tags":["Statistics"],"summary":"Bowling statistics explorer","description":"CricClubs-style leaderboard. Categories: `most-wickets`, `best-bowling`, `best-economy`, `best-average`, `best-strike-rate`, `most-maidens`, `most-dots`, `most-five-wickets`. Filter by tag / season / series / division (`tournament`) / team / player (`q`). combine=true (default) sums each player across the selected divisions; combine=false gives one row per division. Any numeric column can also be range-filtered with `field[gte|gt|lte|lt|eq|ne]=number` (e.g. `runs[gte]=200&strikeRate[gte]=120`). With combine=true the filter applies to combined totals. `format=csv` exports the view.","operationId":"getStatsBowling","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"category","in":"query","required":false,"description":"Leaderboard to rank by, e.g. most-runs, best-economy, most-catches (see GET /stats/categories)","schema":{"type":"string","maxLength":40}},{"name":"sort","in":"query","required":false,"description":"Explicit order instead of the category, e.g. \"-sixes,runs\" (prefix - for descending)","schema":{"type":"string","maxLength":100}},{"name":"team","in":"query","required":false,"description":"Team slug or id","schema":{"type":"string","maxLength":160}},{"name":"group","in":"query","required":false,"description":"Group within a division, e.g. A","schema":{"type":"string","maxLength":20}},{"name":"q","in":"query","required":false,"description":"Player name search","schema":{"type":"string","maxLength":80}},{"name":"minInnings","in":"query","required":false,"description":"Minimum innings (overrides the category default; 0 disables)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minBalls","in":"query","required":false,"description":"Minimum balls faced / bowled","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minWickets","in":"query","required":false,"description":"Minimum wickets (bowling)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"format","in":"query","required":false,"description":"csv downloads the same view as a CricClubs-style sheet","schema":{"default":"json","type":"string","enum":["json","csv"]}},{"name":"columns","in":"query","required":false,"description":"CSV columns: CricClubs layout, or every recorded column","schema":{"default":"primary","type":"string","enum":["primary","all"]}},{"name":"tag","in":"query","required":false,"description":"Comma-separated for several, e.g. Men,U-19","schema":{"type":"string","maxLength":500}},{"name":"season","in":"query","required":false,"description":"Comma-separated for several, e.g. 2025,2026","schema":{"type":"string","maxLength":500}},{"name":"series","in":"query","required":false,"description":"Comma-separated for several, e.g. mens-prime-minister-cup-district-selection","schema":{"type":"string","maxLength":500}},{"name":"tournament","in":"query","required":false,"description":"Comma-separated for several, e.g. a division slug or id","schema":{"type":"string","maxLength":500}},{"name":"matchType","in":"query","required":false,"description":"Comma-separated for several, e.g. T20","schema":{"type":"string","maxLength":500}},{"name":"combine","in":"query","required":false,"description":"true: one row per player, summed across the selected divisions (rates recomputed). false: one row per player per division","schema":{"default":"true","type":"string","enum":["0","1","true","false"]}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BowlingPage"}},"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stats/fielding":{"get":{"tags":["Statistics"],"summary":"Fielding statistics explorer","description":"CricClubs-style leaderboard. Categories: `most-dismissals`, `most-catches`, `most-run-outs`, `most-stumpings`, `most-keeper-dismissals`. Filter by tag / season / series / division (`tournament`) / team / player (`q`). combine=true (default) sums each player across the selected divisions; combine=false gives one row per division. Any numeric column can also be range-filtered with `field[gte|gt|lte|lt|eq|ne]=number` (e.g. `runs[gte]=200&strikeRate[gte]=120`). With combine=true the filter applies to combined totals. `format=csv` exports the view.","operationId":"getStatsFielding","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}},{"name":"category","in":"query","required":false,"description":"Leaderboard to rank by, e.g. most-runs, best-economy, most-catches (see GET /stats/categories)","schema":{"type":"string","maxLength":40}},{"name":"sort","in":"query","required":false,"description":"Explicit order instead of the category, e.g. \"-sixes,runs\" (prefix - for descending)","schema":{"type":"string","maxLength":100}},{"name":"team","in":"query","required":false,"description":"Team slug or id","schema":{"type":"string","maxLength":160}},{"name":"group","in":"query","required":false,"description":"Group within a division, e.g. A","schema":{"type":"string","maxLength":20}},{"name":"q","in":"query","required":false,"description":"Player name search","schema":{"type":"string","maxLength":80}},{"name":"minInnings","in":"query","required":false,"description":"Minimum innings (overrides the category default; 0 disables)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minBalls","in":"query","required":false,"description":"Minimum balls faced / bowled","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"minWickets","in":"query","required":false,"description":"Minimum wickets (bowling)","schema":{"type":"integer","minimum":0,"maximum":10000}},{"name":"format","in":"query","required":false,"description":"csv downloads the same view as a CricClubs-style sheet","schema":{"default":"json","type":"string","enum":["json","csv"]}},{"name":"columns","in":"query","required":false,"description":"CSV columns: CricClubs layout, or every recorded column","schema":{"default":"primary","type":"string","enum":["primary","all"]}},{"name":"tag","in":"query","required":false,"description":"Comma-separated for several, e.g. Men,U-19","schema":{"type":"string","maxLength":500}},{"name":"season","in":"query","required":false,"description":"Comma-separated for several, e.g. 2025,2026","schema":{"type":"string","maxLength":500}},{"name":"series","in":"query","required":false,"description":"Comma-separated for several, e.g. mens-prime-minister-cup-district-selection","schema":{"type":"string","maxLength":500}},{"name":"tournament","in":"query","required":false,"description":"Comma-separated for several, e.g. a division slug or id","schema":{"type":"string","maxLength":500}},{"name":"matchType","in":"query","required":false,"description":"Comma-separated for several, e.g. T20","schema":{"type":"string","maxLength":500}},{"name":"combine","in":"query","required":false,"description":"true: one row per player, summed across the selected divisions (rates recomputed). false: one row per player per division","schema":{"default":"true","type":"string","enum":["0","1","true","false"]}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FieldingPage"}},"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stats/leaderboard":{"get":{"tags":["Statistics"],"summary":"Top N by one metric","description":"Combined across the selected scope; rates recomputed from summed counts.","operationId":"getStatsLeaderboard","parameters":[{"name":"kind","in":"query","required":false,"schema":{"default":"batting","type":"string","enum":["batting","bowling","fielding"]}},{"name":"metric","in":"query","required":false,"schema":{"type":"string","maxLength":40}},{"name":"tournament","in":"query","required":false,"schema":{"type":"string","maxLength":160}},{"name":"season","in":"query","required":false,"schema":{"type":"integer","minimum":1900,"maximum":2200}},{"name":"limit","in":"query","required":false,"schema":{"default":10,"type":"integer","minimum":1,"maximum":100}},{"name":"minInnings","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"minBalls","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"security":[{},{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Leaderboard"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/site-session":{"post":{"tags":["Meta"],"summary":"Website session (first-party only)","description":"Used by this site's own pages to read the API without a key (httpOnly SameSite cookie + same-origin check). Apps must use an API key.","operationId":"postSiteSession","security":[],"responses":{"204":{"description":"No content"},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/billing/me":{"get":{"tags":["Plans & API keys"],"summary":"My plan, usage and upcoming periods","description":"Everyone has at least the Free plan; it starts automatically.","operationId":"getBillingMe","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountStatus"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/account/api-keys":{"get":{"tags":["Plans & API keys"],"summary":"My API keys","operationId":"getAccountApiKeys","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiClient"}}}}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Plans & API keys"],"summary":"Create an API key","description":"The key is shown once. The number of active keys is limited by your plan.","operationId":"postAccountApiKeys","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"A label, e.g. \"Android app\""}},"required":["name"]}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiClientWithKey"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/account/api-keys/{id}/rotate":{"post":{"tags":["Plans & API keys"],"summary":"Rotate one of my keys","operationId":"postAccountApiKeysByIdRotate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiClientWithKey"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/account/api-keys/{id}":{"delete":{"tags":["Plans & API keys"],"summary":"Revoke one of my keys","operationId":"deleteAccountApiKeysById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/imports/datasets":{"get":{"tags":["Admin: imports"],"summary":"Supported datasets, fields and header aliases","description":"**Requires role:** admin.","operationId":"getAdminImportsDatasets","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/imports":{"get":{"tags":["Admin: imports"],"summary":"Import history","description":"**Requires role:** admin.","operationId":"getAdminImports","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["completed","failed"]}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["batting","bowling","fielding"]}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ImportResult"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Admin: imports"],"summary":"Import a file","description":"One ACID transaction. Rows with errors reject the file (422) unless allowPartial=true; suspected mistakes import as published, are flagged for review, and every admin is emailed. The same file twice for one division is refused (409) unless force=true.\n\n**Requires role:** admin.","operationId":"postAdminImports","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"PDF, CSV, XLS, XLSX or JSON stats sheet"},"kind":{"anyOf":[{"type":"string","enum":["batting","bowling","fielding"]},{"type":"string","const":""}],"description":"Dataset; detected from the headers when omitted"},"sheetName":{"type":"string","maxLength":100},"mapping":{"description":"JSON object mapping unusual headers: {\"Tot Runs\": \"runs\", \"Notes\": null}","type":"string","maxLength":10000},"tournamentId":{"anyOf":[{"type":"string"},{"type":"string","const":""}],"description":"Existing division id"},"tournamentName":{"description":"Or: division name (defaults to the name in the sheet title)","type":"string","maxLength":200},"season":{"anyOf":[{"type":"integer","minimum":1900,"maximum":2200},{"type":"string","const":""}]},"district":{"type":"string","maxLength":80},"organizer":{"type":"string","maxLength":150},"seriesId":{"anyOf":[{"type":"string","maxLength":160},{"type":"string","const":""}],"description":"Existing series (slug or id)"},"seriesName":{"description":"Or: find/create a series by name","type":"string","maxLength":200},"matchType":{"type":"string","maxLength":30},"tags":{"type":"string","maxLength":500},"mode":{"default":"upsert","description":"upsert: add and update rows. replace: re-sync the division (rows missing from the file are removed)","type":"string","enum":["upsert","replace"]},"force":{"description":"Allow importing the same file into the same division again","default":"false","type":"string","enum":["true","false"]},"allowPartial":{"description":"Skip rows with errors instead of rejecting the file","default":"false","type":"string","enum":["true","false"]},"strict":{"description":"Also reject rows with suspected mistakes (default: import and flag them)","default":"false","type":"string","enum":["true","false"]}}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportResult"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/imports/{id}":{"get":{"tags":["Admin: imports"],"summary":"One import with its issues and findings","description":"**Requires role:** admin.","operationId":"getAdminImportsById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/imports/results/preview":{"post":{"tags":["Admin: imports"],"summary":"Dry run: parse and check a results export","description":"CricClubs results export (CSV, XLS or XLSX: SNO, Match Type, Date, Team One, Team Two, Result, Score Summary). Shows parsed matches, row errors, and results that disagree with the scores. Nothing is written.\n\n**Requires role:** admin.","operationId":"postAdminImportsResultsPreview","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"PDF, CSV, XLS, XLSX or JSON stats sheet"},"sheetName":{"type":"string","maxLength":100},"tournamentId":{"anyOf":[{"type":"string"},{"type":"string","const":""}],"description":"Existing division id"},"tournamentName":{"description":"Or: division name (defaults to the name in the sheet title)","type":"string","maxLength":200},"season":{"anyOf":[{"type":"integer","minimum":1900,"maximum":2200},{"type":"string","const":""}]},"organizer":{"type":"string","maxLength":150},"seriesId":{"anyOf":[{"type":"string","maxLength":160},{"type":"string","const":""}],"description":"Existing series (slug or id)"},"seriesName":{"description":"Or: find/create a series by name","type":"string","maxLength":200},"matchType":{"type":"string","maxLength":30},"tags":{"type":"string","maxLength":500},"mode":{"default":"upsert","description":"upsert: add and update rows. replace: re-sync the division (rows missing from the file are removed)","type":"string","enum":["upsert","replace"]},"force":{"description":"Allow importing the same file into the same division again","default":"false","type":"string","enum":["true","false"]},"allowPartial":{"description":"Skip rows with errors instead of rejecting the file","default":"false","type":"string","enum":["true","false"]},"oversPerSide":{"anyOf":[{"type":"integer","minimum":1,"maximum":100},{"type":"string","const":""}],"description":"Overs per innings, for net run rate; defaults from matchType (T20 = 20) or the scores"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/imports/results":{"post":{"tags":["Admin: imports"],"summary":"Import match results into a division","description":"One ACID transaction. Give the division (`tournamentId`, or `tournamentName` + `season`, optionally `seriesName`); the export has no competition name. Matches are keyed by date and teams, so a later export updates them in place; `mode=replace` also removes matches the file no longer lists. Results that disagree with the scores import as published and are returned as warnings.\n\n**Requires role:** admin.","operationId":"postAdminImportsResults","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"PDF, CSV, XLS, XLSX or JSON stats sheet"},"sheetName":{"type":"string","maxLength":100},"tournamentId":{"anyOf":[{"type":"string"},{"type":"string","const":""}],"description":"Existing division id"},"tournamentName":{"description":"Or: division name (defaults to the name in the sheet title)","type":"string","maxLength":200},"season":{"anyOf":[{"type":"integer","minimum":1900,"maximum":2200},{"type":"string","const":""}]},"organizer":{"type":"string","maxLength":150},"seriesId":{"anyOf":[{"type":"string","maxLength":160},{"type":"string","const":""}],"description":"Existing series (slug or id)"},"seriesName":{"description":"Or: find/create a series by name","type":"string","maxLength":200},"matchType":{"type":"string","maxLength":30},"tags":{"type":"string","maxLength":500},"mode":{"default":"upsert","description":"upsert: add and update rows. replace: re-sync the division (rows missing from the file are removed)","type":"string","enum":["upsert","replace"]},"force":{"description":"Allow importing the same file into the same division again","default":"false","type":"string","enum":["true","false"]},"allowPartial":{"description":"Skip rows with errors instead of rejecting the file","default":"false","type":"string","enum":["true","false"]},"oversPerSide":{"anyOf":[{"type":"integer","minimum":1,"maximum":100},{"type":"string","const":""}],"description":"Overs per innings, for net run rate; defaults from matchType (T20 = 20) or the scores"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"job":{"type":"object"},"tournament":{"type":"object"},"series":{"type":"object"},"summary":{"type":"object"},"warnings":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/imports/preview":{"post":{"tags":["Admin: imports"],"summary":"Dry run: parse and check a file","description":"PDF, CSV, XLS, XLSX or JSON. Nothing is written.\n\n**Requires role:** admin.","operationId":"postAdminImportsPreview","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"PDF, CSV, XLS, XLSX or JSON stats sheet"},"kind":{"anyOf":[{"type":"string","enum":["batting","bowling","fielding"]},{"type":"string","const":""}],"description":"Dataset; detected from the headers when omitted"},"sheetName":{"type":"string","maxLength":100},"mapping":{"description":"JSON object mapping unusual headers: {\"Tot Runs\": \"runs\", \"Notes\": null}","type":"string","maxLength":10000},"tournamentId":{"anyOf":[{"type":"string"},{"type":"string","const":""}],"description":"Existing division id"},"tournamentName":{"description":"Or: division name (defaults to the name in the sheet title)","type":"string","maxLength":200},"season":{"anyOf":[{"type":"integer","minimum":1900,"maximum":2200},{"type":"string","const":""}]},"district":{"type":"string","maxLength":80},"organizer":{"type":"string","maxLength":150},"seriesId":{"anyOf":[{"type":"string","maxLength":160},{"type":"string","const":""}],"description":"Existing series (slug or id)"},"seriesName":{"description":"Or: find/create a series by name","type":"string","maxLength":200},"matchType":{"type":"string","maxLength":30},"tags":{"type":"string","maxLength":500},"mode":{"default":"upsert","description":"upsert: add and update rows. replace: re-sync the division (rows missing from the file are removed)","type":"string","enum":["upsert","replace"]},"force":{"description":"Allow importing the same file into the same division again","default":"false","type":"string","enum":["true","false"]},"allowPartial":{"description":"Skip rows with errors instead of rejecting the file","default":"false","type":"string","enum":["true","false"]},"strict":{"description":"Also reject rows with suspected mistakes (default: import and flag them)","default":"false","type":"string","enum":["true","false"]}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportPreview"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/api-clients":{"get":{"tags":["Admin: API keys"],"summary":"List partner API keys with usage","description":"**Requires role:** admin.","operationId":"getAdminApiClients","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiClient"}}}}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Admin: API keys"],"summary":"Issue a key","description":"The key is returned once.\n\n**Requires role:** admin.","operationId":"postAdminApiClients","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"rateLimitPerMinute":{"type":"integer","minimum":1,"maximum":100000},"internal":{"description":"Also allow the /internal endpoints (for our own apps)","type":"boolean"}},"required":["name"]}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiClientWithKey"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/api-clients/{id}":{"patch":{"tags":["Admin: API keys"],"summary":"Rename, change the limit, or (de)activate","description":"**Requires role:** admin.","operationId":"patchAdminApiClientsById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":100},"rateLimitPerMinute":{"type":"integer","minimum":1,"maximum":100000},"internal":{"description":"Also allow the /internal endpoints (for our own apps)","type":"boolean"},"isActive":{"type":"boolean"}},"additionalProperties":false}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ApiClient"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Admin: API keys"],"summary":"Revoke a key","description":"**Requires role:** admin.","operationId":"deleteAdminApiClientsById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/api-clients/{id}/rotate":{"post":{"tags":["Admin: API keys"],"summary":"Rotate a key","description":"The old key stops working immediately; the new one is returned once.\n\n**Requires role:** admin.","operationId":"postAdminApiClientsByIdRotate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiClientWithKey"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/players/duplicates":{"get":{"tags":["Admin: players"],"summary":"Merge suggestions","description":"Same name at other clubs, or similar spelling at the same club (likely typos).\n\n**Requires role:** admin.","operationId":"getAdminPlayersDuplicates","parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/players/merge":{"post":{"tags":["Admin: players"],"summary":"Merge duplicate records of one person","description":"Atomic; refused (409) when the records played in the same division.\n\n**Requires role:** admin.","operationId":"postAdminPlayersMerge","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetId":{"type":"string"},"sourceIds":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"string"}}},"required":["targetId","sourceIds"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/players/{id}/unmerge":{"post":{"tags":["Admin: players"],"summary":"Undo a merge","description":"Gives the record back exactly the divisions recorded under it.\n\n**Requires role:** admin.","operationId":"postAdminPlayersByIdUnmerge","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/players/reassign":{"post":{"tags":["Admin: players"],"summary":"Move a division line to another player","description":"For namesake rows assigned to the wrong person.\n\n**Requires role:** admin.","operationId":"postAdminPlayersReassign","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["batting","bowling","fielding"]},"lineId":{"type":"string"},"playerId":{"type":"string"}},"required":["kind","lineId","playerId"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/quality":{"get":{"tags":["Admin: data quality"],"summary":"Review queue of suspected mistakes","description":"**Requires role:** admin.","operationId":"getAdminQuality","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"status","in":"query","required":false,"schema":{"default":"open","type":"string","enum":["open","acknowledged","corrected","all"]}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["batting","bowling","fielding"]}},{"name":"tournament","in":"query","required":false,"schema":{"type":"string"}},{"name":"rule","in":"query","required":false,"schema":{"type":"string","maxLength":60}},{"name":"importJob","in":"query","required":false,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/QualityLine"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/quality/summary":{"get":{"tags":["Admin: data quality"],"summary":"Counts by status and rule","description":"**Requires role:** admin.","operationId":"getAdminQualitySummary","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QualitySummary"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/quality/export.csv":{"get":{"tags":["Admin: data quality"],"summary":"Discrepancy report (CSV)","description":"**Requires role:** admin.","operationId":"getAdminQualityExportCsv","parameters":[{"name":"status","in":"query","required":false,"schema":{"default":"open","type":"string","enum":["open","acknowledged","corrected","all"]}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["batting","bowling","fielding"]}},{"name":"tournament","in":"query","required":false,"schema":{"type":"string"}},{"name":"rule","in":"query","required":false,"schema":{"type":"string","maxLength":60}},{"name":"importJob","in":"query","required":false,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"CSV report to send back to the scorers","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/quality/{kind}/{id}/acknowledge":{"post":{"tags":["Admin: data quality"],"summary":"Confirm figures are as published","description":"**Requires role:** admin.","operationId":"postAdminQualityByKindByIdAcknowledge","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","enum":["batting","bowling","fielding"]}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":500}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StatLine"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/quality/{kind}/{id}/correct":{"post":{"tags":["Admin: data quality"],"summary":"Correct values (with a reason)","description":"Re-applied on re-import while the published row is unchanged; dropped once the scorers revise the row. Refused (422) if it would make the figures contradict each other.\n\n**Requires role:** admin.","operationId":"postAdminQualityByKindByIdCorrect","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","enum":["batting","bowling","fielding"]}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"changes":{"type":"object","propertyNames":{"type":"string","maxLength":40},"additionalProperties":{"type":"number"}},"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["changes","reason"]}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StatLine"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/quality/{kind}/{id}/revert":{"post":{"tags":["Admin: data quality"],"summary":"Undo corrections","description":"**Requires role:** admin.","operationId":"postAdminQualityByKindByIdRevert","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","enum":["batting","bowling","fielding"]}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StatLine"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/billing/plans":{"get":{"tags":["Admin: plans"],"summary":"All plans (including inactive)","description":"**Requires role:** admin.","operationId":"getAdminBillingPlans","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Plans"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/billing/plans/{key}":{"patch":{"tags":["Admin: plans"],"summary":"Edit a plan","description":"Quota, rate limit, keys, features. Changes apply to new grants; periods already granted keep their limits.\n\n**Requires role:** admin.","operationId":"patchAdminBillingPlansByKey","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","maxLength":40}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":60},"description":{"type":"string","maxLength":300},"monthlyQuota":{"type":"integer","minimum":1},"rateLimitPerMinute":{"type":"integer","minimum":1,"maximum":100000},"maxApiKeys":{"type":"integer","minimum":1,"maximum":1000},"features":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":120}},"csvExport":{"type":"boolean"},"isActive":{"type":"boolean"},"sortOrder":{"type":"integer"}},"additionalProperties":false}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Plan"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/admin/billing/grants":{"post":{"tags":["Admin: plans"],"summary":"Grant a plan to a user","description":"Every user starts on Free; this is how they get higher limits.\n\n**Requires role:** admin.","operationId":"postAdminBillingGrants","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string"},"planKey":{"type":"string","maxLength":40},"periods":{"default":1,"type":"integer","minimum":1,"maximum":24}},"required":["userId","planKey"]}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/internal/series":{"get":{"tags":["Internal: international"],"summary":"International series (e.g. ICC Cricket World Cup 2027)","description":"Internal: needs a signed-in admin or an API key issued with `internal: true`. Customer keys get 403.","operationId":"getInternalSeries","parameters":[{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["ODI","T20I","Test"]}},{"name":"season","in":"query","required":false,"schema":{"type":"integer","minimum":1900,"maximum":2200}}],"security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InternationalSeries"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an admin or internal API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/internal/series/{series}":{"get":{"tags":["Internal: international"],"summary":"Series with stages, groups, teams and venues","description":"Internal: needs a signed-in admin or an API key issued with `internal: true`. Customer keys get 403.","operationId":"getInternalSeriesBySeries","parameters":[{"name":"series","in":"path","required":true,"description":"Series id or slug, e.g. icc-cricket-world-cup-2027","schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InternationalSeriesDetail"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an admin or internal API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/internal/series/{series}/matches":{"get":{"tags":["Internal: international"],"summary":"Match schedule","description":"Every match in running order (`ordinal`); filter by stage, group, team, venue, country, status or UTC date range. `startTime` is UTC; `localStartTime` carries the venue's offset. Teams not yet known (qualifiers, group positions, knockout winners) have `placeholder: true`. Internal: needs a signed-in admin or an API key issued with `internal: true`. Customer keys get 403.","operationId":"getInternalSeriesBySeriesMatches","parameters":[{"name":"series","in":"path","required":true,"description":"Series id or slug, e.g. icc-cricket-world-cup-2027","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"page","in":"query","required":false,"schema":{"default":1,"type":"integer","minimum":1,"maximum":10000}},{"name":"limit","in":"query","required":false,"schema":{"default":100,"type":"integer","minimum":1,"maximum":100}},{"name":"stage","in":"query","required":false,"description":"Group, Super 7, Semi Final, Final, …","schema":{"type":"string","minLength":1,"maxLength":40}},{"name":"group","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":20}},{"name":"team","in":"query","required":false,"description":"Team name or short name, e.g. India or IND; also slots like A1","schema":{"type":"string","minLength":1,"maxLength":60}},{"name":"venue","in":"query","required":false,"description":"Ground or city (substring), or ICC venue id","schema":{"type":"string","minLength":1,"maxLength":80}},{"name":"country","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":60}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["upcoming","live","completed","abandoned"]}},{"name":"dayNight","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"from","in":"query","required":false,"description":"Start on or after this UTC date","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"Start on or before this UTC date","schema":{"type":"string","format":"date"}},{"name":"sort","in":"query","required":false,"description":"ordinal (default) or startTime; prefix - for descending","schema":{"type":"string","maxLength":40}}],"security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InternationalMatch"}},"meta":{"$ref":"#/components/schemas/PageMeta"},"series":{"type":"object"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an admin or internal API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/internal/series/{series}/matches/{match}":{"get":{"tags":["Internal: international"],"summary":"One match","description":"By match id or ICC match id. Internal: needs a signed-in admin or an API key issued with `internal: true`. Customer keys get 403.","operationId":"getInternalSeriesBySeriesMatchesByMatch","parameters":[{"name":"series","in":"path","required":true,"description":"Series id or slug, e.g. icc-cricket-world-cup-2027","schema":{"type":"string","minLength":1,"maxLength":160}},{"name":"match","in":"path","required":true,"description":"Match id, or the ICC match id (e.g. 275307)","schema":{"type":"string","pattern":"^([a-f0-9]{24}|\\d{1,12})$"}}],"security":[{"apiKey":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InternationalMatch"},"series":{"type":"object"}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not an admin or internal API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/internal/series/{series}/sync":{"post":{"tags":["Internal: international"],"summary":"Re-pull the schedule from the ICC feed","description":"Upserts every match by ICC match id and removes matches the feed no longer lists, in one transaction. 502 when the feed is unreachable or returns nothing (existing data is kept).\n\n**Requires role:** admin.","operationId":"postInternalSeriesBySeriesSync","parameters":[{"name":"series","in":"path","required":true,"description":"Series id or slug, e.g. icc-cricket-world-cup-2027","schema":{"type":"string","minLength":1,"maxLength":160}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InternationalSeries"},"sync":{"type":"object","properties":{"matches":{"type":"integer"},"removed":{"type":"integer"}}}}}}}},"400":{"description":"Invalid input (details lists each field)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not signed in, token expired or revoked, or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requires role: admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited; see RateLimit / Retry-After headers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"ICC feed unavailable or empty; nothing changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}