PokerDataGet an API key
Menu

Preflop action tree

How every preflop spot is addressed — the action-path grammar, tokens, and a worked walk of the tree.

The preflop API does not take a street, pot type, or free-text line. It takes an action path: an underscore-joined chain of POSITION_ACTION pairs that walks the solver tree in acting order. The same grammar is used for NLHE 6-max, PLO 6-max, and PLO 9-max. Only the raise tokens and hand notation change by game.

UTG_60%_HJ_Call
│   │   │  └─ …and HJ calls.        (path ends in an ACTION → names a range)
│   │   └─ then HJ…
│   └─ UTG raises to 60% (a size token)
└─ UTG acts first…

UTG_60%_HJ
          └─ path ends in a POSITION → names a decision node (HJ to act)

The two forms map onto the two lookup endpoints:

  • A path ending in an action names a single range — pass it as spot to /range.
  • A path ending in a position names a whole decision — pass it as history to /node.

Walking the tree

Think of the dataset as a tree of decision nodes. Each node belongs to one seat. Each legal action is an edge to the next node (or to a range at a terminal for that street).

A 6-max cash hand always starts UTG, then HJ, CO, BTN, SB, BB. Every seat that folds is written out. There is no BTN_60% shortcut for a button open — the folds in front are part of the address:

UTG_Fold_HJ_Fold_CO_Fold_BTN_60%

That string is a spot (ends in an action): UTG/HJ/CO folded, BTN opened 60%. To ask what BB should do facing that open, after SB folds:

history = UTG_Fold_HJ_Fold_CO_Fold_BTN_60%_SB_Fold_BB
spot    = UTG_Fold_HJ_Fold_CO_Fold_BTN_60%_SB_Fold_BB_Call

history ends on BB (BB to act). spot appends _Call (the Call range at that node).

NLHE 6-max

Raise sizes are percent of pot as they appear in the tree: 60%, 100%, plus Fold, Call, AI.

You wantPathEndpoint
UTG's RFI decisionUTG/node?history=UTG
UTG opens 60%UTG_60%/range?spot=UTG_60%25
HJ facing that openUTG_60%_HJ/node?history=UTG_60%25_HJ
HJ 3-bets 100%UTG_60%_HJ_100%/range?spot=UTG_60%25_HJ_100%25
BTN open after three foldsUTG_Fold_HJ_Fold_CO_Fold_BTN_60%/range?spot=…

% in size tokens must be encoded as %25 in the query string.

PLO 6-max / 9-max

Raises are labelled by betting depth, not a percent: Open, 3B, 4B, 5B, … plus Fold, Call, AI.

You wantPathEndpoint
UTG's RFI decisionUTG/node?history=UTG
UTG opensUTG_Open/range?spot=UTG_Open
HJ facing that openUTG_Open_HJ/node?history=UTG_Open_HJ
HJ 3-betsUTG_Open_HJ_3B/range?spot=UTG_Open_HJ_3B
BTN open after three foldsUTG_Fold_HJ_Fold_CO_Fold_BTN_Open/range?spot=…

When a node offers more than one raise size, the label carries a raw size id, e.g. Open-40100. Copy the exact token from /node — do not guess the suffix.

Action tokens

GameTokens
NLHE 6-maxFold, Call, AI (all-in), and raise sizes as percentages, e.g. 60%, 100%
NLHE MTT 8-maxFold, Call, Limp, AI, and raises by betting depth: Open, 3B, 4B, 5B. The chip raise-to is sizeBb on the action, not the token. See NLHE tournament (8-max).
PLOFold, Call, AI, and raises labelled by betting depth: Open, 3B, 4B, 5B, …

Two encoding rules matter in query strings:

  • Encode % in NLHE size tokens as %25 — UTG_60%_HJ_Call becomes spot=UTG_60%25_HJ_Call.
  • When a PLO node offers more than one raise size, the label carries a raw size id suffix, e.g. Open-40100. Never guess these — read the exact tokens from /node or /spots.

Betting depth

/spots tags every decision node with a depth for filtering:

DepthMeaning
1RFI — unraised pot
2Facing a single raise
33-bet pot
44-bet pot or deeper (capped at 4)

Depth counts raises made, not seats acted: a fold-around to a BTN open is still depth 1.

Discovery-first workflow

  1. Call the game discovery endpoint (/nl/v2, /nlmtt8, /plo, or /plo9) — keyless — for live stacks and positions. For 8-max MTT, also call keyless /nlmtt8/config?stack= for blinds, the BB ante, and open sizes.
  2. GET /spots?stack=100 for every valid history at that depth (and each row's depth).
  3. GET /node?stack=100&history=… for available_actions and the mixed strategy at that seat.
  4. Append one of those action tokens to build a spot, then GET /range.

Constructing common lines by hand (UTG open, BTN RFI after folds) works; anything with mixed raise sizes should come from step 3.

Hand notations

NLHE uses the 169-class grid: pairs (AA), suited (AKs), offsuit (AKo). Weights are per class in [0, 1]; the combos field is the weighted concrete-combo count (a pair is 6 combos, suited 4, offsuit 12).

PLO uses suit-grouping notation over the 16,432 four-card starting-hand classes:

ExampleMeaning
AAKKRainbow-agnostic AAKK — no suit constraints stated
(2A)AATrip aces with exactly two suited to the ace
(KA)(KA)Double-suited AK+AK

Encode the parentheses in query strings: ( → %28, ) → %29. So hand=(KA)(KA) is sent as hand=%28KA%29%28KA%29.

Common mistakes

SymptomCause
404 on a path you "know" existsMissing fold-arounds, wrong raise token, or that line is not in this stack's tree
400 malformed pathUnencoded %, or a token the grammar does not allow
Empty / huge PLO payloadOmit minFreq and the 16k-class range comes back in full
Guessing Open-40100Size-id suffixes are tree-specific; copy them from /node