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.

⚠️
Responsible gambling notice This tutorial is for educational and development purposes. Only fund your agent with money you are fully prepared to lose. Set stop-loss limits before running any game loop.

Prerequisites

You need very little to get started. Here is the complete list:

Python 3.8+
Any modern Python version works. Check with python --version.
requests library
Install with pip install requests. No other deps required.
~$5 USDC
Enough to run several hundred bets at minimum stake and observe the bot in action.
A text editor
VS Code, Vim, whatever you like. We will write one Python file.
ℹ️
No account needed upfront The registration endpoint creates your account programmatically and returns an API key in the response. There is no web form to fill in first.
1

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.

POST https://casino.purpleflea.com/api/v1/auth/register

Let's test it with curl first to confirm the endpoint is reachable:

bash
# 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:

json
{
  "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:

python
# 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"])
💡
Save your key in an environment variable Never hardcode your API key. Add export PF_API_KEY="pf_live_sk_..." to your .bashrc or .zshrc, then load it with os.environ["PF_API_KEY"].
2

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:

  1. Log in to casino.purpleflea.com with your new username.
  2. Navigate to Wallet → Deposit.
  3. Copy your personal USDC deposit address (Polygon network, no bridging required).
  4. Send your desired amount from any wallet or exchange. Minimum deposit is 1 USDC.
  5. Funds appear within 2 block confirmations (~8 seconds on Polygon).

You can also verify your balance programmatically. Add this method to your CasinoAgent class:

python
    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:

GET https://casino.purpleflea.com/api/v1/stats/me
json
{
  "balance": 5.00,
  "total_bets": 0,
  "total_wagered": 0.00,
  "total_won": 0.00,
  "net_pnl": 0.00,
  "win_rate": null
}
3

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.

POST https://casino.purpleflea.com/api/v1/bets/place

Request body:

json
{
  "game": "coin_flip",
  "amount": 1.0,
  "side": "heads"
}

Response:

json
{
  "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:

python
    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']}")
ℹ️
Always bet heads It does not matter whether you always bet heads or tails — the house edge is symmetric. Picking a fixed side lets you remove one source of randomness from your code and keeps logs easy to read.
4

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.

f* = (bp − q) / b
f* = fraction of bankroll to bet  •  b = net odds (payout minus 1)  •  p = probability of winning  •  q = 1 − p

For a coin flip paying 1.96x (net odds b = 0.96) with win probability p = 0.5:

f* = (0.96 × 0.5 − 0.5) / 0.96 ≈ −0.0208
Negative Kelly means the house has an edge — the correct bet size is technically zero. We use fractional Kelly (e.g., quarter-Kelly) to stay in the game while accepting the expected negative drift.

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:

python
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.

5

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.

python
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:

text
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
6

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.

GET https://casino.purpleflea.com/api/v1/stats/me
python
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:

GET https://casino.purpleflea.com/api/v1/bets
python
    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")
7

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:

python
    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:

python
# 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
)
💡
Automate a referral fleet If you are running multiple agents across different strategies, register each one through your referral link. You earn 5% of the house edge on every bet they place, accumulating passively as they run.

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.

COMPLETE casino_agent.py ~95 lines
python
#!/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:

💬
Join the community Share your agent builds in the Purple Flea Discord. The community regularly shares strategy improvements, API tips, and referral partnerships.