Complete Betting Flow
End-to-end walkthrough from discovering markets to tracking your portfolio
Overview
This guide walks through the full lifecycle of a bet:
- Discover an event and its markets
- Check the orderbook before placing
- Place a market order (FOK)
- Monitor order status via WebSocket
- Track your position in the portfolio
- Sell (partial or full) before settlement
1. Discover Events and Markets
import requests, time, hmac, hashlib, uuid, json
BASE_URL = "https://api.winnova.pro/api/ext/v1"
API_KEY = "your_api_key"
API_SECRET = "your_api_secret"
def sign(method, path, body=""):
ts = str(int(time.time() * 1000)) # milliseconds
nonce = uuid.uuid4().hex
body_hash = hashlib.sha256(body.encode()).hexdigest()
msg = f"{method}\n{path}\n{ts}\n{nonce}\n{body_hash}"
sig = hmac.new(API_SECRET.encode(), msg.encode(), hashlib.sha256).hexdigest()
return {"X-API-KEY": API_KEY, "X-API-TIMESTAMP": ts,
"X-API-NONCE": nonce, "X-API-SIGNATURE": sig}
def get(path, params=None):
return requests.get(f"{BASE_URL}{path}", params=params, headers=sign("GET", path)).json()
def post(path, body):
raw = json.dumps(body)
hdrs = {**sign("POST", path, raw), "Content-Type": "application/json"}
return requests.post(f"{BASE_URL}{path}", data=raw, headers=hdrs).json()
# Find an active NBA event
events = get("/events", {"status": "active", "sport": "basketball", "limit": 10})
event = events["data"][0]
print(f"Event: {event['title']} — starts {event['game_start_time']}")
# Get its markets
markets = get(f"/events/{event['id']}/markets")
moneyline = next(m for m in markets["data"] if m["type"] == "moneyline")
print(f"Market: {moneyline['question']}")
for o in moneyline["outcomes"]:
print(f" {o['name']}: {o['price']:.2f}")2. Check the Orderbook
Before placing an order, inspect depth to estimate slippage on larger sizes.
# Use the token_id from the desired outcome (e.g. the "yes" token_id)
token_id = moneyline["outcomes"][0]["token_id"]
ob = get(f"/orderbooks/{token_id}")
print("Asks (you buy at these prices):")
for level in ob["data"]["asks"][:5]:
print(f" price={level['price']} size={level['size']}")Sample response:
{
"success": true,
"data": {
"asset_id": "0xabc...",
"bids": [
{ "price": "0.54", "size": "300.00" },
{ "price": "0.53", "size": "500.00" }
],
"asks": [
{ "price": "0.55", "size": "200.00" },
{ "price": "0.56", "size": "150.00" }
],
"timestamp": "2026-04-05T00:00:00Z"
}
}3. Place a Market Order (FOK)
FOK orders fill immediately at the best available price or cancel entirely — no partial fills are left as open orders.
# Buy $100 on outcome "a" (first outcome = index a)
order = post("/orders", {
"market_id": market_id,
"outcome": "a",
"amount": 100
})
order_id = order["data"]["order_id"]
print(f"Order placed: {order_id}")const order = await makeRequest('POST', '/api/ext/v1/orders', {
market_id: '550e8400-e29b-41d4-a716-446655440000',
outcome: 'a', // 'a' = first outcome, 'b' = second outcome
amount: 100
});
const orderId = order.data.order_id;4. Monitor Order Status (WebSocket)
Subscribe to real-time order updates rather than polling.
// After connecting (see WebSocket Connection guide)
ws.send(JSON.stringify({ action: 'subscribe', topics: [`user:${userId}:orders`] }));
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'data' && msg.data.order_id === orderId) {
console.log('Status:', msg.data.status);
// "pending" -> "signing" -> "submitted" -> "matched"
if (msg.data.status === 'matched') {
console.log('Filled at avg price:', msg.data.avg_fill_price);
console.log('Shares received:', msg.data.size_matched / msg.data.avg_fill_price);
}
}
};Or poll via REST if WebSocket is unavailable:
import time
def wait_for_order(order_id, timeout=60):
for _ in range(timeout):
result = get(f"/orders/{order_id}")
status = result["data"]["status"]
print(f" status: {status}")
if status in ("matched", "won", "lost"):
return result["data"]
time.sleep(1)
raise TimeoutError("Order did not settle in time")
order_data = wait_for_order(order_id)
print(f"Filled: {order_data['size_matched']} shares at {order_data['avg_fill_price']}")5. Track Your Portfolio
Once the order is matched, a position appears in your portfolio.
portfolio = get("/portfolio/positions")
for pos in portfolio["data"]:
if pos["market_id"] == market_id:
print(f"Position: {pos['shares']:.4f} YES shares")
print(f" Avg cost: {pos['avg_cost']:.4f}")
print(f" Current price: {pos['current_price']:.4f}")
print(f" Unrealized PnL: ${pos['unrealized_pnl']:.2f}")Sample response:
{
"success": true,
"data": [
{
"id": "f1e2d3c4-b5a6-7890-abcd-012345678901",
"market_id": "550e8400-e29b-41d4-a716-446655440000",
"token_option": "yes",
"shares": 181.82,
"avg_cost": 0.55,
"current_price": 0.62,
"unrealized_pnl": 12.73,
"status": "open"
}
]
}Subscribe to live balance updates (triggered after position changes):
ws.send(JSON.stringify({ action: 'subscribe', topics: [`user:${userId}:balance`] }));
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'data' && msg.topic === `user:${userId}:balance`) {
console.log('Balance updated:', msg.data.balance);
}
};6. Sell Your Position
Sell some or all shares before the market settles.
# Sell 50 shares
sell_order = post("/orders", {
"market_id": market_id,
"outcome": "a",
"side": "SELL",
"shares": 50
})
print("Sell order:", sell_order["data"]["order_id"])// Sell all shares
await makeRequest('POST', '/api/ext/v1/orders', {
market_id: '550e8400-e29b-41d4-a716-446655440000',
outcome: 'a',
side: 'SELL',
shares: 181.82
});Settlement
When the event concludes, WinNova automatically settles all positions:
- Won positions: shares are redeemed at $1.00 each
- Lost positions: shares expire at $0.00
You can track settlement via the user:{userID}:orders WebSocket topic — order status will transition to won or lost.
Full Python Script
"""
Full betting flow: discover -> check -> bet -> wait -> portfolio
"""
# (paste the sign/get/post helpers from Step 1 here)
# 1. Pick event
events = get("/events", {"status": "active", "sport": "basketball"})
event = events["data"][0]
# 2. Pick market
markets = get(f"/events/{event['id']}/markets")
market = next(m for m in markets["data"] if m["type"] == "moneyline")
market_id = market["id"]
# 3. Check book (use token_id of the outcome you want to trade)
token_id = market["outcomes"][0]["token_id"]
ob = get(f"/orderbooks/{token_id}")
best_ask = ob["data"]["asks"][0]["price"]
print(f"Best ask: {best_ask}")
# 4. Place FOK
order = post("/orders", {"market_id": market_id, "outcome": "a", "amount": 50})
order_id = order["data"]["order_id"]
# 5. Wait for fill
filled = wait_for_order(order_id)
print(f"Filled {filled['size_matched']} shares at {filled['avg_fill_price']}")
# 6. Check portfolio
portfolio = get("/portfolio/positions")
pos = next((p for p in portfolio["data"] if p["market_id"] == market_id), None)
if pos:
print(f"Position: {pos['shares']:.4f} shares, PnL: ${pos['unrealized_pnl']:.2f}")Next Steps
- Limit Orders — enter at a specific price with GTC/GTD orders
- WebSocket Topics — full topic reference