overtime-api 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,27 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+
23
+ - name: Install dependencies
24
+ run: pip install -e ".[dev]"
25
+
26
+ - name: Run tests
27
+ run: pytest tests/ -v
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .pytest_cache/
7
+ .eggs/
8
+ *.egg
9
+ .env
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 overtime-api contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,277 @@
1
+ Metadata-Version: 2.4
2
+ Name: overtime-api
3
+ Version: 0.1.0
4
+ Summary: Unofficial Python client for the Overtime Markets API. Access sports betting odds, live scores, and market data without an API key.
5
+ Project-URL: Homepage, https://github.com/glowww/overtime-api
6
+ Project-URL: Documentation, https://github.com/glowww/overtime-api#readme
7
+ Project-URL: Issues, https://github.com/glowww/overtime-api/issues
8
+ Author: overtime-api contributors
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,crypto,odds,overtime,sports-betting,web3
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: httpx>=0.27
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
25
+ Requires-Dist: pytest>=8; extra == 'dev'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # overtime-api
29
+
30
+ Unofficial Python client for the [Overtime Markets](https://www.overtimemarkets.xyz/) API. Grab odds, live scores, and market data without an API key.
31
+
32
+ No API key required for most endpoints. For odds data, you need a [CapSolver](https://dashboard.capsolver.com/passport/register?inviteCode=WBGRP77j2drv) account to handle Cloudflare Turnstile captchas.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pip install overtime-api
38
+ ```
39
+
40
+ To access odds data (`get_markets`, `get_live_markets`), you need a [CapSolver API key](https://dashboard.capsolver.com/passport/register?inviteCode=WBGRP77j2drv) for automatic Turnstile captcha solving.
41
+
42
+ ## Quick start
43
+
44
+ ```python
45
+ import asyncio
46
+ from overtime import OvertimeClient
47
+
48
+ async def main():
49
+ async with OvertimeClient() as client:
50
+ # No API key needed
51
+ sports = await client.get_sports()
52
+ scores = await client.get_live_scores()
53
+ games = await client.get_games_info()
54
+ players = await client.get_players_info()
55
+ market_types = await client.get_market_types()
56
+
57
+ asyncio.run(main())
58
+ ```
59
+
60
+ ## Get odds data
61
+
62
+ The `/markets` and `/live-markets` endpoints are protected by Cloudflare Turnstile. You can either solve it automatically with [CapSolver](https://dashboard.capsolver.com/passport/register?inviteCode=WBGRP77j2drv), or set a session ID manually.
63
+
64
+ ### Option 1: Automatic (recommended)
65
+
66
+ ```python
67
+ from overtime import OvertimeClient
68
+
69
+ async with OvertimeClient(capsolver_api_key="CAI-...") as client:
70
+ # Turnstile is solved automatically behind the scenes
71
+ markets = await client.get_markets()
72
+
73
+ for market in markets.markets:
74
+ home = market.home_team
75
+ away = market.away_team
76
+ odds = market.result_odds.odds # implied probabilities
77
+ print(f"{home} vs {away}: {odds}")
78
+
79
+ # Live odds with scores
80
+ live = await client.get_live_markets()
81
+ for m in live:
82
+ print(f"{m.home_team} {m.home_score}-{m.away_score} {m.away_team}")
83
+ ```
84
+
85
+ ### Option 2: Manual session
86
+
87
+ ```python
88
+ from overtime import OvertimeClient
89
+
90
+ async with OvertimeClient() as client:
91
+ client.set_session("your-session-id-here")
92
+ markets = await client.get_markets()
93
+ ```
94
+
95
+ ## Delta updates
96
+
97
+ Avoid re-fetching all markets every time. Pass the `response_hash` from a previous response to only get markets that changed:
98
+
99
+ ```python
100
+ result = await client.get_markets()
101
+ print(f"Full: {len(result.markets)} markets")
102
+
103
+ # Later, only get changes:
104
+ result2 = await client.get_markets(response_hash=result.response_hash)
105
+ print(f"Changed: {len(result2.markets)} markets")
106
+ ```
107
+
108
+ ## Proxy support
109
+
110
+ ```python
111
+ # Simple proxy URL
112
+ async with OvertimeClient(proxy="http://user:pass@host:port") as client:
113
+ sports = await client.get_sports()
114
+
115
+ # SOCKS5
116
+ async with OvertimeClient(proxy="socks5://host:port") as client:
117
+ markets = await client.get_markets()
118
+ ```
119
+
120
+ ## Bring your own HTTP client
121
+
122
+ If you need to configure TLS, connection pooling, or retries yourself, pass your own `httpx.AsyncClient`:
123
+
124
+ ```python
125
+ import httpx
126
+ from overtime import OvertimeClient
127
+
128
+ http = httpx.AsyncClient(
129
+ proxy="socks5://host:port",
130
+ verify=False,
131
+ timeout=60,
132
+ limits=httpx.Limits(max_connections=10),
133
+ )
134
+
135
+ async with OvertimeClient(http_client=http) as client:
136
+ markets = await client.get_markets()
137
+
138
+ # You manage the lifecycle of your own client
139
+ await http.aclose()
140
+ ```
141
+
142
+ ## Raw JSON responses
143
+
144
+ Every convenience method returns parsed dataclasses. If you want the raw JSON dict instead, use `client.request()`:
145
+
146
+ ```python
147
+ async with OvertimeClient() as client:
148
+ # Raw dict, no parsing
149
+ raw = await client.request("GET", "/overtime-v2/sports")
150
+
151
+ # Also works for any undocumented endpoint
152
+ raw = await client.request("GET", "/some/other/endpoint?foo=bar")
153
+ ```
154
+
155
+ ## Use from any language (standalone headers)
156
+
157
+ You can also skip the client entirely and just generate the auth headers for use with curl, Node.js, Go, or whatever you prefer.
158
+
159
+ ```python
160
+ from overtime import make_auth_headers, build_request
161
+
162
+ # Option A: just the TOTP auth headers
163
+ headers = make_auth_headers("GET", "/overtime-v2/sports")
164
+ # Returns: {"x-client-totp": "...", "x-client-timestamp": "...", ...}
165
+
166
+ # Option B: full URL + all headers, ready to copy-paste
167
+ url, headers = build_request("GET", "/overtime-v2/sports")
168
+ # url = "https://api.overtime.io/overtime-v2/sports"
169
+ # headers = {user-agent, accept, origin, referer, totp, timestamp, ...}
170
+
171
+ # Use with curl:
172
+ import subprocess
173
+ header_args = []
174
+ for k, v in headers.items():
175
+ header_args.extend(["-H", f"{k}: {v}"])
176
+ subprocess.run(["curl", *header_args, url])
177
+
178
+ # Use with requests (sync):
179
+ import requests
180
+ response = requests.get(url, headers=headers)
181
+ ```
182
+
183
+ ### Implementing TOTP in other languages
184
+
185
+ The auth algorithm is simple HMAC-SHA256. Here's the logic to port to any language:
186
+
187
+ ```
188
+ TOTP_KEY = "BEST_DECENTRALIZED_ONCHAIN_SPORTSBOOK"
189
+ TOTPM_KEY = "A_RANDOM_SELECTION_OF_WORDS"
190
+
191
+ timestamp_seconds = floor(now())
192
+ timestamp_millis = floor(now() * 1000)
193
+ window = timestamp_seconds / 5 (integer division)
194
+
195
+ x-client-totp = HMAC-SHA256(TOTP_KEY, "C5S|{window}|{METHOD}|{path+query}")
196
+ x-client-timestamp = str(timestamp_seconds)
197
+ x-client-totpm = HMAC-SHA256(TOTPM_KEY, "C1MS|{timestamp_millis}|{METHOD}|{path+query}")
198
+ x-client-timestampm = str(timestamp_millis)
199
+ ```
200
+
201
+ The `{path+query}` is the full path including query string, e.g. `/overtime-v2/networks/42161/markets?status=open`.
202
+
203
+ ## All endpoints
204
+
205
+ | Method | Session? | Description |
206
+ |--------|:--------:|-------------|
207
+ | `get_sports()` | | All sports and leagues |
208
+ | `get_market_types()` | | Market type definitions (spread, total, etc.) |
209
+ | `get_collaterals(network)` | | Supported tokens per chain |
210
+ | `get_games_info()` | | All games with status, teams, tournament |
211
+ | `get_game_info(game_id)` | | Single game info |
212
+ | `get_live_scores()` | | Live scores for all in-progress games |
213
+ | `get_live_score(game_id)` | | Live score for single game |
214
+ | `get_players_info()` | | All player name mappings |
215
+ | `get_player_info(player_id)` | | Single player info |
216
+ | `get_user_history(address)` | | Betting history for a wallet |
217
+ | `get_markets(network, response_hash)` | Yes | All prematch odds |
218
+ | `get_live_markets(network)` | Yes | All live/in-play odds |
219
+ | `get_quote(trade_data, buy_in, collateral)` | | Price quote for a bet |
220
+ | `request(method, endpoint)` | | Raw JSON for any endpoint |
221
+
222
+ ## Networks
223
+
224
+ Overtime is deployed on multiple chains. Default is Arbitrum.
225
+
226
+ ```python
227
+ from overtime import OvertimeClient, Network
228
+
229
+ async with OvertimeClient(network=Network.OPTIMISM) as client:
230
+ markets = await client.get_markets()
231
+
232
+ # Or per-request:
233
+ markets = await client.get_markets(network=Network.BASE)
234
+ ```
235
+
236
+ Available networks: `Network.ARBITRUM` (42161), `Network.OPTIMISM` (10), `Network.BASE` (8453).
237
+
238
+ ## Understanding odds
239
+
240
+ Overtime returns odds as implied probabilities (values between 0 and 1). To convert:
241
+
242
+ ```python
243
+ implied_prob = 0.45 # from the API
244
+
245
+ # To decimal odds:
246
+ decimal_odds = 1 / implied_prob # 2.22
247
+
248
+ # To American odds:
249
+ if implied_prob >= 0.5:
250
+ american = -100 * implied_prob / (1 - implied_prob) # negative
251
+ else:
252
+ american = 100 * (1 - implied_prob) / implied_prob # positive
253
+ ```
254
+
255
+ ## Error handling
256
+
257
+ ```python
258
+ from overtime import OvertimeClient, AuthenticationError, SessionError, RateLimitError
259
+
260
+ async with OvertimeClient(capsolver_api_key="...") as client:
261
+ try:
262
+ markets = await client.get_markets()
263
+ except AuthenticationError:
264
+ print("TOTP keys may have changed. Update the package.")
265
+ except SessionError as e:
266
+ print(f"Captcha solving failed: {e}")
267
+ except RateLimitError:
268
+ print("Too many requests. Slow down.")
269
+ ```
270
+
271
+ ## Who built this
272
+
273
+ I'm the founder of [Bet Hero](https://www.betherosports.com), a sports betting analytics platform. We use Overtime's odds data in production alongside 400+ other sportsbooks. When they cut off API access, I open-sourced how it works.
274
+
275
+ ## License
276
+
277
+ MIT
@@ -0,0 +1,250 @@
1
+ # overtime-api
2
+
3
+ Unofficial Python client for the [Overtime Markets](https://www.overtimemarkets.xyz/) API. Grab odds, live scores, and market data without an API key.
4
+
5
+ No API key required for most endpoints. For odds data, you need a [CapSolver](https://dashboard.capsolver.com/passport/register?inviteCode=WBGRP77j2drv) account to handle Cloudflare Turnstile captchas.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install overtime-api
11
+ ```
12
+
13
+ To access odds data (`get_markets`, `get_live_markets`), you need a [CapSolver API key](https://dashboard.capsolver.com/passport/register?inviteCode=WBGRP77j2drv) for automatic Turnstile captcha solving.
14
+
15
+ ## Quick start
16
+
17
+ ```python
18
+ import asyncio
19
+ from overtime import OvertimeClient
20
+
21
+ async def main():
22
+ async with OvertimeClient() as client:
23
+ # No API key needed
24
+ sports = await client.get_sports()
25
+ scores = await client.get_live_scores()
26
+ games = await client.get_games_info()
27
+ players = await client.get_players_info()
28
+ market_types = await client.get_market_types()
29
+
30
+ asyncio.run(main())
31
+ ```
32
+
33
+ ## Get odds data
34
+
35
+ The `/markets` and `/live-markets` endpoints are protected by Cloudflare Turnstile. You can either solve it automatically with [CapSolver](https://dashboard.capsolver.com/passport/register?inviteCode=WBGRP77j2drv), or set a session ID manually.
36
+
37
+ ### Option 1: Automatic (recommended)
38
+
39
+ ```python
40
+ from overtime import OvertimeClient
41
+
42
+ async with OvertimeClient(capsolver_api_key="CAI-...") as client:
43
+ # Turnstile is solved automatically behind the scenes
44
+ markets = await client.get_markets()
45
+
46
+ for market in markets.markets:
47
+ home = market.home_team
48
+ away = market.away_team
49
+ odds = market.result_odds.odds # implied probabilities
50
+ print(f"{home} vs {away}: {odds}")
51
+
52
+ # Live odds with scores
53
+ live = await client.get_live_markets()
54
+ for m in live:
55
+ print(f"{m.home_team} {m.home_score}-{m.away_score} {m.away_team}")
56
+ ```
57
+
58
+ ### Option 2: Manual session
59
+
60
+ ```python
61
+ from overtime import OvertimeClient
62
+
63
+ async with OvertimeClient() as client:
64
+ client.set_session("your-session-id-here")
65
+ markets = await client.get_markets()
66
+ ```
67
+
68
+ ## Delta updates
69
+
70
+ Avoid re-fetching all markets every time. Pass the `response_hash` from a previous response to only get markets that changed:
71
+
72
+ ```python
73
+ result = await client.get_markets()
74
+ print(f"Full: {len(result.markets)} markets")
75
+
76
+ # Later, only get changes:
77
+ result2 = await client.get_markets(response_hash=result.response_hash)
78
+ print(f"Changed: {len(result2.markets)} markets")
79
+ ```
80
+
81
+ ## Proxy support
82
+
83
+ ```python
84
+ # Simple proxy URL
85
+ async with OvertimeClient(proxy="http://user:pass@host:port") as client:
86
+ sports = await client.get_sports()
87
+
88
+ # SOCKS5
89
+ async with OvertimeClient(proxy="socks5://host:port") as client:
90
+ markets = await client.get_markets()
91
+ ```
92
+
93
+ ## Bring your own HTTP client
94
+
95
+ If you need to configure TLS, connection pooling, or retries yourself, pass your own `httpx.AsyncClient`:
96
+
97
+ ```python
98
+ import httpx
99
+ from overtime import OvertimeClient
100
+
101
+ http = httpx.AsyncClient(
102
+ proxy="socks5://host:port",
103
+ verify=False,
104
+ timeout=60,
105
+ limits=httpx.Limits(max_connections=10),
106
+ )
107
+
108
+ async with OvertimeClient(http_client=http) as client:
109
+ markets = await client.get_markets()
110
+
111
+ # You manage the lifecycle of your own client
112
+ await http.aclose()
113
+ ```
114
+
115
+ ## Raw JSON responses
116
+
117
+ Every convenience method returns parsed dataclasses. If you want the raw JSON dict instead, use `client.request()`:
118
+
119
+ ```python
120
+ async with OvertimeClient() as client:
121
+ # Raw dict, no parsing
122
+ raw = await client.request("GET", "/overtime-v2/sports")
123
+
124
+ # Also works for any undocumented endpoint
125
+ raw = await client.request("GET", "/some/other/endpoint?foo=bar")
126
+ ```
127
+
128
+ ## Use from any language (standalone headers)
129
+
130
+ You can also skip the client entirely and just generate the auth headers for use with curl, Node.js, Go, or whatever you prefer.
131
+
132
+ ```python
133
+ from overtime import make_auth_headers, build_request
134
+
135
+ # Option A: just the TOTP auth headers
136
+ headers = make_auth_headers("GET", "/overtime-v2/sports")
137
+ # Returns: {"x-client-totp": "...", "x-client-timestamp": "...", ...}
138
+
139
+ # Option B: full URL + all headers, ready to copy-paste
140
+ url, headers = build_request("GET", "/overtime-v2/sports")
141
+ # url = "https://api.overtime.io/overtime-v2/sports"
142
+ # headers = {user-agent, accept, origin, referer, totp, timestamp, ...}
143
+
144
+ # Use with curl:
145
+ import subprocess
146
+ header_args = []
147
+ for k, v in headers.items():
148
+ header_args.extend(["-H", f"{k}: {v}"])
149
+ subprocess.run(["curl", *header_args, url])
150
+
151
+ # Use with requests (sync):
152
+ import requests
153
+ response = requests.get(url, headers=headers)
154
+ ```
155
+
156
+ ### Implementing TOTP in other languages
157
+
158
+ The auth algorithm is simple HMAC-SHA256. Here's the logic to port to any language:
159
+
160
+ ```
161
+ TOTP_KEY = "BEST_DECENTRALIZED_ONCHAIN_SPORTSBOOK"
162
+ TOTPM_KEY = "A_RANDOM_SELECTION_OF_WORDS"
163
+
164
+ timestamp_seconds = floor(now())
165
+ timestamp_millis = floor(now() * 1000)
166
+ window = timestamp_seconds / 5 (integer division)
167
+
168
+ x-client-totp = HMAC-SHA256(TOTP_KEY, "C5S|{window}|{METHOD}|{path+query}")
169
+ x-client-timestamp = str(timestamp_seconds)
170
+ x-client-totpm = HMAC-SHA256(TOTPM_KEY, "C1MS|{timestamp_millis}|{METHOD}|{path+query}")
171
+ x-client-timestampm = str(timestamp_millis)
172
+ ```
173
+
174
+ The `{path+query}` is the full path including query string, e.g. `/overtime-v2/networks/42161/markets?status=open`.
175
+
176
+ ## All endpoints
177
+
178
+ | Method | Session? | Description |
179
+ |--------|:--------:|-------------|
180
+ | `get_sports()` | | All sports and leagues |
181
+ | `get_market_types()` | | Market type definitions (spread, total, etc.) |
182
+ | `get_collaterals(network)` | | Supported tokens per chain |
183
+ | `get_games_info()` | | All games with status, teams, tournament |
184
+ | `get_game_info(game_id)` | | Single game info |
185
+ | `get_live_scores()` | | Live scores for all in-progress games |
186
+ | `get_live_score(game_id)` | | Live score for single game |
187
+ | `get_players_info()` | | All player name mappings |
188
+ | `get_player_info(player_id)` | | Single player info |
189
+ | `get_user_history(address)` | | Betting history for a wallet |
190
+ | `get_markets(network, response_hash)` | Yes | All prematch odds |
191
+ | `get_live_markets(network)` | Yes | All live/in-play odds |
192
+ | `get_quote(trade_data, buy_in, collateral)` | | Price quote for a bet |
193
+ | `request(method, endpoint)` | | Raw JSON for any endpoint |
194
+
195
+ ## Networks
196
+
197
+ Overtime is deployed on multiple chains. Default is Arbitrum.
198
+
199
+ ```python
200
+ from overtime import OvertimeClient, Network
201
+
202
+ async with OvertimeClient(network=Network.OPTIMISM) as client:
203
+ markets = await client.get_markets()
204
+
205
+ # Or per-request:
206
+ markets = await client.get_markets(network=Network.BASE)
207
+ ```
208
+
209
+ Available networks: `Network.ARBITRUM` (42161), `Network.OPTIMISM` (10), `Network.BASE` (8453).
210
+
211
+ ## Understanding odds
212
+
213
+ Overtime returns odds as implied probabilities (values between 0 and 1). To convert:
214
+
215
+ ```python
216
+ implied_prob = 0.45 # from the API
217
+
218
+ # To decimal odds:
219
+ decimal_odds = 1 / implied_prob # 2.22
220
+
221
+ # To American odds:
222
+ if implied_prob >= 0.5:
223
+ american = -100 * implied_prob / (1 - implied_prob) # negative
224
+ else:
225
+ american = 100 * (1 - implied_prob) / implied_prob # positive
226
+ ```
227
+
228
+ ## Error handling
229
+
230
+ ```python
231
+ from overtime import OvertimeClient, AuthenticationError, SessionError, RateLimitError
232
+
233
+ async with OvertimeClient(capsolver_api_key="...") as client:
234
+ try:
235
+ markets = await client.get_markets()
236
+ except AuthenticationError:
237
+ print("TOTP keys may have changed. Update the package.")
238
+ except SessionError as e:
239
+ print(f"Captcha solving failed: {e}")
240
+ except RateLimitError:
241
+ print("Too many requests. Slow down.")
242
+ ```
243
+
244
+ ## Who built this
245
+
246
+ I'm the founder of [Bet Hero](https://www.betherosports.com), a sports betting analytics platform. We use Overtime's odds data in production alongside 400+ other sportsbooks. When they cut off API access, I open-sourced how it works.
247
+
248
+ ## License
249
+
250
+ MIT
@@ -0,0 +1,45 @@
1
+ """Fetch live and prematch odds (requires capsolver API key)."""
2
+
3
+ import asyncio
4
+ import os
5
+ from overtime import OvertimeClient
6
+
7
+
8
+ async def main():
9
+ api_key = os.environ.get("CAPSOLVER_API_KEY")
10
+ if not api_key:
11
+ print("Set CAPSOLVER_API_KEY environment variable to use this example.")
12
+ print(" export CAPSOLVER_API_KEY=CAI-...")
13
+ return
14
+
15
+ async with OvertimeClient(capsolver_api_key=api_key) as client:
16
+
17
+ # Fetch all open prematch markets
18
+ result = await client.get_markets()
19
+ print(f"Prematch markets: {len(result.markets)}")
20
+ print(f"Response hash (for delta updates): {result.response_hash[:20]}...")
21
+
22
+ for market in result.markets[:10]:
23
+ odds_str = " / ".join(f"{o:.4f}" for o in market.result_odds.odds)
24
+ print(f" {market.home_team} vs {market.away_team}: {odds_str}")
25
+ print(f" Lines available: {len(market.child_markets)}")
26
+
27
+ # Fetch live markets
28
+ live = await client.get_live_markets()
29
+ print(f"\nLive markets: {len(live)}")
30
+
31
+ for market in live[:5]:
32
+ odds_str = " / ".join(f"{o:.4f}" for o in market.odds)
33
+ print(f" {market.home_team} vs {market.away_team}: {odds_str}")
34
+ print(f" Score: {market.home_score}-{market.away_score}")
35
+ print(f" Lines available: {len(market.child_markets)}")
36
+
37
+ # Delta update: pass previous hash to only get changed markets
38
+ result2 = await client.get_markets(response_hash=result.response_hash)
39
+ if result2.markets:
40
+ print(f"\nDelta update: {len(result2.markets)} markets changed")
41
+ else:
42
+ print("\nDelta update: no changes since last fetch")
43
+
44
+
45
+ asyncio.run(main())
@@ -0,0 +1,35 @@
1
+ """Quick start: fetch sports, scores, and game info (no API key needed)."""
2
+
3
+ import asyncio
4
+ from overtime import OvertimeClient
5
+
6
+
7
+ async def main():
8
+ async with OvertimeClient() as client:
9
+
10
+ # Get all sports and leagues
11
+ sports = await client.get_sports()
12
+ print(f"Available sports: {len(sports)}")
13
+ for sport in sports[:5]:
14
+ print(f" {sport.name}: {len(sport.leagues)} leagues")
15
+
16
+ # Get market type definitions
17
+ market_types = await client.get_market_types()
18
+ print(f"\nMarket types: {len(market_types)}")
19
+ for mt in market_types[:5]:
20
+ print(f" [{mt.id}] {mt.name}: {mt.description}")
21
+
22
+ # Get live scores
23
+ scores = await client.get_live_scores()
24
+ print(f"\nLive games: {len(scores)}")
25
+ for score in scores[:5]:
26
+ print(f" {score.game_id[:20]}... {score.home_score}-{score.away_score} ({score.status})")
27
+
28
+ # Get all game info
29
+ games = await client.get_games_info()
30
+ print(f"\nAll games: {len(games)}")
31
+ for game in games[:5]:
32
+ print(f" {game.home_team} vs {game.away_team} ({game.sport})")
33
+
34
+
35
+ asyncio.run(main())