strikerapi 0.1.0__py3-none-any.whl
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.
- strikerapi/__init__.py +25 -0
- strikerapi/_core.py +307 -0
- strikerapi/_version.py +1 -0
- strikerapi/client.py +799 -0
- strikerapi/py.typed +0 -0
- strikerapi-0.1.0.dist-info/METADATA +189 -0
- strikerapi-0.1.0.dist-info/RECORD +9 -0
- strikerapi-0.1.0.dist-info/WHEEL +4 -0
- strikerapi-0.1.0.dist-info/licenses/LICENSE +21 -0
strikerapi/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""StrikerAPI: Python client for the StrikerAPI soccer data API."""
|
|
2
|
+
from ._core import (
|
|
3
|
+
APIConnectionError,
|
|
4
|
+
APIError,
|
|
5
|
+
AuthError,
|
|
6
|
+
InsufficientCreditsError,
|
|
7
|
+
NotFoundError,
|
|
8
|
+
RateLimitError,
|
|
9
|
+
to_dataframe,
|
|
10
|
+
)
|
|
11
|
+
from ._version import __version__
|
|
12
|
+
from .client import TOOLS, Client
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"APIConnectionError",
|
|
16
|
+
"APIError",
|
|
17
|
+
"AuthError",
|
|
18
|
+
"Client",
|
|
19
|
+
"InsufficientCreditsError",
|
|
20
|
+
"NotFoundError",
|
|
21
|
+
"RateLimitError",
|
|
22
|
+
"TOOLS",
|
|
23
|
+
"__version__",
|
|
24
|
+
"to_dataframe",
|
|
25
|
+
]
|
strikerapi/_core.py
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"""Shared runtime for the StrikerAPI Python client.
|
|
2
|
+
|
|
3
|
+
Standard library only. The generated methods live in client.py and call
|
|
4
|
+
``Client._call``; everything else (auth, retries, errors, credits headers) is here.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import socket
|
|
11
|
+
import ssl
|
|
12
|
+
import time
|
|
13
|
+
import urllib.error
|
|
14
|
+
import urllib.request
|
|
15
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
16
|
+
|
|
17
|
+
from ._version import __version__
|
|
18
|
+
|
|
19
|
+
BRAND = "StrikerAPI"
|
|
20
|
+
ENV_VAR = "STRIKERAPI_API_KEY"
|
|
21
|
+
DEFAULT_BASE_URL = "https://mcp.strikerapi.com"
|
|
22
|
+
SIGNUP_URL = "https://strikerapi.com/signup"
|
|
23
|
+
DEFAULT_TIMEOUT = 60.0
|
|
24
|
+
MAX_RETRIES = 3
|
|
25
|
+
MAX_RETRY_WAIT = 30.0
|
|
26
|
+
|
|
27
|
+
# A transport takes (method, url, headers, body, timeout) and returns
|
|
28
|
+
# (status, headers, body). Header names in the returned dict are lowercase.
|
|
29
|
+
Transport = Callable[
|
|
30
|
+
[str, str, Dict[str, str], Optional[bytes], float],
|
|
31
|
+
Tuple[int, Dict[str, str], bytes],
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class APIError(Exception):
|
|
36
|
+
"""Any error response from the API, or a failed connection."""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
message: str,
|
|
41
|
+
status_code: Optional[int] = None,
|
|
42
|
+
body: Any = None,
|
|
43
|
+
) -> None:
|
|
44
|
+
super().__init__(message)
|
|
45
|
+
self.message = message
|
|
46
|
+
self.status_code = status_code
|
|
47
|
+
self.body = body
|
|
48
|
+
|
|
49
|
+
def __str__(self) -> str:
|
|
50
|
+
if self.status_code:
|
|
51
|
+
return "%s (HTTP %s)" % (self.message, self.status_code)
|
|
52
|
+
return self.message
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class AuthError(APIError):
|
|
56
|
+
"""401: the API key is missing, invalid or revoked."""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class InsufficientCreditsError(APIError):
|
|
60
|
+
"""402: the account does not have enough credits for this call."""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class NotFoundError(APIError):
|
|
64
|
+
"""404: the game, player, team or other id does not exist."""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class RateLimitError(APIError):
|
|
68
|
+
"""429: too many requests. ``retry_after`` is in seconds when the server sent it."""
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
message: str,
|
|
73
|
+
status_code: Optional[int] = 429,
|
|
74
|
+
body: Any = None,
|
|
75
|
+
retry_after: Optional[float] = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
super().__init__(message, status_code, body)
|
|
78
|
+
self.retry_after = retry_after
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class APIConnectionError(APIError):
|
|
82
|
+
"""The request never got a response (DNS, TLS, timeout, reset)."""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _ssl_context() -> Optional[ssl.SSLContext]:
|
|
86
|
+
"""Use certifi's CA bundle when it is installed, else the system default.
|
|
87
|
+
|
|
88
|
+
Some python.org installs on macOS ship without root certificates. Installing
|
|
89
|
+
certifi (or running the "Install Certificates" script) fixes the resulting
|
|
90
|
+
CERTIFICATE_VERIFY_FAILED error.
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
import certifi
|
|
94
|
+
except ImportError:
|
|
95
|
+
return None
|
|
96
|
+
return ssl.create_default_context(cafile=certifi.where())
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _urllib_transport(
|
|
100
|
+
method: str,
|
|
101
|
+
url: str,
|
|
102
|
+
headers: Dict[str, str],
|
|
103
|
+
body: Optional[bytes],
|
|
104
|
+
timeout: float,
|
|
105
|
+
) -> Tuple[int, Dict[str, str], bytes]:
|
|
106
|
+
req = urllib.request.Request(url, data=body, headers=headers, method=method)
|
|
107
|
+
try:
|
|
108
|
+
with urllib.request.urlopen(req, timeout=timeout, context=_ssl_context()) as resp:
|
|
109
|
+
return (
|
|
110
|
+
resp.status,
|
|
111
|
+
{k.lower(): v for k, v in resp.headers.items()},
|
|
112
|
+
resp.read(),
|
|
113
|
+
)
|
|
114
|
+
except urllib.error.HTTPError as exc:
|
|
115
|
+
try:
|
|
116
|
+
payload = exc.read()
|
|
117
|
+
finally:
|
|
118
|
+
exc.close()
|
|
119
|
+
return (
|
|
120
|
+
exc.code,
|
|
121
|
+
{k.lower(): v for k, v in (exc.headers or {}).items()},
|
|
122
|
+
payload,
|
|
123
|
+
)
|
|
124
|
+
except (urllib.error.URLError, socket.timeout, ConnectionError, OSError) as exc:
|
|
125
|
+
reason = getattr(exc, "reason", exc)
|
|
126
|
+
raise APIConnectionError("Could not reach the API: %s" % (reason,)) from exc
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _to_number(value: Optional[str]) -> Optional[Union[int, float]]:
|
|
130
|
+
if value is None:
|
|
131
|
+
return None
|
|
132
|
+
try:
|
|
133
|
+
return int(value)
|
|
134
|
+
except ValueError:
|
|
135
|
+
try:
|
|
136
|
+
return float(value)
|
|
137
|
+
except ValueError:
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _error_message(parsed: Any, raw: bytes, status: int) -> str:
|
|
142
|
+
if isinstance(parsed, dict):
|
|
143
|
+
err = parsed.get("error")
|
|
144
|
+
if isinstance(err, str) and err:
|
|
145
|
+
return err
|
|
146
|
+
if isinstance(err, dict) and isinstance(err.get("message"), str):
|
|
147
|
+
return err["message"]
|
|
148
|
+
text = raw.decode("utf-8", "replace").strip()
|
|
149
|
+
if text:
|
|
150
|
+
return text[:300]
|
|
151
|
+
return "HTTP %s" % status
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class BaseClient:
|
|
155
|
+
"""Holds the key, base URL, retry policy and the last credit counters."""
|
|
156
|
+
|
|
157
|
+
def __init__(
|
|
158
|
+
self,
|
|
159
|
+
api_key: Optional[str] = None,
|
|
160
|
+
*,
|
|
161
|
+
base_url: Optional[str] = None,
|
|
162
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
163
|
+
max_retries: int = MAX_RETRIES,
|
|
164
|
+
transport: Optional[Transport] = None,
|
|
165
|
+
) -> None:
|
|
166
|
+
key = api_key or os.environ.get(ENV_VAR)
|
|
167
|
+
if not key:
|
|
168
|
+
raise AuthError(
|
|
169
|
+
"No API key. Pass api_key=... or set %s. "
|
|
170
|
+
"A free key is at %s" % (ENV_VAR, SIGNUP_URL)
|
|
171
|
+
)
|
|
172
|
+
self.api_key = key
|
|
173
|
+
self.base_url = (base_url or os.environ.get(BRAND.upper() + "_BASE_URL") or DEFAULT_BASE_URL).rstrip("/")
|
|
174
|
+
self.timeout = timeout
|
|
175
|
+
self.max_retries = max(0, int(max_retries))
|
|
176
|
+
self._transport: Transport = transport or _urllib_transport
|
|
177
|
+
self._sleep: Callable[[float], None] = time.sleep
|
|
178
|
+
self.last_credits_used: Optional[Union[int, float]] = None
|
|
179
|
+
self.last_credits_remaining: Optional[Union[int, float]] = None
|
|
180
|
+
|
|
181
|
+
def __repr__(self) -> str:
|
|
182
|
+
return "<%s.Client base_url=%r>" % (BRAND, self.base_url)
|
|
183
|
+
|
|
184
|
+
def call(self, tool: str, arguments: Optional[Dict[str, Any]] = None) -> Any:
|
|
185
|
+
"""Call any tool by name. Useful for tools newer than this package."""
|
|
186
|
+
return self._call(tool, arguments or {})
|
|
187
|
+
|
|
188
|
+
def _call(self, tool: str, arguments: Dict[str, Any]) -> Any:
|
|
189
|
+
payload = {k: v for k, v in arguments.items() if v is not None}
|
|
190
|
+
url = "%s/v1/%s" % (self.base_url, tool)
|
|
191
|
+
headers = {
|
|
192
|
+
"x-api-key": self.api_key,
|
|
193
|
+
"content-type": "application/json",
|
|
194
|
+
"accept": "application/json",
|
|
195
|
+
"user-agent": "%s-python/%s" % (BRAND.lower(), __version__),
|
|
196
|
+
}
|
|
197
|
+
body = json.dumps(payload).encode("utf-8")
|
|
198
|
+
|
|
199
|
+
attempt = 0
|
|
200
|
+
while True:
|
|
201
|
+
try:
|
|
202
|
+
status, resp_headers, raw = self._transport("POST", url, headers, body, self.timeout)
|
|
203
|
+
except APIConnectionError:
|
|
204
|
+
if attempt >= self.max_retries:
|
|
205
|
+
raise
|
|
206
|
+
self._sleep(self._backoff(attempt, None))
|
|
207
|
+
attempt += 1
|
|
208
|
+
continue
|
|
209
|
+
|
|
210
|
+
self._record_credits(resp_headers)
|
|
211
|
+
if status == 429 or status >= 500:
|
|
212
|
+
if attempt < self.max_retries:
|
|
213
|
+
self._sleep(self._backoff(attempt, self._retry_after(resp_headers)))
|
|
214
|
+
attempt += 1
|
|
215
|
+
continue
|
|
216
|
+
return self._handle(status, resp_headers, raw)
|
|
217
|
+
|
|
218
|
+
@staticmethod
|
|
219
|
+
def _retry_after(headers: Dict[str, str]) -> Optional[float]:
|
|
220
|
+
value = headers.get("retry-after")
|
|
221
|
+
if value is None:
|
|
222
|
+
return None
|
|
223
|
+
try:
|
|
224
|
+
return max(0.0, float(value))
|
|
225
|
+
except ValueError:
|
|
226
|
+
return None
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def _backoff(attempt: int, retry_after: Optional[float]) -> float:
|
|
230
|
+
if retry_after is not None:
|
|
231
|
+
return min(retry_after, MAX_RETRY_WAIT)
|
|
232
|
+
return min(0.5 * (2 ** attempt), MAX_RETRY_WAIT)
|
|
233
|
+
|
|
234
|
+
def _record_credits(self, headers: Dict[str, str]) -> None:
|
|
235
|
+
used = _to_number(headers.get("x-credits-used"))
|
|
236
|
+
remaining = _to_number(headers.get("x-credits-remaining"))
|
|
237
|
+
if used is not None:
|
|
238
|
+
self.last_credits_used = used
|
|
239
|
+
if remaining is not None:
|
|
240
|
+
self.last_credits_remaining = remaining
|
|
241
|
+
|
|
242
|
+
def _handle(self, status: int, headers: Dict[str, str], raw: bytes) -> Any:
|
|
243
|
+
try:
|
|
244
|
+
parsed = json.loads(raw.decode("utf-8")) if raw else None
|
|
245
|
+
except ValueError:
|
|
246
|
+
parsed = None
|
|
247
|
+
|
|
248
|
+
if 200 <= status < 300:
|
|
249
|
+
if parsed is None:
|
|
250
|
+
raise APIError("The API returned a response that is not JSON", status, raw[:300])
|
|
251
|
+
if isinstance(parsed, dict) and "data" in parsed:
|
|
252
|
+
return parsed["data"]
|
|
253
|
+
return parsed
|
|
254
|
+
|
|
255
|
+
message = _error_message(parsed, raw, status)
|
|
256
|
+
if status == 401:
|
|
257
|
+
raise AuthError(message, status, parsed)
|
|
258
|
+
if status == 402:
|
|
259
|
+
raise InsufficientCreditsError(message, status, parsed)
|
|
260
|
+
if status == 404:
|
|
261
|
+
raise NotFoundError(message, status, parsed)
|
|
262
|
+
if status == 429:
|
|
263
|
+
raise RateLimitError(message, status, parsed, self._retry_after(headers))
|
|
264
|
+
raise APIError(message, status, parsed)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _rows(data: Any, key: Optional[str]) -> List[Any]:
|
|
268
|
+
if key is not None:
|
|
269
|
+
cur = data
|
|
270
|
+
for part in key.split("."):
|
|
271
|
+
if not isinstance(cur, dict) or part not in cur:
|
|
272
|
+
raise KeyError("No %r in the response. Keys: %s" % (key, sorted(cur) if isinstance(cur, dict) else type(cur).__name__))
|
|
273
|
+
cur = cur[part]
|
|
274
|
+
if isinstance(cur, list):
|
|
275
|
+
return cur
|
|
276
|
+
return [cur]
|
|
277
|
+
if isinstance(data, list):
|
|
278
|
+
return data
|
|
279
|
+
if isinstance(data, dict):
|
|
280
|
+
lists = {k: v for k, v in data.items() if isinstance(v, list)}
|
|
281
|
+
records = {k: v for k, v in lists.items() if v and all(isinstance(r, dict) for r in v)}
|
|
282
|
+
pool = records or lists
|
|
283
|
+
if pool:
|
|
284
|
+
return pool[max(pool, key=lambda k: len(pool[k]))]
|
|
285
|
+
for v in data.values():
|
|
286
|
+
if isinstance(v, dict) and any(isinstance(x, list) for x in v.values()):
|
|
287
|
+
return _rows(v, None)
|
|
288
|
+
return [data]
|
|
289
|
+
return [data]
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def to_dataframe(data: Any, key: Optional[str] = None) -> Any:
|
|
293
|
+
"""Turn a response into a pandas DataFrame.
|
|
294
|
+
|
|
295
|
+
``data`` is what a client method returned. ``key`` names the list to use
|
|
296
|
+
(dots reach into nested dicts, for example ``"props"``). Without a key the
|
|
297
|
+
longest list of records in the response is used. Nested dicts are flattened
|
|
298
|
+
into dotted columns. pandas is imported here, so it stays optional.
|
|
299
|
+
"""
|
|
300
|
+
try:
|
|
301
|
+
import pandas as pd
|
|
302
|
+
except ImportError as exc: # pragma: no cover
|
|
303
|
+
raise ImportError("to_dataframe needs pandas: pip install pandas") from exc
|
|
304
|
+
rows = _rows(data, key)
|
|
305
|
+
if rows and all(isinstance(r, dict) for r in rows):
|
|
306
|
+
return pd.json_normalize(rows)
|
|
307
|
+
return pd.DataFrame(rows)
|
strikerapi/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
strikerapi/client.py
ADDED
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
"""Generated by packages/python/generate.py from the StrikerAPI OpenAPI spec. Do not edit by hand."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any, Dict, List, Literal, Optional, Union
|
|
5
|
+
|
|
6
|
+
from ._core import BaseClient
|
|
7
|
+
|
|
8
|
+
#: Credits each tool costs, from the spec.
|
|
9
|
+
TOOLS: Dict[str, int] = {
|
|
10
|
+
"list_teams": 1,
|
|
11
|
+
"list_games": 2,
|
|
12
|
+
"get_schedule": 2,
|
|
13
|
+
"get_game": 5,
|
|
14
|
+
"get_lineups": 5,
|
|
15
|
+
"get_standings": 2,
|
|
16
|
+
"get_ratings": 2,
|
|
17
|
+
"get_head_to_head": 2,
|
|
18
|
+
"search_players": 1,
|
|
19
|
+
"get_player": 5,
|
|
20
|
+
"get_player_games": 5,
|
|
21
|
+
"get_leaders": 5,
|
|
22
|
+
"get_team_stats": 5,
|
|
23
|
+
"get_events": 10,
|
|
24
|
+
"get_shot_map": 10,
|
|
25
|
+
"get_odds": 5,
|
|
26
|
+
"get_line_movement": 10,
|
|
27
|
+
"get_player_props": 10,
|
|
28
|
+
"get_prop_history": 10,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Client(BaseClient):
|
|
33
|
+
"""Client for the StrikerAPI API (soccer).
|
|
34
|
+
|
|
35
|
+
Create one with ``Client()`` (reads STRIKERAPI_API_KEY) or ``Client(api_key="...")``.
|
|
36
|
+
Every method returns the unwrapped ``data`` from the response.
|
|
37
|
+
``last_credits_used`` and ``last_credits_remaining`` hold the counters from
|
|
38
|
+
the most recent response.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def list_teams(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
season: Optional[Union[int, float, str]] = None,
|
|
45
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
46
|
+
) -> Any:
|
|
47
|
+
"""List teams.
|
|
48
|
+
|
|
49
|
+
Use to find club ids and abbreviations for a season (default: the latest). Every other tool
|
|
50
|
+
takes a club as an id, abbreviation or name. Pass league for MLS (mls), La Liga (laliga), Serie
|
|
51
|
+
A (seriea), the Bundesliga (bundesliga), Ligue 1 (ligue1), the Champions League (ucl), the EFL
|
|
52
|
+
Championship (championship), the NWSL (nwsl), Liga MX (ligamx), the Europa League (uel), the
|
|
53
|
+
Conference League (uecl), the Eredivisie (eredivisie), the Primeira Liga (primeira), the
|
|
54
|
+
Scottish Premiership (scotland), Brazil's Serie A (brazil) or Argentina's Liga Profesional
|
|
55
|
+
(argentina); default: the Premier League. Costs 1 credit.
|
|
56
|
+
|
|
57
|
+
Costs 1 credit per call.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
season (optional): Season by the year it starts: 2025 = 2025-26. MLS, the NWSL, Liga MX,
|
|
61
|
+
Brazil and Argentina: the calendar year. Default: the latest.
|
|
62
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
63
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
64
|
+
scotland, brazil, argentina.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
The unwrapped ``data`` object from the response.
|
|
68
|
+
"""
|
|
69
|
+
return self._call(
|
|
70
|
+
"list_teams",
|
|
71
|
+
{
|
|
72
|
+
"season": season,
|
|
73
|
+
"league": league,
|
|
74
|
+
},
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def list_games(
|
|
78
|
+
self,
|
|
79
|
+
*,
|
|
80
|
+
season: Optional[Union[int, float, str]] = None,
|
|
81
|
+
stage: Optional[Literal["league", "knockout"]] = None,
|
|
82
|
+
team: Optional[str] = None,
|
|
83
|
+
date: Optional[str] = None,
|
|
84
|
+
from_: Optional[str] = None,
|
|
85
|
+
to: Optional[str] = None,
|
|
86
|
+
status: Optional[Literal["scheduled", "final"]] = None,
|
|
87
|
+
limit: Optional[int] = None,
|
|
88
|
+
offset: Optional[int] = None,
|
|
89
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
90
|
+
) -> Any:
|
|
91
|
+
"""List games.
|
|
92
|
+
|
|
93
|
+
Use to list fixtures and results by season, stage, date, date range or club, newest first. For
|
|
94
|
+
upcoming fixtures with lines use get_schedule; for one match in full use get_game. Costs 2
|
|
95
|
+
credits.
|
|
96
|
+
|
|
97
|
+
Costs 2 credits per call.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
season (optional): Season by the year it starts: 2025 = 2025-26. MLS, the NWSL, Liga MX,
|
|
101
|
+
Brazil and Argentina: the calendar year. Default: the latest.
|
|
102
|
+
stage (optional): league = league-table games (regular season, group stage, league phase);
|
|
103
|
+
knockout = qualifying, knockout rounds and playoffs.
|
|
104
|
+
team (optional): Club id, abbreviation or name.
|
|
105
|
+
date (optional): One date, YYYY-MM-DD (UTC).
|
|
106
|
+
from_ (optional): From date, YYYY-MM-DD.
|
|
107
|
+
to (optional): To date, YYYY-MM-DD.
|
|
108
|
+
status (optional): One of: scheduled, final.
|
|
109
|
+
limit (optional): Max matches (default 50).
|
|
110
|
+
offset (optional): Page offset; use next_offset.
|
|
111
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
112
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
113
|
+
scotland, brazil, argentina.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
The unwrapped ``data`` object from the response.
|
|
117
|
+
"""
|
|
118
|
+
return self._call(
|
|
119
|
+
"list_games",
|
|
120
|
+
{
|
|
121
|
+
"season": season,
|
|
122
|
+
"stage": stage,
|
|
123
|
+
"team": team,
|
|
124
|
+
"date": date,
|
|
125
|
+
"from": from_,
|
|
126
|
+
"to": to,
|
|
127
|
+
"status": status,
|
|
128
|
+
"limit": limit,
|
|
129
|
+
"offset": offset,
|
|
130
|
+
"league": league,
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def get_schedule(
|
|
135
|
+
self,
|
|
136
|
+
*,
|
|
137
|
+
days: Optional[int] = None,
|
|
138
|
+
team: Optional[str] = None,
|
|
139
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
140
|
+
) -> Any:
|
|
141
|
+
"""Schedule.
|
|
142
|
+
|
|
143
|
+
Use for upcoming fixtures (next 1-30 days, default 7) with the median three-way line across
|
|
144
|
+
posted sportsbooks (home, draw, away moneylines, goal total, handicap) and its implied
|
|
145
|
+
probabilities. For every book's line use get_odds. Costs 2 credits.
|
|
146
|
+
|
|
147
|
+
Costs 2 credits per call.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
days (optional): Days ahead (default 7).
|
|
151
|
+
team (optional): Club id, abbreviation or name.
|
|
152
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
153
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
154
|
+
scotland, brazil, argentina.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
The unwrapped ``data`` object from the response.
|
|
158
|
+
"""
|
|
159
|
+
return self._call(
|
|
160
|
+
"get_schedule",
|
|
161
|
+
{
|
|
162
|
+
"days": days,
|
|
163
|
+
"team": team,
|
|
164
|
+
"league": league,
|
|
165
|
+
},
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def get_game(
|
|
169
|
+
self,
|
|
170
|
+
game_id: str,
|
|
171
|
+
*,
|
|
172
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
173
|
+
) -> Any:
|
|
174
|
+
"""Game.
|
|
175
|
+
|
|
176
|
+
Use for one match in full: score (with shootout), both clubs' box scores (possession, shots, xG,
|
|
177
|
+
passing, discipline), every player's line, the key events (goals, cards, substitutions,
|
|
178
|
+
penalties, VAR) and each sportsbook's opening and closing line. For every event use get_events;
|
|
179
|
+
for formations use get_lineups. Costs 5 credits.
|
|
180
|
+
|
|
181
|
+
Costs 5 credits per call.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
game_id: ESPN match id, from list_games or get_schedule.
|
|
185
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
186
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
187
|
+
scotland, brazil, argentina.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
The unwrapped ``data`` object from the response.
|
|
191
|
+
"""
|
|
192
|
+
return self._call(
|
|
193
|
+
"get_game",
|
|
194
|
+
{
|
|
195
|
+
"game_id": game_id,
|
|
196
|
+
"league": league,
|
|
197
|
+
},
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
def get_lineups(
|
|
201
|
+
self,
|
|
202
|
+
game_id: str,
|
|
203
|
+
*,
|
|
204
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
205
|
+
) -> Any:
|
|
206
|
+
"""Lineups.
|
|
207
|
+
|
|
208
|
+
Use for a match's lineups: each club's formation, starting XI with positions and formation
|
|
209
|
+
slots, the substitutes used with the minute they came on (and who went off when), and the unused
|
|
210
|
+
bench. Costs 5 credits.
|
|
211
|
+
|
|
212
|
+
Costs 5 credits per call.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
game_id: ESPN match id, from list_games or get_schedule.
|
|
216
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
217
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
218
|
+
scotland, brazil, argentina.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
The unwrapped ``data`` object from the response.
|
|
222
|
+
"""
|
|
223
|
+
return self._call(
|
|
224
|
+
"get_lineups",
|
|
225
|
+
{
|
|
226
|
+
"game_id": game_id,
|
|
227
|
+
"league": league,
|
|
228
|
+
},
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def get_standings(
|
|
232
|
+
self,
|
|
233
|
+
*,
|
|
234
|
+
season: Optional[Union[int, float, str]] = None,
|
|
235
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil"]] = None,
|
|
236
|
+
) -> Any:
|
|
237
|
+
"""Standings.
|
|
238
|
+
|
|
239
|
+
Use for a season's league table: rank, played, won, drawn, lost, goals for and against, goal
|
|
240
|
+
difference, points (official, with any deduction), qualification or relegation note, plus home
|
|
241
|
+
and away records and recent form. Champions League: one table per group or the league phase.
|
|
242
|
+
Costs 2 credits.
|
|
243
|
+
|
|
244
|
+
Costs 2 credits per call.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
season (optional): Season by the year it starts: 2025 = 2025-26. MLS, the NWSL, Liga MX,
|
|
248
|
+
Brazil and Argentina: the calendar year. Default: the latest.
|
|
249
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
250
|
+
bundesliga, ligue1, ucl, championship, nwsl, uel, uecl, eredivisie, primeira, scotland,
|
|
251
|
+
brazil.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
The unwrapped ``data`` object from the response.
|
|
255
|
+
"""
|
|
256
|
+
return self._call(
|
|
257
|
+
"get_standings",
|
|
258
|
+
{
|
|
259
|
+
"season": season,
|
|
260
|
+
"league": league,
|
|
261
|
+
},
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
def get_ratings(
|
|
265
|
+
self,
|
|
266
|
+
*,
|
|
267
|
+
date: Optional[str] = None,
|
|
268
|
+
limit: Optional[int] = None,
|
|
269
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
270
|
+
) -> Any:
|
|
271
|
+
"""Ratings.
|
|
272
|
+
|
|
273
|
+
Use for our club Elo ratings, strongest first, as of the latest match (or as of date). A
|
|
274
|
+
100-point gap is about a 64% expected score for the stronger side at a neutral venue. Costs 2
|
|
275
|
+
credits.
|
|
276
|
+
|
|
277
|
+
Costs 2 credits per call.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
date (optional): Ratings as of this day, YYYY-MM-DD (default: the latest).
|
|
281
|
+
limit (optional): Max clubs (default 50).
|
|
282
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
283
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
284
|
+
scotland, brazil, argentina.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
The unwrapped ``data`` object from the response.
|
|
288
|
+
"""
|
|
289
|
+
return self._call(
|
|
290
|
+
"get_ratings",
|
|
291
|
+
{
|
|
292
|
+
"date": date,
|
|
293
|
+
"limit": limit,
|
|
294
|
+
"league": league,
|
|
295
|
+
},
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
def get_head_to_head(
|
|
299
|
+
self,
|
|
300
|
+
team: str,
|
|
301
|
+
opponent: str,
|
|
302
|
+
*,
|
|
303
|
+
limit: Optional[int] = None,
|
|
304
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
305
|
+
) -> Any:
|
|
306
|
+
"""Head to head.
|
|
307
|
+
|
|
308
|
+
Use for two clubs' meetings in this competition: wins, draws and goals each, the first meeting,
|
|
309
|
+
and the results newest first. Costs 2 credits.
|
|
310
|
+
|
|
311
|
+
Costs 2 credits per call.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
team: Club id, abbreviation or name.
|
|
315
|
+
opponent: The other club.
|
|
316
|
+
limit (optional): Max results listed (default 20); the summary counts every meeting.
|
|
317
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
318
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
319
|
+
scotland, brazil, argentina.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
The unwrapped ``data`` object from the response.
|
|
323
|
+
"""
|
|
324
|
+
return self._call(
|
|
325
|
+
"get_head_to_head",
|
|
326
|
+
{
|
|
327
|
+
"team": team,
|
|
328
|
+
"opponent": opponent,
|
|
329
|
+
"limit": limit,
|
|
330
|
+
"league": league,
|
|
331
|
+
},
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
def search_players(
|
|
335
|
+
self,
|
|
336
|
+
name: str,
|
|
337
|
+
*,
|
|
338
|
+
team: Optional[str] = None,
|
|
339
|
+
limit: Optional[int] = None,
|
|
340
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
341
|
+
) -> Any:
|
|
342
|
+
"""Search players.
|
|
343
|
+
|
|
344
|
+
Use to find a player's id by name (accents optional), optionally within a club. Returns
|
|
345
|
+
position, current club, last season and appearances. Costs 1 credit.
|
|
346
|
+
|
|
347
|
+
Costs 1 credit per call.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
name: Full or partial name, e.g. Saka.
|
|
351
|
+
team (optional): Club id, abbreviation or name.
|
|
352
|
+
limit (optional): limit
|
|
353
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
354
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
355
|
+
scotland, brazil, argentina.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
The unwrapped ``data`` object from the response.
|
|
359
|
+
"""
|
|
360
|
+
return self._call(
|
|
361
|
+
"search_players",
|
|
362
|
+
{
|
|
363
|
+
"name": name,
|
|
364
|
+
"team": team,
|
|
365
|
+
"limit": limit,
|
|
366
|
+
"league": league,
|
|
367
|
+
},
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
def get_player(
|
|
371
|
+
self,
|
|
372
|
+
player_id: str,
|
|
373
|
+
*,
|
|
374
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
375
|
+
) -> Any:
|
|
376
|
+
"""Player.
|
|
377
|
+
|
|
378
|
+
Use for one player: profile, per-season appearances, starts, minutes, goals, assists, shots, our
|
|
379
|
+
xG, cards and goalkeeping (saves, clean sheets) with per-90 rates, and the last 10 matches.
|
|
380
|
+
Costs 5 credits.
|
|
381
|
+
|
|
382
|
+
Costs 5 credits per call.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
player_id: ESPN player id (search_players).
|
|
386
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
387
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
388
|
+
scotland, brazil, argentina.
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
The unwrapped ``data`` object from the response.
|
|
392
|
+
"""
|
|
393
|
+
return self._call(
|
|
394
|
+
"get_player",
|
|
395
|
+
{
|
|
396
|
+
"player_id": player_id,
|
|
397
|
+
"league": league,
|
|
398
|
+
},
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
def get_player_games(
|
|
402
|
+
self,
|
|
403
|
+
player_id: str,
|
|
404
|
+
*,
|
|
405
|
+
season: Optional[Union[int, float, str]] = None,
|
|
406
|
+
limit: Optional[int] = None,
|
|
407
|
+
offset: Optional[int] = None,
|
|
408
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
409
|
+
) -> Any:
|
|
410
|
+
"""Player games.
|
|
411
|
+
|
|
412
|
+
Use for a player's match log, newest first: opponent, score, minutes on and off, goals, assists,
|
|
413
|
+
shots, xG, fouls, cards and goalkeeping. Costs 5 credits.
|
|
414
|
+
|
|
415
|
+
Costs 5 credits per call.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
player_id: ESPN player id.
|
|
419
|
+
season (optional): One season (the year it starts).
|
|
420
|
+
limit (optional): limit
|
|
421
|
+
offset (optional): offset
|
|
422
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
423
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
424
|
+
scotland, brazil, argentina.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
The unwrapped ``data`` object from the response.
|
|
428
|
+
"""
|
|
429
|
+
return self._call(
|
|
430
|
+
"get_player_games",
|
|
431
|
+
{
|
|
432
|
+
"player_id": player_id,
|
|
433
|
+
"season": season,
|
|
434
|
+
"limit": limit,
|
|
435
|
+
"offset": offset,
|
|
436
|
+
"league": league,
|
|
437
|
+
},
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
def get_leaders(
|
|
441
|
+
self,
|
|
442
|
+
*,
|
|
443
|
+
stat: Optional[Literal["goals", "assists", "goal_contributions", "shots", "shots_on_target", "xg", "yellow_cards", "red_cards", "saves", "clean_sheets"]] = None,
|
|
444
|
+
season: Optional[Union[int, float, str]] = None,
|
|
445
|
+
per90: Optional[bool] = None,
|
|
446
|
+
min_games: Optional[int] = None,
|
|
447
|
+
limit: Optional[int] = None,
|
|
448
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
449
|
+
) -> Any:
|
|
450
|
+
"""Leaders.
|
|
451
|
+
|
|
452
|
+
Use for a season's leaders in goals, assists, goal contributions, shots, shots on target, our
|
|
453
|
+
xG, cards, saves or clean sheets, as totals or per 90 minutes (per90, with a minimum of 10
|
|
454
|
+
matches by default). Costs 5 credits.
|
|
455
|
+
|
|
456
|
+
Costs 5 credits per call.
|
|
457
|
+
|
|
458
|
+
Args:
|
|
459
|
+
stat (optional): Default goals. One of: goals, assists, goal_contributions, shots,
|
|
460
|
+
shots_on_target, xg, yellow_cards, red_cards, saves, clean_sheets.
|
|
461
|
+
season (optional): Season by the year it starts (default: the latest).
|
|
462
|
+
per90 (optional): Rank by the rate per 90 minutes.
|
|
463
|
+
min_games (optional): Minimum appearances.
|
|
464
|
+
limit (optional): limit
|
|
465
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
466
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
467
|
+
scotland, brazil, argentina.
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
The unwrapped ``data`` object from the response.
|
|
471
|
+
"""
|
|
472
|
+
return self._call(
|
|
473
|
+
"get_leaders",
|
|
474
|
+
{
|
|
475
|
+
"stat": stat,
|
|
476
|
+
"season": season,
|
|
477
|
+
"per90": per90,
|
|
478
|
+
"min_games": min_games,
|
|
479
|
+
"limit": limit,
|
|
480
|
+
"league": league,
|
|
481
|
+
},
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
def get_team_stats(
|
|
485
|
+
self,
|
|
486
|
+
*,
|
|
487
|
+
season: Optional[Union[int, float, str]] = None,
|
|
488
|
+
team: Optional[str] = None,
|
|
489
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
490
|
+
) -> Any:
|
|
491
|
+
"""Team stats.
|
|
492
|
+
|
|
493
|
+
Use for clubs' per-match averages over a season, for and against: goals, our xG, shots, shots on
|
|
494
|
+
target, possession, pass accuracy, corners, fouls, cards, tackles, clean sheets. Costs 5
|
|
495
|
+
credits.
|
|
496
|
+
|
|
497
|
+
Costs 5 credits per call.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
season (optional): Season by the year it starts (default: the latest).
|
|
501
|
+
team (optional): One club.
|
|
502
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
503
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
504
|
+
scotland, brazil, argentina.
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
The unwrapped ``data`` object from the response.
|
|
508
|
+
"""
|
|
509
|
+
return self._call(
|
|
510
|
+
"get_team_stats",
|
|
511
|
+
{
|
|
512
|
+
"season": season,
|
|
513
|
+
"team": team,
|
|
514
|
+
"league": league,
|
|
515
|
+
},
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
def get_events(
|
|
519
|
+
self,
|
|
520
|
+
game_id: str,
|
|
521
|
+
*,
|
|
522
|
+
kind: Optional[Literal["goals", "shots", "cards", "substitutions", "set_pieces", "fouls", "all"]] = None,
|
|
523
|
+
limit: Optional[int] = None,
|
|
524
|
+
offset: Optional[int] = None,
|
|
525
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
526
|
+
) -> Any:
|
|
527
|
+
"""Events.
|
|
528
|
+
|
|
529
|
+
Use for a match's events in order: goals (with assister, own goals, penalties), shots with
|
|
530
|
+
location, outcome, body part and our xG, cards, substitutions, fouls, corners, offsides and VAR
|
|
531
|
+
decisions. Filter with kind. Older matches carry goals, cards and substitutions only. Costs 10
|
|
532
|
+
credits.
|
|
533
|
+
|
|
534
|
+
Costs 10 credits per call.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
game_id: ESPN match id.
|
|
538
|
+
kind (optional): goals, shots, cards, substitutions, set_pieces, fouls or all (default).
|
|
539
|
+
limit (optional): Max events (default 300).
|
|
540
|
+
offset (optional): Page offset; use next_offset.
|
|
541
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
542
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
543
|
+
scotland, brazil, argentina.
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
The unwrapped ``data`` object from the response.
|
|
547
|
+
"""
|
|
548
|
+
return self._call(
|
|
549
|
+
"get_events",
|
|
550
|
+
{
|
|
551
|
+
"game_id": game_id,
|
|
552
|
+
"kind": kind,
|
|
553
|
+
"limit": limit,
|
|
554
|
+
"offset": offset,
|
|
555
|
+
"league": league,
|
|
556
|
+
},
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
def get_shot_map(
|
|
560
|
+
self,
|
|
561
|
+
*,
|
|
562
|
+
team: Optional[str] = None,
|
|
563
|
+
player: Optional[str] = None,
|
|
564
|
+
against: Optional[bool] = None,
|
|
565
|
+
season: Optional[Union[int, float, str]] = None,
|
|
566
|
+
game_id: Optional[str] = None,
|
|
567
|
+
include_shots: Optional[bool] = None,
|
|
568
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
569
|
+
) -> Any:
|
|
570
|
+
"""Shot map.
|
|
571
|
+
|
|
572
|
+
Use for a shot map: a club's shots (or, with against, the shots it conceded), a player's, or one
|
|
573
|
+
match's, for a season (default: the latest). Returns totals and zones (six-yard box, penalty
|
|
574
|
+
area, outside the box, penalties) with goals, shots on target, xG and conversion, and every
|
|
575
|
+
located shot with its x/y, end point, outcome and xG. Costs 10 credits.
|
|
576
|
+
|
|
577
|
+
Costs 10 credits per call.
|
|
578
|
+
|
|
579
|
+
Args:
|
|
580
|
+
team (optional): Club id, abbreviation or name.
|
|
581
|
+
player (optional): Player id (search_players).
|
|
582
|
+
against (optional): With team: the shots it conceded.
|
|
583
|
+
season (optional): Season by the year it starts (default: the latest).
|
|
584
|
+
game_id (optional): One match instead of a season.
|
|
585
|
+
include_shots (optional): false = totals and zones only.
|
|
586
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
587
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
588
|
+
scotland, brazil, argentina.
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
The unwrapped ``data`` object from the response.
|
|
592
|
+
"""
|
|
593
|
+
return self._call(
|
|
594
|
+
"get_shot_map",
|
|
595
|
+
{
|
|
596
|
+
"team": team,
|
|
597
|
+
"player": player,
|
|
598
|
+
"against": against,
|
|
599
|
+
"season": season,
|
|
600
|
+
"game_id": game_id,
|
|
601
|
+
"include_shots": include_shots,
|
|
602
|
+
"league": league,
|
|
603
|
+
},
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
def get_odds(
|
|
607
|
+
self,
|
|
608
|
+
*,
|
|
609
|
+
game_id: Optional[str] = None,
|
|
610
|
+
date: Optional[str] = None,
|
|
611
|
+
season: Optional[Union[int, float, str]] = None,
|
|
612
|
+
team: Optional[str] = None,
|
|
613
|
+
limit: Optional[int] = None,
|
|
614
|
+
offset: Optional[int] = None,
|
|
615
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
616
|
+
) -> Any:
|
|
617
|
+
"""Odds.
|
|
618
|
+
|
|
619
|
+
Use for betting lines: each sportsbook's three-way moneyline (home, draw, away), goal handicap
|
|
620
|
+
and total (opening and closing from June 2020 for 16 competitions from The Odds API, and from
|
|
621
|
+
2024 from ESPN; ESPN's final pre-match line before that), the no-margin probabilities each
|
|
622
|
+
book's prices imply, and for finished matches the result and whether the total went over against
|
|
623
|
+
the median close. Pass game_id for one match (5 credits), date for a day's matches (10 credits),
|
|
624
|
+
or season (optionally a team) for a season of priced matches, 2 credits per match returned, up
|
|
625
|
+
to 100 a page.
|
|
626
|
+
|
|
627
|
+
Costs 5 credits per call.
|
|
628
|
+
|
|
629
|
+
Args:
|
|
630
|
+
game_id (optional): One match.
|
|
631
|
+
date (optional): A day's matches, YYYY-MM-DD (UTC).
|
|
632
|
+
season (optional): A season of priced matches, by the year it starts (2025 = 2025-26; MLS,
|
|
633
|
+
the NWSL, Liga MX, Brazil and Argentina: the calendar year).
|
|
634
|
+
team (optional): With season: one club's matches.
|
|
635
|
+
limit (optional): With season: matches per page (default 50).
|
|
636
|
+
offset (optional): With season: page offset; use next_offset.
|
|
637
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
638
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
639
|
+
scotland, brazil, argentina.
|
|
640
|
+
|
|
641
|
+
Returns:
|
|
642
|
+
The unwrapped ``data`` object from the response.
|
|
643
|
+
"""
|
|
644
|
+
return self._call(
|
|
645
|
+
"get_odds",
|
|
646
|
+
{
|
|
647
|
+
"game_id": game_id,
|
|
648
|
+
"date": date,
|
|
649
|
+
"season": season,
|
|
650
|
+
"team": team,
|
|
651
|
+
"limit": limit,
|
|
652
|
+
"offset": offset,
|
|
653
|
+
"league": league,
|
|
654
|
+
},
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
def get_line_movement(
|
|
658
|
+
self,
|
|
659
|
+
game_id: str,
|
|
660
|
+
*,
|
|
661
|
+
provider: Optional[str] = None,
|
|
662
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl", "championship", "nwsl", "ligamx", "uel", "uecl", "eredivisie", "primeira", "scotland", "brazil", "argentina"]] = None,
|
|
663
|
+
) -> Any:
|
|
664
|
+
"""Line movement.
|
|
665
|
+
|
|
666
|
+
Use to see how a match's line moved before kick-off: our pre-game snapshots of each sportsbook's
|
|
667
|
+
three-way moneyline, handicap and total (ESPN's once a day, The Odds API's every hour for
|
|
668
|
+
matches in the next two days). Costs 10 credits.
|
|
669
|
+
|
|
670
|
+
Costs 10 credits per call.
|
|
671
|
+
|
|
672
|
+
Args:
|
|
673
|
+
game_id: Match id.
|
|
674
|
+
provider (optional): One sportsbook, e.g. DraftKings.
|
|
675
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
676
|
+
bundesliga, ligue1, ucl, championship, nwsl, ligamx, uel, uecl, eredivisie, primeira,
|
|
677
|
+
scotland, brazil, argentina.
|
|
678
|
+
|
|
679
|
+
Returns:
|
|
680
|
+
The unwrapped ``data`` object from the response.
|
|
681
|
+
"""
|
|
682
|
+
return self._call(
|
|
683
|
+
"get_line_movement",
|
|
684
|
+
{
|
|
685
|
+
"game_id": game_id,
|
|
686
|
+
"provider": provider,
|
|
687
|
+
"league": league,
|
|
688
|
+
},
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
def get_player_props(
|
|
692
|
+
self,
|
|
693
|
+
*,
|
|
694
|
+
game_id: Optional[str] = None,
|
|
695
|
+
player_id: Optional[str] = None,
|
|
696
|
+
from_date: Optional[str] = None,
|
|
697
|
+
to_date: Optional[str] = None,
|
|
698
|
+
market: Optional[Literal["player_goal_scorer_anytime"]] = None,
|
|
699
|
+
bookmaker: Optional[str] = None,
|
|
700
|
+
snapshot_type: Optional[Literal["opening", "closing"]] = None,
|
|
701
|
+
estimate_only: Optional[bool] = None,
|
|
702
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl"]] = None,
|
|
703
|
+
) -> Any:
|
|
704
|
+
"""Player props.
|
|
705
|
+
|
|
706
|
+
Use for player prop lines by sportsbook: the anytime goalscorer price, Yes in over_odds (and No
|
|
707
|
+
in under_odds where a book posts it), with no line, from DraftKings, FanDuel, William Hill and
|
|
708
|
+
Pinnacle as the archive holds them. Pass game_id for every player's props in one game (10
|
|
709
|
+
credits), or player_id with from_date (and to_date) for one player across games (10 credits per
|
|
710
|
+
game returned, up to 100). Returns the closing line by default (the last before the game starts)
|
|
711
|
+
or the opening line, with each book's over and under prices. Set estimate_only to get the price
|
|
712
|
+
without being charged.
|
|
713
|
+
|
|
714
|
+
Costs 10 credits per call.
|
|
715
|
+
|
|
716
|
+
Args:
|
|
717
|
+
game_id (optional): Game id: every player's props for that game.
|
|
718
|
+
player_id (optional): Player id (e.g. 280555) from search_players. With from_date: that
|
|
719
|
+
player's props across games.
|
|
720
|
+
from_date (optional): With player_id: first date, YYYY-MM-DD (the game's date).
|
|
721
|
+
to_date (optional): With player_id: last date (default: no end), YYYY-MM-DD (the game's
|
|
722
|
+
date).
|
|
723
|
+
market (optional): One market: player_goal_scorer_anytime (anytime goalscorer (over =
|
|
724
|
+
scores))
|
|
725
|
+
bookmaker (optional): Bookmaker key, e.g. draftkings, fanduel, pinnacle.
|
|
726
|
+
snapshot_type (optional): closing (default): the last line before the game starts. opening:
|
|
727
|
+
the first one captured.
|
|
728
|
+
estimate_only (optional): Return what this call would cost, without charging or running it.
|
|
729
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
730
|
+
bundesliga, ligue1, ucl.
|
|
731
|
+
|
|
732
|
+
Returns:
|
|
733
|
+
The unwrapped ``data`` object from the response.
|
|
734
|
+
"""
|
|
735
|
+
return self._call(
|
|
736
|
+
"get_player_props",
|
|
737
|
+
{
|
|
738
|
+
"game_id": game_id,
|
|
739
|
+
"player_id": player_id,
|
|
740
|
+
"from_date": from_date,
|
|
741
|
+
"to_date": to_date,
|
|
742
|
+
"market": market,
|
|
743
|
+
"bookmaker": bookmaker,
|
|
744
|
+
"snapshot_type": snapshot_type,
|
|
745
|
+
"estimate_only": estimate_only,
|
|
746
|
+
"league": league,
|
|
747
|
+
},
|
|
748
|
+
)
|
|
749
|
+
|
|
750
|
+
def get_prop_history(
|
|
751
|
+
self,
|
|
752
|
+
player_id: str,
|
|
753
|
+
market: Literal["player_goal_scorer_anytime"],
|
|
754
|
+
*,
|
|
755
|
+
from_date: Optional[str] = None,
|
|
756
|
+
to_date: Optional[str] = None,
|
|
757
|
+
bookmaker: Optional[str] = None,
|
|
758
|
+
limit: Optional[int] = None,
|
|
759
|
+
league: Optional[Literal["soccer", "mls", "laliga", "seriea", "bundesliga", "ligue1", "ucl"]] = None,
|
|
760
|
+
) -> Any:
|
|
761
|
+
"""Prop history.
|
|
762
|
+
|
|
763
|
+
Use to see how a player did against his prop line over time: for one market (anytime goalscorer:
|
|
764
|
+
one row per match with the closing price and whether he scored), one row per game with the
|
|
765
|
+
closing line (the median across books, or one book's), the opening line, the prices, what the
|
|
766
|
+
player actually recorded from our box scores and the result against the line, plus the over
|
|
767
|
+
rate. Costs 10 credits for up to 200 games. over_odds is the Yes price; result is over when he
|
|
768
|
+
scored, under when he played and did not, and null when he was not in the squad or on the pitch
|
|
769
|
+
(a void).
|
|
770
|
+
|
|
771
|
+
Costs 10 credits per call.
|
|
772
|
+
|
|
773
|
+
Args:
|
|
774
|
+
player_id: Player id (e.g. 280555) from search_players.
|
|
775
|
+
market: The market: player_goal_scorer_anytime (anytime goalscorer (over = scores))
|
|
776
|
+
from_date (optional): First date, YYYY-MM-DD (the game's date).
|
|
777
|
+
to_date (optional): Last date, YYYY-MM-DD (the game's date).
|
|
778
|
+
bookmaker (optional): One book's closing line instead of the median across books, e.g.
|
|
779
|
+
draftkings.
|
|
780
|
+
limit (optional): Games to return, oldest first (default 50, max 200). next_from_date says
|
|
781
|
+
where to continue.
|
|
782
|
+
league (optional): League. Defaults to soccer. One of: soccer, mls, laliga, seriea,
|
|
783
|
+
bundesliga, ligue1, ucl.
|
|
784
|
+
|
|
785
|
+
Returns:
|
|
786
|
+
The unwrapped ``data`` object from the response.
|
|
787
|
+
"""
|
|
788
|
+
return self._call(
|
|
789
|
+
"get_prop_history",
|
|
790
|
+
{
|
|
791
|
+
"player_id": player_id,
|
|
792
|
+
"market": market,
|
|
793
|
+
"from_date": from_date,
|
|
794
|
+
"to_date": to_date,
|
|
795
|
+
"bookmaker": bookmaker,
|
|
796
|
+
"limit": limit,
|
|
797
|
+
"league": league,
|
|
798
|
+
},
|
|
799
|
+
)
|
strikerapi/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: strikerapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the StrikerAPI soccer data API. No dependencies.
|
|
5
|
+
Project-URL: Homepage, https://strikerapi.com
|
|
6
|
+
Project-URL: Documentation, https://strikerapi.com/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/noahowsh/puckapi
|
|
8
|
+
Project-URL: Sign up, https://strikerapi.com/signup
|
|
9
|
+
Author-email: StrikerAPI <support@strikerapi.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api-client,betting,odds,player-props,soccer,sports-data,strikerapi
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Provides-Extra: pandas
|
|
26
|
+
Requires-Dist: pandas>=1.5; extra == 'pandas'
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest>=7; extra == 'test'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# StrikerAPI for Python
|
|
32
|
+
|
|
33
|
+
Python client for the [StrikerAPI](https://strikerapi.com) soccer data API. It has no required dependencies (standard library only) and works on Python 3.9 and newer. Pandas is optional.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install strikerapi
|
|
39
|
+
pip install "strikerapi[pandas]" # only if you want DataFrames
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Set your key
|
|
43
|
+
|
|
44
|
+
Get a free key at https://strikerapi.com/signup. Free accounts get 500 credits a month.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export STRIKERAPI_API_KEY=your_key_here
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from strikerapi import Client
|
|
52
|
+
|
|
53
|
+
client = Client() # reads STRIKERAPI_API_KEY
|
|
54
|
+
client = Client(api_key="your_key") # or pass it in
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Examples
|
|
58
|
+
|
|
59
|
+
### 1. A league table
|
|
60
|
+
|
|
61
|
+
Pass `league` to pick a competition. Here is MLS.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from strikerapi import Client, to_dataframe
|
|
65
|
+
|
|
66
|
+
client = Client()
|
|
67
|
+
|
|
68
|
+
table = client.get_standings(league="mls")
|
|
69
|
+
df = to_dataframe(table, key="standings")
|
|
70
|
+
print(df[["group_name", "rank", "display_name", "played", "points"]].head(10))
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. Top scorers per 90 minutes
|
|
74
|
+
|
|
75
|
+
`get_leaders` can rank by the raw count or per 90 minutes.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from strikerapi import Client
|
|
79
|
+
|
|
80
|
+
client = Client()
|
|
81
|
+
|
|
82
|
+
leaders = client.get_leaders(stat="goals", league="mls", per90=True, limit=5)
|
|
83
|
+
print(leaders)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3. Find a player and see his recent games
|
|
87
|
+
|
|
88
|
+
`search_players` finds the id, `get_player_games` returns his match log.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from strikerapi import Client
|
|
92
|
+
|
|
93
|
+
client = Client()
|
|
94
|
+
|
|
95
|
+
haaland = client.search_players("Haaland", limit=1)["players"][0]
|
|
96
|
+
games = client.get_player_games(haaland["player_id"], limit=5)
|
|
97
|
+
print(haaland["name"], games)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Credits
|
|
101
|
+
|
|
102
|
+
Every method returns the `data` object from the response. After each call, `client.last_credits_used` and `client.last_credits_remaining` hold the counters from the `X-Credits-Used` and `X-Credits-Remaining` headers. Methods that take `estimate_only=True` return the price of a call without running or charging it.
|
|
103
|
+
|
|
104
|
+
## Pandas
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from strikerapi import to_dataframe
|
|
108
|
+
|
|
109
|
+
df = to_dataframe(data) # finds the main list in the response
|
|
110
|
+
df = to_dataframe(data, key="rows") # or name the list yourself
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Nested fields become dotted columns. Install pandas separately or with `pip install "strikerapi[pandas]"`.
|
|
114
|
+
|
|
115
|
+
## Errors
|
|
116
|
+
|
|
117
|
+
Every error is an `APIError` subclass, with the server's message and the HTTP status.
|
|
118
|
+
|
|
119
|
+
| Exception | Status | Meaning |
|
|
120
|
+
| --- | --- | --- |
|
|
121
|
+
| `AuthError` | 401 | Missing, invalid or revoked key |
|
|
122
|
+
| `InsufficientCreditsError` | 402 | Not enough credits for the call |
|
|
123
|
+
| `NotFoundError` | 404 | The id or name does not exist |
|
|
124
|
+
| `RateLimitError` | 429 | Too many requests; has `.retry_after` when the server sends it |
|
|
125
|
+
| `APIError` | 400, 5xx | Bad arguments or a server problem |
|
|
126
|
+
| `APIConnectionError` | none | No response (network or timeout) |
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from strikerapi import Client, APIError, InsufficientCreditsError, RateLimitError
|
|
130
|
+
|
|
131
|
+
client = Client()
|
|
132
|
+
try:
|
|
133
|
+
data = client.list_teams()
|
|
134
|
+
except InsufficientCreditsError:
|
|
135
|
+
print("Out of credits, top up at https://strikerapi.com")
|
|
136
|
+
except RateLimitError as exc:
|
|
137
|
+
print("Slow down, retry after", exc.retry_after)
|
|
138
|
+
except APIError as exc:
|
|
139
|
+
print(exc.status_code, exc.message)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The client retries 429 and 5xx responses and connection failures up to 3 times with backoff, and honors `Retry-After`. Set `Client(max_retries=0)` to turn that off.
|
|
143
|
+
|
|
144
|
+
If you see `CERTIFICATE_VERIFY_FAILED` on a python.org install for macOS, run the "Install Certificates.command" script that came with Python, or `pip install certifi` (the client uses it when present).
|
|
145
|
+
|
|
146
|
+
## Options
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
Client(
|
|
150
|
+
api_key=None, # defaults to $STRIKERAPI_API_KEY
|
|
151
|
+
base_url="https://mcp.strikerapi.com", # point at another host
|
|
152
|
+
timeout=60.0, # seconds per request
|
|
153
|
+
max_retries=3,
|
|
154
|
+
)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`client.call("tool_name", {"arg": "value"})` calls any tool by name, which helps when the API adds a tool before this package does.
|
|
158
|
+
|
|
159
|
+
## Tools
|
|
160
|
+
|
|
161
|
+
Method names match the API tool names. Arguments are keyword arguments; required ones can also be passed positionally. Each method's docstring lists its arguments (`help(client.list_teams)`).
|
|
162
|
+
|
|
163
|
+
| Method | Credits | What it does |
|
|
164
|
+
| --- | --- | --- |
|
|
165
|
+
| `list_teams` | 1 | List teams |
|
|
166
|
+
| `list_games` | 2 | List games |
|
|
167
|
+
| `get_schedule` | 2 | Schedule |
|
|
168
|
+
| `get_game` | 5 | Game |
|
|
169
|
+
| `get_lineups` | 5 | Lineups |
|
|
170
|
+
| `get_standings` | 2 | Standings |
|
|
171
|
+
| `get_ratings` | 2 | Ratings |
|
|
172
|
+
| `get_head_to_head` | 2 | Head to head |
|
|
173
|
+
| `search_players` | 1 | Search players |
|
|
174
|
+
| `get_player` | 5 | Player |
|
|
175
|
+
| `get_player_games` | 5 | Player games |
|
|
176
|
+
| `get_leaders` | 5 | Leaders |
|
|
177
|
+
| `get_team_stats` | 5 | Team stats |
|
|
178
|
+
| `get_events` | 10 | Events |
|
|
179
|
+
| `get_shot_map` | 10 | Shot map |
|
|
180
|
+
| `get_odds` | 5 | Odds |
|
|
181
|
+
| `get_line_movement` | 10 | Line movement |
|
|
182
|
+
| `get_player_props` | 10 | Player props |
|
|
183
|
+
| `get_prop_history` | 10 | Prop history |
|
|
184
|
+
|
|
185
|
+
Full API reference: https://strikerapi.com/docs
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
strikerapi/__init__.py,sha256=PtYwDM6xwn5CkrO3FGz26f_VmDbR5796cebDo8zTPmo,514
|
|
2
|
+
strikerapi/_core.py,sha256=pfLGo1z21KGgQcIi3ii9xL7FzTydjr7Bbw5PNPajIAc,10609
|
|
3
|
+
strikerapi/_version.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
|
|
4
|
+
strikerapi/client.py,sha256=Y865ZxajyvkYOR6tSLYqVWw7GNSouTS4rAzie6qNpEk,33077
|
|
5
|
+
strikerapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
strikerapi-0.1.0.dist-info/METADATA,sha256=XP_mAxFv4UTmBWwKdSTPqsIAZABcvHDU0nva6o9BZtc,6206
|
|
7
|
+
strikerapi-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
8
|
+
strikerapi-0.1.0.dist-info/licenses/LICENSE,sha256=WKIp5NCP-OXFw6DNzFGZrxcR9NxNsMJyVZdN4DDRl2s,1067
|
|
9
|
+
strikerapi-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 StrikerAPI
|
|
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.
|