> ## 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 Live Odds

> Build a parlay calculator with real live odds from 30+ sports. Combined odds, potential payout, odds format switcher. React + FieldFunded SDK.

# 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 Method      | Endpoint                     | Purpose                               |
| --------------- | ---------------------------- | ------------------------------------- |
| `getEvents()`   | `GET /v1/events`             | List events with main market odds     |
| `getEvent()`    | `GET /v1/events/{id}`        | Get all markets for an event          |
| `checkParlay()` | `POST /v1/bets/check-parlay` | Validate 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

```typescript theme={null}
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)

```tsx theme={null}
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:

```typescript theme={null}
// 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:

```typescript theme={null}
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

```tsx theme={null}
<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**

<CardGroup cols={2}>
  <Card title="Check Parlay Reference" icon="layer-group" href="/api-reference/settlement/check-parlay">
    See parlay endpoint docs →
  </Card>

  <Card title="Events Reference" icon="calendar" href="/api-reference/events/get-events">
    See event filters and odds\_format →
  </Card>
</CardGroup>

***

## Related Guides

* [Build a Settlement Engine](/guides/build-settlement-engine) — resolve parlays automatically
* [Build a Betting Platform](/guides/build-betting-platform) — full-stack architecture
* [For Startups](/compare/for-startups) — ship your MVP this week

<Card title="Get Your Free API Key" icon="key" href="/quickstart">
  Start building in 5 minutes — 10,000 free requests/month
</Card>
