Skip to main content

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 Parlay Calculator with Real Odds

Most parlay calculators online use manual input — you type in odds by hand. This one pulls real live odds and lets users build parlays by clicking selections.

What You’ll Use

SDK MethodEndpointPurpose
getEvents()GET /v1/eventsList events with main market odds
getEvent()GET /v1/events/{id}Get all markets for an event
checkParlay()POST /v1/bets/check-parlayValidate parlay and get combined odds

The Idea

  1. User browses live/upcoming events
  2. Clicks selections to add to a bet slip
  3. App calculates combined odds in real-time
  4. User enters stake → sees potential payout
  5. Optional: verify with checkParlay() for settlement simulation

Step 1: Fetch Events with Odds

import { FieldFundedSDK } from '@fieldfunded/sdk';

const client = new FieldFundedSDK({
  apiKey: process.env.FIELDFUNDED_API_KEY!,
  baseUrl: 'https://api.fieldfunded.com/v1',
});

// Fetch today's games with main market odds included
async function getTodaysGames(sport: string) {
  const events = await client.getEvents({
    sport,
    status: 'prematch',
    starts_within: '12h',
  });
  return events.events;
}

Step 2: Build the Bet Slip (React)

interface Selection {
  event_id: string;
  home_team: string;
  away_team: string;
  market: string;
  outcome: string;
  odds: number;
  market_id?: number;
  selection_id?: number;
}

const [slip, setSlip] = useState<Selection[]>([]);
const [stake, setStake] = useState<number>(10);

function addToSlip(selection: Selection) {
  // Prevent same event twice
  if (slip.some(s => s.event_id === selection.event_id)) return;
  setSlip([...slip, selection]);
}

function removeFromSlip(eventId: string) {
  setSlip(slip.filter(s => s.event_id !== eventId));
}

// Combined odds = product of all decimal odds
const combinedOdds = slip.reduce((acc, s) => acc * s.odds, 1);
const potentialPayout = stake * combinedOdds;

Step 3: Odds Format Switcher

FieldFunded supports decimal, american, and fractional via the odds_format parameter:
// Fetch with specific format
const events = await client.getEvents({
  sport: 'soccer',
  odds_format: 'american', // or 'decimal' or 'fractional'
});

// Or convert client-side
function decimalToAmerican(decimal: number): string {
  if (decimal >= 2.0) return `+${Math.round((decimal - 1) * 100)}`;
  return `-${Math.round(100 / (decimal - 1))}`;
}

function decimalToFractional(decimal: number): string {
  const fraction = decimal - 1;
  // Simple approximation
  const denominator = 100;
  const numerator = Math.round(fraction * denominator);
  const gcd = (a: number, b: number): number => b ? gcd(b, a % b) : a;
  const d = gcd(numerator, denominator);
  return `${numerator / d}/${denominator / d}`;
}

Step 4: Validate with the API

Use checkParlay() to verify the parlay is valid and get the official combined odds:
async function validateParlay() {
  const result = await client.checkParlay({
    legs: slip.map(s => ({
      event_id: s.event_id,
      market: s.market,
      outcome: s.outcome,
      odds: s.odds,
      market_id: s.market_id,
      selection_id: s.selection_id,
    })),
    stake,
  });

  console.log(`Status: ${result.payout.status}`);
  console.log(`Combined odds: ${result.payout.combined_odds}`);
  console.log(`Potential payout: $${result.payout.payout}`);

  // If any leg is voided, the API recalculates automatically
  return result;
}

Step 5: Display the Slip

<div className="bet-slip">
  <h3>Bet Slip ({slip.length} selections)</h3>

  {slip.map(s => (
    <div key={s.event_id} className="slip-item">
      <span>{s.home_team} vs {s.away_team}</span>
      <span>{s.market}: {s.outcome} @ {s.odds.toFixed(2)}</span>
      <button onClick={() => removeFromSlip(s.event_id)}>×</button>
    </div>
  ))}

  <div className="slip-summary">
    <div>Combined Odds: {combinedOdds.toFixed(2)}</div>
    <input
      type="number"
      value={stake}
      onChange={e => setStake(Number(e.target.value))}
      placeholder="Stake"
    />
    <div className="payout">
      Potential Payout: <strong>${potentialPayout.toFixed(2)}</strong>
    </div>
  </div>
</div>

Rate Limit Math

  • Browsing events: 1 request per sport/filter
  • Loading event detail: 1 request per event clicked
  • Validating parlay: 1 request per validation
  • Typical session: 5-10 requests
  • Free tier (10K/month) supports ~1,000 user sessions

Check Parlay Reference

See parlay endpoint docs →

Events Reference

See event filters and odds_format →

Get Your Free API Key

Start building in 5 minutes — 10,000 free requests/month