Documentation Index Fetch the complete documentation index at: https://docs.fieldfunded.com/llms.txt
Use this file to discover all available pages before exploring further.
Build a Sports Betting Bot with Node.js
Build a Node.js bot that monitors live odds across 30+ sports, detects value opportunities based on your criteria, and automatically settles bets after matches end. This is a complete tutorial with working code you can run today.
What the Bot Does
Prerequisites
Step 1: API Client
// bot/api.js
const BASE_URL = "https://api.fieldfunded.com/v1" ;
const API_KEY = process . env . FIELDFUNDED_API_KEY ;
async function apiGet ( path , params = {}) {
const url = new URL ( ` ${ BASE_URL }${ path } ` );
Object . entries ( params ). forEach (([ k , v ]) => url . searchParams . set ( k , v ));
const res = await fetch ( url , {
headers: { "X-API-Key" : API_KEY },
});
if ( ! res . ok ) {
if ( res . status === 429 ) {
const retry = res . headers . get ( "Retry-After" ) || 1 ;
console . log ( `Rate limited. Retrying in ${ retry } s...` );
await new Promise (( r ) => setTimeout ( r , retry * 1000 ));
return apiGet ( path , params );
}
throw new Error ( `API ${ res . status } : ${ await res . text () } ` );
}
return res . json ();
}
async function apiPost ( path , body ) {
const res = await fetch ( ` ${ BASE_URL }${ path } ` , {
method: "POST" ,
headers: {
"X-API-Key" : API_KEY ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ( body ),
});
if ( ! res . ok ) throw new Error ( `API ${ res . status } : ${ await res . text () } ` );
return res . json ();
}
module . exports = { apiGet , apiPost };
Step 2: Odds Monitor
Track odds movements and detect significant changes:
// bot/monitor.js
const { apiGet } = require ( "./api" );
const oddsHistory = new Map (); // key -> [{ odds, timestamp }]
async function scanEvents ( sport = "soccer" ) {
const data = await apiGet ( "/events" , { sport });
const alerts = [];
for ( const event of data . events . slice ( 0 , 10 )) {
const odds = await apiGet ( `/events/ ${ event . id } /odds` );
for ( const market of odds . markets ) {
if ( ! market . name . toLowerCase (). includes ( "winner" )) continue ;
for ( const sel of market . selections ) {
const key = ` ${ event . id } _ ${ market . id } _ ${ sel . id } ` ;
const history = oddsHistory . get ( key ) || [];
const current = sel . odds ;
// Record history
history . push ({ odds: current , timestamp: Date . now () });
if ( history . length > 100 ) history . shift (); // Keep last 100
oddsHistory . set ( key , history );
// Detect drift
if ( history . length >= 2 ) {
const previous = history [ history . length - 2 ]. odds ;
const change = (( current - previous ) / previous ) * 100 ;
if ( Math . abs ( change ) >= 5 ) {
alerts . push ({
event: ` ${ event . home_team } vs ${ event . away_team } ` ,
market: market . name ,
selection: sel . name ,
previous ,
current ,
change: change . toFixed ( 1 ),
direction: change > 0 ? "DRIFTED" : "SHORTENED" ,
});
}
}
}
}
// Brief pause between events to respect rate limits
await new Promise (( r ) => setTimeout ( r , 200 ));
}
return alerts ;
}
module . exports = { scanEvents };
Step 3: Settlement Checker
After matches end, check if bets won:
// bot/settler.js
const { apiPost } = require ( "./api" );
// In-memory bet tracker (use a database in production)
const activeBets = [];
function placeBet ( bet ) {
activeBets . push ({
... bet ,
status: "pending" ,
placedAt: new Date (). toISOString (),
});
console . log (
`[BET] ${ bet . selection } @ ${ bet . odds } — $ ${ bet . stake } on ${ bet . event } `
);
}
async function settleBets () {
const pending = activeBets . filter (( b ) => b . status === "pending" );
if ( pending . length === 0 ) return ;
console . log ( ` \n [SETTLE] Checking ${ pending . length } pending bets...` );
for ( const bet of pending ) {
try {
const result = await apiPost ( "/bets/check" , {
event_id: bet . eventId ,
market: bet . market ,
selection: bet . selection ,
stake: bet . stake ,
odds: bet . odds ,
market_id: bet . marketId ,
selection_id: bet . selectionId ,
});
if ( result . status !== "pending" ) {
bet . status = result . status ;
bet . payout = result . payout || 0 ;
const emoji = result . status === "won" ? "✅" : "❌" ;
console . log (
` ${ emoji } ${ bet . selection } : ${ result . status } — ` +
`Payout: $ ${ bet . payout } `
);
}
} catch ( err ) {
// Event not finished yet — try again later
}
}
}
module . exports = { placeBet , settleBets , activeBets };
Step 4: Main Loop
// bot/index.js
const { scanEvents } = require ( "./monitor" );
const { settleBets } = require ( "./settler" );
const POLL_INTERVAL = 30_000 ; // 30 seconds
const SPORTS = [ "soccer" , "basketball" , "tennis" ];
async function run () {
console . log ( "=== Sports Odds Bot Started === \n " );
setInterval ( async () => {
for ( const sport of SPORTS ) {
try {
const alerts = await scanEvents ( sport );
for ( const alert of alerts ) {
console . log (
`[ ${ alert . direction } ] ${ alert . event } — ` +
` ${ alert . selection } : ${ alert . previous } → ${ alert . current } ` +
`( ${ alert . change } %)`
);
}
} catch ( err ) {
console . error ( `Error scanning ${ sport } :` , err . message );
}
}
}, POLL_INTERVAL );
// Check settlements every 5 minutes
setInterval ( async () => {
try {
await settleBets ();
} catch ( err ) {
console . error ( "Settlement error:" , err . message );
}
}, 300_000 );
}
run ();
Step 5: Run It
export FIELDFUNDED_API_KEY = "your_key_here"
node bot/index.js
Output:
=== Sports Odds Bot Started ===
[DRIFTED] Arsenal vs Chelsea — Arsenal: 1.85 → 2.00 (+8.1%)
[SHORTENED] Lakers vs Celtics — Celtics: 1.95 → 1.80 (-7.7%)
✅ Liverpool: won — Payout: $105.00
Rate Limit Math
Configuration Requests/cycle Cycles/day Daily total Monthly Plan 3 sports × 10 events, 30s poll 33 2,880 95,040 2,851,200 Ultra ($99.99) 1 sport × 5 events, 60s poll 6 1,440 8,640 259,200 Starter ($29) 1 sport × 3 events, 5-min poll 4 288 1,152 34,560 Free
For a hobby bot monitoring a few matches, the free tier is enough. Scale up to Starter or Pro when you need more sports or faster polling.
Production Improvements
Before running this bot 24/7, consider:
Get Your Free API Key Start building in 5 minutes — 10,000 free requests/month
See Pricing All plans compared side by side