Introduction

This guide will walk you through everything you need to know to start working with sports odds APIs, from choosing a provider to making your first API request and handling the data.

What You'll Learn

Step 1: Choose Your Odds API

Start by selecting an API that fits your project requirements:

For Learning & Prototypes

Look for providers offering:

See all free odds APIs →

For Production Applications

Evaluate based on:

Find the Right API for Your Project

Compare features, pricing, and free tiers across all providers.

Browse API Directory →

Step 2: Sign Up and Get Your API Key

Registration Process

  1. Visit your chosen provider's website
  2. Create an account (usually requires email verification)
  3. Navigate to API settings or dashboard
  4. Generate your API key

API Key Security Best Practices

  • Never commit API keys to Git: Use environment variables
  • Rotate keys periodically: Generate new keys every 3-6 months
  • Use separate keys for dev/production: Easier to debug and secure
  • Store securely: Use .env files (add to .gitignore)

Example .env file:

ODDS_API_KEY=your_api_key_here
ODDS_API_URL=https://api.your-provider.com/v1

Step 3: Make Your First API Request

Most odds APIs follow a similar pattern for fetching data. Here's the general approach:

General Request Pattern

1. Build Your Request URL

Typical odds API endpoints follow this structure:

GET /sports/{sport}/odds
    ?apiKey={your_api_key}
    ®ions={us,uk,eu}
    &markets={h2h,spreads,totals}

2. Common Parameters

  • sport: Sport identifier (e.g., americanfootball_nfl, basketball_nba)
  • regions: Which sportsbook regions to include (us, uk, eu, au)
  • markets: Bet types to return (h2h = moneyline, spreads, totals)
  • bookmakers: Filter to specific sportsbooks (optional)

3. Handle the Response

  • Check HTTP status code (200 = success, 429 = rate limited)
  • Parse JSON response containing games and odds
  • Check response headers for remaining API requests
  • Handle errors gracefully with try/catch

Tip: Check your chosen provider's documentation for exact endpoint URLs, parameter names, and authentication methods. Each provider has slightly different conventions.

Find Documentation

Browse providers and access their official documentation and code examples.

Browse API Directory →

Step 4: Understanding the Response Data

Typical Odds API Response Structure

{
  "id": "abc123",
  "sport_key": "americanfootball_nfl",
  "sport_title": "NFL",
  "commence_time": "2025-02-04T23:30:00Z",
  "home_team": "Kansas City Chiefs",
  "away_team": "San Francisco 49ers",
  "bookmakers": [
    {
      "key": "draftkings",
      "title": "DraftKings",
      "markets": [
        {
          "key": "h2h",
          "outcomes": [
            {
              "name": "Kansas City Chiefs",
              "price": -120
            },
            {
              "name": "San Francisco 49ers",
              "price": +100
            }
          ]
        },
        {
          "key": "spreads",
          "outcomes": [
            {
              "name": "Kansas City Chiefs",
              "price": -110,
              "point": -1.5
            },
            {
              "name": "San Francisco 49ers",
              "price": -110,
              "point": 1.5
            }
          ]
        }
      ]
    }
  ]
}

Key Fields Explained

Step 5: Handle Rate Limits

All APIs have rate limits to prevent abuse. Here's how to work within them:

Common Rate Limit Strategies

1. Implement Caching

Don't fetch the same data repeatedly. Cache responses for 1-5 minutes:

const cache = new Map();
const CACHE_DURATION = 60000; // 1 minute

async function getCachedOdds(sport) {
  const cacheKey = `odds_${sport}`;
  const cached = cache.get(cacheKey);

  if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
    return cached.data;
  }

  const freshData = await fetchOdds(sport);
  cache.set(cacheKey, {
    data: freshData,
    timestamp: Date.now()
  });

  return freshData;
}

2. Monitor Your Usage

Check response headers for remaining requests:

const remaining = response.headers.get('x-requests-remaining');
const used = response.headers.get('x-requests-used');

if (remaining < 10) {
  console.warn('Low on API requests!');
}

3. Implement Exponential Backoff

If you hit rate limits, wait before retrying:

async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url);
      if (response.status === 429) {
        // Rate limited, wait and retry
        const waitTime = Math.pow(2, i) * 1000;
        await new Promise(resolve => setTimeout(resolve, waitTime));
        continue;
      }
      return response;
    } catch (error) {
      if (i === retries - 1) throw error;
    }
  }
}

Step 6: Best Practices for Production

Error Handling

Always handle network errors, invalid responses, and API downtime gracefully. Show users friendly error messages.

Data Validation

Validate API responses before using them. Check for null values, unexpected formats, and missing fields.

Logging & Monitoring

Log all API requests/responses. Monitor error rates and response times to catch issues early.

Fallback Strategies

Have a plan for when the API is down: show cached data, display a message, or use a backup provider.

Optimize Requests

Request only the data you need. Use query parameters to filter sports, markets, and regions.

Security

Never expose API keys in client-side code. Make API calls from your backend server.

Common Pitfalls to Avoid

❌ Exposing API Keys in Frontend Code

Problem: Including your API key in JavaScript that runs in the browser exposes it to anyone who views your source code.

Solution: Always make API calls from your backend server. Use a simple proxy endpoint that your frontend can call.

❌ Not Handling Timezones Properly

Problem: Game times are returned in UTC, but your users expect local time.

Solution: Convert UTC timestamps to user's local timezone using JavaScript Date methods or libraries like date-fns.

❌ Polling Too Frequently

Problem: Fetching odds every few seconds wastes API requests. Pregame odds don't change that often.

Solution: Update pregame odds every 5-30 minutes. Only poll frequently for live odds during games.

❌ Not Checking Stale Data

Problem: Displaying odds from games that already started or finished.

Solution: Filter out games where commence_time has passed before displaying.

Next Steps

Now that you understand the basics, here are some ideas for what to build:

Start with a free API →

Need Help Getting Started?

Join our Discord community of 500+ developers. Get your questions answered, share code, and learn from others building sports apps.