Portal
Sign In Console

Protocol v2 strategy_grid Query Formats

This document explains how to query /strategy_grid for Squid, Short Deck, Bombpot, MTT, and PLO spots. It is focused on request fields, response fields, and JSON examples.

The examples use chips, not BB, for stacks and action amounts. With big_blind: 100, a 100 BB stack is 10000.

Output examples are representative snippets. Live strategy probabilities, EVs, bucket ids, and model metadata will depend on the loaded model and spot.

Endpoint

POST <gto-glue-environment-URL>/strategy_grid
Content-Type: application/json

For Holdem-like v2 formats, send protocol_ver: "v2". PLO is selected before the v2 Holdem route by hand.game_type being plo4, plo5, or plo6; keep protocol_ver: "v2" for consistency.

Common Input Fields

All formats use a strategy-act-style top-level request with a required hand object.

FieldTypeNotes
protocol_verstringUse "v2" for the v2 strategy-grid route.
strategy_min_thresholdnumberOptional. Drops tiny action probabilities and renormalizes. The UI commonly sends 0.05.
hand.game_typestring"nlhe", "shortdeck", "plo4", "plo5", or "plo6".
hand.game_mode_codestring"normal", "squid", "bomb", or "spin".
hand.big_blindintegerBig blind in chips.
hand.small_blindintegerSmall blind in chips. Defaults to big_blind / 2 if omitted.
hand.anteintegerPer-player ante in chips. For pure Bombpot, this is the bomb deposit. For Short Deck, the backend forces ante to 1 BB.
hand.dealer_seatintegerButton seat, 0-indexed. The UI uses last seat for 3+ players and seat 0 for heads-up.
hand.sb_seatintegerSmall blind seat, usually 0; use -1 for dead-SB MTT spots.
hand.bb_seatintegerBig blind seat, usually 1.
hand.straddle_seatintegerStraddle seat, usually 2 for 3-blind cash, otherwise -1.
hand.players[]arrayOne item per table seat: { "seat_no": 0, "stack": 10000 }. Omit hole_cards for range-viewer grid requests.
hand.rake_ratio_pctnumberOptional cash rake percentage, e.g. 3. Use 0 for MTT if desired.
hand.rake_cap_bbnumberOptional rake cap in BB, e.g. 3.
hand.actions.entries[]arrayAction and board history so far. Empty means first decision.

Action entries use this shape:

{
  "hand": {
    "actions": {
      "entries": [
        { "seat_no": 2, "action": "fold" },
        { "seat_no": 3, "action": "call" },
        { "seat_no": 4, "action": "raise", "amount": 300, "raise_to": 300 },
        { "action": "Ah7d2c" },
        { "action": "Ks" }
      ]
    }
  }
}

Player actions use action: "fold", "call", "check", "raise", "bet", or "allin". amount is raise-by/bet-by in chips. The v2 frontend also sends raise_to, the cumulative raise-to in chips; the backend preserves it and prefers it when present.

Board cards are deal entries: put the card string in action and omit seat_no and amount. Flop uses six characters such as "Ah7d2c"; turn/river use two characters such as "Ks".

Common Holdem-like Output Fields

Squid, Short Deck, Bombpot, and MTT use the v2 Holdem response shape.

FieldTypeNotes
hands[]arrayThe 169 grid cells. Each item has handName, strategy, reach, ev, actions, and combos.
hands[].handNamestringMatrix label such as "AA", "AKs", or "AKo". This replaces v1 top-level combo.
hands[].strategynumber[]Strategy vector in action-slot order.
hands[].reachnumberAverage reach for that grid cell.
hands[].evnumberAggregated EV for that grid cell.
hands[].actions[]arrayAggregated action rows: { "actionName", "probability", "ev" }.
hands[].combos[]arrayConcrete two-card combos in that cell. Each combo still uses combo, e.g. "AsAh".
overallStrategynumber[]Overall range strategy in action-slot order.
overallReachnumberAverage overall reach.
gridWeightTypestring"uniform" by default, or "reach" when requested.
actionLabels[]arrayLegal action labels. Each label includes slot, name, rawAction, amount, amountBb, and raiseByBb.
currentPlayerintegerSeat number for the acting player, or -1 if terminal.
numBoardCardsintegerNumber of board cards currently dealt.
pendingDealstring"", "flop", "turn", or "river" when more board cards are required.
numCombosintegerNumber of concrete NLHE combos evaluated.
tableStateobjectPot, board, player stacks/commitments, acting context, and equity arrays.
actionHistory[]arrayBackend-rendered action history for UI replay.
stateRenderstringDebug render of the engine state.
obsDebugobjectDebug fields for action mask, action sizes, game tags, raw board, and obs dim.
modelstringSelected model name.
modelMd5stringSelected model checksum.
computeTimeMsintegerTotal service-side compute time.
inferenceTimeMsintegerModel inference time for v2 Holdem.
supportScorenumberOptional support score when provided by the model output.

MTT fills tableState.icmEquityBb and tableState.bountyBb. Squid fills tableState.squidEquityBb.

Squid

Squid is a Holdem-like v2 request with hand.game_mode_code: "squid" and a top-level squid object. Use hand.game_type: "nlhe" for regular Squid and "shortdeck" for Short Deck Squid.

Squid Input Fields

FieldTypeNotes
hand.game_typestring"nlhe" or "shortdeck".
hand.game_mode_codestringMust be "squid".
squid.squid_value_in_bbnumberSquid value in BB. Legacy alias val_v is still normalized, but use this canonical name.
squid.modestring"classic", "blood_battle", or "double".
squid.players[]arrayPer-seat squid counts: { "seat_no": 0, "squid_count": 1 }.
squid.total_squidsintegerTotal squid markers this round. Classic is commonly num_players - 1; blood/double commonly num_players + 4.
squid.remaining_squidsintegerMarkers not yet awarded.
squid.super_squid_countintegerOptional blood/double super-squid count.
squid.super_squid_remainingintegerOptional remaining super squids.
squid.is_super_squid_handbooleanOptional marker that this hand has a super squid at stake.
squid.double_thresholdsinteger[]Optional threshold/multiplier pairs, e.g. [3, 2, 5, 4].

Squid Request Example

{
  "protocol_ver": "v2",
  "strategy_min_threshold": 0.05,
  "hand": {
    "game_type": "nlhe",
    "game_mode_code": "squid",
    "big_blind": 100,
    "small_blind": 50,
    "ante": 0,
    "dealer_seat": 5,
    "sb_seat": 0,
    "bb_seat": 1,
    "straddle_seat": -1,
    "players": [
      { "seat_no": 0, "stack": 10000 },
      { "seat_no": 1, "stack": 10000 },
      { "seat_no": 2, "stack": 10000 },
      { "seat_no": 3, "stack": 10000 },
      { "seat_no": 4, "stack": 10000 },
      { "seat_no": 5, "stack": 10000 }
    ],
    "rake_ratio_pct": 0,
    "rake_cap_bb": 0,
    "actions": { "entries": [] }
  },
  "squid": {
    "squid_value_in_bb": 5,
    "mode": "classic",
    "players": [
      { "seat_no": 0, "squid_count": 0 },
      { "seat_no": 1, "squid_count": 1 },
      { "seat_no": 2, "squid_count": 0 },
      { "seat_no": 3, "squid_count": 2 },
      { "seat_no": 4, "squid_count": 0 },
      { "seat_no": 5, "squid_count": 0 }
    ],
    "total_squids": 5,
    "remaining_squids": 2
  }
}

Squid Output Example

{
  "hands": [
    {
      "handName": "AA",
      "strategy": [0.0, 0.18, 0.0, 0.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
      "reach": 1.0,
      "ev": 14.25,
      "actions": [
        { "actionName": "call", "probability": 0.18, "ev": 11.2 },
        { "actionName": "raise3.0", "probability": 0.82, "ev": 15.1 }
      ],
      "combos": [
        {
          "combo": "AsAh",
          "reach": 1.0,
          "actions": [
            { "actionName": "call", "probability": 0.12, "ev": 10.9 },
            { "actionName": "raise3.0", "probability": 0.88, "ev": 15.4 }
          ]
        }
      ]
    }
  ],
  "overallStrategy": [0.11, 0.31, 0.0, 0.58, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
  "overallReach": 1.0,
  "gridWeightType": "uniform",
  "actionLabels": [
    { "index": 0, "slot": 0, "name": "fold", "rawAction": -1, "amount": null, "amountBb": 0.0, "raiseByBb": 0.0 },
    { "index": 1, "slot": 1, "name": "call 1.0 BB", "rawAction": 0, "amount": 100, "amountBb": 1.0, "raiseByBb": 0.0 },
    { "index": 2, "slot": 3, "name": "raise 3.0 BB", "rawAction": 300, "amount": 300, "amountBb": 3.0, "raiseByBb": 2.0 }
  ],
  "currentPlayer": 2,
  "numBoardCards": 0,
  "pendingDeal": "",
  "tableState": {
    "street": "preflop",
    "pot": 150,
    "chipsPerBb": 100,
    "board": [],
    "actingPlayer": 2,
    "squidEquityBb": [0.0, 5.2, 0.0, 10.1, 0.0, 0.0]
  },
  "model": "example-model.onnx",
  "modelMd5": "example-md5",
  "computeTimeMs": 18,
  "inferenceTimeMs": 7
}

Short Deck

Short Deck is selected by hand.game_type: "shortdeck". Use hand.game_mode_code: "normal" for regular Short Deck. The backend forces ante = big_blind for all Short Deck variants, matching the v1 behavior; send that value explicitly for readability.

Short Deck Input Fields

FieldTypeNotes
hand.game_typestringMust be "shortdeck".
hand.game_mode_codestring"normal" for regular Short Deck. Use "squid" or "bomb" only for combined variants.
hand.anteintegerBackend treats this as 1 BB regardless of request value. Send big_blind.
hand.players[]arrayTwo to six players are typical for Short Deck configs.
hand.actions.entries[]arraySame action/deal entry format as NLHE.

Short Deck Request Example

{
  "protocol_ver": "v2",
  "strategy_min_threshold": 0.05,
  "hand": {
    "game_type": "shortdeck",
    "game_mode_code": "normal",
    "big_blind": 100,
    "small_blind": 50,
    "ante": 100,
    "dealer_seat": 5,
    "sb_seat": 0,
    "bb_seat": 1,
    "straddle_seat": -1,
    "players": [
      { "seat_no": 0, "stack": 10000 },
      { "seat_no": 1, "stack": 10000 },
      { "seat_no": 2, "stack": 10000 },
      { "seat_no": 3, "stack": 10000 },
      { "seat_no": 4, "stack": 10000 },
      { "seat_no": 5, "stack": 10000 }
    ],
    "rake_ratio_pct": 3,
    "rake_cap_bb": 3,
    "actions": { "entries": [] }
  }
}

Short Deck Output Example

{
  "hands": [
    {
      "handName": "AKs",
      "strategy": [0.08, 0.52, 0.0, 0.40, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
      "reach": 1.0,
      "ev": 5.2,
      "actions": [
        { "actionName": "fold", "probability": 0.08, "ev": 0.0 },
        { "actionName": "call", "probability": 0.52, "ev": 4.7 },
        { "actionName": "raise4.0", "probability": 0.40, "ev": 6.1 }
      ],
      "combos": [
        {
          "combo": "AsKs",
          "reach": 1.0,
          "actions": [
            { "actionName": "fold", "probability": 0.06, "ev": 0.0 },
            { "actionName": "call", "probability": 0.54, "ev": 4.8 },
            { "actionName": "raise4.0", "probability": 0.40, "ev": 6.2 }
          ]
        }
      ]
    }
  ],
  "actionLabels": [
    { "index": 0, "slot": 0, "name": "fold", "rawAction": -1, "amount": null, "amountBb": 0.0, "raiseByBb": 0.0 },
    { "index": 1, "slot": 1, "name": "call 1.0 BB", "rawAction": 0, "amount": 100, "amountBb": 1.0, "raiseByBb": 0.0 },
    { "index": 2, "slot": 3, "name": "raise 4.0 BB", "rawAction": 400, "amount": 400, "amountBb": 4.0, "raiseByBb": 3.0 }
  ],
  "currentPlayer": 0,
  "numBoardCards": 0,
  "pendingDeal": "",
  "tableState": {
    "street": "preflop",
    "pot": 700,
    "chipsPerBb": 100,
    "board": [],
    "actingPlayer": 0,
    "players": [
      { "position": "SB", "stack": 9900, "startStack": 10000, "committed": 100, "folded": false, "allIn": false }
    ]
  },
  "model": "example-model.onnx",
  "computeTimeMs": 15,
  "inferenceTimeMs": 6
}

Bombpot

Bombpot is selected by hand.game_mode_code: "bomb". Use hand.game_type: "nlhe" for regular Bombpot and "shortdeck" for Short Deck Bombpot.

For pure non-shortdeck Bombpot, hand.ante is the bomb deposit in chips. For Short Deck Bombpot, the backend follows Short Deck behavior and forces the effective ante to 1 BB, then uses a 2 BB bomb deposit internally to match v1.

Bombpot Input Fields

FieldTypeNotes
hand.game_typestring"nlhe" or "shortdeck".
hand.game_mode_codestringMust be "bomb".
hand.anteintegerBomb deposit in chips for regular Bombpot.
hand.actions.entries[]arrayInclude board card deal entries to query a board-specific spot.

Bombpot Request Example

{
  "protocol_ver": "v2",
  "strategy_min_threshold": 0.05,
  "hand": {
    "game_type": "nlhe",
    "game_mode_code": "bomb",
    "big_blind": 100,
    "small_blind": 50,
    "ante": 500,
    "dealer_seat": 5,
    "sb_seat": 0,
    "bb_seat": 1,
    "straddle_seat": -1,
    "players": [
      { "seat_no": 0, "stack": 10000 },
      { "seat_no": 1, "stack": 10000 },
      { "seat_no": 2, "stack": 10000 },
      { "seat_no": 3, "stack": 10000 },
      { "seat_no": 4, "stack": 10000 },
      { "seat_no": 5, "stack": 10000 }
    ],
    "rake_ratio_pct": 3,
    "rake_cap_bb": 3,
    "actions": {
      "entries": [
        { "action": "Ah7d2c" }
      ]
    }
  }
}

Bombpot Output Example

{
  "hands": [
    {
      "handName": "KQo",
      "strategy": [0.34, 0.46, 0.0, 0.20, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
      "reach": 1.0,
      "ev": 2.15,
      "actions": [
        { "actionName": "fold", "probability": 0.34, "ev": 0.0 },
        { "actionName": "call", "probability": 0.46, "ev": 1.7 },
        { "actionName": "bet5.0", "probability": 0.20, "ev": 3.9 }
      ],
      "combos": [
        {
          "combo": "KhQc",
          "reach": 1.0,
          "actions": [
            { "actionName": "fold", "probability": 0.31, "ev": 0.0 },
            { "actionName": "call", "probability": 0.49, "ev": 1.8 },
            { "actionName": "bet5.0", "probability": 0.20, "ev": 4.0 }
          ]
        }
      ]
    }
  ],
  "currentPlayer": 0,
  "numBoardCards": 3,
  "pendingDeal": "",
  "tableState": {
    "street": "flop",
    "pot": 3150,
    "chipsPerBb": 100,
    "board": ["Ah", "7d", "2c"],
    "actingPlayer": 0
  },
  "actionHistory": [
    { "isDeal": true, "label": "Flop: Ah 7d 2c" }
  ],
  "modelMd5": "example-md5",
  "computeTimeMs": 16,
  "inferenceTimeMs": 7
}

MTT

MTT is selected by a top-level mtt object with tournament data. Use hand.game_type: "nlhe" and hand.game_mode_code: "normal" for regular MTT. Use hand.game_type: "shortdeck" with the same mtt object for Short Deck MTT.

MTT Input Fields

FieldTypeNotes
hand.game_typestring"nlhe" or "shortdeck".
hand.game_mode_codestringUsually "normal".
mtt.total_entriesintegerTotal tournament entries, including rebuys.
mtt.total_alive_playersintegerPlayers still alive. Defaults to total_entries if omitted.
mtt.prize_poolnumberTotal prize pool in dollars.
mtt.initial_chipsnumberStarting stack in chips.
mtt.payout_structure_limit_top10[]arrayTop payout entries: { "position": 1, "prize_value": 2500 }. Legacy alias payout_structure is accepted and truncated to top 10.
mtt.current_table_players_mttinfo[]arrayPer-seat tournament info: seat_no, stack, rank, optional head_bounty. Legacy alias players is accepted.
mtt.bounty_structureobjectRequired for bounty formats; use { "bounty_type": "normal" } for no bounty.
mtt.prize_feenumberOptional prize component of buy-in.
mtt.bounty_feenumberOptional bounty component of buy-in.
mtt.registration_feenumberOptional total buy-in.
mtt.current_levelintegerOptional current tournament level.
mtt.current_blind_levelintegerOptional blind level id.
mtt.blind_structure[]arrayOptional levels with level, ante, small_blind, and big_blind.

bounty_structure.bounty_type can be "normal", "progressive_bounty_pko", "normal_knockout_ko", "mystery_bounty", or "spin".

MTT Request Example

{
  "protocol_ver": "v2",
  "strategy_min_threshold": 0.05,
  "hand": {
    "game_type": "nlhe",
    "game_mode_code": "normal",
    "big_blind": 1000,
    "small_blind": 500,
    "ante": 100,
    "dealer_seat": 5,
    "sb_seat": 0,
    "bb_seat": 1,
    "straddle_seat": -1,
    "players": [
      { "seat_no": 0, "stack": 42000 },
      { "seat_no": 1, "stack": 38000 },
      { "seat_no": 2, "stack": 61000 },
      { "seat_no": 3, "stack": 27000 },
      { "seat_no": 4, "stack": 51000 },
      { "seat_no": 5, "stack": 33000 }
    ],
    "rake_ratio_pct": 0,
    "rake_cap_bb": 0,
    "actions": {
      "entries": [
        { "seat_no": 2, "action": "raise", "amount": 2400, "raise_to": 2500 },
        { "seat_no": 3, "action": "fold" },
        { "seat_no": 4, "action": "call" }
      ]
    }
  },
  "mtt": {
    "total_entries": 100,
    "total_alive_players": 54,
    "prize_pool": 9000,
    "initial_chips": 30000,
    "payout_structure_limit_top10": [
      { "position": 1, "prize_value": 2500 },
      { "position": 2, "prize_value": 1600 },
      { "position": 3, "prize_value": 1100 },
      { "position": 4, "prize_value": 800 },
      { "position": 5, "prize_value": 600 }
    ],
    "bounty_structure": {
      "bounty_type": "normal",
      "initial_bounty": 0,
      "bounty_proportion": 0
    },
    "current_table_players_mttinfo": [
      { "seat_no": 0, "stack": 42000, "rank": 18 },
      { "seat_no": 1, "stack": 38000, "rank": 24 },
      { "seat_no": 2, "stack": 61000, "rank": 8 },
      { "seat_no": 3, "stack": 27000, "rank": 39 },
      { "seat_no": 4, "stack": 51000, "rank": 12 },
      { "seat_no": 5, "stack": 33000, "rank": 31 }
    ],
    "prize_fee": 90,
    "bounty_fee": 0,
    "registration_fee": 100,
    "current_level": 10,
    "current_blind_level": 10,
    "blind_structure": [
      { "level": 10, "ante": 100, "small_blind": 500, "big_blind": 1000 }
    ]
  }
}

MTT Output Example

{
  "hands": [
    {
      "handName": "AQs",
      "strategy": [0.22, 0.48, 0.0, 0.30, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
      "reach": 0.77,
      "ev": 6.4,
      "actions": [
        { "actionName": "fold", "probability": 0.22, "ev": 0.0 },
        { "actionName": "call", "probability": 0.48, "ev": 5.8 },
        { "actionName": "raise7.5", "probability": 0.30, "ev": 7.9 }
      ],
      "combos": [
        {
          "combo": "AsQs",
          "reach": 0.8,
          "actions": [
            { "actionName": "fold", "probability": 0.18, "ev": 0.0 },
            { "actionName": "call", "probability": 0.52, "ev": 5.7 },
            { "actionName": "raise7.5", "probability": 0.30, "ev": 8.1 }
          ]
        }
      ]
    }
  ],
  "tableState": {
    "street": "preflop",
    "pot": 9500,
    "chipsPerBb": 1000,
    "board": [],
    "actingPlayer": 5,
    "icmEquityBb": [38.2, 34.7, 55.1, 24.3, 46.5, 30.2],
    "bountyBb": []
  },
  "actionLabels": [
    { "index": 0, "slot": 0, "name": "fold", "rawAction": -1, "amount": null, "amountBb": 0.0, "raiseByBb": 0.0 },
    { "index": 1, "slot": 1, "name": "call 2.5 BB", "rawAction": 0, "amount": 2500, "amountBb": 2.5, "raiseByBb": 0.0 },
    { "index": 2, "slot": 3, "name": "raise 7.5 BB", "rawAction": 7500, "amount": 7500, "amountBb": 7.5, "raiseByBb": 5.0 }
  ],
  "currentPlayer": 5,
  "numBoardCards": 0,
  "pendingDeal": "",
  "model": "example-model.onnx",
  "computeTimeMs": 20,
  "inferenceTimeMs": 9
}

PLO

PLO uses the PLO-specific bucket taxonomy pipeline, not the Holdem hands[] grid. Select it with hand.game_type: "plo4", "plo5", or "plo6".

Do not expect the v2 Holdem hands[] array to contain strategy data for PLO. PLO strategy is returned in ploStrategy, keyed by concrete PLO combo string.

PLO Input Fields

FieldTypeNotes
hand.game_typestring"plo4", "plo5", or "plo6". Controls hole-card count.
hand.game_mode_codestringUsually "normal".
hand.players[]arrayOmit hole_cards; the grid enumerates/samples PLO combos.
hand.actions.entries[]arraySame action/deal format. For normal PLO, only add board cards after a valid completed preflop sequence.
postProcess.ploSampling.perGroupintegerCurrent JSON route reads camelCase postProcess.ploSampling; default is 100.
postProcess.ploSampling.groupParentIdstringOptional taxonomy parent to sample within.
postProcess.ploSampling.fullIdstringOptional taxonomy group id to return in full, paged.
postProcess.ploSampling.fullOffsetintegerOptional page offset for fullId; page size is capped internally.
reach_query.target_seat_nointegerOptional. Seat whose replayed range reach should be reported. Defaults to current player.
reach_query.normalizestringOptional. "conditional" or "absolute".
reach_query.group_bystringOptional. "bucket" or "combo"; current response builder returns bucketed data.
reach_query.max_bucketsintegerOptional cap on returned reach buckets.
reach_query.max_examples_per_bucketintegerOptional cap on example combos per bucket.

The proto schema names post-processing as post_process.plo_sampling, but the current /strategy_grid PLO route reads the UI JSON spelling postProcess.ploSampling. Use the camelCase spelling for PLO sampling on this endpoint.

PLO Output Fields

FieldTypeNotes
taxonomyOnlybooleanPresent because the response includes taxonomy data. Check ploStrategy to see strategy results.
ploBucketTree[]arrayHierarchical taxonomy buckets.
ploBucketMapobjectConcrete combo string to bucket id.
ploMultiplicityobjectCombo string to suit-isomorphic multiplicity/weight. Sampling may scale this value.
ploBucketCountsobjectTrue combo count per leaf bucket when sampling is used.
sampledModebooleanPresent when sampling was applied.
fullTotalCountintegerPresent when fullId full-mode paging is used.
holeCardCountinteger4, 5, or 6.
hands[]arrayEmpty for PLO; do not consume this for PLO strategy.
ploStrategyobjectStrategy keyed by combo string. Each value has strategy, evs, ev, and optional reach.
ploReachobjectCombo-level reach map when reach computation runs.
reachResultobjectBucketed reach summary when reach_query is sent.
actionLabels[]arrayLegal action labels for interpreting the 11 strategy slots.
tableStateobjectPot, board, acting player, players, and acting context.
pendingDealstring"", "flop", "turn", or "river" when board cards are required.
currentPlayerintegerActing seat, or -1 if terminal/pending.
numBoardCardsintegerCount of board cards in the request/session.
modelstringSelected PLO model.
modelMd5stringSelected model checksum.
computeTimeMsintegerTotal service-side compute time.

PLO Request Example

{
  "protocol_ver": "v2",
  "strategy_min_threshold": 0.05,
  "hand": {
    "game_type": "plo4",
    "game_mode_code": "normal",
    "big_blind": 100,
    "small_blind": 50,
    "ante": 0,
    "dealer_seat": 5,
    "sb_seat": 0,
    "bb_seat": 1,
    "straddle_seat": -1,
    "players": [
      { "seat_no": 0, "stack": 10000 },
      { "seat_no": 1, "stack": 10000 },
      { "seat_no": 2, "stack": 10000 },
      { "seat_no": 3, "stack": 10000 },
      { "seat_no": 4, "stack": 10000 },
      { "seat_no": 5, "stack": 10000 }
    ],
    "rake_ratio_pct": 3,
    "rake_cap_bb": 3,
    "actions": { "entries": [] }
  },
  "postProcess": {
    "ploSampling": {
      "perGroup": 100
    }
  },
  "reach_query": {
    "target_seat_no": 2,
    "normalize": "conditional",
    "group_by": "bucket",
    "max_buckets": 10,
    "max_examples_per_bucket": 3
  }
}

PLO Output Example

{
  "taxonomyOnly": true,
  "holeCardCount": 4,
  "sampledMode": true,
  "ploBucketTree": [
    {
      "id": "made_hand",
      "label": "Made hand",
      "children": [
        { "id": "one_pair", "label": "One pair", "children": [] }
      ]
    }
  ],
  "ploBucketMap": {
    "AsAhKdQc": "one_pair"
  },
  "ploMultiplicity": {
    "AsAhKdQc": 124.0
  },
  "ploBucketCounts": {
    "one_pair": 8420
  },
  "hands": [],
  "ploStrategy": {
    "AsAhKdQc": {
      "strategy": [0.0, 0.42, 0.0, 0.58, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
      "evs": [-1.0, 2.4, 0.0, 3.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
      "ev": 2.806,
      "reach": 1.0
    }
  },
  "ploReach": {
    "AsAhKdQc": 1.0
  },
  "reachResult": {
    "normalization": "conditional",
    "range_buckets": [
      {
        "bucket": "one_pair",
        "mass": 1.0,
        "examples": [
          { "hand": "AsAhKdQc", "reach_prob": 1.0, "multiplicity": 124.0 }
        ]
      }
    ],
    "covered_mass": 1.0
  },
  "actionLabels": [
    { "index": 0, "slot": 0, "name": "fold", "rawAction": -1, "amount": null, "amountBb": 0.0, "raiseByBb": 0.0 },
    { "index": 1, "slot": 1, "name": "call 1.0 BB", "rawAction": 0, "amount": 100, "amountBb": 1.0, "raiseByBb": 0.0 },
    { "index": 2, "slot": 3, "name": "raise 3.0 BB", "rawAction": 300, "amount": 300, "amountBb": 3.0, "raiseByBb": 2.0 }
  ],
  "tableState": {
    "street": "preflop",
    "pot": 150,
    "chipsPerBb": 100,
    "board": [],
    "actingPlayer": 2
  },
  "currentPlayer": 2,
  "numBoardCards": 0,
  "pendingDeal": "",
  "model": "example-plo-model.onnx",
  "modelMd5": "example-md5",
  "computeTimeMs": 32
}