Why Build a Casino Agent?
Autonomous agents that control their own money are one of the most compelling demonstrations of programmable finance. A casino agent is the simplest possible proof of concept: it has a goal (maximize balance), a strategy (Kelly Criterion sizing), a feedback loop (win/loss results), and real skin in the game (actual USDC on the line).
Beyond the entertainment angle, building this agent teaches you patterns you will reuse everywhere: API key authentication, retry logic, state management, and stop-loss guards. The same skeleton powers trading bots, arbitrage scrapers, and LangChain tool-use agents.
Purple Flea's Casino API is purpose-built for agents. Every response is structured JSON, errors return consistent status codes, and the rate limits are generous enough that a simple polling loop works without backoff from the start. Let's build it.
Prerequisites
You need very little to get started. Here is the complete list:
python --version.pip install requests. No other deps required.Register Your Agent
The first call creates a new agent account and returns your permanent api_key and
agent_id. Store both values safely — the API key is shown only once.
Let's test it with curl first to confirm the endpoint is reachable:
# Register a new agent account
curl -s -X POST https://casino.purpleflea.com/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username": "my_agent_01", "email": "agent@example.com"}' | python -m json.tool
A successful response looks like this:
{
"api_key": "pf_live_sk_a3f9b2c1d4e5...",
"agent_id": "agt_7x9k2m",
"username": "my_agent_01",
"balance": 0.0,
"created_at": "2026-02-27T10:00:00Z"
}
Now replicate this in Python with a reusable helper class:
# casino_agent.py
import requests
import json
import os
BASE_URL = "https://casino.purpleflea.com/api/v1"
class CasinoAgent:
def __init__(self, api_key=None):
self.api_key = api_key
self.session = requests.Session()
if api_key:
self.session.headers["Authorization"] = f"Bearer {api_key}"
def register(self, username, email):
"""Create a new agent account. Returns api_key and agent_id."""
resp = self.session.post(
f"{BASE_URL}/auth/register",
json={"username": username, "email": email},
)
resp.raise_for_status()
data = resp.json()
# Persist the key for future sessions
self.api_key = data["api_key"]
self.session.headers["Authorization"] = f"Bearer {self.api_key}"
return data
# --- Run once to get your credentials ---
if __name__ == "__main__":
agent = CasinoAgent()
creds = agent.register("my_agent_01", "agent@example.com")
print("API Key:", creds["api_key"])
print("Agent ID:", creds["agent_id"])
export PF_API_KEY="pf_live_sk_..." to your
.bashrc or .zshrc, then load it with os.environ["PF_API_KEY"].
Fund Your Agent
After registering, your balance starts at zero. You need to deposit USDC before you can place any bets. The deposit flow works like this:
- Log in to casino.purpleflea.com with your new username.
- Navigate to Wallet → Deposit.
- Copy your personal USDC deposit address (Polygon network, no bridging required).
- Send your desired amount from any wallet or exchange. Minimum deposit is 1 USDC.
- Funds appear within 2 block confirmations (~8 seconds on Polygon).
You can also verify your balance programmatically. Add this method to your CasinoAgent class:
def get_stats(self):
"""Fetch account stats including current balance."""
resp = self.session.get(f"{BASE_URL}/stats/me")
resp.raise_for_status()
return resp.json()
# Usage:
agent = CasinoAgent(api_key=os.environ["PF_API_KEY"])
stats = agent.get_stats()
print(f"Current balance: ${stats['balance']:.2f} USDC")
The stats endpoint returns a clean JSON object you will use repeatedly throughout the bot to verify your running balance without needing to track it manually:
{
"balance": 5.00,
"total_bets": 0,
"total_wagered": 0.00,
"total_won": 0.00,
"net_pnl": 0.00,
"win_rate": null
}
Your First Bet
The coin flip is the cleanest game to start with: 50/50 probability, instant
resolution, and a payout of 1.96x the stake (a small house edge of 2%). Pick "heads"
or "tails", specify your stake amount, and the API resolves it immediately.
Request body:
{
"game": "coin_flip",
"amount": 1.0,
"side": "heads"
}
Response:
{
"bet_id": "bet_4j8mq2",
"game": "coin_flip",
"side": "heads",
"result": "tails",
"won": false,
"amount_bet": 1.0,
"amount_won": 0.0,
"new_balance": 4.0
}
Add the place_bet method to your class:
def place_bet(self, game, amount, **kwargs):
"""Place a bet. Extra kwargs are forwarded as JSON fields."""
payload = {"game": game, "amount": round(amount, 2), **kwargs}
resp = self.session.post(f"{BASE_URL}/bets/place", json=payload)
resp.raise_for_status()
return resp.json()
# Test with a single flip:
result = agent.place_bet("coin_flip", 1.0, side="heads")
outcome = "WON" if result["won"] else "LOST"
print(f"{outcome} — result was {result['result']}, new balance: ${result['new_balance']}")
Add Kelly Criterion Sizing
Flat-betting $1 every time is boring and suboptimal. The Kelly Criterion is a mathematically proven formula for maximizing the long-run growth rate of a bankroll by sizing each bet proportionally to your edge and bankroll.
For a coin flip paying 1.96x (net odds b = 0.96) with win probability p = 0.5:
For games with a genuine player edge (e.g., a promotional bonus that shifts EV positive), Kelly gives you the growth-optimal fraction. Here is the full implementation:
def kelly_fraction(p_win, net_odds, fraction=0.25):
"""
Compute the Kelly bet fraction.
Args:
p_win : probability of winning (0..1)
net_odds : net payout per unit staked (e.g. 0.96 for a 1.96x payout)
fraction : Kelly multiplier; 0.25 = quarter-Kelly (conservative)
Returns:
Fraction of bankroll to wager, floored at 0.
"""
p_lose = 1.0 - p_win
kelly = (net_odds * p_win - p_lose) / net_odds
return max(kelly * fraction, 0.0)
def kelly_bet_amount(balance, p_win, net_odds, min_bet=0.10,
max_bet=10.0, fraction=0.25):
"""
Translate the Kelly fraction into a dollar amount,
clamped between min_bet and max_bet.
"""
f = kelly_fraction(p_win, net_odds, fraction)
amount = balance * f
# Clamp to the table limits
amount = max(amount, min_bet)
amount = min(amount, max_bet)
return round(amount, 2)
# Coin flip parameters
COIN_FLIP_P_WIN = 0.50 # 50% win probability
COIN_FLIP_PAYOUT = 1.96 # 1.96x payout multiplier
COIN_FLIP_NET = COIN_FLIP_PAYOUT - 1.0 # = 0.96
# Example: $5 balance, quarter-Kelly
amount = kelly_bet_amount(5.0, COIN_FLIP_P_WIN, COIN_FLIP_NET)
print(f"Quarter-Kelly bet on $5 bankroll: ${amount}")
# Prints: Quarter-Kelly bet on $5 bankroll: $0.10 (floored at min)
Because coin flips are negative EV for the player, the raw Kelly fraction is negative. The
max(..., 0.0) clamp means we always fall back to the minimum bet. This is intentional:
it keeps the bot running for demonstration purposes. If you wire in a positive-EV signal (such as
a reload bonus that changes effective p_win), Kelly will size up automatically.
Game Loop with Stop-Loss
Now we combine everything into a full game loop. The loop runs until one of three exit conditions is met: the target profit is hit, the stop-loss floor is breached, or the maximum number of bets is reached.
import time
import random
def run_game_loop(
agent,
starting_balance,
stop_loss_pct = 0.30, # Quit if balance drops 30% below start
take_profit_pct = 0.50, # Quit if balance rises 50% above start
max_bets = 100,
delay_secs = 0.5, # Pause between bets (be polite to the API)
min_bet = 0.10,
max_bet = 5.0,
):
stop_loss_floor = starting_balance * (1 - stop_loss_pct)
take_profit_ceil = starting_balance * (1 + take_profit_pct)
balance = starting_balance
bets_made = 0
wins = 0
losses = 0
print(f"Starting loop | balance=${balance:.2f} | "
f"floor=${stop_loss_floor:.2f} | ceil=${take_profit_ceil:.2f}")
while bets_made < max_bets:
# ── Exit conditions ──────────────────────────────────
if balance <= stop_loss_floor:
print(f"[STOP-LOSS] Balance ${balance:.2f} hit floor. Exiting.")
break
if balance >= take_profit_ceil:
print(f"[TAKE-PROFIT] Balance ${balance:.2f} hit ceiling. Exiting.")
break
if balance < min_bet:
print(f"[BUST] Balance ${balance:.2f} below min bet. Exiting.")
break
# ── Size the bet ─────────────────────────────────────
amount = kelly_bet_amount(
balance, COIN_FLIP_P_WIN, COIN_FLIP_NET,
min_bet=min_bet, max_bet=max_bet,
)
# ── Place the bet ────────────────────────────────────
try:
result = agent.place_bet("coin_flip", amount, side="heads")
except requests.HTTPError as exc:
print(f"[ERROR] HTTP {exc.response.status_code}: {exc.response.text}")
break
# ── Update state ─────────────────────────────────────
balance = result["new_balance"]
bets_made += 1
if result["won"]:
wins += 1
else:
losses += 1
win_rate = wins / bets_made * 100
icon = "+" if result["won"] else "-"
print(
f"Bet #{bets_made:03d} [{icon}] "
f"${amount:.2f} wagered | "
f"result={result['result']:5s} | "
f"balance=${balance:.2f} | "
f"W/L={wins}/{losses} ({win_rate:.1f}%)"
)
time.sleep(delay_secs)
net_pnl = balance - starting_balance
print(f"\nSession complete: {bets_made} bets | "
f"W/L {wins}/{losses} | "
f"PnL ${net_pnl:+.2f}")
return balance
Sample output for a 20-bet session:
Starting loop | balance=$5.00 | floor=$3.50 | ceil=$7.50
Bet #001 [+] $0.10 wagered | result=heads | balance=$5.10 | W/L=1/0 (100.0%)
Bet #002 [-] $0.10 wagered | result=tails | balance=$5.00 | W/L=1/1 (50.0%)
Bet #003 [+] $0.10 wagered | result=heads | balance=$5.10 | W/L=2/1 (66.7%)
Bet #004 [-] $0.10 wagered | result=tails | balance=$5.00 | W/L=2/2 (50.0%)
...
Session complete: 20 bets | W/L 9/11 | PnL $-0.20
Check Your Stats
After running a session, pull your full stats to review performance. The /stats/me
endpoint aggregates lifetime totals and is useful for building dashboards or logging to a
database.
def print_stats(agent):
stats = agent.get_stats()
print("\n── Account Stats ────────────────────────")
print(f" Balance: ${stats['balance']:.4f} USDC")
print(f" Total bets: {stats['total_bets']}")
print(f" Total wagered: ${stats['total_wagered']:.4f}")
print(f" Total won: ${stats['total_won']:.4f}")
print(f" Net PnL: ${stats['net_pnl']:+.4f}")
win_rate = stats.get("win_rate")
if win_rate is not None:
print(f" Win rate: {win_rate:.1f}%")
print("──────────────────────────────────────────")
print_stats(agent)
You can also retrieve your recent bet history:
def get_recent_bets(self, limit=20):
"""Fetch recent bet history."""
resp = self.session.get(
f"{BASE_URL}/bets",
params={"limit": limit},
)
resp.raise_for_status()
return resp.json()
# Print last 5 bets
bets = agent.get_recent_bets(limit=5)
for bet in bets:
icon = "W" if bet["won"] else "L"
print(f"[{icon}] {bet['game']:12s} ${bet['amount_bet']:.2f} wagered")
Set Up Referrals for Passive Income
Purple Flea's referral program pays you a 5% revenue share on the house edge generated by anyone who signs up using your referral code. If you are building a multi-agent system or writing a tutorial that sends other developers to the platform, referrals can offset your own losses.
Your referral code is derived from your agent_id:
def get_referral_info(self):
"""Returns referral code, link, and earnings so far."""
resp = self.session.get(f"{BASE_URL}/referrals/me")
resp.raise_for_status()
return resp.json()
ref = agent.get_referral_info()
print(f"Your referral link: https://casino.purpleflea.com?ref={ref['code']}")
print(f"Total referred users: {ref['total_referrals']}")
print(f"Earnings from referrals: ${ref['total_earned']:.4f} USDC")
When registering new agents programmatically, pass the referral_code field during
registration to attribute them to your account automatically:
# Register a sub-agent under your referral code
new_agent = CasinoAgent()
creds = new_agent.register(
username="sub_agent_02",
email="sub@example.com",
referral_code="AGT7X9K2M", # your code
)
Complete Final Code
Everything above combined into a single, fully runnable file. Copy it, set your
PF_API_KEY environment variable, and run it directly with
python casino_agent.py.
#!/usr/bin/env python3
"""
casino_agent.py — Purple Flea Casino Bot
A complete autonomous betting agent with Kelly Criterion sizing,
stop-loss protection, and session stats reporting.
Usage:
export PF_API_KEY="pf_live_sk_..."
python casino_agent.py
To register a new account (run once):
python casino_agent.py --register
"""
import argparse
import os
import sys
import time
import requests
# ── Constants ─────────────────────────────────────────────────────
BASE_URL = "https://casino.purpleflea.com/api/v1"
COIN_FLIP_P_WIN = 0.50
COIN_FLIP_PAYOUT = 1.96
COIN_FLIP_NET = COIN_FLIP_PAYOUT - 1.0
# ── Kelly Criterion ────────────────────────────────────────────────
def kelly_fraction(p_win, net_odds, fraction=0.25):
p_lose = 1.0 - p_win
kelly = (net_odds * p_win - p_lose) / net_odds
return max(kelly * fraction, 0.0)
def kelly_bet_amount(balance, p_win, net_odds,
min_bet=0.10, max_bet=5.0, fraction=0.25):
f = kelly_fraction(p_win, net_odds, fraction)
amount = balance * f
amount = max(amount, min_bet)
amount = min(amount, max_bet)
return round(amount, 2)
# ── Casino Agent class ─────────────────────────────────────────────
class CasinoAgent:
def __init__(self, api_key=None):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({"Content-Type": "application/json"})
if api_key:
self.session.headers["Authorization"] = f"Bearer {api_key}"
def register(self, username, email, referral_code=None):
payload = {"username": username, "email": email}
if referral_code:
payload["referral_code"] = referral_code
resp = self.session.post(f"{BASE_URL}/auth/register", json=payload)
resp.raise_for_status()
data = resp.json()
self.api_key = data["api_key"]
self.session.headers["Authorization"] = f"Bearer {self.api_key}"
return data
def place_bet(self, game, amount, **kwargs):
payload = {"game": game, "amount": round(amount, 2), **kwargs}
resp = self.session.post(f"{BASE_URL}/bets/place", json=payload)
resp.raise_for_status()
return resp.json()
def get_stats(self):
resp = self.session.get(f"{BASE_URL}/stats/me")
resp.raise_for_status()
return resp.json()
def get_recent_bets(self, limit=20):
resp = self.session.get(f"{BASE_URL}/bets", params={"limit": limit})
resp.raise_for_status()
return resp.json()
def get_referral_info(self):
resp = self.session.get(f"{BASE_URL}/referrals/me")
resp.raise_for_status()
return resp.json()
# ── Game loop ──────────────────────────────────────────────────────
def run_game_loop(agent, starting_balance, stop_loss_pct=0.30,
take_profit_pct=0.50, max_bets=100,
delay_secs=0.5, min_bet=0.10, max_bet=5.0):
floor = starting_balance * (1 - stop_loss_pct)
ceil = starting_balance * (1 + take_profit_pct)
balance= starting_balance
bets = wins = losses = 0
print(f"Loop start: ${balance:.2f} | floor=${floor:.2f} | ceil=${ceil:.2f}")
while bets < max_bets:
if balance <= floor:
print(f"[STOP-LOSS] ${balance:.2f} <= ${floor:.2f}"); break
if balance >= ceil:
print(f"[TAKE-PROFIT] ${balance:.2f} >= ${ceil:.2f}"); break
if balance < min_bet:
print(f"[BUST] ${balance:.2f}"); break
amount = kelly_bet_amount(
balance, COIN_FLIP_P_WIN, COIN_FLIP_NET,
min_bet=min_bet, max_bet=max_bet,
)
try:
r = agent.place_bet("coin_flip", amount, side="heads")
except requests.HTTPError as e:
print(f"HTTP error: {e}"); break
balance = r["new_balance"]
bets += 1
if r["won"]: wins += 1
else: losses += 1
icon = "+" if r["won"] else "-"
print(f"#{bets:03d}[{icon}] ${amount:.2f} | {r['result']:5s} | balance=${balance:.2f}")
time.sleep(delay_secs)
pnl = balance - starting_balance
print(f"\nDone: {bets} bets, W/L {wins}/{losses}, PnL ${pnl:+.2f}")
return balance
# ── Stats printer ──────────────────────────────────────────────────
def print_stats(agent):
s = agent.get_stats()
print("\n── Account Stats ──────────────────────────")
print(f" Balance: ${s['balance']:.4f} USDC")
print(f" Total bets: {s['total_bets']}")
print(f" Total wagered: ${s['total_wagered']:.4f}")
print(f" Net PnL: ${s['net_pnl']:+.4f}")
if s.get("win_rate"):
print(f" Win rate: {s['win_rate']:.1f}%")
print("────────────────────────────────────────────\n")
# ── Entry point ────────────────────────────────────────────────────
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Purple Flea Casino Agent")
parser.add_argument("--register", action="store_true")
parser.add_argument("--username", default="my_agent_01")
parser.add_argument("--email", default="agent@example.com")
parser.add_argument("--bets", type=int, default=50)
parser.add_argument("--stop-loss", type=float, default=0.30)
args = parser.parse_args()
if args.register:
agent = CasinoAgent()
creds = agent.register(args.username, args.email)
print("Registered successfully!")
print(f"API Key : {creds['api_key']}")
print(f"Agent ID : {creds['agent_id']}")
print("\nAdd to your shell:")
print(f" export PF_API_KEY=\"{creds['api_key']}\"")
sys.exit(0)
api_key = os.environ.get("PF_API_KEY")
if not api_key:
print("Error: PF_API_KEY environment variable not set.")
print("Run with --register first, then export PF_API_KEY=...")
sys.exit(1)
agent = CasinoAgent(api_key=api_key)
# Print starting stats
print_stats(agent)
stats = agent.get_stats()
start_balance = stats["balance"]
if start_balance < 0.10:
print("Balance too low. Please deposit USDC first.")
sys.exit(1)
# Run the game loop
run_game_loop(
agent,
starting_balance = start_balance,
stop_loss_pct = args.stop_loss,
take_profit_pct = 0.50,
max_bets = args.bets,
delay_secs = 0.5,
min_bet = 0.10,
max_bet = 5.0,
)
# Print final stats
print_stats(agent)
What's Next
You now have a working autonomous casino agent. Here are three high-value directions to extend it: