{"openapi":"3.1.0","info":{"title":"Tennis Score API","version":"1.0.0","description":"Tennis scoring maths as an API, computed locally and deterministically — the game, set and match logic a scoring app, umpire tool or tennis league runs on. The game endpoint plays a game from a sequence of who won each point and returns the proper tennis score: points run 0, 15, 30, 40 and then game, but at 40-40 it is Deuce and a player must lead by two — Advantage, then game — so a,a,a,a is 40-0 and a win, while three-all is Deuce; a tiebreak flag scores to seven by two instead (and keeps going at 7-7). The set endpoint reads a set from the games each player has won: a set is taken at six games with a two-game lead, 6-6 triggers a tiebreak that ends it 7-6, and 7-5 wins if a player pulls ahead first. The match endpoint settles the match from the sets won — best-of-three is decided by two sets, best-of-five by three — and tells you the winner the moment it is reached. Everything is computed locally and deterministically, so it is instant and private. Ideal for tennis, racket-sport, scoring, umpiring and league app developers, scoreboard and live-scoring tools, and club software. Pure local computation — no key, no third-party service, instant. Scoring logic, not analytics. Live, nothing stored. 3 compute endpoints.","contact":{"name":"PremiumApi","url":"https://www.oanor.com/by/premiumapi"}},"servers":[{"url":"https://api.oanor.com/tennis-api","description":"oanor gateway"}],"tags":[{"name":"Tennis"},{"name":"Meta"}],"components":{"securitySchemes":{"oanorKey":{"type":"apiKey","in":"header","name":"x-oanor-key","description":"Get your key at https://www.oanor.com/developer/keys"}}},"security":[{"oanorKey":[]}],"paths":{"/v1/game":{"get":{"operationId":"get_v1_game","tags":["Tennis"],"summary":"Score a game","description":"","parameters":[{"name":"points","in":"query","required":true,"description":"Sequence of 'a'/'b' point winners","schema":{"type":"string"},"example":"a,a,b,a,a"},{"name":"tiebreak","in":"query","required":false,"description":"Score as a tiebreak (true/false)","schema":{"type":"string"},"example":"false"},{"name":"tiebreak_target","in":"query","required":false,"description":"Tiebreak target points (default 7)","schema":{"type":"string"},"example":"7"}],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"note":"Standard game: points run 0, 15, 30, 40, then game — but at 40-40 it is Deuce and a player must lead by two (Advantage, then game). Points after the game is won are ignored.","score":"40-15","inputs":{"points":["a","a","b","a","a"],"tiebreak":false},"winner":"a","complete":true,"points_a":4,"points_b":1},"meta":{"timestamp":"2026-06-06T07:13:58.211Z","request_id":"45792aa8-b1c1-4d57-9182-ced4f99b1c64"},"status":"ok","message":"Game score","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}},"/v1/match":{"get":{"operationId":"get_v1_match","tags":["Tennis"],"summary":"Match status","description":"","parameters":[{"name":"sets_a","in":"query","required":true,"description":"Sets won by A","schema":{"type":"string"},"example":"2"},{"name":"sets_b","in":"query","required":true,"description":"Sets won by B","schema":{"type":"string"},"example":"1"},{"name":"best_of","in":"query","required":false,"description":"Best of 3 or 5 (default 3)","schema":{"type":"string"},"example":"3"}],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"note":"Best-of-3 is won with 2 sets, best-of-5 with 3. The match ends as soon as a player reaches that many sets.","score":"2-1","inputs":{"sets_a":2,"sets_b":1,"best_of":3},"winner":"a","complete":true,"sets_to_win":2},"meta":{"timestamp":"2026-06-06T07:13:58.315Z","request_id":"5581dfed-a130-47e0-9ac6-1d56f1542131"},"status":"ok","message":"Match status","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}},"/v1/set":{"get":{"operationId":"get_v1_set","tags":["Tennis"],"summary":"Set status","description":"","parameters":[{"name":"games_a","in":"query","required":true,"description":"Games won by A","schema":{"type":"string"},"example":"6"},{"name":"games_b","in":"query","required":true,"description":"Games won by B","schema":{"type":"string"},"example":"4"},{"name":"tiebreak_at","in":"query","required":false,"description":"Games count that triggers a tiebreak (default 6)","schema":{"type":"string"},"example":"6"}],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"note":"A set is won at 6 games with a two-game lead; at 6-6 a tiebreak decides it (final score 7-6), or 7-5 if a player pulls ahead first. Some formats use an advantage set with no tiebreak.","score":"6-4","inputs":{"games_a":6,"games_b":4,"tiebreak_at":6},"status":"set won","winner":"a","needs_tiebreak":false},"meta":{"timestamp":"2026-06-06T07:13:58.414Z","request_id":"ff528ba1-41b6-4916-b5f4-955fbe7f6c3a"},"status":"ok","message":"Set status","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}},"/v1/meta":{"get":{"operationId":"get_v1_meta","tags":["Meta"],"summary":"Spec","description":"","parameters":[],"security":[{"oanorKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"data":{"notes":"Players are 'a' and 'b'. Game points: 0/15/30/40, deuce and advantage at 40-40. Set: 6 games, win by 2, tiebreak at 6-6. Match: best-of-3 or best-of-5. Scoring only — not shot or rally analytics.","service":"tennis-api","endpoints":{"GET /v1/set":"Set status and winner from the games each player has won.","GET /v1/game":"Score a game (or tiebreak) from a sequence of 'a'/'b' points.","GET /v1/meta":"This document.","GET /v1/match":"Match status and winner from the sets each player has won."},"description":"Tennis scoring: a game from a point sequence (deuce/advantage/tiebreak), a set from its games, and a match from its sets."},"meta":{"timestamp":"2026-06-06T07:13:58.501Z","request_id":"bf9d8be5-886f-46a8-9339-478198668fb0"},"status":"ok","message":"Meta","success":true}}}},"401":{"description":"Missing or invalid x-oanor-key header"},"402":{"description":"Active subscription required"},"429":{"description":"Rate-limit or monthly quota reached"},"502":{"description":"Upstream did not respond"}}}}},"x-oanor-pricing":[{"slug":"free","name":"Free","price_cents_month":0,"monthly_call_quota":6980,"rps_limit":2,"hard_limit":true},{"slug":"starter","name":"Starter","price_cents_month":428,"monthly_call_quota":55600,"rps_limit":6,"hard_limit":true},{"slug":"pro","name":"Pro","price_cents_month":1182,"monthly_call_quota":228300,"rps_limit":15,"hard_limit":true},{"slug":"mega","name":"Mega","price_cents_month":3755,"monthly_call_quota":1333000,"rps_limit":40,"hard_limit":true}],"x-oanor-marketplace-url":"https://www.oanor.com/api/tennis-api"}