Work in progress. Public API access is coming. Play Blitzfold in the meantime
DEVELOPER REFERENCE · PREVIEW

Equity Actions API

One endpoint for hand-aware Hold’em action probabilities and conditional bet sizing.

Public access is in progress. This reference describes the current endpoint contract. Self-service API keys and the updated SDK are not yet available. Play Blitzfold in the meantime ↗
POST/api/equity_actions

Make a decision request

Send the acting player’s exact hand and the public game state immediately before a decision. The API combines learned public-context action frequencies with equity-based allocation and returns an action distribution. Your application samples the action and applies its game rules.

This public reference covers equity actions only. Range tracking and range updates are not part of this endpoint.

Authentication

Call the API from your backend using JSON and an x-api-key header. Keep the key on the server, out of browser bundles and public repositories. Use the deployment origin supplied with your access as the base URL; append /api/equity_actions.

Content-Type: application/json
x-api-key: YOUR_SERVER_SIDE_API_KEY

Examples use HOLDEM_API_URL and HOLDEM_API_KEY as application environment variables. Public key generation and account access are coming later.

Request body

Send the following fields only. All numbers must be finite.

FieldDescription
policyRequired object containing schemaVersion, context, history, and legalMask.
policy.schemaVersionRequired literal: holdem-public-board-joint-v1.
policy.contextRequired array of exactly 316 encoded public features. See the encoding reference below.
policy.historyRequired chronological array of up to 512 events, each exactly 32 numbers. Include only events before the decision. An empty array is supported.
policy.legalMaskRequired [fold, passive, aggressive] array. Each value is 0 or 1, and at least one action must be allowed. Passive means call/check; aggressive means raise/bet. Use actual engine legality. Folding must be disabled when no bet is faced.
handRequired exact combo, such as AsAh. Ranks: 23456789TJQKA; suits: cdhs. Cards must differ and cannot overlap the board.
rangeOptional exact-combo map of nonnegative candidate weights for the actor. At most 1,326 entries; weights need not sum to 1, but their total must be finite. The actual hand must retain positive mass.
gateSlopeOptional finite number greater than 0 and at most 200; defaults to 20. Controls the steepness of the equity-based continuation and aggression gates.
styleOptional: tight-passive, tight-aggressive, loose-passive, or loose-aggressive. Requires a configured compatible style model. Omit to use the public policy.

Game-state encoding

The current wire format uses numeric vectors, not a raw game-state object. Keep seat IDs consistent across context and history. Use zero-based seat indexes 0–8 and street order preflop, flop, turn, river. The forthcoming SDK will be documented separately when its equity-actions integration is available.

Context · 316 values

Index (zero-based)Description
0–259Five 52-value board slots in board order. A present card is one-hot; an unused slot is all zeros. Card index = rankIndex × 4 + suitIndex, using ranks 23456789TJQKA and suits cdhs. Slots must be contiguous, without duplicate cards.
260–268Nine-value one-hot acting seat.
269–272Four-value one-hot street. Board length must match: 0, 3, 4, or 5 cards.
273–278Scaled potBB, facingBB, callBB, minRaiseToBB, maxRaiseToBB, and seatCount, in that order. Raise-to values are street totals, not additional payments.
279–314Nine seat records of four values: present (0/1), scaled remaining stackBB, scaled contributionBB on the current street, active (0/1). Absent seats use four zeros.
315Number of remaining active opponents divided by 9.

Apply Math.log1p(Math.max(0, value)) / Math.log1p(400) to every scaled value, including seatCount. Amounts before scaling are in big blinds. Do not scale one-hot fields, boolean flags, or the final opponent fraction.

History · 32 values per event

Index (zero-based)Description
0–8One-hot acting seat.
9–12One-hot street.
13–18One-hot action, ordered posts, folds, checks, calls, bets, raises.
19–22Scaled amountAddedBB, raiseToBB (0 when absent), livePostBB (0 when absent), deadPostBB (0 when absent). amountAddedBB is the payment added by this event.
23–31Scaled refunds after the event, one total per seat.

Use the same scaling function as context. Preserve all preceding events in order; do not include the action being predicted or future cards and outcomes. Histories longer than 512 events are rejected.

Server-side request example

This complete encoding example represents a heads-up preflop decision. Replace the state with your engine’s actual snapshot and configure your deployment URL and credential. It uses native fetch; it is not an SDK example.

// Server-side JavaScript. Illustrative heads-up preflop state:
// SB acts after posting 0.5 BB; BB has posted 1 BB.
const scale = (n) => Math.log1p(Math.max(0, n)) / Math.log1p(400);
const oneHot = (index, width) =>
  Array.from({ length: width }, (_, i) => Number(i === index));
const post = (seat, amount) => [
  ...oneHot(seat, 9), ...oneHot(0, 4), ...oneHot(0, 6),
  ...[amount, 0, amount, 0].map(scale), ...Array(9).fill(0),
];
const context = [
  ...Array(260).fill(0),           // No board cards preflop
  ...oneHot(0, 9),                // Actor: seat 0
  ...oneHot(0, 4),                // Street: preflop
  ...[1.5, 0.5, 0.5, 2, 100, 2].map(scale),
  1, scale(99.5), scale(0.5), 1,   // Seat 0
  1, scale(99), scale(1), 1,       // Seat 1
  ...Array(7 * 4).fill(0),         // Seven absent seats
  1 / 9,                         // One remaining opponent
];

const response = await fetch(
  new URL('/api/equity_actions', process.env.HOLDEM_API_URL),
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.HOLDEM_API_KEY,
    },
    body: JSON.stringify({
      policy: {
        schemaVersion: 'holdem-public-board-joint-v1',
        context,
        history: [post(0, 0.5), post(1, 1)],
        legalMask: [1, 1, 1],      // Fold, call, raise
      },
      hand: 'AsAh',
      gateSlope: 20,
    }),
  },
);
const result = await response.json();
if (!response.ok || !result.ok) {
  throw new Error(result.error ?? 'Decision request failed');
}
console.log(result.output, result.sizes, result.weights);

Response & sizing

Facing a bet, output contains fold, call, and raise. Otherwise it contains check and bet. Probabilities sum to one, with illegal actions at zero.

// Illustrative response excerpt, not a complete response
{
  "ok": true,
  "hand": "AsAh",
  "equity": 0.84,
  "facingBet": true,
  "output": { "fold": 0.02, "call": 0.26, "raise": 0.72 },
  "population": { "fold": 0.40, "passive": 0.35, "aggressive": 0.25 },
  "gateSlope": 20
}
FieldDescription
ok / requestIdSuccess flag and request identifier.
hand / equity / facingBetCanonical acting hand, its uniform heads-up equity benchmark (0–1), and whether a bet is faced.
outputFinal action probabilities for the actual hand. No action is sampled by the API.
populationOriginal model targets: fold, passive, aggressive, before hand-specific equity allocation.
sizes / weightsParallel arrays of size labels and conditional aggression probabilities. Sample from these only after choosing bet or raise. Weights sum to one.
gateSlope / styleThe gate slope used, and the requested style when supplied.
expectedValuesSimplified showdown benchmark in BB, including assumptions, action output, and per-size paymentBB/evBB. Illegal or unusable values can be null. This is not a strategic EV prediction.
learnedExpectedValuesOptional experimental server-configured output. Predicts historical observed-action returns from public context; alternative-action scores are not validated counterfactual EVs. Does not change the policy.

Size classes

["22%", "34%", "47%", "63%", "85%", "112%", "147%", "200%", "280%+", "all-in"]

Percentages mean chips paid this action divided by the pot before the action. They are not raise-to totals. The 280%+ class is open-ended; all-in is a separate class. Convert the sampled size to a legal payment in your engine, enforcing minimum raises, reopening, stack limits, rounding, and side pots.

Expected-value assumptions

The showdown benchmark uses uniform heads-up equity, one opponent always calling aggression, no future betting, no rake, and no side pots. Checking assumes a free showdown; the open-ended size uses 280% as its representative amount. It does not estimate fold equity or changes in calling ranges. Do not replace the returned action policy with these estimates.

Ranges & equity allocation

The optional range is the acting player’s candidate population, not the opponent’s range. Board-blocked combos are removed and reversed card order is canonicalized. Do not send opponents’ actual cards. Do not reduce the candidate population to only the actual hand: that removes equity differentiation.

Omitting range uses equally weighted physical combos compatible with the board. This population is not conditioned on preceding action history. The endpoint does not return an updated range.

Candidate equities use a uniform heads-up opponent benchmark, not opponent-range-specific or multiway equity. Continuation and aggression gates assign stronger-equity hands less folding and more aggression while matching the model’s weighted population targets. Equal-equity hands receive equal probabilities; passive probability can peak in the middle. Sizing itself is not equity-gated. This policy is not a guarantee of optimal or profitable play.

Errors

HTTP / codeDescription
400 BAD_REQUESTInvalid JSON, unsupported fields, wrong vector sizes, inconsistent board/street, invalid hand, legal mask, range, style, or gate slope. Fix the request before retrying.
401 UnauthorizedMissing or invalid x-api-key. Authentication failures use an error field and may not include ok or requestId.
502 EQUITY_UNAVAILABLEThe equity dependency failed or returned invalid/incomplete results. Placeholder equity is not returned.
503 MODEL_UNAVAILABLEThe required public or style model is missing or unusable.
503 ACTION_VALUE_MODEL_UNAVAILABLEAn explicitly enabled experimental action-value model could not be used.
503 authentication unavailableServer-side API authentication is not configured. The response contains an error message.
{
  "ok": false,
  "requestId": "request-identifier",
  "error": "BAD_REQUEST",
  "message": "Supplementary validation detail"
}

Endpoint errors include ok: false, requestId, and error; message is optional. Inspect the HTTP status as well as the body. Handle failures explicitly rather than treating them as decisions.

COMING WITH PUBLIC ACCESS

JavaScript & TypeScript SDK

A server-side SDK will be available for integrating equity actions into your application. The existing SDK targets Node.js 20+, provides TypeScript declarations, and has no runtime dependencies.

Not yet available for this endpoint. The current SDK targets earlier API contracts and is not published on npm. Equity-actions support, the public package name, installation instructions, and supported methods will be documented here when ready.

For now, the HTTP request above is the integration reference. Keep API calls and credentials on your backend.

Back to HoldemAPI