For the complete documentation index, see llms.txt. This page is also available as Markdown.

ComboBuilder ✨

Combine multiple selections into a single bet with correlated pricing

Overview

The LSports ComboBuilder API enables operators to offer Combo Bet functionality — allowing bettors to combine multiple selections from a single fixture into one bet with a correlation-aware combined price.

Unlike naive parlay pricing that simply multiplies individual odds, the ComboBuilder engine accounts for statistical dependencies between selections (e.g., "Home Win" and "Over 2.5 Goals" are correlated events), producing a fair margined price that reflects joint probabilities.

Authentication

All ComboBuilder API endpoints require authentication via JWT access tokens. To obtain your credentials and authenticate, see the Authentication Guide.

Integration Workflow

The API consists of two endpoints designed to be used together:

1. Resolve market dependencies — For each selection the end user wants to include, call /v1/markets to determine which market data the pricing engine requires. Markets often have dependencies - for example, pricing a "Player Total Shots" selection may require you to also provide "Shots on Target" and "Assists" data in the same request. This endpoint tells you exactly what to supply.

2. Build the combined price — Call /v1/combobuilder with the fixture's market data (as determined in step 1), the user's selections, and participant/player information. The API returns a single combined decimal odds value along with metadata indicating which selections are required vs. redundant.

Coverage: ComboBuilder is available for all Football leagues. No coverage check is required.

Key Principle

The operator is responsible for supplying the underlying market odds data to the pricing engine. The ComboBuilder does not source odds - it derives the combined price from the data you provide. The richer and more complete the market data you supply (more lines, more periods), the more accurate the combined pricing will be.

Refer to the full API specification below for request/response schemas, supported market keys, period definitions, and worked examples for Football.

Previous endpoint URLsPOST /v1/betbuilder and POST /v1/betbuilder/markets are still active and will be supported until August 31, 2026. New integrations should use the updated endpoints documented below.

Derive combined combo price

post

Calculates a margined combined price for two or more selections on a fixture.

The markets object uses actual LSports market IDs as string keys. Each market ID value contains the source odds payload for that market. For example, Football market "1" is Match Result, "2" is Total Goals, and "13" is European Handicap.

IncomingRequest logs preserve this ID-keyed request shape; UpstreamRequest logs show the normalized internal shape used by the pricing engine.

Authorizations
AuthorizationstringRequired

JWT Bearer token issued by the authentication provider (Frontegg). Include the token in the Authorization header as Bearer <token>.

Header parameters
customerIdintegerRequired

Customer ID. Must match the tenantId claim in the JWT token. Used for authorization — the customer must be registered for ComboBuilder access.

Example: 12345
Body

ComboBuilder request using ID-keyed source markets.

sportIdinteger · enumRequired

LSports sport ID

Example: 6046Possible values:
leagueIdinteger · nullableOptional

LSports league/tournament ID. Required for Basketball to select the correct pricing model format.

Known values

LeagueID
NBA64
WNBA761
NCAA Basketball4045
Euroleague33249
MLB183
Example: 64
fixtureIdinteger · nullableOptional

LSports fixture ID. Each request must use a unique value so the engine treats it as an independent event. Reusing the same ID across requests can cause state caching issues on the engine side.

Example: 100001
eventIdstring · nullableOptional

Optional external event reference ID.

viewIdstring · nullableOptional

Optional view/session reference ID.

Responses
200

Combined bet price successfully derived

application/json
correlationIdstring · nullableOptional

Internal correlation ID for tracing.

Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
pricenumber · doubleOptional

Combined margined decimal odds for all selections.

Example: 3.45
requiredSelectionsinteger[] · nullableOptional

Indices of selections that are required for the bet to be valid.

Example: [0,1]
post/v1/combobuilder
POST /v1/combobuilder HTTP/1.1
Host: combo-builder-gw.lsports.eu
Authorization: Bearer YOUR_SECRET_TOKEN
customerId: 1
Content-Type: application/json
Accept: */*
Content-Length: 632

{
  "sportId": 6046,
  "leagueId": 218,
  "fixtureId": 10001,
  "participants": [
    {
      "id": 1,
      "name": "Liverpool",
      "players": [
        {
          "id": 101,
          "name": "Salah"
        },
        {
          "id": 102,
          "name": "Firmino"
        }
      ]
    },
    {
      "id": 2,
      "name": "Chelsea",
      "players": [
        {
          "id": 201,
          "name": "Palmer"
        },
        {
          "id": 202,
          "name": "Jackson"
        }
      ]
    }
  ],
  "selections": [
    {
      "marketId": 1,
      "outcome": "1"
    },
    {
      "marketId": 2,
      "outcome": "O",
      "line": 2.5
    }
  ],
  "markets": {
    "1": {
      "1": 2,
      "2": 3.6,
      "X": 3.4
    },
    "2": {
      "1.5": {
        "O": 1.3,
        "U": 3.4
      },
      "2.5": {
        "O": 1.9,
        "U": 1.9
      },
      "3.5": {
        "O": 3.6,
        "U": 1.28
      }
    },
    "3": {
      "-1.5": {
        "1": 3.4,
        "2": 1.32
      },
      "-0.5": {
        "1": 2,
        "2": 1.8
      },
      "0.5": {
        "1": 1.4,
        "2": 2.9
      }
    },
    "13": {
      "0": {
        "1": 2,
        "2": 3.6,
        "X": 3.4
      },
      "1": {
        "1": 1.36,
        "2": 6.5,
        "X": 4.5
      },
      "-1": {
        "1": 3.4,
        "2": 2.1,
        "X": 3.6
      }
    }
  }
}
{
  "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "price": 3.45,
  "requiredSelections": [
    0,
    1
  ],
  "selections": [
    {
      "bet": {
        "marketId": 1,
        "outcome": "1",
        "line": null,
        "playerId": null,
        "period": null
      },
      "isRequired": true
    }
  ]
}

Get supported markets for a sport

post

Returns the list of LSports markets supported by ComboBuilder for the requested sport, together with the source markets that should be provided in the pricing request to price each market with full calibration.

Supported sports:

  • Football (sportId: 6046)

  • Basketball (sportId: 48242)

  • Baseball (sportId: 154914)

dependedMarketIds lists the other markets that should be present in the markets payload of the /v1/combobuilder request alongside the requested market.

Football (sportId 6046)

Markets are grouped into the following dependency buckets, mirroring the LSports ComboBuilder dependency contract:

  • Group A — Goal-based / full-match markets (1X2, Double Chance, HT/FT, Correct Score, Both Teams To Score, totals, team totals, etc.) depend on European Handicap (13), 1X2 (1), Under/Over (2), Asian Handicap (3).

  • Group B — Half-period markets (1st Period Winner, 2nd Period Winner, U/O 1st/2nd Period, Correct Score 1st/2nd Period, halftime DC, etc.) depend on European Handicap (13), 1X2 (1), Under/Over 1st Period (21), Asian Handicap (3), 1st Period Winner (41), Under/Over (2).

  • Group C — Corners markets depend on Team With Most Corners (259), Total Corners (11).

  • Group D — Cards market Under/Over Cards (214) is self-contained and returns dependedMarketIds: null. Will A Red Card Be Shown? (82) depends on Under/Over Cards (214).

  • Group F — Player markets depend on Player To Score In Anytime (711). Player To Score In Anytime itself returns null. Per-player odds (asianPlayerTotals) are passed via the corresponding players[].sourceMarkets block, not via markets.

Basketball (sportId 48242)

Markets fall into the following groups, mirroring the LSports ComboBuilder dependency contract for basketball:

  • Halftime-derived (H1) markets (1st/2nd Period Winner, U/O 1st/2nd Period — Home/Away Team, 12 Halftime, 1st/2nd Period Odd/Even, 1st/2nd Period Odd/Even — Home/Away Team) depend on 1X2 Halftime (282). The engine consumes 282's odds to calibrate the halftime home/away points split. 282 itself returns dependedMarketIds: null because it is the source for this group.

  • 2nd-Half-derived (H2) markets (3rd/4th Period Winner, 3rd/4th Period Odd/Even, U/O 3rd/4th Period — Home/Away Team, 12 2nd Half, U/O 2nd Half markets including incl-OT variants) depend on both Asian Handicap 2nd Half (283) and 1X2 2nd Half (284). The engine consumes the joint (ML, spread) signal via compute_basketball_h2_means to calibrate the Q3+Q4 home/away points split — the AH line sharpens the H2 sigma_diff vs ML alone. 283 and 284 themselves return dependedMarketIds: null.

  • Odd/Even (5) depends on Under/Over (2) — the engine reads the implied total mean from market 2 to price 5.

  • Double Chance (7) depends on 1X2 (1) — Double Chance is analytically derivable from 1X2 outcome probabilities.

  • HT/FT (4) depends on both 1X2 (1) and 1X2 Halftime (282).

  • To Win Both Halves (84) depends on 1X2 Halftime (282), Asian Handicap 2nd Half (283) and 1X2 2nd Half (284) since the outcome is the joint event of winning both halves and the engine consumes all three sources to calibrate per-half lambdas.

  • OT-related markets (Will The Game Go To Overtime? (69), 12 Including Overtime (226)) depend on 1X2 (1) since the engine extends the full-game ML simulation into overtime.

  • Full-game team totals (U/O - Home Team (101), U/O - Away Team (102)) depend on Under/Over (2) since the engine extracts home/away expected points from the game total.

  • Including-OT team totals (U/O Home incl. OT (221), U/O Away incl. OT (220)) depend on their regulation counterparts (101, 102 respectively).

  • Full-game source markets (1X2 (1), Under/Over (2), Asian Handicap (3)) and the H1/H2 source anchors (282, 283, 284) themselves return dependedMarketIds: null.

Baseball (sportId 154914)

Baseball markets are grouped into eight dependency buckets, mirroring the LSports ComboBuilder dependency contract:

  • Group A — Full-game core sources (every full-game market depends on these): 1X2 (1), Under/Over (2), Both Teams to Score (17), 12 Including Overtime (226). Markets in this group (Correct Score, Total Odd/Even, Highest Scoring Inning, Match to go to Overtime, First/Last Team to Score, combo markets, …) only return Group A as their dependency list.

  • Group A′ — Half-Time/Full-Time (HT/FT (4), HT/FT (incl. overtime) (390)) additionally depends on First-Half Result (Team based) (282) since the engine consumes the halftime moneyline to calibrate the F5 home/away lambdas that drive the HT outcome.

  • Group B — Run line / Handicap (Handicap incl. OT (3, 342)) additionally depends on Handicap (incl. Overtime) (3).

  • Group C — Team-specific (Home/Away O/U Team Total, team Odd/Even, Race to X Runs) additionally depends on Over/Under Home Total Points (101) and Over/Under Away Total Points (102). Under/Over - Home Team Including Overtime (221) and Under/Over - Away Team Including Overtime (220) additionally cross-reference each other so a bet on either side carries both team totals in the payload.

  • Group D — First-3 innings (First 3 Innings Winner (1561), 3 Full Innings Total (1562)) additionally depends on the F3 sources 1561, 1562.

  • Group E — First-5 innings / First-half (5 Full Innings Winner (235), 5 Full Innings Total (236), 5 Full Innings Run Line (281), 5 Full Innings Winner (Draw No Bet) (1618), First-Half Result (Team based) (282), Asian Handicap Half-Time Betting (53)) additionally depends on the F5 sources 53, 235, 236, 281, 282 — the engine consumes both the 5-full-innings markets and the halftime ML/AH to calibrate per-inning F5 lambdas via compute_baseball_halftime_lambdas.

  • Group F — First-7 innings (First 7 Innings Winner (524), 7 Full Innings Total (525), 7 Full Innings Handicap (526)) additionally depends on the F7 sources 524, 525, 526.

  • Group G — Per-inning (every winner / total / handicap / team total / odd-even market scoped to a specific inning) additionally depends on that inning's own marketIds (e.g. inning 4 → 47, 44, 205, 67).

  • Group H — Player props (Player Total Runs Over/Under (1624), Player Total Home Runs Over/Under (1626), Player Total Earned Runs Over/Under (1635), Player Total Hits Allowed Over/Under (1636), Under/Over Pitcher Strikeouts (1637)) additionally depends on the player prop's own marketId.

A market is never listed as its own dependency. dependedMarketIds: null means the market either has no source-market dependencies in the LSports contract, or it is itself the sole source of its group (e.g. Under/Over Cards, Player To Score In Anytime, First-Half Result (Team based)).

null semantics

dependedMarketIds: null is the contract for "no source markets needed for this market id" and is semantically equivalent to an empty list []. Clients should treat both shapes identically; the API deliberately uses null to make the absence explicit (rather than an empty array, which can be ambiguous on some deserialisers). This is consistent across all supported sports (Football, Basketball, Baseball).

Authorizations
AuthorizationstringRequired

JWT Bearer token issued by the authentication provider (Frontegg). Include the token in the Authorization header as Bearer <token>.

Header parameters
customerIdintegerRequired

Customer ID. Must match the tenantId claim in the JWT token. Used for authorization — the customer must be registered for ComboBuilder access.

Example: 12345
Body
sportIdinteger · enumRequired

LSports sport ID. Football (6046), Basketball (48242) and Baseball (154914) are supported.

Example: 6046Possible values:
marketIdinteger · nullableOptional

Optional filter — return data for a single market only.

Example: 1397
Responses
200

List of supported markets with dependencies

application/json
post/v1/markets
POST /v1/markets HTTP/1.1
Host: combo-builder-gw.lsports.eu
Authorization: Bearer YOUR_SECRET_TOKEN
customerId: 1
Content-Type: application/json
Accept: */*
Content-Length: 16

{
  "sportId": 6046
}
{
  "result": [
    {
      "sport": {
        "id": 6046,
        "name": "Football"
      },
      "market": {
        "id": 1,
        "name": "1X2"
      },
      "dependedMarketIds": [
        {
          "id": 13,
          "name": "European Handicap"
        },
        {
          "id": 2,
          "name": "Under/Over"
        },
        {
          "id": 3,
          "name": "Asian Handicap"
        }
      ]
    },
    {
      "sport": {
        "id": 6046,
        "name": "Football"
      },
      "market": {
        "id": 21,
        "name": "Under/Over 1st Period"
      },
      "dependedMarketIds": [
        {
          "id": 13,
          "name": "European Handicap"
        },
        {
          "id": 1,
          "name": "1X2"
        },
        {
          "id": 3,
          "name": "Asian Handicap"
        },
        {
          "id": 41,
          "name": "1st Period Winner"
        },
        {
          "id": 2,
          "name": "Under/Over"
        }
      ]
    },
    {
      "sport": {
        "id": 6046,
        "name": "Football"
      },
      "market": {
        "id": 11,
        "name": "Total Corners"
      },
      "dependedMarketIds": [
        {
          "id": 259,
          "name": "Team With Most Corners"
        }
      ]
    },
    {
      "sport": {
        "id": 6046,
        "name": "Football"
      },
      "market": {
        "id": 1397,
        "name": "Under/Over Player Shots"
      },
      "dependedMarketIds": [
        {
          "id": 711,
          "name": "Player To Score In Anytime"
        }
      ]
    },
    {
      "sport": {
        "id": 6046,
        "name": "Football"
      },
      "market": {
        "id": 214,
        "name": "Under/Over Cards"
      },
      "dependedMarketIds": null
    },
    {
      "sport": {
        "id": 48242,
        "name": "Basketball"
      },
      "market": {
        "id": 41,
        "name": "1st Period Winner"
      },
      "dependedMarketIds": [
        {
          "id": 282,
          "name": "1X2 Halftime"
        }
      ]
    },
    {
      "sport": {
        "id": 48242,
        "name": "Basketball"
      },
      "market": {
        "id": 153,
        "name": "Under/Over 1st Period - Home Team"
      },
      "dependedMarketIds": [
        {
          "id": 282,
          "name": "1X2 Halftime"
        }
      ]
    },
    {
      "sport": {
        "id": 48242,
        "name": "Basketball"
      },
      "market": {
        "id": 282,
        "name": "1X2 Halftime"
      },
      "dependedMarketIds": null
    },
    {
      "sport": {
        "id": 48242,
        "name": "Basketball"
      },
      "market": {
        "id": 1,
        "name": "1X2"
      },
      "dependedMarketIds": null
    },
    {
      "sport": {
        "id": 154914,
        "name": "Baseball"
      },
      "market": {
        "id": 1,
        "name": "1X2"
      },
      "dependedMarketIds": [
        {
          "id": 2,
          "name": "Under/Over"
        },
        {
          "id": 17,
          "name": "Both Teams to Score"
        },
        {
          "id": 226,
          "name": "12 Including Overtime"
        }
      ]
    },
    {
      "sport": {
        "id": 154914,
        "name": "Baseball"
      },
      "market": {
        "id": 41,
        "name": "First Inning Winner"
      },
      "dependedMarketIds": [
        {
          "id": 1,
          "name": "1X2"
        },
        {
          "id": 2,
          "name": "Under/Over"
        },
        {
          "id": 17,
          "name": "Both Teams to Score"
        },
        {
          "id": 21,
          "name": "1st Period Over/Under"
        },
        {
          "id": 64,
          "name": "1st Inning - Handicap"
        },
        {
          "id": 153,
          "name": "1st Inning Home Total"
        },
        {
          "id": 155,
          "name": "1st Inning Away Total"
        },
        {
          "id": 202,
          "name": "1st Inning Winner (2-way)"
        },
        {
          "id": 226,
          "name": "12 Including Overtime"
        },
        {
          "id": 1427,
          "name": "1st Inning Over/Under"
        }
      ]
    },
    {
      "sport": {
        "id": 154914,
        "name": "Baseball"
      },
      "market": {
        "id": 1637,
        "name": "Under/Over Pitcher Strikeouts"
      },
      "dependedMarketIds": [
        {
          "id": 1,
          "name": "1X2"
        },
        {
          "id": 2,
          "name": "Under/Over"
        },
        {
          "id": 17,
          "name": "Both Teams to Score"
        },
        {
          "id": 226,
          "name": "12 Including Overtime"
        }
      ]
    }
  ]
}

Auto Endpoint — Simplified Integration

The /v1/combobuilder/auto endpoint is an alternative integration path for operators who want to offer Combo Bets without building the full market data pipeline.

With the standard flow, your system supplies the live odds and scoreboard data for each pricing request. The Auto endpoint removes that requirement: you send only the fixtureId and the user's selections, and TRADE fills in the market odds and live scoreboard automatically from its own data feeds.

When to use it: The Auto endpoint is designed for faster integrations. It is a good fit if you are not already consuming TRADE market data in a format suitable for the standard request, or if you want to launch quickly and optimise later.

Tradeoff: The pricing engine uses TRADE's odds data for all available coverage, regardless of your package configuration for the fixture. If the odds you display to your customers differ from TRADE's — due to your own margin settings, provider selection, or adjustments — end users may experience a discrepancy between the odds they see and the combined price they receive. The standard /v1/markets + /v1/combobuilder flow, where you supply your own market data, eliminates that gap.

Derive combined combo price from a minimal request (auto-filled)

post

Same pricing as /v1/combobuilder, but the service auto-fills the request from internal LSports data so the client sends only the fixture and the selections.

From a minimal body { fixtureId, inPlay, selections } the service resolves sportId, leagueId, locationId, participants (including player rosters) and the source market odds (and the live scoreboard for in-play) by fixtureId, then prices the slip exactly like a /v1/combobuilder request.

sportId, leagueId, locationId and participants are optional overrides — when supplied they take precedence over the auto-filled values. Do not send markets or scoreboard; they are populated by the service and rejected if present.

fixtureId must be a current LSports fixture (the IDs in the examples are illustrative). For in-play, the fixture must be trading live.

Authorizations
AuthorizationstringRequired

JWT Bearer token issued by the authentication provider (Frontegg). Include the token in the Authorization header as Bearer <token>.

Header parameters
customerIdintegerRequired

Customer ID. Must match the tenantId claim in the JWT token. Used for authorization.

Example: 12345
Body

Minimal request for the auto-filled combo price endpoint. Send fixtureId, inPlay and selections; the service resolves sport/league/location/participants and the source market odds (and scoreboard for in-play) from internal data by fixtureId. sportId/leagueId/locationId/participants are optional overrides. markets and scoreboard must not be sent.

fixtureIdintegerRequired

LSports fixture ID to price. Must be a current fixture so the service can resolve it.

Example: 11001
inPlaybooleanOptional

Whether the fixture is live. When true the service fetches the live scoreboard.

Default: falseExample: false
sportIdinteger · enum · nullableOptional

Optional override. Resolved from the fixture when omitted.

Example: 6046Possible values:
leagueIdinteger · nullableOptional

Optional override. Resolved from the fixture when omitted.

locationIdinteger · nullableOptional

Optional override. Resolved from the fixture when omitted.

eventIdstring · nullableOptional

Optional external event reference ID.

viewIdstring · nullableOptional

Optional view/session reference ID.

Responses
200

Combined bet price successfully derived

application/json
correlationIdstring · nullableOptional

Internal correlation ID for tracing.

Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
pricenumber · doubleOptional

Combined margined decimal odds for all selections.

Example: 3.45
requiredSelectionsinteger[] · nullableOptional

Indices of selections that are required for the bet to be valid.

Example: [0,1]
post/v1/combobuilder/auto
POST /v1/combobuilder/auto HTTP/1.1
Host: combo-builder-gw.lsports.eu
Authorization: Bearer YOUR_SECRET_TOKEN
customerId: 1
Content-Type: application/json
Accept: */*
Content-Length: 118

{
  "fixtureId": 11001,
  "inPlay": false,
  "selections": [
    {
      "marketId": 1,
      "outcome": "1"
    },
    {
      "marketId": 2,
      "outcome": "O",
      "line": 2.5
    }
  ]
}
{
  "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "price": 3.45,
  "requiredSelections": [
    0,
    1
  ],
  "selections": [
    {
      "bet": {
        "marketId": 1,
        "outcome": "1",
        "line": null,
        "playerId": null,
        "period": null
      },
      "isRequired": true
    }
  ]
}

Planning for high traffic? See Rate Limits & Throughput for how ComboBuilder handles request volume and how to prepare for tournament peaks.

Last updated

Was this helpful?