Same-game parlay

Default HTTP is POST /v7/cs2/sgp/quote. Full route list: Route Index.

Combine several outcomes from one CS2 match into a single price. Every leg is evaluated on the same simulated match scenarios, so the price reflects how those outcomes move together instead of pretending they are independent bets.

Choose a match, pick at least two legs, send them to /v7/cs2/sgp/quote, receive the combined price, then record the ticket and read its settlement. Builder plan and above; pre-match only.

POST/v7/cs2/sgp/quote
ParamTypeRequiredDescription
matchstringYesCS2 kr_match_id.
legsarrayYes2 or more legs: {market, selection, map, maps, line, direction}.
pricing.sourcestring-model (default) or book. book takes leg levels from live prices; correlation stays the model’s.
pricing.booksobject-book → weight, e.g. {"pinnacle": 1}. Weights are relative, not percentages.
pricing.min_sourcesint-Books that must price a leg on both sides. Default 1.
operator.margin_pctfloat-0-100. Applied to the joint probability, not per leg.
operator.max_legsint-2-8. Default 8.
operator.allowed_marketsarray-Restrict which markets a ticket may use.
operator.max_decimalfloat-Price cap. A capped price says price_limited.
operator.price_override_decimalfloat-Fixed price override.
operator.quote_ttl_secondsfloat-1-600. Sets expires_at.
scenariosint-Joint tape size, 1,000-100,000. Default 20,000.
seedint-Deterministic seed. Same seed and legs give the same price.

Legs are match_winner, map_winner, total_maps, total_rounds and player_kills. Team markets take a kr_tm id as selection; line markets take direction: over|under plus a half-point line; kill legs take a kr_pl id plus maps (for example [1, 2] for kills across maps 1 and 2).

cURLPOST
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  "https://kashrock.up.railway.app/v7/cs2/sgp/quote" \
  -d '{"match":"kr_cs2_bojong-vs-sinqu-04-11-2026","legs":[{"market":"match_winner","selection":"kr_tm_87b794cec83a"},{"market":"map_winner","selection":"kr_tm_87b794cec83a","map":1}]}'
200 · live (trimmed)
{
  "available": true,
  "sport": "cs2",
  "kr_match_id": "kr_cs2_bojong-vs-sinqu-04-11-2026",
  "best_of": 3,
  "quote_id": "sgq_1f4c0b2a9d6e71",
  "legs": [
    {
      "index": 0,
      "market": "match_winner",
      "selection": "kr_tm_87b794cec83a",
      "model_probability": 0.47595,
      "resolves": "series_winner"
    },
    {
      "index": 1,
      "market": "map_winner",
      "selection": "kr_tm_87b794cec83a",
      "map": 1,
      "model_probability": 0.4847,
      "resolves": "map_1_winner"
    }
  ],
  "pricing": {
    "source": "model",
    "fair_decimal": 2.789,
    "fair_american": 179,
    "priced_decimal": 2.789,
    "priced_american": 179,
    "margin_pct": 0,
    "model_joint_probability": 0.35855,
    "priced_probability": 0.35855,
    "independence_probability": 0.230693,
    "correlation_ratio": 1.5542,
    "correlation_delta": 0.127857
  },
  "simulation": {
    "version": "cs2-sgp-joint-v1",
    "method": "measured_joint_scenarios",
    "n_scenarios": 20000,
    "seed": 0,
    "standard_error": 0.003391,
    "p_ct": 0.5,
    "p_t": 0.4917,
    "map_name": "Ancient",
    "team_side_sample": 58,
    "live_conditioned": false
  },
  "in_play": {
    "supported": false,
    "reason": "no_live_conditioning"
  }
}

Reading the price

model_joint_probability is the share of simulation.n_scenarios scenarios in which every leg won together. independence_probability is what multiplying the individual probabilities would have given; correlation_ratio is the joint divided by that product. Above 1 the legs help each other, below 1 they work against each other. In the example above the model joint is 35.9% against an independence product of 23.1%: a 1.55x ratio and fair_decimal 2.789 instead of 4.335.

fair_decimalis the model's price, which is not a sportsbook's executable ticket price. With operator.margin_pct the returned priced_decimal is the model joint with that margin applied. With pricing.source: "book"the leg levels come from the named books' live two-sided devigged prices and only the correlation comes from the model; pricing.source always says which one the number is.

What is refused, and why

A refused ticket returns available: false with a reason and one entry per bad leg in unsupported_legs. Whole-number lines are refused because they can push. Maps that are only played if the series reaches them (map 3 at 1-1 on a Bo3) are refused because such a leg voids rather than loses. Contradictory legs, duplicate outcomes, markets the operator disallows, players with no stored kill sample, stale or suspended prices, and matches that have already started all come back with their own reason rather than a quietly different price.

Record and settle

POST /v7/cs2/sgp/ticket takes the same body plus an optional stake. The price is recomputed server-side and stored with the legs, quote id, simulation version and seed, so a caller cannot record a price of its own choosing. GET /v7/cs2/sgp/ticket/{ticket_id} returns the ticket with every leg marked hit, miss, void, pending or unresolved, the actual value it settled on, and the final ticket status. Settlement reads KashRock's stored match, map and player-map rows, so it is the same data the result pages show. A leg that must be voided on an otherwise-live correlated ticket is reported as needing a requote rather than silently repriced.

cURLPOST
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  "https://kashrock.up.railway.app/v7/cs2/sgp/ticket" \
  -d '{"match":"kr_cs2_bojong-vs-sinqu-04-11-2026","stake":10,"legs":[{"market":"match_winner","selection":"kr_tm_87b794cec83a"},{"market":"map_winner","selection":"kr_tm_87b794cec83a","map":1}]}'