DEV Community

PulseScore
PulseScore

Posted on

How to Fetch Live Sports Odds via API with TypeScript (Bet365, Paddy Power & More)

What You'll Need

  • A free PulseScore API key → grab one here (no credit card required)
  • Basic knowledge of HTTP requests
  • Node.js installed with TypeScript (npm install -g typescript ts-node)

Step 1 — Get Your Free API Key

Head to pulsescore.net/dashboard and sign up for free. The Basic plan gives you 500 requests/month at no cost — more than enough to get started.

Once registered, copy your API key from the dashboard.


Step 2 — Define Your Types

One of TypeScript's biggest advantages is type safety. Let's define the response structure first:

interface Price {
  decimal: string;
}

interface MarketOption {
  name: string;
  pa: Price[];
}

interface MarketGroup {
  name: string;
  ma: MarketOption[];
}

interface Match {
  fi: string;
  sport: string;
  league: string;
  home: string;
  away: string;
  live: 0 | 1;
  tab?: string;
  mg: MarketGroup[];
}

interface WebSocketMessage {
  type: 'data';
  timestamp: number;
  events: Match[];
}
Enter fullscreen mode Exit fullscreen mode

Step 3 — Fetch Live Odds (REST API)

All requests use the X-Secret header with your API key:

const API_KEY: string = 'YOUR_API_KEY';
const BASE_URL: string = 'https://api.pulsescore.net/api/v2/bet365';

async function getLiveOdds(sport: string = 'soccer'): Promise<Match[]> {
  const response = await fetch(`${BASE_URL}/live-events?sport=${sport}`, {
    headers: {
      'X-Secret': API_KEY
    }
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  return response.json() as Promise<Match[]>;
}

// Run it
getLiveOdds('soccer')
  .then((matches) => {
    matches.forEach((match) => {
      console.log(`${match.home} vs ${match.away}${match.league}`);
      match.mg.forEach((market) => {
        console.log(`  Market: ${market.name}`);
        market.ma.forEach((option) => {
          console.log(`    ${option.name}: ${option.pa[0].decimal}`);
        });
      });
    });
  })
  .catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Using cURL

curl -X GET "https://api.pulsescore.net/api/v2/bet365/live-events?sport=soccer" \
  -H "X-Secret: YOUR_API_KEY"
Enter fullscreen mode Exit fullscreen mode

Step 4 — Understanding the Response

The API returns clean JSON like this:

[
  {
    "fi": "98734521",
    "sport": "Soccer",
    "league": "Premier League",
    "home": "Liverpool",
    "away": "Man City",
    "live": 1,
    "tab": "Popular",
    "mg": [
      {
        "name": "Fulltime Result",
        "ma": [
          { "name": "Liverpool", "pa": [{ "decimal": "2.10" }] },
          { "name": "Draw",      "pa": [{ "decimal": "3.40" }] },
          { "name": "Man City",  "pa": [{ "decimal": "3.25" }] }
        ]
      },
      {
        "name": "Over/Under 2.5 Goals",
        "ma": [
          { "name": "Over 2.5",  "pa": [{ "decimal": "1.75" }] },
          { "name": "Under 2.5", "pa": [{ "decimal": "2.05" }] }
        ]
      }
    ]
  }
]
Enter fullscreen mode Exit fullscreen mode

Here's what each field means:

Field Description
fi Unique match ID
sport Sport type (Soccer, Tennis, Basketball...)
league League name
home / away Team names
live 1 = live match, 0 = pre-match
tab Market tab (e.g. Popular)
mg Market groups (e.g. Fulltime Result)
ma Market options with odds
pa Price array with decimal odds

Step 5 — Fetch Pre-Match Odds

Want odds for upcoming matches? First fetch the available leagues, then pull events:

// Step 1 — get available leagues
async function getLeagues(sport: string = 'soccer'): Promise<any[]> {
  const path = sport === 'soccer' ? 'leagues' : `${sport}/leagues`;
  const response = await fetch(`${BASE_URL}/${path}`, {
    headers: { 'X-Secret': API_KEY }
  });
  return response.json();
}

// Step 2 — get events for a league
async function getEvents(league: string, sport: string = 'soccer'): Promise<Match[]> {
  const path = sport === 'soccer' ? 'events' : `${sport}/events`;
  const response = await fetch(
    `${BASE_URL}/${path}?league=${encodeURIComponent(league)}`,
    { headers: { 'X-Secret': API_KEY } }
  );
  return response.json() as Promise<Match[]>;
}

// Usage
const leagues = await getLeagues('soccer');
const events = await getEvents('Premier League', 'soccer');
Enter fullscreen mode Exit fullscreen mode

Supported sports: soccer, tennis, basketball, ice-hockey, american-football, horse-racing, volleyball, handball, table-tennis, e-sports, baseball, greyhounds.


Step 6 — Real-Time Odds via WebSocket

For apps that need odds updated every 2 seconds, use the WebSocket connection (available on Pro plan and above). The API key is passed as a query parameter:

import WebSocket from 'ws';

const API_KEY: string = 'YOUR_API_KEY';

const ws = new WebSocket(
  `wss://api.pulsescore.net/api/v2/bet365/ws/live?key=${API_KEY}&sport=soccer`
);

ws.on('open', (): void => {
  console.log('Connected to PulseScore live feed');
});

ws.on('message', (data: WebSocket.Data): void => {
  const msg: WebSocketMessage = JSON.parse(data.toString());
  if (msg.type === 'data') {
    console.log(`Received ${msg.events.length} live events`);
    msg.events.forEach((match) => {
      console.log(`  ${match.home} vs ${match.away}${match.league}`);
    });
  }
});

ws.on('error', (error: Error): void => {
  console.error('WebSocket error:', error.message);
});

ws.on('close', (code: number, reason: Buffer): void => {
  console.log(`Disconnected: ${code} ${reason}`);
});
Enter fullscreen mode Exit fullscreen mode

This is perfect for building live odds dashboards, arbitrage bots, or trading desk tools.


What Can You Build With This?

Here are some ideas developers are already building with PulseScore:

  • Odds comparison tools — compare Bet365 vs Paddy Power side by side
  • Arbitrage betting bots — detect price differences across bookmakers automatically
  • Sports analytics dashboards — visualize odds movement over time
  • Fantasy sports apps — enrich your app with real-time data
  • Trading algorithms — automate decisions based on live odds shifts

Pricing

Plan Price Requests WebSocket
Basic Free 500 req/month None
Starter €20/mo 30,000 req/month None
Pro €79/mo Unlimited 1 connection
Max €149/mo Unlimited 3 connections

Wrap Up

In just a few lines of TypeScript you can pull live odds from the biggest bookmakers in the world. No scraping, no maintenance, no headaches.

Give it a try and drop a comment if you build something cool with it!

Top comments (0)