Merkur Bets Data API

Merkur Bets API for Pre-Match, Live & Settled Results Data

Access pre-match and live odds from Merkur Bets, the GGL-licensed German sportsbook, across 11 sports — Soccer, Ice Hockey, Basketball, Tennis, American Football, Handball and more. Every market carries a canonical type next to its German name, in-play events ship a running score and per-period scores, and the results archive settles every selection WON or LOST. REST and WebSocket, one API key.

What a Merkur Bets API Response Looks Like

GET /api/merkur/soccer/events?page=1&limit=5
{
  "total": 517,
  "page": 1,
  "limit": 5,
  "totalPages": 104,
  "hasNextPage": true,
  "events": [
    {
      "sport": "soccer",
      "country": "Deutschland",
      "league": "Deutschland Bundesliga",
      "eventId": "3196906572",
      "home": "Bayern München",
      "away": "FC Union Berlin",
      "live": false,
      "startTime": "2026-09-18T18:30:00.000Z",
      "slug": "/de/sports/game-details/3196906572",
      "moreInfo": {
        "leagueId": 6843,
        "leagueNameFull": "Deutschland Bundesliga",
        "gameType": 4,
        "countryCode": "DEU",
        "countryId": 2,
        "topGame": true,
        "betbuilder": true,
        "bettingAllowedUntil": "2026-09-18T18:30:00Z",
        "leagueSlug": "/de/sports/s/0/s1/2/6843",
        "externalIds": {
          "betradar": "72513202"
        }
      },
      "markets": [
        {
          "canonicalMarket": "MATCH_RESULT",
          "rawName": "Wer gewinnt das Spiel?",
          "period": "FULL_TIME",
          "isActive": true,
          "selections": [
            {
              "canonicalOutcome": "HOME",
              "rawName": "1",
              "odds": 1.08,
              "isActive": true,
              "selectionId": "2224201"
            },
            {
              "canonicalOutcome": "DRAW",
              "rawName": "X",
              "odds": 12,
              "isActive": true,
              "selectionId": "2224202"
            },
            {
              "canonicalOutcome": "AWAY",
              "rawName": "2",
              "odds": 21.86,
              "isActive": true,
              "selectionId": "2224203"
            }
          ],
          "marketId": "22242",
          "moreInfo": {
            "categoryIds": [
              1
            ],
            "subcategoryIds": [
              1
            ]
          }
        },
        {
          "canonicalMarket": "OVER_UNDER",
          "rawName": "Over + / Under - 2,5",
          "period": "FULL_TIME",
          "isActive": true,
          "selections": [
            {
              "canonicalOutcome": "OVER",
              "rawName": "3+",
              "odds": 1.16,
              "isActive": true,
              "selectionId": "2225201"
            },
            {
              "canonicalOutcome": "UNDER",
              "rawName": "0-2",
              "odds": 4.82,
              "isActive": true,
              "selectionId": "2225203"
            }
          ],
          "marketId": "22252",
          "line": 2.5,
          "moreInfo": {
            "categoryIds": [
              1,
              2
            ],
            "subcategoryIds": [
              9
            ]
          }
        },
        {
          "canonicalMarket": "OVER_UNDER",
          "rawName": "Over + / Under - 0,5",
          "period": "FULL_TIME",
          "isActive": true,
          "selections": [
            {
              "canonicalOutcome": "UNDER",
              "rawName": "0",
              "odds": 45.5,
              "isActive": true,
              "selectionId": "2246203"
            }
          ],
          "marketId": "22462",
          "line": 0.5,
          "moreInfo": {
            "categoryIds": [
              1,
              2
            ],
            "subcategoryIds": [
              9
            ]
          }
        }
      ]
    }
  ]
}

In-Play — Score, Per-Period Scores, Clock & Statistics

GET /api/merkur/live-events?sport=soccer&limit=1
{
  "total": 4,
  "page": 1,
  "limit": 1,
  "sport": "soccer",
  "events": [
    {
      "sport": "soccer",
      "country": "Singapur",
      "league": "Singapur Premier League",
      "eventId": "3196975552",
      "home": "Geylang Intern.",
      "away": "Tanjong Pagar Utd.",
      "startTime": "2026-09-14T11:30:00.000Z",
      "score": {
        "home": "1",
        "away": "0"
      },
      "periodScores": {
        "home": [
          1
        ],
        "away": [
          0
        ],
        "scheduled": 2
      },
      "matchClock": {
        "minute": 45,
        "periodId": "BREAK",
        "period": "BREAK",
        "running": false
      },
      "statistics": {
        "football": {
          "home": {
            "yellowCards": 0,
            "redCards": 0,
            "corners": 0
          },
          "away": {
            "yellowCards": 0,
            "redCards": 1,
            "corners": 0
          }
        }
      },
      "slug": "/de/sports/live/game-details/35353401",
      "moreInfo": {
        "leagueId": 6376,
        "leagueNameFull": "Singapur Premier League",
        "gameType": 1,
        "countryCode": "SGP",
        "countryId": 148,
        "leagueSlug": "/de/sports/s/0/s1/148/6376",
        "externalIds": {
          "merkurPrematch": "3196975552",
          "betradar": "73550102"
        },
        "liveGameId": 35353401,
        "cornersPublished": false
      },
      "markets": [
        {
          "canonicalMarket": "MATCH_RESULT",
          "rawName": "Wer gewinnt das Spiel?",
          "period": "FULL_TIME",
          "isActive": true,
          "selections": [
            {
              "canonicalOutcome": "HOME",
              "rawName": "1",
              "odds": 1.07,
              "isActive": true,
              "selectionId": "1101"
            },
            {
              "canonicalOutcome": "DRAW",
              "rawName": "X",
              "odds": 7.69,
              "isActive": true,
              "selectionId": "1102"
            },
            {
              "canonicalOutcome": "AWAY",
              "rawName": "2",
              "odds": 33.01,
              "isActive": true,
              "selectionId": "1103"
            }
          ],
          "marketId": "11",
          "moreInfo": {
            "categoryIds": [
              1
            ],
            "subcategoryIds": [
              1
            ]
          }
        },
        {
          "canonicalMarket": "DOUBLE_CHANCE",
          "rawName": "Doppelchance",
          "period": "FULL_TIME",
          "isActive": true,
          "selections": [
            {
              "canonicalOutcome": "HOME_DRAW",
              "rawName": "1/X",
              "odds": 1,
              "isActive": true,
              "selectionId": "1784101"
            },
            {
              "canonicalOutcome": "HOME_AWAY",
              "rawName": "1/2",
              "odds": 1.03,
              "isActive": true,
              "selectionId": "1784102"
            },
            {
              "canonicalOutcome": "DRAW_AWAY",
              "rawName": "X/2",
              "odds": 6.99,
              "isActive": true,
              "selectionId": "1784103"
            }
          ],
          "marketId": "17841",
          "moreInfo": {
            "categoryIds": [
              1
            ],
            "subcategoryIds": [
              5
            ]
          }
        }
      ]
    }
  ]
}

Results — Every Selection Settled WON or LOST

GET /api/merkur/results?sport=soccer&final=true&limit=20
{
  "total": 71,
  "page": 1,
  "limit": 20,
  "totalPages": 4,
  "hasNextPage": true,
  "results": [
    {
      "sport": "soccer",
      "country": "Japan",
      "league": "Japan J-League 3",
      "eventId": "3196975382",
      "home": "FC Osaka",
      "away": "Ehime FC",
      "startTime": "2026-09-14T10:00:00.000Z",
      "score": {
        "home": "2",
        "away": "1"
      },
      "periodScores": {
        "home": [
          1,
          1
        ],
        "away": [
          0,
          1
        ],
        "scheduled": 2
      },
      "matchClock": {
        "minute": 90,
        "periodId": "ENDED",
        "period": "ENDED",
        "running": false
      },
      "statistics": {
        "football": {
          "home": {
            "yellowCards": 1,
            "redCards": 0,
            "corners": 0
          },
          "away": {
            "yellowCards": 1,
            "redCards": 0,
            "corners": 0
          }
        }
      },
      "participants": {
        "home": {
          "id": 138060,
          "name": "FC Osaka"
        },
        "away": {
          "id": 98416,
          "name": "Ehime FC"
        }
      },
      "settlement": {
        "source": "merkur",
        "final": true,
        "inPlay": false,
        "settledSelections": 121,
        "totalSelections": 124,
        "settledMarkets": 31,
        "totalMarkets": 32,
        "scrapedAt": "2026-09-14T12:34:04.720Z"
      },
      "settledOpportunities": [
        {
          "market": "MATCH_RESULT",
          "period": "FULL_TIME",
          "outcome": "HOME",
          "selection": "1",
          "result": "WON"
        },
        {
          "market": "MATCH_RESULT",
          "period": "FULL_TIME",
          "outcome": "DRAW",
          "selection": "X",
          "result": "LOST"
        },
        {
          "market": "MATCH_RESULT",
          "period": "FULL_TIME",
          "outcome": "AWAY",
          "selection": "2",
          "result": "LOST"
        },
        {
          "market": "OVER_UNDER",
          "period": "FULL_TIME",
          "outcome": "OVER",
          "selection": "3+",
          "result": "WON",
          "line": 2.5
        },
        {
          "market": "OVER_UNDER",
          "period": "FULL_TIME",
          "outcome": "UNDER",
          "selection": "0-2",
          "result": "LOST",
          "line": 2.5
        },
        {
          "market": "OVER_UNDER",
          "period": "FULL_TIME",
          "outcome": "OVER",
          "selection": "2+",
          "result": "WON",
          "line": 1.5
        }
      ],
      "moreInfo": {
        "leagueId": 9584,
        "leagueNameFull": "Japan J-League 3",
        "gameType": 1,
        "countryCode": "JPN",
        "countryId": 33,
        "leagueSlug": "/de/sports/s/0/s1/33/9584",
        "externalIds": {
          "merkurPrematch": "3196975382",
          "betradar": "72151960"
        },
        "liveGameId": 35353381,
        "cornersPublished": false,
        "ended": true,
        "lastSeenAt": "2026-09-14T12:01:01.509Z",
        "countryName": "Japan"
      },
      "slug": "/de/sports/live/game-details/35353381",
      "externalIds": {
        "betradar": "72151960"
      },
      "nameFull": "FC Osaka - Ehime FC"
    }
  ]
}

Why Use PulseScore for Merkur Bets Data

A German Board You Do Not Have to Read in German

Market and selection names come through exactly as Merkur Bets prints them — Wer gewinnt das Spiel?, Doppelchance, Over + / Under - 2,5, Ja / Nein, gerade / unger. — and every market carries a canonicalMarket with every selection a canonicalOutcome next to it. Thirty-one canonical market types on soccer alone, so a MATCH_RESULT / HOME selection means the same thing here as on every other book PulseScore serves.

Market IDs That Line Up Across Fixtures

Merkur uses market-template IDs rather than per-event keys: the same 289 marketIds cover every soccer fixture on the board, 22242 is always the 1X2 market and 22252 always Over/Under 2.5, with matching selectionIds for each outcome slot. Line-movement tracking and cross-fixture comparisons become a group-by instead of a name-matching problem — just key on eventId plus marketId, since the IDs repeat by design.

Per-Selection Settlement, Not Just a Score

The results archive publishes how each individual selection settled — something only NEO.bet also does: settledOpportunities lists every market, period, outcome and selection with a WON or LOST verdict and the line it settled against — up to 523 entries on a single soccer match, alongside counts of settled versus total markets and selections. Backtest a strategy against real settled prices without rebuilding the settlement logic yourself.

Deep Soccer and Ice Hockey Boards

Soccer fixtures average 88 markets and reach 280 across 112 competitions in 52 countries, with LaLiga around 195 per fixture and the Bundesliga around 148 — 1X2, double chance, draw no bet, European and Asian handicaps, match, half and team totals, correct score, half-time/full-time, odd/even and player markets. Ice hockey averages 34 markets with per-period totals, and American football runs a flat 48-market NFL board.

Live Events With Score, Clock and Period Scores

Every in-play document carries a running score, a periodScores block with goals by half, points by quarter, runs by inning or games by set, a match clock with machine period codes, and statistics — cards and corners on soccer, set games and server on tennis. Live events share the prematch eventId, so joining the in-play board to its pre-match prices is a single lookup.

REST Plus WebSocket Streaming

Poll the REST endpoints for pre-match boards, leagues and results, or subscribe over WebSocket for in-play pushes roughly every second. All 11 sports are subscribable on PRO, MAX and ULTRA plans, and one PulseScore API key works across Merkur Bets and every other bookmaker on the platform.

Frequently Asked Questions

What data does the Merkur Bets API provide?

PulseScore provides pre-match and live odds from Merkur Bets (merkurbets.de), the GGL-licensed German sportsbook, across 11 sports, plus a 30-day results archive with per-selection settlement. Each event includes normalized market data with canonical market types and outcomes, decimal odds, Merkur's own market-template IDs and Betradar cross-reference IDs, alongside the book's German market names.

Which sports are covered?

Eleven: Soccer, Ice Hockey, Basketball, Tennis, American Football, Handball, Baseball, Volleyball, Rugby League, Australian Rules and Cycling. Each exposes /leagues, /leagues/:league/events, /events and /events/:eventId, and all 11 are subscribable on the WebSocket. Soccer is the deepest board with 112 competitions across 52 countries; cycling is priced as per-rider rows plus outright boards for the Road World Championships.

Do I need to understand German to use this feed?

No. Market names (rawName) and selection labels stay in German because that is what the book publishes, but every market carries a canonicalMarket (MATCH_RESULT, OVER_UNDER, ASIAN_HANDICAP, BOTH_TEAMS_TO_SCORE, CORRECT_SCORE and 26 more on soccer) and every selection a canonicalOutcome (HOME, DRAW, AWAY, OVER, UNDER, YES, NO, ODD, EVEN, OTHER). Handicap and total lines are also exposed as a numeric line field, so you never have to parse '2,5' out of a German market name. Country names are German too (Deutschland, Dänemark, Tschechien), with the ISO-3 code in moreInfo.countryCode for programmatic joins.

What are settledOpportunities in the results feed?

They are Merkur's settlement of every selection on a match. Each entry gives the canonical market, the period, the outcome, the selection label as the book printed it, the line where one applies, and a result of WON or LOST — about 200 entries on an average settled soccer match and up to 523 on a deep board. The settlement block alongside them counts settled versus total markets and selections and carries final: true once the match is fully settled. NEO.bet is the only other bookmaker feed on PulseScore that publishes settlement at selection level, in the same shape.

How do I get only finished matches from the results endpoint?

Pass ?final=true. Merkur writes results while a match is still being settled, so rows can appear with settlement.final false and inPlay true mid-match; the final flag is the reliable finished marker and it is indexed. You can also filter by sport, league, country and team, and matchClock.period reads ENDED on finished rows.

Are the marketId and selectionId values unique per event?

No — and that is deliberate. They are market-template IDs: 289 distinct marketIds cover all 45,000+ soccer market documents on the board, so marketId 22242 is the 1X2 market on every fixture and 22252 is Over/Under 2.5 on every fixture, with selectionIds following the same pattern per outcome. Use eventId plus marketId as your key, and use the template ID on its own when you want the same market across many fixtures.

Is live in-play data available?

Yes. The live endpoints return in-play events with the current market board, a running score, per-period scores, a match clock with machine period codes (PERIOD_1, QUARTER_3, SET_2, BREAK, ENDED), and statistics — cards and corners on soccer, set games and server on tennis. Soccer, tennis, basketball and baseball are what the German board runs live most of the day; call /live-events/sports to see what is on right now. Live access requires a STARTER plan or above, and WebSocket streaming requires PRO or above.

How do I connect to the Merkur Bets WebSocket?

Connect to wss://api.pulsescore.net/api/merkur/ws/live?key=YOUR_KEY&sport=soccer. The sport parameter is required and takes kebab-case keys (ice-hockey, american-football, rugby-league, australian-rules). The server sends a connected frame with the list of valid sports, then pushes a snapshot of that sport's live events roughly every second. PRO allows 1 concurrent connection, MAX 3 and ULTRA 6.

How do I join Merkur Bets events to other bookmakers?

Most fixtures carry moreInfo.externalIds.betradar, the Betradar/Sportradar match ID, which is the cleanest cross-book key when another feed exposes it. Failing that, canonical market types plus team names and start times work well: canonicalMarket and canonicalOutcome are shared vocabulary across every bookmaker on PulseScore, so a MATCH_RESULT / HOME price lines up directly.

What is Quotenboost in the soccer league list?

It is Merkur's odds-boost shelf, which the site files as a competition of its own, so it appears alongside real leagues such as Deutschland Bundesliga and England Premier League in /soccer/leagues. Filter it out if you only want genuine competitions — the fixtures under it are boosted prices on matches that also appear in their own league.

How fresh is the data?

Pre-match boards and league lists refresh on a rolling scrape with a one-hour retention window, live events carry a two-minute window so a finished match leaves the feed quickly, and results are kept for 30 days. Every document carries createdAt and updatedAt so you can measure freshness yourself. The Merkur Bets feed is new on PulseScore, so the results archive fills toward its full 30-day window from the day the book was added.

What are the rate limits?

Rate limits depend on your plan. BASIC is free with 500 requests per month, STARTER adds live data and higher throughput, and PRO, MAX and ULTRA raise the per-second limits and add WebSocket connections (1, 3 and 6 respectively). See the pricing page for current numbers.

Can I use this data commercially?

Yes. PulseScore plans permit commercial use for odds comparison, analytics dashboards, trading models and betting tools. You are responsible for complying with the gambling regulations that apply in your jurisdiction and for any licensing your own product needs.

Start Using the Merkur Bets API Today

Free tier available. No credit card required. Get your API key in 30 seconds.