StakeAPI Client
The main async client class — your entry point for every Stake.com API call.
💡 Don't have a Stake.com account yet? Sign up here to get started and unlock all API features.
Overview
StakeAPI is the central class of this library. It manages the HTTP session, authentication headers and cookies, Cloudflare bypass, rate-limiting, and exposes every high-level method for casino games, sports events, user data, and betting.
All public methods are async and must be awaited inside an async function.
Import:
from stakeapi import StakeAPI
Constructor
StakeAPI(
access_token: Optional[str] = None,
session_cookie: Optional[str] = None,
cf_clearance: Optional[str] = None,
user_agent: Optional[str] = None,
base_url: str = "https://stake.com",
timeout: int = 30,
rate_limit: int = 10,
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
access_token | Optional[str] | None | Your Stake.com x-access-token header value. Required for account-specific methods. |
session_cookie | Optional[str] | None | Value of the session cookie from your browser. Alternative or complement to access_token. |
cf_clearance | Optional[str] | None | Value of the cf_clearance cookie. Required to bypass Cloudflare protection. |
user_agent | Optional[str] | None | The exact User-Agent string from the browser session that generated cf_clearance. Must match. |
base_url | str | "https://stake.com" | Base URL for all requests. Change only for testing or proxy use. |
timeout | int | 30 | Per-request timeout in seconds. Increase for slow connections. |
rate_limit | int | 10 | Maximum requests per second before throttling kicks in. |
Cloudflare: Stake.com is protected by Cloudflare. Without a valid
cf_clearancecookie you will receive403 Forbiddenon most endpoints. See Authentication for how to obtain it.
Full Example
import asyncio
from stakeapi import StakeAPI
async def main():
client = StakeAPI(
access_token="your_x_access_token",
session_cookie="your_session_cookie",
cf_clearance="your_cf_clearance_cookie",
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
timeout=60,
rate_limit=5,
)
balance = await client.get_user_balance()
await client.close()
asyncio.run(main())
Async Context Manager
The recommended way to use StakeAPI is as an async context manager. It automatically creates and closes the HTTP session for you.
async with StakeAPI(
access_token="your_token",
cf_clearance="your_cf_clearance",
user_agent="your_user_agent",
) as client:
balance = await client.get_user_balance()
profile = await client.get_user_profile()
# Session is closed automatically here — no need to call client.close()
__aenter__(self)
Creates the internal aiohttp.ClientSession with all configured headers and cookies, then returns self.
__aexit__(self, exc_type, exc_val, exc_tb)
Gracefully closes the session. Called automatically at the end of an async with block, even if an exception occurred.
Session Management
_create_session()
async def _create_session(self) -> None
Creates the aiohttp.ClientSession with the following headers pre-populated:
| Header | Value |
|---|---|
User-Agent | Provided value or sensible Chrome/Windows default |
Accept | application/graphql+json, application/json |
Content-Type | application/json |
Origin | https://stake.com |
Referer | https://stake.com/ |
X-Language | en |
X-Access-Token | Your access_token (if provided) |
Cookies session and cf_clearance are injected at the session level so they are sent with every request automatically.
You do not normally need to call this method directly — it is called automatically on first use or by
__aenter__.
close()
async def close(self) -> None
Close the underlying HTTP session and free resources.
client = StakeAPI(access_token="token", cf_clearance="...")
try:
balance = await client.get_user_balance()
finally:
await client.close()
Prefer the
async withpattern over manualclose()calls — it is safer and more concise.
Casino Methods
All casino methods read public data, so no login is needed. Requests still have to pass Cloudflare, so pass your browser cookies (for example cookie_file="cookie.txt", which includes cf_clearance). Game and group slugs are the ones in site URLs: /casino/games/<slug> and /casino/group/<slug>.
get_casino_games(category=None, limit=50, offset=0, sort="popular7d")
async def get_casino_games(
self,
category: Optional[str] = None,
limit: int = 50,
offset: int = 0,
sort: str = "popular7d",
) -> List[Game]
Fetch the games in a casino lobby group.
| Parameter | Type | Default | Description |
|---|---|---|---|
category | Optional[str] | "slots" | Group slug, e.g. "slots", "stake-originals", "live-casino" |
limit | int | 50 | Maximum games to return |
offset | int | 0 | Games to skip, for pagination |
sort | str | "popular7d" | Sort order |
Returns: List[Game]. rtp is derived from the house edge, and player_count is the number of current players.
Raises: StakeAPIError if the group does not exist.
async with StakeAPI(cookie_file="cookie.txt") as client:
originals = await client.get_casino_games(category="stake-originals")
for game in originals[:5]:
print(f"{game.name} ({game.provider}): RTP {game.rtp}%, {game.player_count} playing")
get_game_details(game_id)
async def get_game_details(self, game_id: str) -> Game
Fetch one game by its slug, e.g. "stake-dice" or "stake-plinko".
Raises: StakeAPIError if the game does not exist.
search_casino_games(query, limit=20, offset=0)
Search games by name. Returns List[Game].
get_casino_collection(collection_type="provider", sort="popular", filter="all")
List a lobby collection, such as all game providers. Each item is a dict with id, slug, translation, gameCount and playerCount.
get_game_payouts()
Payout tables for Keno, Plinko and Wheel: {"keno": [...], "plinko": [...], "wheel": [...]}. Each entry has payouts and risk, plus rows for Plinko and Wheel.
get_crash_history(limit=20, offset=0) / get_slide_history(limit=20, offset=0)
Recent rounds of the multiplayer Crash and Slide games, with their result and provably-fair hash.
get_crash_game(game_id)
One Crash round with its revealed seed, hash and bet leaderboard.
get_highroller_bets(limit=10)
The public high-roller casino bet feed, as List[Bet].
Sports Methods
All sports methods read public data, so no login is needed (Cloudflare cookies are still required, as above). Wherever a search_type appears it is "upcoming", "live" or "active", and group selects which market’s odds are included ("winner" covers match-winner odds).
get_sports_events(sport=None)
async def get_sports_events(self, sport: Optional[str] = None) -> List[SportEvent]
Popular fixtures for one sport (default "soccer"), mapped to SportEvent objects with winner odds.
async with StakeAPI(cookie_file="cookie.txt") as client:
for event in await client.get_sports_events("basketball"):
print(f"{event.home_team} vs {event.away_team} ({event.league}): {event.odds}")
get_sport_index(sport="soccer", group="winner", search_type="popular", market_limit=1)
The raw data behind a sport’s landing page: featured fixtures with odds, top tournaments, and every category with its tournaments.
get_sports(search_type="upcoming", sport_type="sport", limit=100)
Every sport with its fixture count. Pass sport_type="esport" for esports.
get_trending_sports(limit=10)
The most popular sports.
get_fixtures(search_type="upcoming", sport_type="sport", group="winner", limit=20, offset=0, market_limit=1)
Fixtures across all sports. Returns {"count": <total>, "fixtures": [...]}.
get_sport_fixtures(sport, search_type="upcoming", group="winner", tournament_limit=25, tournament_offset=0, fixture_limit=20, market_limit=1)
A sport’s tournaments, each with its fixtures and odds.
get_tournament(sport, category, tournament, search_type="upcoming", groups=None, limit=10, offset=0, market_limit=1)
One tournament by the slugs in its URL, /sports/<sport>/<category>/<tournament>.
async with StakeAPI(cookie_file="cookie.txt") as client:
epl = await client.get_tournament("soccer", "england", "premier-league")
print(epl["name"], epl["fixtureCount"])
search_sports(query, group="winner", limit=20, offset=0)
Search fixtures by team, player or event name.
get_trending_matches(sort_by="totalBetCount", sport_id=None, groups=None)
The matches with the most betting activity, with user counts and bets per outcome.
get_top_picks(sort_by="totalBetValue", sport_id=None)
The most-backed single outcomes.
get_top_multis()
The most popular multi (accumulator) bets and their legs.
Promotion & Info Methods
get_challenges(limit=20, offset=0, sort="startAt", direction="desc")
Public casino challenges. Returns {"count": <total>, "challenges": [...]}.
get_active_races(leaderboard_limit=10)
Running wager races, each with its leaderboard.
get_currency_limits()
Maximum bet and maximum profit per currency: {"btc": {"bet_max": 100.0, "bet_max_profit": 10.0}, ...}.
User Methods
get_user_profile()
async def get_user_profile(self) -> User
Fetch the authenticated user’s profile information.
Returns: User object with id, username, email, verified, created_at, country, and currency.
Raises: AuthenticationError if not authenticated.
async with StakeAPI(access_token="...", cf_clearance="...") as client:
user = await client.get_user_profile()
print(f"Username: {user.username}")
print(f"ID: {user.id}")
print(f"Verified: {user.verified}")
print(f"Country: {user.country}")
print(f"Currency: {user.currency}")
print(f"Joined: {user.created_at.strftime('%Y-%m-%d')}")
get_user_balance()
async def get_user_balance(self) -> Dict[str, Dict[str, float]]
Fetch the user’s wallet balances across all currencies using the GraphQL API. Returns both the spendable (available) amount and the locked (vault) amount separately.
Returns:
{
"available": {
"btc": 0.00104200,
"eth": 0.05000000,
"usdt": 150.00,
"ltc": 0.0,
# ... one key per currency with a non-zero balance
},
"vault": {
"btc": 0.01000000,
"eth": 0.0,
"usdt": 0.0,
}
}
Raises: AuthenticationError if the session is not authenticated.
async with StakeAPI(access_token="...", cf_clearance="...") as client:
balance = await client.get_user_balance()
print("=== Available ===")
for currency, amount in balance["available"].items():
if amount > 0:
print(f" {currency.upper()}: {amount:.8f}")
print("=== Vault ===")
for currency, amount in balance["vault"].items():
if amount > 0:
print(f" {currency.upper()}: {amount:.8f}")
This method uses the
UserBalancesGraphQL query under the hood. See GraphQL Queries for the raw query.
Account Methods
These read your own account, so they need a logged-in session (access token or cookie_file). Without one they raise PermissionDeniedError. The one exception is get_user_stats(), which looks up any player’s public profile.
| Method | Returns |
|---|---|
get_user_stats(name) | Any player’s public profile: join date, VIP flags, high-roller badges, and per-currency bet stats (statisticScoped is None if they hide them). No login needed. |
get_account_status() | KYC status, email/phone verification, ban/suspension flags, self-exclusion |
get_vip_info() | VIP rank flags, flagProgress to the next rank, rakeback balances, reload, dailyBonus, topUpBonus, and your VIP host (vipInfo) |
get_claimable_bonuses() | Self-serve bonuses you can claim now |
get_unclaimed_bonuses(limit=20, offset=0) | Bonus codes credited to you but not redeemed |
get_active_rollovers() | Wagering requirements on your bonuses (amount, progress, expectedAmount, maxBet) |
get_seed_pair() | Provably-fair seeds: client_seed, server_seed_hash, next_server_seed_hash, nonce, active_bets |
get_sport_bet_history(limit=20, offset=0, status=None) | Your sports bets; filter status with "confirmed" (open), "settled", "cashout", "cancelled" |
get_active_sport_bets(limit=20, offset=0) | Your open sports bets |
get_deposits(limit=10, offset=0) / get_withdrawals(limit=10, offset=0) | Crypto deposits and withdrawals (amount, currency, chain, status, hash) |
get_tip_history(limit=20, offset=0, name=None) | Tips you sent and received |
get_game_statistics(period="all", sort="wagered", limit=20, offset=0) | Per-game bet count, wagered, profit and RTP. period: "day", "week", "month", "all". sort: "wagered", "profit", "bets", "rtp" |
get_favourite_games(limit=50, offset=0) / get_recent_games(limit=20, offset=0) | List[Game] |
get_race_positions(limit=20, offset=0) | Your positions and payouts in races |
get_notifications(limit=20, offset=0) | Notifications; data.__typename says what each one is ("ChatTip", "WalletDeposit", "NotificationUserBonus", …) |
get_gambling_limits() | Responsible-gambling limits on your account |
get_sessions(limit=10, offset=0) | Login sessions (device, IP, location, last seen) |
async with StakeAPI(cookie_file="cookie.txt") as client:
vip = await client.get_vip_info()
print("VIP progress:", vip["flagProgress"])
for stat in await client.get_game_statistics(period="month", sort="profit", limit=5):
print(f"{stat['game']['name']}: {stat['betCount']} bets, profit {stat['profitValue']}")
seeds = await client.get_seed_pair()
print("Server seed hash:", seeds["server_seed_hash"], "nonce:", seeds["nonce"])
Betting Methods
Unvalidated, real money. These methods were built from the site’s own code but have never been sent to the live API. Try each one with
dry_run=Truefirst, then with the smallest possible amount, before relying on it.
Every bet method:
- needs the client to be created with
allow_betting=True, and raisesBettingDisabledErrorotherwise - takes
dry_run=True, which returns the request it would send (endpoint, operation and variables) without sending anything, and works even withoutallow_betting - rejects negative amounts and missing currencies with
ValidationErrorbefore sending
async with StakeAPI(cookie_file="cookie.txt", allow_betting=True) as client:
print(await client.dice_roll(0, "btc", target=50.5, condition="above", dry_run=True))
result = await client.dice_roll(0.00000100, "btc", target=50.5, condition="above")
print(result["payoutMultiplier"], result["payout"])
| Method | Game | Notes |
|---|---|---|
dice_roll(amount, currency, target, condition="above") | Dice | target 2–98, condition "above"/"below". Request shape taken from the site’s code. |
casino_bet(path, variables) | Any Stake Original | POSTs JSON to /_api/casino/<path> and returns the result object. Known paths: "dice/roll", "limbo/bet", "mines/bet", "mines/next". Copy the variables for games other than Dice from DevTools. |
crash_bet(amount, currency, cashout_at) | Crash | Joins the next round with an auto-cashout multiplier |
crash_cashout() | Crash | Cashes out now |
slide_bet(currency, bets, identifier=None) | Slide | bets passed through as given |
flip_bet(amount, currency, guesses, identifier=None), flip_next(condition), flip_cashout(identifier) | Flip | Enum values not confirmed |
zoo_bet(currency, animals, identifier=None) | Zoo | animals passed through as given |
place_sport_bet(amount, currency, outcome_ids, odds_change, bet_type, identifier=None) | Sports | outcome_ids from any fixture’s markets. odds_change and bet_type are required because their valid values are not confirmed; copy them from a BetSlipFooter_SportBet request in DevTools. |
cashout_sport_bet(bet_id, multiplier, cashout_percent=None) | Sports | bet_id from get_active_sport_bets() |
place_bet(bet_data) is kept for compatibility but always raises, pointing to the per-game methods above.
get_bet_history(limit=50, offset=0, game=None)
async def get_bet_history(
self, limit: int = 50, offset: int = 0, game: Optional[str] = None
) -> List[Bet]
Retrieve the authenticated user’s recent casino bet history.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Maximum number of bets to return |
offset | int | 0 | Bets to skip, for pagination |
game | Optional[str] | None | Only one Stake Original, e.g. "dice", "limbo", "mines", "plinko", "crash", "dragonTower", "videoPoker" |
Returns: List[Bet] — Most recent bets first.
Raises: AuthenticationError, StakeAPIError
async with StakeAPI(access_token="...", cf_clearance="...") as client:
bets = await client.get_bet_history(limit=100)
wins = [b for b in bets if b.status == "won"]
losses = [b for b in bets if b.status == "lost"]
print(f"Last {len(bets)} bets:")
print(f" Won: {len(wins)}")
print(f" Lost: {len(losses)}")
if bets:
win_rate = len(wins) / len(bets) * 100
print(f" Win rate: {win_rate:.1f}%")
Internal / Low-Level Methods
These methods are used internally but are also useful for advanced users who need to make custom requests.
_graphql_request(query, variables=None, operation_name=None)
async def _graphql_request(
self,
query: str,
variables: Optional[Dict[str, Any]] = None,
operation_name: Optional[str] = None
) -> Dict[Any, Any]
Send a raw GraphQL request to /_api/graphql. Automatically handles authentication headers, checks for errors in the response, and returns the data field.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query | str | — | GraphQL query or mutation string |
variables | Optional[Dict] | None | Variables dict for parameterised queries |
operation_name | Optional[str] | None | Optional operation name sent in the payload |
Returns: The data key of the GraphQL response as a dict.
Raises: StakeAPIError if the response contains a errors key.
async with StakeAPI(access_token="...", cf_clearance="...") as client:
data = await client._graphql_request(
query="""
query UserProfile {
user { id name email }
}
""",
operation_name="UserProfile",
)
print(data["user"]["name"])
_request(method, endpoint, params=None, data=None)
async def _request(
self,
method: str,
endpoint: str,
params: Optional[Dict] = None,
data: Optional[Dict] = None,
) -> Dict[Any, Any]
Make a raw authenticated HTTP request.
Parameters:
| Parameter | Type | Description |
|---|---|---|
method | str | HTTP verb: "GET", "POST", "PUT", "DELETE" |
endpoint | str | Path relative to base_url, e.g. "/_api/graphql" |
params | Optional[Dict] | URL query parameters |
data | Optional[Dict] | JSON request body (serialised automatically) |
Raises:
| Status | Exception |
|---|---|
401 | AuthenticationError |
403 | StakeAPIError (Cloudflare block) |
429 | RateLimitError |
4xx/5xx | StakeAPIError |
| Network error | StakeAPIError |
Complete Working Example
import asyncio
from stakeapi import StakeAPI
from stakeapi.utils import format_currency
from decimal import Decimal
async def main():
async with StakeAPI(
access_token="YOUR_ACCESS_TOKEN",
cf_clearance="YOUR_CF_CLEARANCE",
user_agent="YOUR_USER_AGENT",
) as client:
# Profile
user = await client.get_user_profile()
print(f"Logged in as: {user.username}")
# Balance
balance = await client.get_user_balance()
for currency, amount in balance["available"].items():
if amount > 0:
print(f" {currency.upper()}: {amount:.8f}")
# Casino games
games = await client.get_casino_games(category="slots")
print(f"\nSlots available: {len(games)}")
# Bet history
bets = await client.get_bet_history(limit=20)
won = sum(1 for b in bets if b.status == "won")
print(f"\nLast 20 bets — Won: {won}, Lost: {len(bets) - won}")
asyncio.run(main())
💬 Join the StakeAPI Community on Discord
Get help, share your projects, discuss strategies, and stay up to date with the latest StakeAPI news.
Join Our Discord Server →✏️ Built with ChipaEditor
ChipaEditor is the ultimate code editor built for speed, simplicity, and power. Try it free today.
Try ChipaEditor Free →See Also
- AuthManager — Token and cookie management
- Data Models —
User,Game,Bet,SportEvent - Endpoints — All URL constants and GraphQL queries
- Exceptions — Error handling reference
- Utilities — Helper functions
- Authentication Guide — How to get your tokens