sharpapi 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.
- sharpapi/__init__.py +93 -0
- sharpapi/_base.py +121 -0
- sharpapi/_utils.py +39 -0
- sharpapi/async_client.py +464 -0
- sharpapi/client.py +682 -0
- sharpapi/exceptions.py +52 -0
- sharpapi/models.py +433 -0
- sharpapi/py.typed +0 -0
- sharpapi/streaming.py +200 -0
- sharpapi-0.1.0.dist-info/METADATA +203 -0
- sharpapi-0.1.0.dist-info/RECORD +12 -0
- sharpapi-0.1.0.dist-info/WHEEL +4 -0
sharpapi/async_client.py
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
"""SharpAPI asynchronous Python client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional, Union
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from ._base import (
|
|
10
|
+
DEFAULT_BASE_URL,
|
|
11
|
+
DEFAULT_TIMEOUT,
|
|
12
|
+
handle_errors,
|
|
13
|
+
make_headers,
|
|
14
|
+
parse_rate_limit,
|
|
15
|
+
parse_response,
|
|
16
|
+
)
|
|
17
|
+
from ._utils import _clean_params
|
|
18
|
+
from .models import (
|
|
19
|
+
APIResponse,
|
|
20
|
+
AccountInfo,
|
|
21
|
+
ArbitrageOpportunity,
|
|
22
|
+
EVOpportunity,
|
|
23
|
+
Event,
|
|
24
|
+
League,
|
|
25
|
+
LowHoldOpportunity,
|
|
26
|
+
MiddleOpportunity,
|
|
27
|
+
OddsLine,
|
|
28
|
+
RateLimitInfo,
|
|
29
|
+
Sportsbook,
|
|
30
|
+
Sport,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AsyncSharpAPI:
|
|
35
|
+
"""Async SharpAPI Python client.
|
|
36
|
+
|
|
37
|
+
Provides typed access to odds, +EV, arbitrage, middles, and streaming
|
|
38
|
+
endpoints using ``async``/``await``.
|
|
39
|
+
|
|
40
|
+
Example::
|
|
41
|
+
|
|
42
|
+
import asyncio
|
|
43
|
+
from sharpapi import AsyncSharpAPI
|
|
44
|
+
|
|
45
|
+
async def main():
|
|
46
|
+
async with AsyncSharpAPI("sk_live_xxx") as client:
|
|
47
|
+
arbs = await client.arbitrage.get(min_profit=1.0)
|
|
48
|
+
for arb in arbs.data:
|
|
49
|
+
print(f"{arb.profit_percent}% — {arb.event_name}")
|
|
50
|
+
|
|
51
|
+
asyncio.run(main())
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
api_key: str,
|
|
57
|
+
*,
|
|
58
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
59
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
60
|
+
):
|
|
61
|
+
if not api_key:
|
|
62
|
+
raise ValueError("api_key is required")
|
|
63
|
+
|
|
64
|
+
self._api_key = api_key
|
|
65
|
+
self._base_url = base_url.rstrip("/")
|
|
66
|
+
self._timeout = timeout
|
|
67
|
+
self._http = httpx.AsyncClient(
|
|
68
|
+
base_url=f"{self._base_url}/api/v1",
|
|
69
|
+
headers=make_headers(api_key),
|
|
70
|
+
timeout=timeout,
|
|
71
|
+
)
|
|
72
|
+
self._last_rate_limit = RateLimitInfo()
|
|
73
|
+
|
|
74
|
+
# Resource namespaces
|
|
75
|
+
self.odds = _AsyncOddsResource(self)
|
|
76
|
+
self.ev = _AsyncEVResource(self)
|
|
77
|
+
self.arbitrage = _AsyncArbitrageResource(self)
|
|
78
|
+
self.middles = _AsyncMiddlesResource(self)
|
|
79
|
+
self.low_hold = _AsyncLowHoldResource(self)
|
|
80
|
+
self.sports = _AsyncSportsResource(self)
|
|
81
|
+
self.leagues = _AsyncLeaguesResource(self)
|
|
82
|
+
self.sportsbooks = _AsyncSportsbooksResource(self)
|
|
83
|
+
self.events = _AsyncEventsResource(self)
|
|
84
|
+
self.account = _AsyncAccountResource(self)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def rate_limit(self) -> RateLimitInfo:
|
|
88
|
+
"""Rate limit info from the last request."""
|
|
89
|
+
return self._last_rate_limit
|
|
90
|
+
|
|
91
|
+
async def _request(self, method: str, path: str, params: dict | None = None, **kwargs) -> Any:
|
|
92
|
+
"""Make an async API request and return parsed JSON."""
|
|
93
|
+
if params:
|
|
94
|
+
params = _clean_params(params)
|
|
95
|
+
|
|
96
|
+
response = await self._http.request(method, path, params=params, **kwargs)
|
|
97
|
+
self._last_rate_limit = parse_rate_limit(response)
|
|
98
|
+
handle_errors(response)
|
|
99
|
+
return response.json()
|
|
100
|
+
|
|
101
|
+
async def _get(self, path: str, params: dict | None = None) -> Any:
|
|
102
|
+
return await self._request("GET", path, params)
|
|
103
|
+
|
|
104
|
+
async def _post(self, path: str, json_body: Any = None, params: dict | None = None) -> Any:
|
|
105
|
+
return await self._request("POST", path, params, json=json_body)
|
|
106
|
+
|
|
107
|
+
async def close(self) -> None:
|
|
108
|
+
"""Close the async HTTP client."""
|
|
109
|
+
await self._http.aclose()
|
|
110
|
+
|
|
111
|
+
async def __aenter__(self):
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
async def __aexit__(self, *args):
|
|
115
|
+
await self.close()
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# =============================================================================
|
|
119
|
+
# Async Resource Namespaces
|
|
120
|
+
# =============================================================================
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class _AsyncOddsResource:
|
|
124
|
+
"""Async access to odds data."""
|
|
125
|
+
|
|
126
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
127
|
+
self._client = client
|
|
128
|
+
|
|
129
|
+
async def get(
|
|
130
|
+
self,
|
|
131
|
+
*,
|
|
132
|
+
sportsbook: Optional[Union[str, list[str]]] = None,
|
|
133
|
+
add_sportsbook: Optional[Union[str, list[str]]] = None,
|
|
134
|
+
sport: Optional[Union[str, list[str]]] = None,
|
|
135
|
+
league: Optional[Union[str, list[str]]] = None,
|
|
136
|
+
market: Optional[Union[str, list[str]]] = None,
|
|
137
|
+
event: Optional[Union[str, list[str]]] = None,
|
|
138
|
+
live: Optional[bool] = None,
|
|
139
|
+
sort: Optional[str] = None,
|
|
140
|
+
group_by: Optional[str] = None,
|
|
141
|
+
fields: Optional[Union[str, list[str]]] = None,
|
|
142
|
+
limit: Optional[int] = None,
|
|
143
|
+
offset: Optional[int] = None,
|
|
144
|
+
) -> APIResponse[list[OddsLine]]:
|
|
145
|
+
"""Get current odds snapshot."""
|
|
146
|
+
data = await self._client._get("/odds", {
|
|
147
|
+
"sportsbook": sportsbook,
|
|
148
|
+
"add_sportsbook": add_sportsbook,
|
|
149
|
+
"sport": sport,
|
|
150
|
+
"league": league,
|
|
151
|
+
"market": market,
|
|
152
|
+
"event": event,
|
|
153
|
+
"live": live,
|
|
154
|
+
"sort": sort,
|
|
155
|
+
"group_by": group_by,
|
|
156
|
+
"fields": fields,
|
|
157
|
+
"limit": limit,
|
|
158
|
+
"offset": offset,
|
|
159
|
+
})
|
|
160
|
+
return parse_response(data, OddsLine)
|
|
161
|
+
|
|
162
|
+
async def best(
|
|
163
|
+
self,
|
|
164
|
+
*,
|
|
165
|
+
sport: Optional[Union[str, list[str]]] = None,
|
|
166
|
+
league: Optional[Union[str, list[str]]] = None,
|
|
167
|
+
market: Optional[Union[str, list[str]]] = None,
|
|
168
|
+
event: Optional[Union[str, list[str]]] = None,
|
|
169
|
+
live: Optional[bool] = None,
|
|
170
|
+
sportsbook: Optional[Union[str, list[str]]] = None,
|
|
171
|
+
add_sportsbook: Optional[Union[str, list[str]]] = None,
|
|
172
|
+
limit: Optional[int] = None,
|
|
173
|
+
offset: Optional[int] = None,
|
|
174
|
+
) -> APIResponse[list[OddsLine]]:
|
|
175
|
+
"""Get best odds per selection across all sportsbooks."""
|
|
176
|
+
data = await self._client._get("/odds/best", {
|
|
177
|
+
"sport": sport,
|
|
178
|
+
"league": league,
|
|
179
|
+
"market": market,
|
|
180
|
+
"event": event,
|
|
181
|
+
"live": live,
|
|
182
|
+
"sportsbook": sportsbook,
|
|
183
|
+
"add_sportsbook": add_sportsbook,
|
|
184
|
+
"limit": limit,
|
|
185
|
+
"offset": offset,
|
|
186
|
+
})
|
|
187
|
+
return parse_response(data, OddsLine)
|
|
188
|
+
|
|
189
|
+
async def comparison(
|
|
190
|
+
self,
|
|
191
|
+
event_id: str,
|
|
192
|
+
*,
|
|
193
|
+
market: Optional[str] = None,
|
|
194
|
+
) -> APIResponse[list[OddsLine]]:
|
|
195
|
+
"""Get side-by-side odds comparison for an event."""
|
|
196
|
+
data = await self._client._get("/odds/comparison", {
|
|
197
|
+
"event_id": event_id,
|
|
198
|
+
"market": market,
|
|
199
|
+
})
|
|
200
|
+
return parse_response(data, OddsLine)
|
|
201
|
+
|
|
202
|
+
async def batch(self, event_ids: list[str]) -> APIResponse[list[OddsLine]]:
|
|
203
|
+
"""Batch odds lookup for multiple events."""
|
|
204
|
+
data = await self._client._post("/odds/batch", {"event_ids": event_ids})
|
|
205
|
+
return parse_response(data, OddsLine)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class _AsyncEVResource:
|
|
209
|
+
"""Async access to +EV opportunities."""
|
|
210
|
+
|
|
211
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
212
|
+
self._client = client
|
|
213
|
+
|
|
214
|
+
async def get(
|
|
215
|
+
self,
|
|
216
|
+
*,
|
|
217
|
+
sport: Optional[Union[str, list[str]]] = None,
|
|
218
|
+
league: Optional[Union[str, list[str]]] = None,
|
|
219
|
+
sportsbook: Optional[Union[str, list[str]]] = None,
|
|
220
|
+
add_sportsbook: Optional[Union[str, list[str]]] = None,
|
|
221
|
+
market: Optional[Union[str, list[str]]] = None,
|
|
222
|
+
min_ev: Optional[float] = None,
|
|
223
|
+
max_ev: Optional[float] = None,
|
|
224
|
+
min_market_width: Optional[float] = None,
|
|
225
|
+
max_market_width: Optional[float] = None,
|
|
226
|
+
max_odds_age: Optional[int] = None,
|
|
227
|
+
date_range: Optional[str] = None,
|
|
228
|
+
live: Optional[bool] = None,
|
|
229
|
+
sort: Optional[str] = None,
|
|
230
|
+
limit: Optional[int] = None,
|
|
231
|
+
offset: Optional[int] = None,
|
|
232
|
+
) -> APIResponse[list[EVOpportunity]]:
|
|
233
|
+
"""Get +EV opportunities. Requires Pro tier or higher."""
|
|
234
|
+
data = await self._client._get("/opportunities/ev", {
|
|
235
|
+
"sport": sport,
|
|
236
|
+
"league": league,
|
|
237
|
+
"sportsbook": sportsbook,
|
|
238
|
+
"add_sportsbook": add_sportsbook,
|
|
239
|
+
"market": market,
|
|
240
|
+
"min_ev": min_ev,
|
|
241
|
+
"max_ev": max_ev,
|
|
242
|
+
"min_market_width": min_market_width,
|
|
243
|
+
"max_market_width": max_market_width,
|
|
244
|
+
"max_odds_age": max_odds_age,
|
|
245
|
+
"date_range": date_range,
|
|
246
|
+
"live": live,
|
|
247
|
+
"sort": sort,
|
|
248
|
+
"limit": limit,
|
|
249
|
+
"offset": offset,
|
|
250
|
+
})
|
|
251
|
+
return parse_response(data, EVOpportunity)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class _AsyncArbitrageResource:
|
|
255
|
+
"""Async access to arbitrage opportunities."""
|
|
256
|
+
|
|
257
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
258
|
+
self._client = client
|
|
259
|
+
|
|
260
|
+
async def get(
|
|
261
|
+
self,
|
|
262
|
+
*,
|
|
263
|
+
sport: Optional[Union[str, list[str]]] = None,
|
|
264
|
+
league: Optional[Union[str, list[str]]] = None,
|
|
265
|
+
sportsbook: Optional[Union[str, list[str]]] = None,
|
|
266
|
+
add_sportsbook: Optional[Union[str, list[str]]] = None,
|
|
267
|
+
market: Optional[Union[str, list[str]]] = None,
|
|
268
|
+
min_profit: Optional[float] = None,
|
|
269
|
+
max_odds_age: Optional[int] = None,
|
|
270
|
+
live: Optional[bool] = None,
|
|
271
|
+
sort: Optional[str] = None,
|
|
272
|
+
group: Optional[str] = None,
|
|
273
|
+
limit: Optional[int] = None,
|
|
274
|
+
offset: Optional[int] = None,
|
|
275
|
+
) -> APIResponse[list[ArbitrageOpportunity]]:
|
|
276
|
+
"""Get arbitrage opportunities. Requires Hobby tier or higher."""
|
|
277
|
+
data = await self._client._get("/opportunities/arbitrage", {
|
|
278
|
+
"sport": sport,
|
|
279
|
+
"league": league,
|
|
280
|
+
"sportsbook": sportsbook,
|
|
281
|
+
"add_sportsbook": add_sportsbook,
|
|
282
|
+
"market": market,
|
|
283
|
+
"min_profit": min_profit,
|
|
284
|
+
"max_odds_age": max_odds_age,
|
|
285
|
+
"live": live,
|
|
286
|
+
"sort": sort,
|
|
287
|
+
"group": group,
|
|
288
|
+
"limit": limit,
|
|
289
|
+
"offset": offset,
|
|
290
|
+
})
|
|
291
|
+
return parse_response(data, ArbitrageOpportunity)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class _AsyncMiddlesResource:
|
|
295
|
+
"""Async access to middle opportunities."""
|
|
296
|
+
|
|
297
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
298
|
+
self._client = client
|
|
299
|
+
|
|
300
|
+
async def get(
|
|
301
|
+
self,
|
|
302
|
+
*,
|
|
303
|
+
sport: Optional[Union[str, list[str]]] = None,
|
|
304
|
+
league: Optional[Union[str, list[str]]] = None,
|
|
305
|
+
sportsbook: Optional[Union[str, list[str]]] = None,
|
|
306
|
+
market: Optional[Union[str, list[str]]] = None,
|
|
307
|
+
min_size: Optional[float] = None,
|
|
308
|
+
max_odds_age: Optional[int] = None,
|
|
309
|
+
live: Optional[bool] = None,
|
|
310
|
+
state: Optional[str] = None,
|
|
311
|
+
sort: Optional[str] = None,
|
|
312
|
+
limit: Optional[int] = None,
|
|
313
|
+
offset: Optional[int] = None,
|
|
314
|
+
) -> APIResponse[list[MiddleOpportunity]]:
|
|
315
|
+
"""Get middle opportunities. Requires Pro tier or higher."""
|
|
316
|
+
data = await self._client._get("/opportunities/middles", {
|
|
317
|
+
"sport": sport,
|
|
318
|
+
"league": league,
|
|
319
|
+
"sportsbook": sportsbook,
|
|
320
|
+
"market": market,
|
|
321
|
+
"min_size": min_size,
|
|
322
|
+
"max_odds_age": max_odds_age,
|
|
323
|
+
"live": live,
|
|
324
|
+
"state": state,
|
|
325
|
+
"sort": sort,
|
|
326
|
+
"limit": limit,
|
|
327
|
+
"offset": offset,
|
|
328
|
+
})
|
|
329
|
+
return parse_response(data, MiddleOpportunity)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class _AsyncLowHoldResource:
|
|
333
|
+
"""Async access to low-hold opportunities."""
|
|
334
|
+
|
|
335
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
336
|
+
self._client = client
|
|
337
|
+
|
|
338
|
+
async def get(
|
|
339
|
+
self,
|
|
340
|
+
*,
|
|
341
|
+
sport: Optional[Union[str, list[str]]] = None,
|
|
342
|
+
league: Optional[Union[str, list[str]]] = None,
|
|
343
|
+
sportsbook: Optional[Union[str, list[str]]] = None,
|
|
344
|
+
market: Optional[Union[str, list[str]]] = None,
|
|
345
|
+
max_hold: Optional[float] = None,
|
|
346
|
+
live: Optional[bool] = None,
|
|
347
|
+
state: Optional[str] = None,
|
|
348
|
+
sort: Optional[str] = None,
|
|
349
|
+
limit: Optional[int] = None,
|
|
350
|
+
offset: Optional[int] = None,
|
|
351
|
+
) -> APIResponse[list[LowHoldOpportunity]]:
|
|
352
|
+
"""Get low-hold opportunities."""
|
|
353
|
+
data = await self._client._get("/opportunities/low_hold", {
|
|
354
|
+
"sport": sport,
|
|
355
|
+
"league": league,
|
|
356
|
+
"sportsbook": sportsbook,
|
|
357
|
+
"market": market,
|
|
358
|
+
"max_hold": max_hold,
|
|
359
|
+
"live": live,
|
|
360
|
+
"state": state,
|
|
361
|
+
"sort": sort,
|
|
362
|
+
"limit": limit,
|
|
363
|
+
"offset": offset,
|
|
364
|
+
})
|
|
365
|
+
return parse_response(data, LowHoldOpportunity)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
class _AsyncSportsResource:
|
|
369
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
370
|
+
self._client = client
|
|
371
|
+
|
|
372
|
+
async def list(self) -> APIResponse[list[Sport]]:
|
|
373
|
+
"""List all available sports."""
|
|
374
|
+
data = await self._client._get("/sports")
|
|
375
|
+
return parse_response(data, Sport)
|
|
376
|
+
|
|
377
|
+
async def get(self, sport_id: str) -> Sport:
|
|
378
|
+
"""Get a specific sport."""
|
|
379
|
+
data = await self._client._get(f"/sports/{sport_id}")
|
|
380
|
+
raw = data.get("data", data)
|
|
381
|
+
return Sport.model_validate(raw)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class _AsyncLeaguesResource:
|
|
385
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
386
|
+
self._client = client
|
|
387
|
+
|
|
388
|
+
async def list(self, *, sport: Optional[str] = None) -> APIResponse[list[League]]:
|
|
389
|
+
"""List all leagues, optionally filtered by sport."""
|
|
390
|
+
data = await self._client._get("/leagues", {"sport": sport})
|
|
391
|
+
return parse_response(data, League)
|
|
392
|
+
|
|
393
|
+
async def get(self, league_id: str) -> League:
|
|
394
|
+
"""Get a specific league."""
|
|
395
|
+
data = await self._client._get(f"/leagues/{league_id}")
|
|
396
|
+
raw = data.get("data", data)
|
|
397
|
+
return League.model_validate(raw)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
class _AsyncSportsbooksResource:
|
|
401
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
402
|
+
self._client = client
|
|
403
|
+
|
|
404
|
+
async def list(self) -> APIResponse[list[Sportsbook]]:
|
|
405
|
+
"""List all active sportsbooks."""
|
|
406
|
+
data = await self._client._get("/sportsbooks")
|
|
407
|
+
return parse_response(data, Sportsbook)
|
|
408
|
+
|
|
409
|
+
async def get(self, book_id: str) -> Sportsbook:
|
|
410
|
+
"""Get a specific sportsbook."""
|
|
411
|
+
data = await self._client._get(f"/sportsbooks/{book_id}")
|
|
412
|
+
raw = data.get("data", data)
|
|
413
|
+
return Sportsbook.model_validate(raw)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class _AsyncEventsResource:
|
|
417
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
418
|
+
self._client = client
|
|
419
|
+
|
|
420
|
+
async def list(
|
|
421
|
+
self,
|
|
422
|
+
*,
|
|
423
|
+
sport: Optional[str] = None,
|
|
424
|
+
league: Optional[Union[str, list[str]]] = None,
|
|
425
|
+
live: Optional[bool] = None,
|
|
426
|
+
limit: Optional[int] = None,
|
|
427
|
+
offset: Optional[int] = None,
|
|
428
|
+
) -> APIResponse[list[Event]]:
|
|
429
|
+
"""List events."""
|
|
430
|
+
data = await self._client._get("/events", {
|
|
431
|
+
"sport": sport,
|
|
432
|
+
"league": league,
|
|
433
|
+
"live": live,
|
|
434
|
+
"limit": limit,
|
|
435
|
+
"offset": offset,
|
|
436
|
+
})
|
|
437
|
+
return parse_response(data, Event)
|
|
438
|
+
|
|
439
|
+
async def get(self, event_id: str) -> Event:
|
|
440
|
+
"""Get a specific event."""
|
|
441
|
+
data = await self._client._get(f"/events/{event_id}")
|
|
442
|
+
raw = data.get("data", data)
|
|
443
|
+
return Event.model_validate(raw)
|
|
444
|
+
|
|
445
|
+
async def search(self, query: str) -> APIResponse[list[Event]]:
|
|
446
|
+
"""Search events by name."""
|
|
447
|
+
data = await self._client._get("/events/search", {"q": query})
|
|
448
|
+
return parse_response(data, Event)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class _AsyncAccountResource:
|
|
452
|
+
def __init__(self, client: AsyncSharpAPI):
|
|
453
|
+
self._client = client
|
|
454
|
+
|
|
455
|
+
async def me(self) -> AccountInfo:
|
|
456
|
+
"""Get current account info (tier, limits, features)."""
|
|
457
|
+
data = await self._client._get("/account")
|
|
458
|
+
raw = data.get("data", data)
|
|
459
|
+
return AccountInfo.model_validate(raw)
|
|
460
|
+
|
|
461
|
+
async def usage(self) -> dict:
|
|
462
|
+
"""Get current usage stats."""
|
|
463
|
+
data = await self._client._get("/account/usage")
|
|
464
|
+
return data.get("data", data)
|