Skip to content
PA
PuckAPI

Documentation

Everything you need to connect and query 12 NHL data endpoints.

Getting Started

Authentication

Every request requires an API key. Pass it via header:

bash
x-api-key: YOUR_API_KEY
# or
Authorization: Bearer YOUR_API_KEY

Get your API key from the dashboard after signing up. Free accounts get 500 credits.

Base URL

text
https://mcp.puckapi.com/mcp

MCP protocol over Streamable HTTP. Works with Claude Desktop, Claude Code, Cursor, and any MCP-compatible client. Also accepts standard JSON-RPC POST requests.

Rate Limits

PlanRate Limit
Free10 req/min
Starter / Pro / Scale60 req/min
EnterpriseCustom

Error Handling

CodeMeaningWhat to do
401Invalid or missing API keyCheck your x-api-key header
402Insufficient creditsTop up your wallet or upgrade your plan
429Rate limit exceededWait and retry (see limits above)
500Server errorRetry with idempotency key. Credits auto-refund on server errors.

Pass x-idempotency-key or x-request-id headers to make retries duplicate-safe.

Setup

Claude Desktop

Add to your claude_desktop_config.json:

json
{
  "mcpServers": {
    "puckapi": {
      "url": "https://mcp.puckapi.com/mcp",
      "headers": {
        "x-api-key": "YOUR_API_KEY"
      }
    }
  }
}

Claude Code

One command:

bash
claude mcp add puckapi https://mcp.puckapi.com/mcp --header "x-api-key: YOUR_API_KEY"

REST / cURL

Send JSON-RPC POST requests directly. No MCP client needed:

bash
curl -X POST https://mcp.puckapi.com/mcp \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "list_teams",
      "arguments": {}
    },
    "id": 1
  }'

Which Endpoint Should I Use?

Start from what you want to do, not the API path.

Endpoint Reference

12 endpoints grouped by credit cost. Each includes parameters, example requests in three formats, and documented response fields.

Static reference

1 credit/call
POST

list_teams

1 credit

All 32 active NHL teams with divisions, conferences, and arenas.

When to use: You need a reference list of teams -- team abbreviations for other endpoints, arena names for travel planning, or division/conference groupings for analysis.

Parameters
NameTypeRequiredDescription
conferencestringoptional"Eastern" or "Western"
divisionstringoptionalDivision name (e.g. "Atlantic")
Example Request
{
  "tool": "list_teams",
  "arguments": {
    "conference": "Eastern",
    "division": "Atlantic"
  }
}
Example Response
json
{
  "teams": [
    {
      "abbrev": "BUF",
      "name": "Sabres",
      "city": "Buffalo",
      "conference": "Eastern",
      "division": "Atlantic",
      "arena": "KeyBank Center"
    },
    {
      "abbrev": "TOR",
      "name": "Maple Leafs",
      "city": "Toronto",
      "conference": "Eastern",
      "division": "Atlantic",
      "arena": "Scotiabank Arena"
    },
    {
      "abbrev": "FLA",
      "name": "Panthers",
      "city": "Florida",
      "conference": "Eastern",
      "division": "Atlantic",
      "arena": "Amerant Bank Arena"
    }
  ]
}
Response Fields
FieldTypeDescription
teams[].abbrevstring3-letter team code (e.g. "BUF")
teams[].namestringTeam name (e.g. "Sabres")
teams[].citystringCity name
teams[].conferencestringEastern or Western
teams[].divisionstringDivision name
teams[].arenastringHome arena name

Basic lookup

2 credits/call
POST

get_schedule

2 credits

Upcoming games for the next N days. Defaults to 7 days.

When to use: You want to know what games are coming up this week -- for a specific team or across the league. Useful for building game-day alerts or planning which games to watch.

Parameters
NameTypeRequiredDescription
teamstringoptionalTeam abbreviation (e.g. "BUF")
daysintegeroptionalDays ahead (1-30, default 7)
Example Request
{
  "tool": "get_schedule",
  "arguments": {
    "team": "BUF",
    "days": 7
  }
}
Example Response
json
{
  "games": [
    {
      "id": "2025021143",
      "gameDate": "2026-04-10",
      "startTime": "19:00:00",
      "homeTeam": "BUF",
      "awayTeam": "TOR",
      "homeTeamName": "Buffalo Sabres",
      "awayTeamName": "Toronto Maple Leafs",
      "venue": "KeyBank Center",
      "gameType": "regular"
    },
    {
      "id": "2025021187",
      "gameDate": "2026-04-12",
      "startTime": "19:30:00",
      "homeTeam": "FLA",
      "awayTeam": "BUF",
      "homeTeamName": "Florida Panthers",
      "awayTeamName": "Buffalo Sabres",
      "venue": "Amerant Bank Arena",
      "gameType": "regular"
    }
  ]
}
Response Fields
FieldTypeDescription
games[].idstringUnique game ID
games[].gameDatestringDate (YYYY-MM-DD)
games[].startTimestringStart time (HH:MM:SS)
games[].homeTeamstringHome team abbreviation
games[].awayTeamstringAway team abbreviation
games[].venuestringArena name
games[].gameTypestringregular, playoff, or preseason
POST

search_players

2 credits

Find players by name, team, or position.

When to use: You need a player's ID to look up their stats, or you want to search a roster by position. For example, "find all active centers on the Sabres" or "look up Tage Thompson's player ID."

Parameters
NameTypeRequiredDescription
querystringrequiredSearch string (e.g. "Tage Thompson")
teamstringoptionalFilter by team abbreviation
positionstringoptionalG, D, C, LW, or RW
activebooleanoptionalActive players only (default true)
limitintegeroptionalMax results (1-50, default 10)
Example Request
{
  "tool": "search_players",
  "arguments": {
    "query": "Thompson",
    "team": "BUF"
  }
}
Example Response
json
{
  "players": [
    {
      "id": 8480208,
      "name": "Tage Thompson",
      "team": "BUF",
      "teamName": "Buffalo Sabres",
      "position": "C",
      "jerseyNumber": 72,
      "active": true
    }
  ]
}
Response Fields
FieldTypeDescription
players[].idintegerPlayer ID (use in get_player_stats)
players[].namestringFull name
players[].teamstringTeam abbreviation
players[].positionstringPosition code
players[].jerseyNumberintegerJersey number
players[].activebooleanCurrently active
POST

get_standings

2 credits

Current standings with advanced stats (Corsi%, Fenwick%, point pace).

When to use: You want to see how teams rank in the league right now -- points, win percentage, goal differential, and advanced possession stats like Corsi and Fenwick.

Parameters
NameTypeRequiredDescription
conferencestringoptional"Eastern" or "Western"
divisionstringoptionalDivision name (e.g. "Atlantic")
seasonstringoptionalSeason (e.g. "20252026", default current)
Example Request
{
  "tool": "get_standings",
  "arguments": {
    "conference": "Eastern",
    "division": "Atlantic"
  }
}
Example Response
json
{
  "standings": [
    {
      "rank": 1,
      "team": "FLA",
      "teamName": "Florida Panthers",
      "points": 112,
      "wins": 52,
      "losses": 20,
      "otLosses": 8,
      "pointPct": 0.683,
      "goalDiff": 48,
      "corsiPct": 53.2,
      "fenwickPct": 52.8
    },
    {
      "rank": 2,
      "team": "TOR",
      "teamName": "Toronto Maple Leafs",
      "points": 106,
      "wins": 49,
      "losses": 23,
      "otLosses": 8,
      "pointPct": 0.65,
      "goalDiff": 31,
      "corsiPct": 51.4,
      "fenwickPct": 51.1
    },
    {
      "rank": 3,
      "team": "BUF",
      "teamName": "Buffalo Sabres",
      "points": 98,
      "wins": 44,
      "losses": 28,
      "otLosses": 10,
      "pointPct": 0.598,
      "goalDiff": 12,
      "corsiPct": 50.1,
      "fenwickPct": 49.8
    }
  ]
}
Response Fields
FieldTypeDescription
standings[].rankintegerLeague or division rank
standings[].teamstringTeam abbreviation
standings[].pointsintegerTotal points
standings[].winsintegerWins
standings[].lossesintegerLosses
standings[].otLossesintegerOvertime losses
standings[].goalDiffintegerGoal differential
standings[].corsiPctnumberCorsi percentage (5v5 shot attempts)
standings[].fenwickPctnumberFenwick percentage (unblocked shots)

Stats + aggregation

5 credits/call
POST

get_games

5 credits

Query games by date range, team, season, game state, or type.

When to use: You're building a dataset for analysis -- pull all games from a date range, all playoff games for a team, or all final scores from last season. This is the workhorse endpoint for model training data.

Parameters
NameTypeRequiredDescription
date_fromstringoptionalStart date (YYYY-MM-DD)
date_tostringoptionalEnd date (YYYY-MM-DD)
teamstringoptionalTeam abbreviation
seasonstringoptionalSeason (e.g. "20252026")
game_statestringoptionalFUT, LIVE, FINAL, or OFF
game_typestringoptionalregular, playoff, or preseason
limitintegeroptionalMax results (1-500, default 100)
Example Request
{
  "tool": "get_games",
  "arguments": {
    "team": "TOR",
    "date_from": "2026-03-01",
    "date_to": "2026-03-07",
    "game_state": "FINAL"
  }
}
Example Response
json
{
  "games": [
    {
      "id": "2025020934",
      "season": "20252026",
      "gameDate": "2026-03-02",
      "startTime": "19:00:00",
      "homeTeam": "TOR",
      "awayTeam": "BOS",
      "homeScore": 4,
      "awayScore": 2,
      "gameState": "FINAL",
      "gameType": "regular",
      "venue": "Scotiabank Arena"
    },
    {
      "id": "2025020958",
      "season": "20252026",
      "gameDate": "2026-03-05",
      "startTime": "19:30:00",
      "homeTeam": "MTL",
      "awayTeam": "TOR",
      "homeScore": 1,
      "awayScore": 3,
      "gameState": "FINAL",
      "gameType": "regular",
      "venue": "Bell Centre"
    }
  ]
}
Response Fields
FieldTypeDescription
games[].idstringUnique game ID
games[].seasonstringSeason code (e.g. "20252026")
games[].gameDatestringDate (YYYY-MM-DD)
games[].homeTeamstringHome team abbreviation
games[].awayTeamstringAway team abbreviation
games[].homeScoreintegerHome team score (FINAL only)
games[].awayScoreintegerAway team score (FINAL only)
games[].gameStatestringFUT, LIVE, FINAL, or OFF
games[].venuestringArena name
POST

get_team_stats

5 credits

Detailed stats for a specific team including advanced metrics and league rankings.

When to use: You want a complete statistical profile of a team -- goals, power play, penalty kill, Corsi, Fenwick, expected goals, plus where they rank in the league on each metric.

Parameters
NameTypeRequiredDescription
teamstringrequiredTeam abbreviation (e.g. "BUF")
seasonstringoptionalSeason (e.g. "20252026")
Example Request
{
  "tool": "get_team_stats",
  "arguments": {
    "team": "BUF",
    "season": "20252026"
  }
}
Example Response
json
{
  "team": {
    "abbrev": "BUF",
    "name": "Sabres",
    "city": "Buffalo",
    "conference": "Eastern",
    "division": "Atlantic"
  },
  "current_stats": {
    "gamesPlayed": 82,
    "wins": 44,
    "losses": 28,
    "otLosses": 10,
    "points": 98,
    "goalsFor": 268,
    "goalsAgainst": 256,
    "powerPlayPct": 22.4,
    "penaltyKillPct": 79.8,
    "corsiPct": 50.1,
    "fenwickPct": 49.8,
    "xGoalsFor": 261.3,
    "xGoalsAgainst": 258.7
  },
  "rankings": {
    "overall": 14,
    "powerPlay": 10,
    "penaltyKill": 20,
    "goalsFor": 12,
    "goalsAgainst": 18
  }
}
Response Fields
FieldTypeDescription
team.abbrevstringTeam abbreviation
current_stats.gamesPlayedintegerGames played
current_stats.winsintegerWins
current_stats.pointsintegerTotal points
current_stats.powerPlayPctnumberPower play percentage
current_stats.penaltyKillPctnumberPenalty kill percentage
current_stats.corsiPctnumberCorsi percentage
current_stats.xGoalsFornumberExpected goals for
rankings.overallintegerLeague rank
rankings.powerPlayintegerPP rank
POST

get_player_stats

5 credits

Full season stats for a skater including bio information.

When to use: You have a player ID (from search_players) and want their full stat line -- goals, assists, points, shooting percentage, ice time, power play production, and biographical info.

Parameters
NameTypeRequiredDescription
player_idintegerrequiredPlayer ID (from search_players)
Example Request
{
  "tool": "get_player_stats",
  "arguments": {
    "player_id": 8480208
  }
}
Example Response
json
{
  "player": {
    "id": 8480208,
    "name": "Tage Thompson",
    "team": "BUF",
    "teamName": "Buffalo Sabres",
    "position": "C",
    "jerseyNumber": 72,
    "birthDate": "1997-10-30",
    "birthCity": "Phoenix",
    "birthCountry": "USA",
    "height": "6'7\"",
    "weight": 225
  },
  "stats": {
    "season": "20252026",
    "gamesPlayed": 78,
    "goals": 41,
    "assists": 37,
    "points": 78,
    "plusMinus": 12,
    "pim": 28,
    "shots": 298,
    "shootingPct": 13.8,
    "timeOnIce": "20:14",
    "powerPlayGoals": 14,
    "shortHandedGoals": 1,
    "gameWinningGoals": 8,
    "faceoffPct": 51.2
  }
}
Response Fields
FieldTypeDescription
player.idintegerPlayer ID
player.namestringFull name
player.positionstringPosition
player.heightstringHeight
player.weightintegerWeight (lbs)
stats.gamesPlayedintegerGames played
stats.goalsintegerGoals
stats.assistsintegerAssists
stats.pointsintegerPoints
stats.shootingPctnumberShooting percentage
stats.timeOnIcestringAverage TOI (MM:SS)
POST

get_goalie_stats

5 credits

Goalie leaderboard sorted by save%, GAA, GSAX, or wins.

When to use: You want to rank goalies across the league or within a team. GSAX (goals saved above expected) is the advanced metric that tells you who's actually good versus who plays behind a strong defense.

Parameters
NameTypeRequiredDescription
teamstringoptionalFilter by team abbreviation
seasonstringoptionalSeason (e.g. "20252026")
min_gamesintegeroptionalMinimum games played (default 10)
sort_bystringoptionalsave_pct, gaa, gsax, or wins
limitintegeroptionalMax results (1-50, default 20)
Example Request
{
  "tool": "get_goalie_stats",
  "arguments": {
    "sort_by": "gsax",
    "limit": 3
  }
}
Example Response
json
{
  "goalies": [
    {
      "playerId": 8479361,
      "playerName": "Connor Hellebuyck",
      "team": "WPG",
      "gamesPlayed": 64,
      "wins": 38,
      "losses": 18,
      "savePct": 0.924,
      "gaa": 2.31,
      "gsax": 24.7,
      "shutouts": 5
    },
    {
      "playerId": 8477424,
      "playerName": "Sergei Bobrovsky",
      "team": "FLA",
      "gamesPlayed": 55,
      "wins": 34,
      "losses": 14,
      "savePct": 0.918,
      "gaa": 2.48,
      "gsax": 18.3,
      "shutouts": 4
    },
    {
      "playerId": 8480045,
      "playerName": "Ukko-Pekka Luukkonen",
      "team": "BUF",
      "gamesPlayed": 58,
      "wins": 30,
      "losses": 20,
      "savePct": 0.912,
      "gaa": 2.71,
      "gsax": 12.1,
      "shutouts": 3
    }
  ]
}
Response Fields
FieldTypeDescription
goalies[].playerIdintegerPlayer ID
goalies[].playerNamestringGoalie name
goalies[].teamstringTeam abbreviation
goalies[].gamesPlayedintegerGames played
goalies[].winsintegerWins
goalies[].savePctnumberSave percentage
goalies[].gaanumberGoals against average
goalies[].gsaxnumberGoals saved above expected
goalies[].shutoutsintegerShutouts

Multi-table

10 credits/call
POST

get_odds

10 credits

Odds for a specific game with optional bookmaker and snapshot type filters.

When to use: You have a game ID and want the betting lines -- moneyline, spread, and total from specific bookmakers. Filter by opening, current, or closing lines to see how the market priced the game.

Parameters
NameTypeRequiredDescription
game_idstringrequiredGame ID (e.g. "2025020887")
bookmakerstringoptionalFilter by bookmaker (e.g. "draftkings")
snapshot_typestringoptionalopening, current, or closing
Example Request
{
  "tool": "get_odds",
  "arguments": {
    "game_id": "2025020887",
    "bookmaker": "draftkings"
  }
}
Example Response
json
{
  "odds": [
    {
      "bookmaker": "draftkings",
      "snapshotType": "opening",
      "mlHome": -115,
      "mlAway": -105,
      "spreadHome": -1.5,
      "spreadAway": 1.5,
      "total": 6,
      "overPrice": -110,
      "underPrice": -110,
      "capturedAt": "2026-03-14T12:00:00Z"
    },
    {
      "bookmaker": "draftkings",
      "snapshotType": "closing",
      "mlHome": -125,
      "mlAway": 105,
      "spreadHome": -1.5,
      "spreadAway": 1.5,
      "total": 6.5,
      "overPrice": -110,
      "underPrice": -110,
      "capturedAt": "2026-03-15T18:50:00Z"
    }
  ]
}
Response Fields
FieldTypeDescription
odds[].bookmakerstringBookmaker name
odds[].snapshotTypestringopening, current, or closing
odds[].mlHomeintegerHome moneyline
odds[].mlAwayintegerAway moneyline
odds[].spreadHomenumberHome puck line
odds[].totalnumberOver/under total
odds[].overPriceintegerOver price
odds[].underPriceintegerUnder price
odds[].capturedAtstringTimestamp of snapshot
POST

get_game_detail

10 credits

Full game detail including odds snapshots and confirmed goalie starts.

When to use: You want everything about a single game in one call -- scores, odds from multiple bookmakers, and confirmed goalie starts. Saves you from making separate get_odds and search_players calls.

Parameters
NameTypeRequiredDescription
game_idstringrequiredGame ID (e.g. "2025020887")
Example Request
{
  "tool": "get_game_detail",
  "arguments": {
    "game_id": "2025020887"
  }
}
Example Response
json
{
  "game": {
    "id": "2025020887",
    "season": "20252026",
    "gameDate": "2026-03-15",
    "startTime": "19:00:00",
    "gameState": "FINAL",
    "gameType": "regular",
    "venue": "KeyBank Center"
  },
  "home_team": {
    "abbrev": "BUF",
    "name": "Buffalo Sabres",
    "score": 5
  },
  "away_team": {
    "abbrev": "TOR",
    "name": "Toronto Maple Leafs",
    "score": 3
  },
  "odds": [
    {
      "bookmaker": "draftkings",
      "mlHome": -125,
      "mlAway": 105,
      "spreadHome": -1.5,
      "total": 6.5,
      "snapshotType": "closing"
    },
    {
      "bookmaker": "fanduel",
      "mlHome": -130,
      "mlAway": 110,
      "spreadHome": -1.5,
      "total": 6.5,
      "snapshotType": "closing"
    }
  ],
  "goalie_starts": {
    "home": {
      "id": 8480045,
      "name": "Ukko-Pekka Luukkonen",
      "confirmed": true
    },
    "away": {
      "id": 8479361,
      "name": "Joseph Woll",
      "confirmed": true
    }
  }
}
Response Fields
FieldTypeDescription
game.idstringGame ID
game.gameDatestringDate
game.gameStatestringFUT, LIVE, FINAL, or OFF
home_team.abbrevstringHome team abbreviation
home_team.scoreintegerHome team score
away_team.abbrevstringAway team abbreviation
away_team.scoreintegerAway team score
odds[]arrayOdds from all bookmakers
goalie_starts.homeobjectHome goalie (id, name, confirmed)
goalie_starts.awayobjectAway goalie (id, name, confirmed)
POST

get_head_to_head

10 credits

Matchup history between two teams with win/loss records.

When to use: You're previewing a matchup and want to know the rivalry history -- who has the edge, recent results, and head-to-head record for a specific season or all-time.

Parameters
NameTypeRequiredDescription
team1stringrequiredFirst team abbreviation
team2stringrequiredSecond team abbreviation
seasonstringoptionalFilter to specific season
limitintegeroptionalMax games (1-100, default 20)
Example Request
{
  "tool": "get_head_to_head",
  "arguments": {
    "team1": "BUF",
    "team2": "TOR",
    "season": "20252026"
  }
}
Example Response
json
{
  "record": {
    "team1": "BUF",
    "team2": "TOR",
    "team1_wins": 2,
    "team2_wins": 1,
    "ties": 0
  },
  "total_games": 3,
  "games": [
    {
      "id": "2025020412",
      "gameDate": "2025-12-14",
      "homeTeam": "TOR",
      "awayTeam": "BUF",
      "homeScore": 3,
      "awayScore": 4,
      "venue": "Scotiabank Arena"
    },
    {
      "id": "2025020623",
      "gameDate": "2026-01-28",
      "homeTeam": "BUF",
      "awayTeam": "TOR",
      "homeScore": 2,
      "awayScore": 5,
      "venue": "KeyBank Center"
    }
  ]
}
Response Fields
FieldTypeDescription
record.team1_winsintegerTeam 1 wins
record.team2_winsintegerTeam 2 wins
total_gamesintegerTotal games in range
games[].idstringGame ID
games[].gameDatestringDate
games[].homeScoreintegerHome team score
games[].awayScoreintegerAway team score

Time-series

25 credits/call
POST

get_line_movement

25 credits

Time-series odds snapshots grouped by bookmaker. Shows how lines moved from open to close.

When to use: You're analyzing sharp money or building a betting model and need to see how odds changed over time. Opening vs. closing line differences reveal where the market moved, which is the strongest signal in sports betting.

Parameters
NameTypeRequiredDescription
game_idstringrequiredGame ID (e.g. "2025020887")
bookmakerstringoptionalFilter to one bookmaker
Example Request
{
  "tool": "get_line_movement",
  "arguments": {
    "game_id": "2025020887",
    "bookmaker": "draftkings"
  }
}
Example Response
json
{
  "game_id": "2025020887",
  "movement": {
    "draftkings": {
      "snapshots": [
        {
          "snapshotType": "opening",
          "mlHome": -115,
          "mlAway": -105,
          "spreadHome": -1.5,
          "total": 6,
          "capturedAt": "2026-03-14T12:00:00Z"
        },
        {
          "snapshotType": "current",
          "mlHome": -120,
          "mlAway": 100,
          "spreadHome": -1.5,
          "total": 6.5,
          "capturedAt": "2026-03-15T14:30:00Z"
        },
        {
          "snapshotType": "closing",
          "mlHome": -125,
          "mlAway": 105,
          "spreadHome": -1.5,
          "total": 6.5,
          "capturedAt": "2026-03-15T18:50:00Z"
        }
      ],
      "summary": {
        "mlHome_open": -115,
        "mlHome_close": -125,
        "total_open": 6,
        "total_close": 6.5
      }
    }
  }
}
Response Fields
FieldTypeDescription
game_idstringGame ID
movement[book].snapshots[]arrayChronological odds snapshots
movement[book].snapshots[].snapshotTypestringopening, current, or closing
movement[book].snapshots[].mlHomeintegerHome moneyline at this snapshot
movement[book].snapshots[].totalnumberOver/under at this snapshot
movement[book].snapshots[].capturedAtstringTimestamp
movement[book].summaryobjectOpen vs close comparison

Ready to build?

500 free credits on signup. No credit card required.

Get Your API Key