pokerai.bet API 文档
两套扑克 API,同一把 key 与配额:GTO 策略 API(/v1/gto/*,preflop/flop/turn/river 全街,返回每个动作的混合频率)+ Poker 引擎 / 语义 API(/v1/pokerkit/*,牌面/评牌/听牌/范围权益/牌局模拟)。两套都在交互式参考里。
GTO 策略 API · 两种获取方式:① 预解方案——preflop / flop 用预先算好的 GTO 数据,毫秒级返回;② 实时求解器计算——flop / turn / river 由求解器实时计算(从 flop 开始耗时较长)。另有 范围转换 沿行动线更新范围。
适用范围:当前仅支持 6 人桌(6-max) 与 100BB 起始有效栈。更多人数与后手深度即将上线。
无状态 / 自包含请求:每次请求相互独立,服务端不保存牌局状态,也不要求你先调用前面的街——可直接查询任意局面,只需给齐该局面所需信息。
两套 API,同一把 Key:本页是 GTO 策略 API(/v1/gto/*)。另有 Poker 引擎 / 语义 API(/v1/pokerkit/*:牌面 texture、成手/听牌/补牌/阻断、范围权益、评牌、ICM、牌局模拟…),复用同一 API key 与配额(便宜端点扣通用配额、蒙特卡洛扣 solve 配额)。两套都在交互式参考里(顶栏切换),其文档/规范见 /v1/pokerkit/docs · openapi.json(随代码自动同步)。
牌面 / 手牌格式(统一):所有端点的 board 与 hole_cards 输入都用无分隔字符串(每张牌 2 字符:点数 AKQJT98765432 + 花色 c d h s),如 "board": "2c2h2s"、"hole_cards": "AdKd"。响应里 board 统一返回数组,如 ["2c","2h","2s"]。
范围记法:oop_range / ip_range 等范围串是逗号分隔的 手牌:权重。手牌用类别记法——对子 AA、同花 AKs、非同花 AKo(大点在前);权重 0~1,省略默认 1。例:"AA:1,KK,AKs:0.5,72o:0.1"。注:range_strategy 的键与 range_*_new_raw 用具体组合记法(如 "AhKh")。
机器可读规范:OpenAPI 3.0 spec —— 可导入 Postman / Insomnia,或用 openapi-generator 生成各语言客户端。交互式参考:在线 API 参考(可直接试一试) —— 填入 Key 即可逐端点发请求(会消耗真实配额)。
鉴权
所有请求需携带 API Key。60 秒拿到 Key:
- 打开 控制台,输入邮箱 → 收验证码邮件(免密登录,无需注册)。
- 填验证码登录 → 新建 API Key → 复制(仅显示一次,请妥善保存)。
- 设为环境变量:
export POKERAI_API_KEY=gto_xxxxxxxx,即可跑下方 Quickstart。
之后每个请求都带上同一把 Key(就是上一步复制的 gto_xxx,也就是各处说的 “Bearer token”)放进请求头。下面两种写法二选一即可——不是两把 key:
Authorization: Bearer gto_xxxxxxxx # 标准写法(推荐;对应 OpenAPI 安全方案 BearerApiKey)
# 或(完全等价,二选一)
X-API-Key: gto_xxxxxxxx # 等价(OpenAPI 安全方案 XApiKey);某些网关 / SDK / 快速测试工具更顺手
配额
两类每月配额,分开计量、每月 1 日重置,当前用量见控制台:
- 通用配额(默认 100 次/月):preflop、preflop 整段范围、flop 决策树取树、范围转换
/v1/gto/range、flop 投影范围 各扣 1 次。 - solve 配额(默认 100 次/月):实时求解器
/v1/gto/solver每触发一次新求解扣 1 次;复用缓存解、取树/取节点均不扣费(响应有solve_quota字段=已扣,无=未扣)。
错误模型
所有错误返回统一 JSON:{ "error": "<code>", "message": "<说明>" }。少数变体:部分 502 用 reason 代替 message;求解器全忙的 429 形如 { "status": "busy", "message": ... }。各端点的特有 error 取值见对应端点的「可能的错误」小表;通用状态码如下:
| HTTP | error / 含义 | 是否重试 |
|---|---|---|
| 400 | 输入不合法或缺字段(具体 error 见各端点小表)。 | 否,改正输入 |
| 401 | missing_api_key / invalid_api_key:缺少或无效 Key。 | 否,检查 Key |
| 403 | invalid_node_token / invalid_solve:令牌/句柄无效或非本人。 | 否,先重新取树/调度 |
| 404 | no_solution:该局面暂无 GTO 数据。 | 否,换局面 |
| 429 | quota_exceeded(通用)/ solve_quota_exceeded(solve):本月配额用尽。 | 否,下月 1 日重置或升级额度 |
| 429 | status: busy:求解器全忙(仅 /v1/gto/solver),不扣费。 | 是,退避后重试 |
| 502 | no_result(reason: timeout / no_worker_available)/ auth_unavailable / solver_unreachable:后端瞬时不可用。 | 是,退避重试 2–3 次 |
错误响应体示例
400(输入不合法):
{
"error": "invalid_board",
"message": "board must be 3 cards, e.g. \"2c2h2s\""
}
401(缺少 Key)/ 404(无数据)/ 429(配额用尽)——单字段或短消息:
{ "error": "missing_api_key" }
{ "error": "no_solution", "message": "no GTO data for this spot/board" }
{ "error": "quota_exceeded" }
502(后端瞬时不可用,可重试):
{
"error": "no_result",
"reason": "timeout"
}
重试:只有 429 busy 与 502 值得重试——指数退避(~1s 起翻倍,最多 2–3 次)。其余(400/401/403/404/配额用尽)是终态,重试无用:改正输入 / 换 Key / 重新取树,或等配额每月 1 日重置。无每秒限流,故无 Retry-After 头。
Quickstart
拿到 Key 后(见上),复制这条 curl(把 $POKERAI_API_KEY 换成你的)——最简单的一次成功调用:Hero UTG 开池机会(RFI),preflop 毫秒级返回:
curl -s https://pokerai.bet/v1/gto/preflop \
-H "Authorization: Bearer $POKERAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"hole_cards":"AhKh","positions":{"hero":"UTG"},"preflop_actions":[{"position":"SB","action":"small blind","amount":0.5},{"position":"BB","action":"big blind","amount":1}]}'
真实返回(UTG 用 AKs,开池机会 → 100% 开池到 3BB):
{
"hole_cards": "AhKh",
"situation": "RFI",
"strategy": [
{ "action": "raise", "frequency": 1, "amount_bb": 3, "sizing_pot": 0.8 }
],
"quota": { "used": 6, "limit": 100 }
}
面对别人加注?把对方动作加进 preflop_actions 即可(追加 {"position":"UTG","action":"raise","amount":3}、Hero 改 MP → 变成 3bet 局面,situation 返回 Raise)。返回每个动作的混合频率(不返回推荐动作,按 frequency 自行选择)。下面按 预解方案(preflop / flop)、实时求解器计算、范围转换 三块展开。
客户端 SDK Python · TypeScript · MCP
不想手写 HTTP?官方客户端从 OpenAPI 规范 自动生成、全类型化,和 API 永远同步。鉴权就是你的 API Key。
Python pip
pip install pokerai-bet # 分发名 pokerai-bet,导入名 pokerai
同一个 Quickstart 局面(Hero UTG 开池),类型化调用:
from pokerai import AuthenticatedClient
from pokerai.api.lookup import preflop_strategy
from pokerai.models import (
PreflopRequest, PreflopRequestPositions, PreflopRequestPreflopActionsItem,
)
from pokerai.models.preflop_request_preflop_actions_item_action import (
PreflopRequestPreflopActionsItemAction as Act,
)
from pokerai.models.position import Position
client = AuthenticatedClient(base_url="https://pokerai.bet", token="gto_...")
resp = preflop_strategy.sync(client=client, body=PreflopRequest(
hole_cards="AhKh",
positions=PreflopRequestPositions(hero=Position.UTG),
preflop_actions=[
PreflopRequestPreflopActionsItem(position=Position.SB, action=Act.SMALL_BLIND, amount=0.5),
PreflopRequestPreflopActionsItem(position=Position.BB, action=Act.BIG_BLIND, amount=1.0),
],
))
print(resp.to_dict())
真实输出(与 Quickstart 同一局面):
{"hole_cards": "AhKh", "situation": "RFI",
"strategy": [{"action": "raise", "frequency": 1, "sizing_pot": 0.8, "amount_bb": 3}],
"quota": {"used": 2702, "limit": 100000}}
TypeScript / JavaScript npm
npm install @pokerai/client
import { createPokeraiClient } from "@pokerai/client";
const client = createPokeraiClient({ apiKey: "gto_..." });
const { data, error } = await client.POST("/v1/gto/preflop", {
body: {
hole_cards: "AhKh",
positions: { hero: "UTG" },
preflop_actions: [
{ position: "SB", action: "small blind", amount: 0.5 },
{ position: "BB", action: "big blind", amount: 1 },
],
},
});
if (error) throw new Error(JSON.stringify(error));
console.log(data.situation, data.strategy);
// "RFI" [{ action: "raise", frequency: 1, amount_bb: 3, sizing_pot: 0.8 }]
路径、请求体、响应字段全程类型检查——编辑器自动补全整套 API。类型由 openapi-typescript 从规范生成,运行时是 openapi-fetch。
MCP(给 LLM agent)npm
让 Claude / Cursor 等把 Pokerai API 直接当工具调用(@pokerai/mcp):
// mcp.json
{ "mcpServers": { "pokerai": {
"command": "npx", "args": ["-y", "@pokerai/mcp"],
"env": { "POKERAI_API_KEY": "gto_..." }
}}}
默认 5 个预解查询工具;加 "POKERAI_ENABLE_SOLVE": "1" 开启实时求解工具(消耗 solve 配额)。
概念
整体心智模型——先看这一遍,往下读各端点会更顺。
两种获取方式
- 预解方案(presolved solutions):preflop / flop 用预先算好的 GTO 数据,毫秒级返回,适合需要短时返回的业务。
- 实时求解器计算:flop / turn / river 由求解器实时算(flop 约 70 秒,turn/river 较快),适合任意自定义范围/局面。
- 范围转换:沿一条行动线把范围更新成进入下一条街的范围,再喂给求解器。
不返回推荐动作
所有策略都返回每个动作的混合频率(0~1),不替你选动作——你按 frequency 自行实现(取最大概率,或按频率随机)。
下注尺度:amount_bb 与 sizing_pot
每个 bet/raise 带两个尺度字段:amount_bb(绝对额,加注到多少 BB)与 sizing_pot(相对底池的数值,标准 % 底池口径):
- bet(首注) = 下注 ÷ 底池。
- raise(面对下注) = (加注到 − 当前注) ÷ 跟注后的底池。
例:3bet 到 9 面对 open 3 —— 底池 4.5,跟注后 4.5+3=7.5,加注超出 9−3=6,sizing_pot = 6/7.5 = 0.8。全下时另带 allin: true。
tree → node(取树 → 取节点)
flop 决策树和实时求解器都是两步:先取整棵树(每个决策节点带一个 token),再用 Hero 节点的 token 取该步策略。
取树 /flop/tree 或 /solver(+ 轮询 /solver/tree)
└─→ nodes[]:每个节点带 is_hero + token
└─→ 选 is_hero:true 的节点
取节点 /flop/node 或 /solver/node (body 带该节点 token)
└─→ 这一步的混合策略
- flop:
/flop/tree(扣 1)→/flop/node(免费)。root节点 = Hero 第一个决策。 - solver:
/solver调度返回solve句柄(扣 1)→/solver/tree轮询 +/solver/node(都免费)。范围只在调度给一次,不重复传。
节点路径记法(两套,取决于树的来源):flop 决策树用 BET_8(下划线、整数 BB);solver 树用 BET 8.000000(空格、6 位小数)。传 node_id / 导航时要和那棵树(或 solver_results)里的标签逐字一致。
节点状态机(实时求解)
调度后轮询 /solver/tree 的 spot_status:available(未调度)→ computing(求解中,继续轮询)→ queryable(可取节点)→ expired(缓存按 TTL 回收,需重新调度)。无需也无法手动释放计算资源。
预解方案 presolved · 毫秒级
preflop 与 flop 使用预先算好的 GTO 策略,毫秒即返回,适合需要短时返回的业务场景。有效栈固定 100BB(已预先算好,非输入项)。想对 flop 用真实求解器实时算,见下一节。
Preflop
POST https://pokerai.bet/v1/gto/preflop 扣 1 通用
完整参数 / 响应 schema、在线试一试 → 交互式参考。
不需要你判断“几bet池”——按顺序给出 Hero 之前的翻前动作,服务端自动推导局面(未开池/面对加注/3bet/4bet…)。
说明 · 请求体
| 字段 | 类型 | 说明 |
|---|---|---|
hole_cards | string | Hero 的 2 张手牌,如 "AdKd"。 |
positions.hero | string | Hero 位置,SB BB UTG MP CO BTN 之一(放在 positions 下)。 |
preflop_actions | array | 从小盲到 Hero 之前一位玩家的完整、显式动作序列(Hero 不在序列中,其位置由 positions.hero 给出,序列止于 Hero 前一位)。每项 { position, action, amount, allin? },见下表。 |
preflop_version | string | 可选。选用哪套 6max 翻前策略图表:6max(默认)/ 6max_RC_100bb_200NL / 6max_RC_100bb_100NL / 6max_RC_40bb。省略=平台默认(6max);未知值 → 400 unsupported_preflop_version。同一局面不同版本频率不同。 |
preflop_actions 每项字段
| 字段 | 类型 | 说明 |
|---|---|---|
position | string | 该动作所在位置,SB BB UTG MP CO BTN 之一。 |
action | string | ∈ "small blind" / "big blind" / "raise" / "call" / "fold"(注意盲注是两个单词的字符串)。 |
amount | number | 该动作新投入的增量(BB,不是累计总额)。例:小盲 0.5;大盲 1;开池加注到 3 → amount 3(从 0 起);已投入 1 的玩家再加注到 9 → amount 8。fold 省略(记 0)。底池 = 所有 amount 之和。 |
allin | boolean | 可选。标记一次短码全下(下注/跟注额低于最小加注额);为 true 时跳过最小加注校验。 |
校验(违反 → 400 invalid_actions):序列必须以 small blind(0.5)、再 big blind(1)开头;每个 raise/call 需正的 amount;raise 的累计总额须大于当前注额且满足最小加注额(= 当前注额 + 上一次加注的幅度;故开池 ≥ 2BB,对 open-to-3 的 3bet 须 ≥ 5BB)——除非 allin:true;call 的累计总额须恰好等于当前注额——除非 allin:true。
精确金额只影响底池 / sizing_pot,不影响频率:给出精确的 amount 只是让 底池 / sizing_pot 精确;GTO 频率是按局面(RFI / 3bet / 4bet + 位置)决定的,不随下注尺寸变化。
调用示例
curl -s https://pokerai.bet/v1/gto/preflop \
-H "Authorization: Bearer $POKERAI_API_KEY" -H "Content-Type: application/json" \
-d '{"hole_cards":"AhKh","positions":{"hero":"MP"},"preflop_version":"6max_RC_100bb_200NL",
"preflop_actions":[{"position":"SB","action":"small blind","amount":0.5},
{"position":"BB","action":"big blind","amount":1},
{"position":"UTG","action":"raise","amount":3}]}'
省略 preflop_version = 默认 6max。可选版本见下,或用 GET /v1/gto/preflop/versions 实时查询。
响应(200)
{"hole_cards": "AhKh", "situation": "Raise", "strategy": [{"action": "raise", "frequency": 1, "amount_bb": 9, "sizing_pot": 0.8}], "quota": {"used": 7, "limit": 100}}
| 字段 | 说明 |
|---|---|
hole_cards | 回显的手牌。 |
situation | 轮到 Hero 时牌桌面对的状态:RFI(无人入池,Hero 开池机会)/ Limp(有人 limp、无加注)/ Raise(面对 1 个开池加注)/ 3-Bet / 4-Bet / 5-Bet。注:BB 永远落 Limp(它行动前必有人入池)。 |
strategy[] | 每个动作的混合策略。raise 带 amount_bb(加注到的绝对额,BB)与 sizing_pot(见 下注尺度)。preflop 的 amount_bb 按 Hero 之前的加注次数给定,见下表。不返回推荐动作,按 frequency 自行选择。 |
quota | 本月通用配额用量(used / limit)。 |
preflop amount_bb(由 flop 预解方案底池推导,加注到):
| Hero 之前加注次数 | 局面 | amount_bb |
|---|---|---|
| 0 | 开池 | 3 |
| 1 | 3bet | 9 |
| 2 | 4bet | 25 |
| ≥3 | 5bet+ | 全下 100(allin: true) |
可选策略版本 preflop_version
同样 6max,可选不同策略图表(同一局面频率不同);省略=默认 6max。权威列表用发现端点 GET /v1/gto/preflop/versions 实时查(免费,返回 id+标签+默认):
id(传给 preflop_version) | 说明 |
|---|---|
6max(默认) | 6 max 100bb Deepsolver |
6max_RC_100bb_200NL | 6 max 100bb GG 200NL 3b/f 2.2x - 2.5x |
6max_RC_100bb_100NL | 6 max 100bb GG 100NL 3b/f |
6max_RC_40bb | 6 max 40bb GG 100NL |
curl -s https://pokerai.bet/v1/gto/preflop/versions -H "Authorization: Bearer $POKERAI_API_KEY"
// {"versions": [{"id": "6max", "label": "6 max 100bb Deepsolver", "default": true}, …], "default": "6max"}
可能的错误
| HTTP | error | 触发 / 怎么修 |
|---|---|---|
| 400 | invalid_hole_cards | hole_cards 不是 2 张牌(如 "AdKd")。 |
| 400 | unsupported_table_size / invalid_positions / invalid_actions | 桌型(当前仅 6max)、hero/位置、或 preflop_actions 不合法。 |
| 400 | unsupported_preflop_version | preflop_version 不在允许集合(6max / 6max_RC_100bb_200NL / 6max_RC_100bb_100NL / 6max_RC_40bb)。 |
| 404 | no_solution | 该 preflop 局面无预求解数据,换局面。 |
整段范围(13×13) 扣 1 通用
POST https://pokerai.bet/v1/gto/preflop/range · 同一局面(位置 + 行动线)的**整张 13×13 范围**,一次返回 169 个手型的 fold/call/raise。不传 hole_cards(局面由 positions + preflop_actions 决定)。计费 1 次通用(一次返回,不是 169 次)。用于画范围表。
// 请求(不传 hole_cards)
{"table_size": "6max", "positions": {"hero": "BTN"}, "preflop_actions": [{"position": "SB", "action": "small blind", "amount": 0.5}, {"position": "BB", "action": "big blind", "amount": 1}, {"position": "UTG", "action": "fold"}, {"position": "MP", "action": "fold"}, {"position": "CO", "action": "fold"}]}
// 响应
{ "range": {"22": {"fold": 0.69, "call": 0, "raise": 0.31}, "33": {"fold": 0, "call": 0, "raise": 1}, "ATs": {"fold": 0, "call": 0, "raise": 1}, "AKs": {"fold": 0, "call": 0, "raise": 1}, "AKo": {"fold": 0, "call": 0, "raise": 1}, "KQs": {"fold": 0, "call": 0, "raise": 1}, "72o": {"fold": 1, "call": 0, "raise": 0}, "JJ": {"fold": 0, "call": 0, "raise": 1} , …共 169 项… },
"quota": {"used": 7, "limit": 100} }
手型记法:对子 AA、同花 AKs、杂色 AKo(高牌在前);每项 fold+call+raise≈1。完整 schema / 在线试一试 → 交互式参考。
Flop 决策树
flop 策略是一棵决策树:先取树(拿到全部决策节点 + 每个节点的 token),业务系统按实际下注在树上走路径,到 Hero 的节点再取该步策略。两步,和 solver 一致(tree → node)。
① 取决策树 扣 1 通用
POST https://pokerai.bet/v1/gto/flop/tree · 输入 board + pot_type + positions(不需要 hole_cards,树与手牌无关)。
完整参数 / 响应 schema、在线试一试 → 交互式参考。
board | 翻牌 3 张,如 "2c2h2s"。 |
pot_type | "SRP" 单加注 / "3BET" / "4BET" / "LIMP" 跛入。 |
positions | 各角色位置(SB BB UTG MP CO BTN),按 pot_type 要求见下。 |
flop_version | 可选。选用哪套 flop 数据集(每个 preflop 版本各解一套):6max(默认)/ 6max_RC_100bb_200NL / 6max_RC_100bb_100NL / 6max_RC_40bb。省略=默认 6max;该版本无此 spot 数据时优雅降级到 6max;未知值 → 400 unsupported_flop_version。与 preflop_version 相互独立。node token 会带上此版本,故 /v1/gto/flop/node 保持同一数据集。 |
| pot_type | 必填位置 | Hero 取值 |
|---|---|---|
SRP | hero, raiser, caller | raiser 或 caller |
3BET / 4BET | hero, raiser, three_bettor | raiser 或 three_bettor |
LIMP | hero, limper | Hero 或 limper 必有一个是 BB |
// 请求(不需要 hole_cards)
{"board": "2c2h2s", "pot_type": "SRP", "positions": {"hero": "UTG", "raiser": "UTG", "caller": "BTN"}}
// 响应(nodes 共 36 个,此处示前 5)
{"board": ["2c", "2h", "2s"], "pot_type": "SRP", "pot": 7.5, "effective_stack": 97, "oop_range": "AA:1,AKs:1,AQs:1,AJs:1,ATs:1,A9s:1,A8s:1,A7s:1,A6s:1,A5s:1,…", "ip_range": "AQs:0.05,AJs:0.86,ATs:0.436,A9s:0.356,A8s:0.36,A7s:0.196,…", "node_count": 36, "nodes": [{"node": "root", "is_hero": true, "token": "eyJ…"}, {"node": "root/BET_4", "is_hero": false, "token": "eyJ…"}, {"node": "root/BET_8", "is_hero": false, "token": "eyJ…"}, {"node": "root/BET_97", "is_hero": false, "token": "eyJ…"}, {"node": "root/CHECK", "is_hero": false, "token": "eyJ…"}, …], "quota": {"used": 7, "limit": 100}}
| 字段 | 说明 |
|---|---|
oop_range / ip_range | 本局面的起手范围(加权组合串),用于范围转换的起手权重。 |
nodes[] | 全部决策节点:node(动作路径,如 "root/CHECK/BET_8")、is_hero(是否 Hero 决策点)、token(取该节点策略的凭证,传给 ②;绑定账号+局面,不可伪造)。 |
pot / effective_stack / node_count | 底池、有效栈(BB)与决策节点总数。 |
quota | 本月通用配额用量(used / limit)。 |
② 取某节点策略 免费
POST https://pokerai.bet/v1/gto/flop/node · 带 node(①里某节点的 token)。带 hole_cards → 这手牌的混合策略;不传 hole_cards → 整段范围策略。
完整参数 / 响应 schema、在线试一试 → 交互式参考。
Hero 的每个决策都走这里:Hero 第一个行动 = root 节点(OOP 先手 check/bet);Hero 在 IP、面对下注、或第二次行动,就选对应的 is_hero:true 节点(如 root/CHECK/BET_8 = 我过牌后面对下注 → fold/call/raise)。翻牌树是单街;跨街(转牌/河牌)走 /v1/gto/solver/*。
// 请求(Hero 节点,带手牌) -> Hero 策略
{"node": "eyJ…", "hole_cards": "AdKd"}
{"hole_cards": "AdKd", "node": "root", "is_hero": true, "strategy": [{"action": "check", "frequency": 0.7208}, {"action": "bet", "amount_bb": 4, "sizing_pot": 0.5333, "frequency": 0.0533}, {"action": "bet", "amount_bb": 8, "sizing_pot": 1.0667, "frequency": 0.2259}, {"action": "bet", "amount_bb": 97, "sizing_pot": 12.9333, "allin": true, "frequency": 0}]}
// 请求(不传 hole_cards) -> 整段范围策略
{"node": "eyJ…"}
{"node": "root/BET_4", "is_hero": false, "actions": [{"action": "call"}, {"action": "raise", "amount_bb": 12, "sizing_pot": 0.5161}, {"action": "raise", "amount_bb": 20, "sizing_pot": 1.0323}, {"action": "raise", "amount_bb": 97, "sizing_pot": 6, "allin": true}, {"action": "fold"}], "range_strategy": {"3d3c": [0.93067, 4e-05, 0.06922, 1e-05, 7e-05], "3h3c": [0.92172, 6e-05, 0.07812, 1e-05, 0.0001], "3h3d": [0.94334, 4e-05, 0.05655, 1e-05, 7e-05], "…": "共 188 手"}, "range_hand_count": 188}
| 字段 | 说明 |
|---|---|
is_hero | 该节点是否轮到 Hero 决策。 |
strategy[] | Hero 节点(带 hole_cards):这手牌的混合策略。action ∈ check / bet / call / raise / fold(bet=首注、raise=面对下注的加注);bet/raise 带 amount_bb 与 sizing_pot(见 下注尺度),全下另带 allin: true;frequency 为 0~1 概率。不返回推荐动作,按 frequency 自行选择。 |
actions[] + range_strategy | 对手节点(或不传 hole_cards):整段范围策略,每手牌频率对齐 actions;含 range_hand_count。可用于「范围转换」组装 solver_results。 |
节点 id 里的 BET_8 / RAISE_20 即绝对下注额(BB)。
可能的错误
| HTTP | error | 触发 / 怎么修 |
|---|---|---|
| 400 | ① invalid_board / invalid_positions;② missing_node / invalid_hole_cards | ① board 非 3 张、或 hero/位置不合法;② 缺 node 或 hole_cards 非 2 张。 |
| 403 | invalid_node_token | (②)node 令牌无效或非本人——先调 /v1/gto/flop/tree 取树。 |
| 404 | no_solution | 该局面/棋盘无预求解数据。 |
下载:tree_request.jsontree_response.jsonnode_request.jsonnode_response.json
实时求解器计算 solver
POST https://pokerai.bet/v1/gto/solver 系列。纯 postflop 求解器实时计算,走独立的 solve 配额。输入即解的本质:牌面 + oop/ip 范围 + 底池 + 后手筹码 + 谁是 Hero,不需要历史,可从任意局面切入。三步:调度 → 轮询取树 → 取节点策略。
完整参数 / 响应 schema、在线试一试 → 交互式参考(含 /solver/tree、/solver/node)。
board 长度定街:3=flop / 4=turn / 5=river。⚠ 从 flop 开始实时求解耗时较长(实测 SRP 翻牌约 70 秒),不适合需要短时返回的业务场景——flop 想要快,请用上面的「预解方案」(毫秒级);turn / river 较快(数秒到数十秒)。
调用示例(三步:① 调度 → ② 轮询取树 → ③ 取节点)
# ① 调度(board 3/4/5 = flop/turn/river;flop 约 70 秒)
curl -s https://pokerai.bet/v1/gto/solver -H "Authorization: Bearer $POKERAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"board":"2c2h2s","oop_range":"AA,KK,QQ,AKs","ip_range":"JJ,TT,AQs,KQs","pot":7.5,"effective_stack":97,"hero":"OOP"}'
# ② 轮询取树,直到 spot_status=queryable;③ 取节点
curl -s https://pokerai.bet/v1/gto/solver/tree -H "Authorization: Bearer $POKERAI_API_KEY" \
-H "Content-Type: application/json" -d '{"solve":"eyJ...<上一步 solve>"}'
① 调度求解 扣 1 solve
board | 3=flop / 4=turn / 5=river,如 "2c2h2s9d"(turn)。 |
oop_range / ip_range | 必填。进入该街的双方范围,加权组合串,如 "AsKs:1,QQ:0.75,..."。 |
pot / effective_stack | 必填。进入该街的底池与后手有效栈(BB),决定下注档,必须真实。 |
hero | 必填:"OOP" 或 "IP"。 |
bet_sizes | 可选:覆盖各街下注档,如 {"flop":[33,75],"turn":[33,67,120],"river":[33,75,150]}(底池%);flop 不传默认 50%。 |
// 请求(flop 例)
{"board": "2c2h2s", "oop_range": "AA,KK,QQ,AKs", "ip_range": "JJ,TT,AQs,KQs", "pot": 7.5, "effective_stack": 97, "hero": "OOP"}
// 响应(首次触发求解,扣 1 solve)
{"status": "computing", "solve": "eyJ0Ijoic2x2XzJmMjk2MWU3Y2Y0ODU3OGUiLCJ1IjoiYjk4Y2Y5NzAtZTVjMS00Njk5LTg4ODQtOGQzYzcwMGIyNGJlIiwidHMiOjE3ODIxMjkxMTUyMDJ9.rtmeNcZoBNWJRhkAGkTSSR58ZafpAh35mi510bgPU6c", "solve_quota": {"used": 1, "limit": 100}}
| 字段 / 情况 | 说明 |
|---|---|
solve | solve 句柄,后续 /tree 与 /node 用它;范围只在这一步给一次。 |
status = computing | 已触发新求解,扣 1 solve 配额(见 solve_quota)。 |
status = queryable | 同一局面已有缓存解,不扣费(无 solve_quota 字段),直接轮询 /tree。 |
429 status = busy | 所有求解器都在忙,不扣费,稍后重试。 |
缓存命中(不重复扣费):同一局面(相同 board/范围/底池/筹码/hero/bet_sizes)重复调度不再扣 solve 配额——响应里没有 solve_quota 字段即表示未扣费,直接用返回的 solve 句柄轮询 /tree。示例:request / response。
② 取决策树 + 节点状态 免费
POST https://pokerai.bet/v1/gto/solver/tree · 带 solve 句柄,轮询直到 spot_status = queryable。取后续街道的策略:带上已发的牌 —— turn_card(flop 解 → 指定 turn)和/或 river_card。flop 解取 river 需同时传 turn_card + river_card(光给 river 不唯一);turn 解只需 river_card;都不传则取本街。
// ② 取本街(flop)树
{"solve": "eyJ…"}
{"street": "flop", "spot_status": "queryable", "pot": 7.5, "effective_stack": 97, "solve_seconds": 25.84, "node_count": 14, "nodes": [{"node": "root", "is_hero": true, "status": "queryable", "token": "eyJ…"}, {"node": "root/BET 4.000000", "is_hero": false, "status": "queryable", "token": "eyJ…"}, {"node": "root/BET 4.000000/RAISE 12.000000", "is_hero": true, "status": "queryable", "token": "eyJ…"}, …]}
// 取 turn 树(flop 解 + turn_card)
{"solve": "eyJ…", "turn_card": "9d"}
{"street": "turn", "spot_status": "queryable", "pot": 7.5, "effective_stack": 97, "solve_seconds": 25.84, "node_count": 104, "nodes": [{"node": "root/BET 4.000000/CALL/9d", "is_hero": false, "status": "queryable", "token": "eyJ…"}, {"node": "root/BET 4.000000/CALL/9d/BET 10.000000", "is_hero": true, "status": "queryable", "token": "eyJ…"}, {"node": "root/BET 4.000000/CALL/9d/BET 10.000000/RAISE 34.000000", "is_hero": false, "status": "queryable", "token": "eyJ…"}, …]}
// 取 river 树(flop 解 + turn_card + river_card)
{"solve": "eyJ…", "turn_card": "9d", "river_card": "Qh"}
{"street": "river", "spot_status": "queryable", "pot": 7.5, "effective_stack": 97, "solve_seconds": 25.84, "node_count": 308, "nodes": [{"node": "root/BET 4.000000/CALL/9d/BET 10.000000/CALL/Qh", "is_hero": true, "status": "queryable", "token": "eyJ…"}, {"node": "root/BET 4.000000/CALL/9d/BET 10.000000/CALL/Qh/BET 27.000000", "is_hero": false, "status": "queryable", "token": "eyJ…"}, {"node": "root/BET 4.000000/CALL/9d/BET 10.000000/CALL/Qh/BET 27.000000/RAISE 83.000000", "is_hero": true, "status": "queryable", "token": "eyJ…"}, …]}
| 字段 | 说明 |
|---|---|
spot_status | 求解状态:available(未调度)/ computing(求解中,继续轮询)/ queryable(可取)/ expired(缓存已回收,需重新调度 ①)/ no_nodes(解已收敛,但该 runout/街在树中无决策节点 —— 终态,停止轮询)。 |
nodes[] | 各决策节点:node(动作路径)、is_hero、status、token(取该节点策略的凭证,传给 ③)。河牌 runout 为 chance 节点,按河牌导航。 |
street / pot / effective_stack / node_count | 街道、底池、有效栈与决策节点总数。 |
solve_seconds | 本次实时求解从调度到收敛的耗时(秒)。仅在 queryable 返回;同一个解的各 runout 共享该值。 |
③ 取某节点策略 免费
POST https://pokerai.bet/v1/gto/solver/node · 带 node token。Hero 节点返回 Hero 策略;对手节点(或不传 hole_cards)返回范围策略。
{"node": "eyJ…", "hole_cards": "AhKh"}
{"hole_cards": "AhKh", "node": "root", "is_hero": true, "strategy": [{"action": "check", "frequency": 0}, {"action": "bet", "amount_bb": 4, "sizing_pot": 0.5333, "frequency": 0.2666}, {"action": "bet", "amount_bb": 97, "sizing_pot": 12.9333, "allin": true, "frequency": 0.7334}]}
| 字段 | 说明 |
|---|---|
is_hero | 该节点是否轮到 Hero 决策。 |
strategy[] | Hero 节点:Hero 这手牌的混合策略(action / amount_bb / sizing_pot(见 下注尺度)/ frequency),全下时另带 allin: true。 |
actions[] + range_strategy | 对手节点(或不传 hole_cards):range_strategy 每手牌的频率对齐 actions 顺序;另含 range_hand_count。 |
无需也无法手动释放计算资源,系统按 TTL 自动回收;缓存已回收或被新解替换时该步返回 { "node_status": "expired" },重新调度 ① 即可。节点级求解错误返回 { "node_status": "error", "message": … }(终态,别再轮询)。
可能的错误
| HTTP | error | 触发 / 怎么修 |
|---|---|---|
| 400 | invalid_board / missing_range / invalid_pot / invalid_effective_stack / invalid_hero | (调度)board、oop/ip 范围、底池、后手筹码或 Hero 等求解输入不合法。 |
| 400 | missing_solve / missing_node | (取树/取节点)缺 solve 句柄或 node 令牌。 |
| 403 | invalid_solve / invalid_node_token | 句柄/令牌无效或非本人——重新调度 / 取树。 |
| 429 | status: busy | 所有求解器都在忙,不扣费,退避后重试。 |
| 502 | solve_failed | 求解触发失败,稍后重试。 |
| 503 | upstream_unavailable | (取树/取节点)求解器多次重试后仍不可达(传输错 / 5xx)——可重试。 |
下载(turn,board=4):schedule_reqschedule_restree_reqtree_resnode_reqnode_res
下载(flop,board=3):schedule_reqschedule_restree_reqtree_resnode_reqnode_res
下载(river,board=5):schedule_reqschedule_restree_reqtree_resnode_reqnode_res
端到端轮询示例(Python)
import requests, time
H = {"Authorization": "Bearer $POKERAI_API_KEY"}
BASE = "https://pokerai.bet/v1/gto"
# ① 调度(扣 1 solve 配额;命中缓存则不扣)
solve = requests.post(f"{BASE}/solver", headers=H, json={
"board": "2c2h2s9d", "oop_range": "AA,KK,QQ,AKs", "ip_range": "JJ,TT,AQs,KQs",
"pot": 20, "effective_stack": 90, "hero": "OOP"}).json()["solve"]
# ② 轮询取树,直到 queryable
while True:
tree = requests.post(f"{BASE}/solver/tree", headers=H, json={"solve": solve}).json()
if tree["spot_status"] == "queryable": break
time.sleep(2) # computing -> 退避后再查
# ③ 取 Hero 根节点策略
root = next(n for n in tree["nodes"] if n["node"] == "root")
strat = requests.post(f"{BASE}/solver/node", headers=H,
json={"node": root["token"], "hole_cards": "AhKh"}).json()
print(strat["strategy"])
范围转换 range
POST https://pokerai.bet/v1/gto/range 扣 1 通用
完整参数 / 响应 schema、在线试一试 → 交互式参考。
沿一条行动线更新 OOP/IP 范围。主要用于得到进入下一条街的范围(flop→turn / turn→river),再喂给 /v1/gto/solver。范围更新的全部计算(含 normalize、诈唬折扣)由求解器完成,与求解器结果一致。
这是一个透传代理:你自己组织全部输入,包括 solver_results(决策树)。决策树可用你已有的解,或用本平台 flop 决策树拼出:走 /v1/gto/flop/tree 拿起手范围,逐节点 /v1/gto/flop/node不传 hole_cards 取整段 range_strategy,按 {node_type,player,strategy,childrens} 嵌套。见文末脚本。
请求体
{
"range_oop": "AQs:1,AJs:0.48,...", // 必填,起手 OOP 范围
"range_ip": "AA:1,AKs:1,...", // 必填,起手 IP 范围
"solver_results": { /* 必填:决策树 */ },
"node_id": "root/CHECK", // 必填,行动线
"board": "2c2h2s", // 可选,无分隔串(同其它端点)
"normalize": true, // 可选,默认 true
"explain": false, // 可选,逐手牌变化解释
"track_hands": ["AA"], // 可选,只追踪这些手牌
"bluff_discount_ratio": 0.8, // 可选,诈唬折扣
"hero_position": "oop", // 可选,"oop"/"ip" — Hero 是哪一方(牌阻挡用)
"hero_hand": "AsKs" // 可选,从范围里移除含 Hero 底牌的组合(牌阻挡);会回显
}
牌阻挡(可选):设 hero_position("oop"/"ip")+ hero_hand,可把范围里所有含 Hero 底牌的组合移除——适合「范围 vs 具体手牌」分析。两者都会在响应里回显。(投影范围两个包装端点同样支持;/v1/gto/flop/projected-range 另支持 partner_hands。)
调用示例
# solver_results 较大,放文件用 -d @
curl -s https://pokerai.bet/v1/gto/range -H "Authorization: Bearer $POKERAI_API_KEY" \
-H "Content-Type: application/json" -d @range_request.json
响应(200,真实返回,长串截断)
{"bluff_combos_ratio": 0.33, "bluff_discount_ratio": 1, "board": ["2c", "2h", "2s"], "hand_bottom_ranks_ip": "KsQh:2413,KsQd:2413,KsQc:2413,KhQs:2413,…", "hand_bottom_ranks_oop": "KcJh:2414,KcTs:2415,KsTs:2415,KsTh:2415,…", "hand_ranks_ip": "QcQh:313,QdQh:313,QdQs:313,QhQs:313,QcQs:313,…", "hand_ranks_oop": "Ad2d:155,AdAc:311,AhAc:311,AhAd:311,AsAc:311,…", "node_id": "root/CHECK", "path_length": 1, "range_ip_new": "33:0.193023,44:0.216279,54s:0.65814,…", "range_ip_new_raw": "3c3d:0.193023,3c3h:0.193023,3c3s:0.193023,…", "range_ip_new_raw_before_normalization": "3c3d:0.166,3c3h:0.166,3c3s:0.166,3d3h:0.166,…", "range_oop_new": "33:0.245724,44:0.272975,54s:0.420008,…", "range_oop_new_raw": "3d3c:0.245857,3h3c:0.245847,3h3d:0.24586,…", "range_oop_new_raw_before_normalization": "3d3c:0.245843,3h3c:0.245833,3h3d:0.245845,…", "quota": {"used": 7, "limit": 100}}
| 字段 | 说明 |
|---|---|
range_oop_new / range_ip_new | 归一后的更新范围(类记法),直接当下一条街的 oop_range / ip_range 喂给 solver。 |
range_oop_new_raw / range_ip_new_raw | 诈唬折扣后、未归一的中间值(组合记法),按需取用。 |
range_oop_new_raw_before_normalization / range_ip_new_raw_before_normalization | 仅沿行动线收窄,未做诈唬折扣与归一的原始值。 |
hand_ranks_oop / hand_ranks_ip | 手牌强度排名(组合:rank,数值越小越强)。 |
hand_bottom_ranks_oop / hand_bottom_ranks_ip | 底部范围排名。 |
node_id / board / path_length | 回显的行动线、公共牌与行动线步数。 |
bluff_discount_ratio / bluff_combos_ratio | 本次实际使用的诈唬折扣参数。 |
quota | 本月通用配额用量(used / limit)。 |
可能的错误
| HTTP | error | 触发 / 怎么修 |
|---|---|---|
| 400 | missing_field | 缺 range_oop / range_ip / solver_results / node_id 之一。 |
| 400 | bad_request | solver 端拒绝(如 node_id 在你给的决策树里走不通)。 |
下载:request.json(~1MB,含决策树)response.jsonassemble_solver_results.py(端到端脚本)
flop 投影范围 projected-range
POST https://pokerai.bet/v1/gto/flop/projected-range 扣 1 通用
完整参数 / 响应 schema、在线试一试 → 交互式参考。
沿一条 flop 行动线收窄 OOP/IP 范围,直接得到进入 turn 的起手范围。给齐局面(board/pot_type/positions)与一条行动线(node_id),平台在服务端自动拼出决策树并完成范围更新,返回与 范围转换 基本相同的字段(另多一个回显的 pot_type)。
这是 /v1/gto/range 的便捷封装:省去你手动走 /v1/gto/flop/tree + 逐节点 /v1/gto/flop/node 拼 solver_results 的步骤。只适用于 flop 行动线(决策树由本平台 flop 预求解结果拼出);turn→river 等需自带决策树时仍用 /v1/gto/range。
请求体
{
"board": "2c2h2s",
"pot_type": "SRP",
"positions": { "hero": "UTG", "raiser": "UTG", "caller": "BTN" },
"node_id": "root/BET_4",
"normalize": true,
"bluff_discount_ratio": 0.8,
"bluff_combos_ratio": 0.5,
"hero_position": "oop",
"hero_hand": "AsKs",
"partner_hands": ["Ac9c"]
}
| 字段 | 说明 |
|---|---|
board | 必填。翻牌(无分隔串,同其它端点),如 "2c2h2s"。 |
pot_type | 必填。底池类型,如 "SRP"。 |
positions | 必填。{ hero, raiser, caller }(同 flop);3bet/limp 局面可带 three_bettor / limper。 |
node_id | 可选,默认 "root"。flop 行动线,用 /v1/gto/flop/tree 返回的 api 记法(下注额绝对 BB),如 "root/BET_4"、"root/CHECK/BET_8/CALL"。 |
normalize | 可选,默认 true。是否对更新后范围归一。 |
bluff_discount_ratio / bluff_combos_ratio | 可选,各自取值 [0,1](越界 → 400)。bluff_discount_ratio 是对底部诈唬组合的折扣系数;bluff_combos_ratio 是范围里被当作诈唬的比例。省略则用服务端 turn/river 默认值。两者都会回显。 |
hero_position / hero_hand | 可选牌阻挡。设 hero_position("oop"/"ip")+ hero_hand(如 "AsKs"):把对手更新后范围(range_*_new_raw)里所有含 Hero 底牌的组合移除,并确保 Hero 自己底牌出现在自己范围里。两者都会回显。仅作用于 range_*_new_raw——hand_ranks / hand_bottom_ranks 只按 board 过滤。 |
partner_hands | 可选,4 字符组合数组(如 ["Ac9c"]),需配合 hero_position。把对手 range_*_new_raw 里所有含这些牌的组合移除——用于建模已知死牌(弃掉的手牌、暴露的牌)。仅输入不回显。/v1/gto/turn/projected-range 也支持。 |
flop_version | 可选。选用哪套 flop 数据集(每个 preflop 版本各解一套):6max(默认)/ 6max_RC_100bb_200NL / 6max_RC_100bb_100NL / 6max_RC_40bb。省略=默认 6max;该版本无此 spot 数据时优雅降级到 6max;未知值 → 400 unsupported_flop_version。与 preflop_version 相互独立。 |
调用示例
curl -s https://pokerai.bet/v1/gto/flop/projected-range -H "Authorization: Bearer $POKERAI_API_KEY" \
-H "Content-Type: application/json" -d @projected_range_request.json
响应(200,字段全列,长串截断)
{"board": ["2c", "2h", "2s"], "pot_type": "SRP", "node_id": "root/BET_4", "bluff_combos_ratio": 0.5, "bluff_discount_ratio": 0.8, "hero_position": "oop", "hero_hand": "AsKs", "hand_bottom_ranks_ip": "AhTh:2405,AsTs:2405,Ac9c:2406,Ad9d:2406,…", "hand_bottom_ranks_oop": "AhJs:2404,AsJc:2404,AsJd:2404,AsJh:2404,…", "hand_ranks_ip": "QcQd:313,QcQh:313,QcQs:313,QdQh:313,…", "hand_ranks_oop": "Ad2d:155,AdAc:311,AdAh:311,AdAs:311,…", "path_length": 1, "range_ip_new": "33:0.193023,44:0.216279,54s:0.65814,55:0.344186,…", "range_ip_new_raw": "3c3d:0.193023,3c3h:0.193023,3c3s:0.193023,3d3h:0.193023,…", "range_ip_new_raw_before_normalization": "3c3d:0.166,3c3h:0.166,3c3s:0.166,3d3h:0.166,…", "range_oop_new": "44:0.0120032,55:0.0422217,66:0.181192,77:0.327323,…", "range_oop_new_raw": "4s4c:0.0666554,4s4h:0.0666554,5d5c:0.005,5d5h:0.005,…", "range_oop_new_raw_before_normalization": "4s4c:0.011816,4s4h:0.011816,5s5c:0.0392591,5s5h:0.0392591,…", "quota": {"used": 7, "limit": 100}}
| 字段 | 说明 |
|---|---|
range_oop_new / range_ip_new | 归一后的更新范围(类记法),直接当下一条街的 oop_range / ip_range 喂给 solver。 |
range_oop_new_raw / range_ip_new_raw | 诈唬折扣后、未归一的中间值(组合记法),按需取用。 |
range_oop_new_raw_before_normalization / range_ip_new_raw_before_normalization | 仅沿行动线收窄,未做诈唬折扣与归一的原始值。 |
hand_ranks_oop / hand_ranks_ip | 手牌强度排名(组合:rank,数值越小越强)。 |
hand_bottom_ranks_oop / hand_bottom_ranks_ip | 底部范围排名。 |
node_id / board / pot_type / path_length | 回显的行动线、公共牌、底池类型与行动线步数。 |
bluff_discount_ratio / bluff_combos_ratio | 本次实际使用的诈唬折扣参数。 |
quota | 本月通用配额用量(used / limit)。 |
可能的错误
| HTTP | error | 触发 / 怎么修 |
|---|---|---|
| 400 | invalid_board / invalid_positions | board 非 3 张,或 positions.hero 不合法。 |
| 404 | no_solution(及服务端 errorType 如 no_ranges / no_root_node) | 该局面无 flop 预求解树,或 node_id 行动线走不通。 |
turn 投影范围(turn→river)projected-range
POST https://pokerai.bet/v1/gto/turn/projected-range 免费
完整参数 / 响应 schema、在线试一试 → 交互式参考。
flop 投影范围的 turn→river 版,用于一个实时 turn 求解。沿一条 turn 行动线(含收尾的 CALL/CHECK)收窄范围,直接得到进入 river 的起手范围。进入 turn 的 OOP/IP 范围直接取自该求解自己的配置(即 /v1/gto/solver 调度时用的范围),你只需给求解句柄 solve + 一条 node_id。免费(该求解已在 /v1/gto/solver 计费),与 /v1/gto/solver/tree 一样;返回字段与 范围转换 相同。
先轮询 /v1/gto/solver/tree 到 spot_status = queryable 再调用。turn→river 不必手动拼 solver_results(平台从该求解读取并拼出)。
请求体
{
"solve": "eyJ…",
"node_id": "root/CHECK/BET 6.000000/CALL",
"normalize": true,
"bluff_discount_ratio": 0.8,
"hero_position": "oop",
"hero_hand": "AsKs"
}
| 字段 | 说明 |
|---|---|
solve | 必填。/v1/gto/solver 返回的求解句柄(一个 turn 求解)。 |
node_id | 必填。turn 行动线,可以以收尾的 CALL/CHECK 结尾。求解器节点记法(带空格),如 "root/CHECK/BET 6.000000/CALL"(取自 /v1/gto/solver/tree 的节点)。 |
normalize | 可选,默认 true。是否对更新后范围归一。 |
bluff_discount_ratio | 可选。诈唬折扣(0..1)。 |
hero_position / hero_hand | 可选牌阻挡:hero_position("oop"/"ip")+ hero_hand(如 "AsKs"),把对手更新后范围里含 Hero 底牌的组合移除。 |
partner_hands | 可选,4 字符组合数组(如 ["Ac9c"]),需配合 hero_position。把对手 range_*_new_raw 里所有含这些牌的组合移除。仅输入。 |
调用示例
curl -s https://pokerai.bet/v1/gto/turn/projected-range -H "Authorization: Bearer $POKERAI_API_KEY" \
-H "Content-Type: application/json" -d @turn_projected_range_request.json
响应(200,字段全列,长串截断)
{"bluff_combos_ratio": 0.33, "bluff_discount_ratio": 1, "board": ["8d", "4h", "8s", "Qc"], "hand_bottom_ranks_ip": "TcTs:2943,TdTh:2943,TdTs:2943,9h9s:3020,…", "hand_bottom_ranks_oop": "AhKd:4646,AhKc:4646,AcKh:4646,JsTs:4746,…", "hand_ranks_ip": "Ac8c:2007,Ah8h:2007,KcKs:2645,KhKs:2645,…", "hand_ranks_oop": "8c8h:85,Ah8h:2007,Ac8c:2007,9c8c:2029,…", "node_id": "root/CHECK/BET 6.000000/CALL", "path_length": 3, "range_ip_new": "99:0.603064,A8s:0.5,AKs:0.70197,AQs:0.453337,…", "range_ip_new_raw": "9c9d:0.71487,9c9h:0.394271,9c9s:0.71487,…", "range_ip_new_raw_before_normalization": "9c9d:0.714699,9c9h:0.394176,9c9s:0.714699,…", "range_oop_new": "88:0.131148,98s:0.0902494,A8s:0.0344418,…", "range_oop_new_raw": "8c8h:0.777777,9c8c:0.185048,9h8h:0.17177,…", "range_oop_new_raw_before_normalization": "8c8h:0.418968,9c8c:0.0996806,9h8h:0.0925282,…"}
| 字段 | 说明 |
|---|---|
range_oop_new / range_ip_new | 归一后的进入 river 范围(类记法),直接当 river 求解的 oop_range / ip_range。 |
range_*_raw / range_*_raw_before_normalization | 未归一 / 未折扣的中间值(组合记法)。 |
hand_ranks_* / hand_bottom_ranks_* | 手牌强度排名 / 底部范围排名(组合:rank,越小越强)。 |
node_id / board / path_length | 回显的行动线、公共牌(4 张)、行动线步数。 |
bluff_discount_ratio / bluff_combos_ratio | 本次实际使用的诈唬折扣参数。 |
注:免费,故响应无 quota 字段;也无 pot_type(那是 flop 专有)。
可能的错误 / 状态
| HTTP | error / 状态 | 触发 / 怎么修 |
|---|---|---|
| 200 | { "spot_status": "computing" } | 求解尚未收敛 —— 继续轮询 /v1/gto/solver/tree 到 queryable。 |
| 400 | missing_solve / missing_node_id | 缺 solve 句柄或 node_id。 |
| 410 | expired | 求解已过期(TTL)—— 用 /v1/gto/solver 重新调度。 |
| 502 | no_solution 等 | 上游求解出错。 |
节点 EV solver
POST https://pokerai.bet/v1/gto/evs 免费
完整参数 / 响应 schema、在线试一试 → 交互式参考。
已完成解在某个节点的逐手、逐动作期望值(EV)。给 solve 句柄 solve(来自 /v1/gto/solver)+ 一个 node_id(来自 /v1/gto/solver/tree);可选 hand 只取一手。免费(解已在 /v1/gto/solver 计过费)。先轮询 /v1/gto/solver/tree 到 spot_status = queryable。
请求体
{
"solve": "eyJ0Ijoic2x2X3h4eXoi...(来自 /v1/gto/solver 的句柄)",
"node_id": "root",
"hand": "2c2d"
}
| 字段 | 说明 |
|---|---|
solve | 必填。/v1/gto/solver 返回的 solve 句柄。 |
node_id | 必填。/v1/gto/solver/tree 里的节点(solver 记法,如 "root"、"root/CHECK/BET 6.000000")。 |
hand | 可选。只取一手的 EV(如 "2c2d");省略=全部手牌。 |
响应(200,每手的 EV 数组与 actions 对齐)
{"node_id": "root", "task_id": "slv_srp_…", "player": 1, "round": "FLOP", "actions": ["CHECK", "BET 4.000000", "BET 97.000000"], "evs": {"2c2d": [-0.826359, -0.792223, -1.643411], "2c2h": […], …}}
| 字段 | 说明 |
|---|---|
actions | 节点的动作(有序);每手的 EV 数组与之对齐。 |
evs | 每手 → 各动作的 EV 数组(bb)。传了 hand 时,evs 是该手的单个数组。 |
player / round / node_id / task_id | 谁行动、街、回显的节点 / 解 id。 |
注:免费,无 quota 字段。解未收敛时返回 { "spot_status": "computing" }(轮询 /v1/gto/solver/tree)。
打一手牌(全流程)
把各端点串起来:一手 SRP(UTG 开池、BTN 跟注),Hero = UTG。下面 curl 省略了鉴权头(同 Quickstart)。
① Preflop — 该不该开池
POST /v1/gto/preflop
{ "hole_cards": "AdKd", "positions": { "hero": "UTG" },
"preflop_actions": [ { "position": "SB", "action": "small blind", "amount": 0.5 }, { "position": "BB", "action": "big blind", "amount": 1 } ] }
preflop_actions 只含 SB+BB 盲注(无加注)= Hero 是首个行动者(开池局面)。返回开池频率与尺度。
② Flop — 翻牌策略
翻牌 2c2h2s。flop 是决策树,两步:先取树,再用 Hero 节点的 token 取策略。
// 1) 取树(不需要 hole_cards)
POST /v1/gto/flop/tree
{ "board": "2c2h2s", "pot_type": "SRP",
"positions": { "hero": "UTG", "raiser": "UTG", "caller": "BTN" } }
// → nodes[] 中 root (is_hero:true) 带一个 token
// 2) 用 root 的 token 取 Hero 策略
POST /v1/gto/flop/node
{ "node": "<root 的 token>", "hole_cards": "AdKd" }
Hero 第一个决策 = root;面对下注 / 第二次行动 → 选对应的 is_hero:true 节点。详见 Flop 决策树。
③ Turn — 实时求解,范围从 flop 推导
转牌(如 9d)要实时解,需要进入 turn 的双方范围。用 flop 决策树 + 范围转换得到:
/v1/gto/flop/tree拿起手oop_range/ip_range与决策节点。- 沿一条 flop 行动线(如
root/CHECK/BET_8/CALL)逐节点/v1/gto/flop/node(不传 hole_cards)取range_strategy,拼出solver_results——脚本见 范围转换 节的assemble_solver_results.py。 /v1/gto/range沿该线更新 →range_oop_new/range_ip_new即进入 turn 的范围。- 喂给 solver(board 给 4 张),轮询取树到
queryable后取节点:POST /v1/gto/solver { "board": "2c2h2s9d", "oop_range": "<进turn的OOP范围>", "ip_range": "<进turn的IP范围>", "pot": <进turn底池>, "effective_stack": <进turn有效栈>, "hero": "OOP" }
已有自己的范围/局面?第 3 步直接给 oop_range / ip_range,跳过推导。
④ River — 实时求解
河牌(board 给 5 张)同 turn:可单独求解(直接给进入 river 的范围),或用范围转换把 turn 行动线再更新一次,得到进入 river 的范围再喂给 solver。
Poker 引擎 / 语义 API
包住 pokerkit-plus(pokerkit 0.7.3 超集):牌面/手牌语义、范围与权益、评牌/equity/ICM/记法、牌局模拟。复用同一 API key 与配额——便宜端点扣通用配额,蒙特卡洛端点扣 solve 配额。基址 /v1/pokerkit/*;牌输入用无分隔串(AsKsQs),枚举返回 {name,value}。完整 per-endpoint 参数/schema、在线试一试 → 交互式参考;机读 spec → /v1/pokerkit/openapi.json(随代码自动同步)。
牌面 / 手牌语义 扣 1 通用
牌面无关:/texture(湿度/连接性/听牌面)、/nuts(坚果 + 并列 combo)、/category-combos、/board-report(texture+nuts)。Hero 相关:/hand-tier(成手档位)、/draws(听牌)、/outs(补牌)、/blockers(阻断坚果)、/hand-report(texture+tier+draws+outs 一次拿全)。
请求字段(本组通用)
| 字段 | 说明 |
|---|---|
board | 必填。3/4/5 张公共牌,无分隔串,如 "AsKsQs"。 |
hole | Hero 端点(hand-tier / draws / outs / blockers / hand-report)必填。2 张底牌,如 "JhTh";牌面端点(texture / nuts / category-combos / board-report)不需要。 |
hand_type | 可选,默认 StandardHighHand(v1 仅此,其它牌型返回 400)。 |
dead | 可选。死牌 / 已移除的牌(本组所有端点适用)。 |
Texture 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/texture — 牌面结构:湿度/连接性/rank band/听牌可成性/花色形态。 完整参数 / 在线试一试 →
{"board": "AsKsQs"}
{"result": {"cards": ["As", "Ks", "Qs"], "wetness": {"name": "WET", "value": "Wet"}, "connectivity": {"name": "HIGH", "value": "High"}, "rank_band": {"name": "HIGH", "value": "High"}, "straight_draw": {"name": "OPEN_ENDED", "value": "Open-ended"}, "flush_draw": {"name": "LIVE", "value": "Live"}, "are_two_tone": false, "are_monotone": true, "are_rainbow": false}}
Nuts 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/nuts — 该牌面的最强成手 + 所有并列的两张组合(含 is_royal / board_is_nuts)。 完整参数 / 在线试一试 →
{"board": "AsKsQs"}
{"result": {"hand": "TsJsKsQsAs", "combos": [{"cards": ["Ts", "Js"], "hand": "TsJsKsQsAs", "as_frozenset": ["Js", "Ts"]}], "candidate_count": 1176, "board_is_nuts": false, "is_royal": true, "label": {"name": "STRAIGHT_FLUSH", "value": "Straight flush"}}}
Category combos 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/category-combos — 所有活的两张组合按成手类别分组。 完整参数 / 在线试一试 →
{"board": "AsKsQs"}
{"result": {"by_category": {"HIGH_CARD": [{"cards": ["2c", "3c"], "hand": "2c3cKsQsAs", "as_frozenset": ["2c", "3c"]}, {"cards": ["2c", "3d"], "hand": "2c3dKsQsAs", "as_frozenset": ["2c", "3d"]}], …}}}
Board report 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/board-report — texture + nuts 一次返回(牌面综合)。 完整参数 / 在线试一试 →
{"board": "AsKsQs"}
{"result": {"texture": {"cards": ["As", "Ks", "Qs"], "wetness": {"name": "WET", "value": "Wet"}, "connectivity": {"name": "HIGH", "value": "High"}, "rank_band": {"name": "HIGH", "value": "High"}, "straight_draw": {"name": "OPEN_ENDED", "value": "Open-ended"}, "flush_draw": {"name": "LIVE", "value": "Live"}, "are_two_tone": false, "are_monotone": true, "are_rainbow": false}, "nuts": {"hand": "TsJsKsQsAs", "combos": [{"cards": ["Ts", "Js"], "hand": "TsJsKsQsAs", "as_frozenset": ["Js", "Ts"]}], "candidate_count": 1176, "board_is_nuts": false, "is_royal": true, "label": {"name": "STRAIGHT_FLUSH", "value": "Straight flush"}}}}
Hand tier 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/hand-tier — Hero 成手档位(对子 / 两对 / 三条 / 踢脚档,是否坚果)。 完整参数 / 在线试一试 →
{"hole": "JhTh", "board": "AsKsQs"}
{"result": {"category": {"name": "STRAIGHT", "value": "Straight"}, "is_nut": false, "pair_tier": null, "two_pair_tier": null, "three_of_a_kind_tier": null, "kicker_tier": null, "nut_rank": {"name": "NON_NUT", "value": "Non-nut"}}}
Draws 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/draws — Hero 的听牌(顺子听牌 / 同花听牌 / 听牌坚果度)。 完整参数 / 在线试一试 →
{"hole": "Ah5h", "board": "Kh7h2c"}
{"result": {"straight_draw": null, "flush_draw": {"name": "LIVE", "value": "Live"}, "nut_rank": {"name": "NUT", "value": "Nut"}}}
Outs 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/outs — Hero 能升级成手类别的补牌,按结果类别分组 + 总数。 完整参数 / 在线试一试 →
{"hole": "Ah5h", "board": "Kh7h2c"}
{"result": {"by_category": {"ONE_PAIR": ["2d", "2s", "5c", "5d", "5s", "7c", "7d", "7s", "Kc", "Kd", "Ks", "Ac", "Ad", "As"], "FLUSH": ["2h", "3h", "4h", "6h", "8h", "9h", "Th", "Jh", "Qh"]}, "count": 23}}
Blockers 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/blockers — Hero 的牌阻断了多少坚果组合(阻断牌 / 阻断比例)。 完整参数 / 在线试一试 →
{"hole": "AhAd", "board": "AsKsQs"}
{"result": {"nut_combos_total": 1, "nut_combos_blocked": 0, "blocker_cards": [], "block_fraction": 0.0, "blocks_nuts": false}}
Hand report 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/hand-report — texture + tier + draws + outs 一次返回(Hero 综合,旗舰)。 完整参数 / 在线试一试 →
{"hole": "JhTh", "board": "AsKsQs"}
{"result": {"texture": {"cards": ["As", "Ks", "Qs"], "wetness": {"name": "WET", "value": "Wet"}, "connectivity": {"name": "HIGH", "value": "High"}, "rank_band": {"name": "HIGH", "value": "High"}, "straight_draw": {"name": "OPEN_ENDED", "value": "Open-ended"}, "flush_draw": {"name": "LIVE", "value": "Live"}, "are_two_tone": false, "are_monotone": true, "are_rainbow": false}, "tier": {"category": {"name": "STRAIGHT", "value": "Straight"}, "is_nut": false, "pair_tier": null, "two_pair_tier": null, "three_of_a_kind_tier": null, "kicker_tier": null, "nut_rank": {"name": "NON_NUT", "value": "Non-nut"}}, "draws": {"straight_draw": null, "flush_draw": null, "nut_rank": null}, "outs": {"by_category": {}, "count": 0}}}
范围 / 权益 扣 1 通用
/range/expand(notation→具体 combo)、/range/value(按成手类别阈值建价值范围,aggression ∈ NO_BET/SINGLE_BET/RAISED)、/range/nut-advantage(精确坚果占比,无抽样)。
请求字段(本组通用)
| 字段 | 说明 |
|---|---|
notation | (expand)范围记法数组,如 ["AA","KQs","QQ+"]。 |
hero / villain | (nut-advantage)各一个范围记法数组。 |
board | 公共牌(value / nut-advantage 必填;expand 不需要)。 |
aggression | (value)NO_BET / SINGLE_BET / RAISED 定成手类别阈值;或用 floor 显式指定类别。 |
Range expand 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/range/expand — 把范围记法展开成具体两张组合。 完整参数 / 在线试一试 →
{"notation": ["AA", "KQs"]}
{"result": [["Ac", "Ad"], ["Ac", "Ah"], ["Ac", "As"], ["Ad", "Ah"], ["Ad", "As"], ["Ah", "As"], ["Kc", "Qc"], ["Kd", "Qd"], ["Kh", "Qh"], ["Ks", "Qs"]]}
Range value 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/range/value — 按成手类别阈值(aggression)构造价值范围。 完整参数 / 在线试一试 →
{"board": "AsKsQs", "aggression": "SINGLE_BET"}
{"result": [["2s", "3s"], ["2s", "4s"], ["2s", "5s"], ["2s", "6s"], ["2s", "7s"], ["2s", "8s"], …]}
Range nut-advantage 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/range/nut-advantage — 精确按坚果类别计数的双方占比(无抽样,确定性)。 完整参数 / 在线试一试 →
{"hero": ["AA", "KK"], "villain": ["QQ", "JJ"], "board": "AsKsQs"}
{"result": {"hero_share": 0.5, "villain_share": 0.5, "basis": {"name": "NUT_SHARE", "value": "Nut share"}}}
评牌 · equity · ICM · 记法
扣 1 通用 /eval/hand、/eval/compare(多手排名+并列)、/icm(确定性)、/notation/parse(.phh→结构化)。扣 1 solve 蒙特卡洛:/equity、/hand-strength、/range/equity-advantage——带 sample_count(有上限)与 seed(可复现,~2s@10k)。
请求字段(本组通用)
蒙特卡洛端点(equity / hand-strength / range/equity-advantage)扣 solve 配额,其余扣通用配额。
| 字段 | 说明 |
|---|---|
hole / holdings / board | 评牌输入:单手 hole + board(eval/hand),或多手 holdings(2+)+ board(eval/compare)。 |
ranges / hole_range / hero / villain | 范围记法(equity / hand-strength / range/equity-advantage)。 |
sample_count / seed | 蒙特卡洛:样本数(有上限,超出按上限)/ 随机种子(可复现)。 |
payouts / chips | (icm)奖励结构 / 各方筹码。 |
text | (notation/parse).phh 手牌历史字符串。 |
Eval hand 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/eval/hand — 评出 hole + board 的成手(5 张 + 类别 label)。 完整参数 / 在线试一试 →
{"hole": "JhTh", "board": "AsKsQs"}
{"result": {"hand": "JhThAsKsQs", "label": {"name": "STRAIGHT", "value": "Straight"}}}
Eval compare 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/eval/compare — 多手在同一牌面排名(含并列 rank)。 完整参数 / 在线试一试 →
{"holdings": ["AcAd", "KsKh", "JhTh"], "board": "AsKsQs"}
{"result": [{"index": 2, "hole": "JhTh", "hand": "JhThAsKsQs", "rank": 1, "label": {"name": "STRAIGHT", "value": "Straight"}}, {"index": 0, "hole": "AcAd", "hand": "AcAdAsKsQs", "rank": 2, "label": {"name": "THREE_OF_A_KIND", "value": "Three of a kind"}}, {"index": 1, "hole": "KsKh", "hand": "KsKhAsKsQs", "rank": 3, "label": {"name": "THREE_OF_A_KIND", "value": "Three of a kind"}}]}
Equity 扣 1 solve
POST https://pokerai.bet/v1/pokerkit/equity — 多个范围在牌面上的权益(蒙特卡洛)。 完整参数 / 在线试一试 →
{"ranges": [["AA"], ["KK"]], "board": "", "sample_count": 2000, "seed": 7}
{"result": {"equities": [0.8235, 0.1765], "sample_count": 2000}}
Hand strength 扣 1 solve
POST https://pokerai.bet/v1/pokerkit/hand-strength — Hero 一手 / 范围对 N 人的胜率(蒙特卡洛)。 完整参数 / 在线试一试 →
{"hole_range": ["AhKh"], "board": "Qh7c2d", "player_count": 3, "sample_count": 2000, "seed": 7}
{"result": {"hand_strength": 0.3945, "player_count": 3, "sample_count": 2000}}
ICM 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/icm — 按筹码 / 奖励结构算 ICM 权益分配(确定性)。 完整参数 / 在线试一试 →
{"payouts": [50, 30, 20], "chips": [5000, 3000, 2000]}
{"result": {"icm": [38.392857142857146, 32.75, 28.857142857142854]}}
Range equity-advantage 扣 1 solve
POST https://pokerai.bet/v1/pokerkit/range/equity-advantage — 双方范围的权益占比(蒙特卡洛)。 完整参数 / 在线试一试 →
{"hero": ["AA", "KK"], "villain": ["QQ", "JJ"], "board": "AsKsQs", "sample_count": 2000, "seed": 7}
{"result": {"hero_share": 0.80325, "villain_share": 0.19675, "basis": {"name": "EQUITY", "value": "Equity"}, "sample_count": 2000}}
Notation parse 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/notation/parse — 解析 .phh 手牌历史为结构化配置(variant / 盲注 / 筹码 / 动作…)。 完整参数 / 在线试一试 →
{"text": "variant = \"NT\"\nante_trimming_status = true\nantes = [0, 0]\nblinds_or_straddles = [1, 2]\nmin_bet = 2\nstarting_stacks = [200, 200]\nactions = [\"d dh p1 AhKh\", \"d dh p2 QsQd\", \"p1 cbr 6\", \"p2 cc\", \"d db Qh7c2d\"]\n"}
{"result": {"variant": "NT", "ante_trimming_status": true, "antes": [0, 0], "blinds_or_straddles": [1, 2], "bring_in": null, "small_bet": null, "big_bet": null, "min_bet": 2, "starting_stacks": [200, 200], "actions": ["d dh p1 AhKh", "d dh p2 QsQd", "p1 cbr 6", "p2 cc", "d db Qh7c2d"], "automations": [{"name": "ANTE_POSTING", "value": "Ante posting"}, …], "author": null, "event": null, "day": null, "month": null, "year": null, "hand": null, "currency": null}}
牌局模拟 扣 1 通用
完全信息、无状态回放:客户端携带动作列表,服务端用 pokerkit 重建局面(零服务端状态)。/games/state(当前局面快照)、/games/step(追加 next_action;带 expected_action_count 作并发令牌,不符回 409)、/notation/replay(config 或 .phh 文本 → 逐步快照)、/cards/normalize(校验/规整牌串)。
请求字段(本组通用)
| 字段 | 说明 |
|---|---|
variant | 必填。变体码,如 "NT"(无限德州);全部见 /v1/pokerkit/meta。 |
antes / starting_stacks | 必填。每位玩家前注 / 起始筹码(整数数组)。 |
blinds_or_straddles / min_bet | 盲注 / 跨注;无限 / 底池限注必填 min_bet(固定限注 / 梭哈用 small_bet / big_bet / bring_in)。 |
actions | 到目前为止的动作列表(pokerkit 记法:d dh p1 AhKh 发底牌、p2 cbr 6 加注到 6、p1 cc 过牌/跟注、p1 f 弃牌)。 |
next_action / expected_action_count | (step)要应用的动作 / 并发令牌(= 你扩展的列表长度,不符回 409)。 |
text / index | (replay)可改用 .phh 文本;index 只取某一步快照。cards/normalize 仅需 cards(牌串)。 |
Games state 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/games/state — 给动作列表 → 重建并返回当前局面快照(亮所有底牌)。 完整参数 / 在线试一试 →
{"variant": "NT", "antes": [0, 0], "blinds_or_straddles": [1, 2], "min_bet": 2, "starting_stacks": [200, 200], "actions": ["d dh p1 AhKh", "d dh p2 QsQd", "p2 cbr 6"]}
{"result": {"snapshot": {"terminal": false, "street_index": 0, "actor_index": 0, "pot": 8, "bets": [2, 6], "stacks": [198, 194], "board": [], "hole_cards": [{"player": 0, "cards": ["Ah", "Kh"]}, {"player": 1, "cards": ["Qs", "Qd"]}], "legal_actions": [{"action": "fold"}, {"action": "check_or_call", "amount": 4}, {"action": "complete_bet_or_raise_to", "min": 10, "max": 200}]}, "actions": ["d dh p1 AhKh", "d dh p2 QsQd", "p2 cbr 6"]}}
Games step 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/games/step — 追加 next_action → 新快照(带并发令牌,不符回 409)。 完整参数 / 在线试一试 →
{"variant": "NT", "antes": [0, 0], "blinds_or_straddles": [1, 2], "min_bet": 2, "starting_stacks": [200, 200], "actions": ["d dh p1 AhKh", "d dh p2 QsQd", "p2 cbr 6"], "next_action": "p1 cc", "expected_action_count": 3}
{"result": {"snapshot": {"terminal": false, "street_index": 1, "actor_index": null, "pot": 12, "bets": [0, 0], "stacks": [194, 194], "board": [], "hole_cards": [{"player": 0, "cards": ["Ah", "Kh"]}, {"player": 1, "cards": ["Qs", "Qd"]}], "legal_actions": [{"action": "deal_board"}]}, "actions": ["d dh p1 AhKh", "d dh p2 QsQd", "p2 cbr 6", "p1 cc"]}}
Notation replay 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/notation/replay — config 或 .phh → 每步局面快照(可选 index 取单步)。 完整参数 / 在线试一试 →
{"variant": "NT", "antes": [0, 0], "blinds_or_straddles": [1, 2], "min_bet": 2, "starting_stacks": [200, 200], "actions": ["d dh p1 AhKh", "d dh p2 QsQd", "p2 cbr 6", "p1 f"], "index": 2}
{"result": {"snapshot": {"terminal": false, "street_index": 0, "actor_index": 1, "pot": 3, "bets": [2, 1], "stacks": [198, 199], "board": [], "hole_cards": [{"player": 0, "cards": ["Ah", "Kh"]}, {"player": 1, "cards": ["Qs", "Qd"]}], "legal_actions": [{"action": "fold"}, {"action": "check_or_call", "amount": 1}, {"action": "complete_bet_or_raise_to", "min": 4, "max": 200}]}, "step_count": 5}}
Cards normalize 扣 1 通用
POST https://pokerai.bet/v1/pokerkit/cards/normalize — 校验 / 规整牌串为标准两字符牌。 完整参数 / 在线试一试 →
{"cards": "Ah Ks Qs"}
{"result": ["Ah", "Ks", "Qs"]}
另有 GET /v1/pokerkit/meta(版本 / 变体码 / 牌型 / 枚举词表)。每个端点的完整参数 schema 与在线试一试,见交互式参考(顶部可在两套 API 间浏览)。
全部示例下载
每个端点的完整请求/响应(真实数据、字段不省略)汇总,见上面各节的「下载」,或: preflop · flop tree · flop node · solver · range · projected range · projected range 响应 · assemble 脚本。
版本与变更
版本策略
- 路径里的
/v1是大版本。破坏性变更(删/改字段、改语义)会走新大版本/v2,/v1保持可用。 - 向后兼容的新增(新端点、新可选字段、响应新增字段)直接加到
/v1,不另行通知——请用“忽略未知字段”的方式解析,不要对响应字段做严格白名单校验。 - 字段弃用会提前在下方 changelog 标注,过渡期后再移除。
Changelog
| 日期 | 变更 |
|---|---|
| 2026-07-04 | 新增 /v1/gto/evs(已完成解在某节点的逐手逐动作 EV);/v1/gto/turn/projected-range 现在也支持 partner_hands。 |
| 2026-07-04 | /v1/gto/flop/projected-range 现在会读取请求里的 bluff_discount_ratio / bluff_combos_ratio、把 Hero 自己底牌注入 Hero 范围,并新增 partner_hands(把队友死牌从对手范围里阻挡)。 |
| 2026-06-22 | 新增 Poker 引擎 / 语义 API /v1/pokerkit/*(牌面/手牌语义、范围/权益、评牌/equity/ICM/记法、牌局模拟;复用同一 key 与配额)。见 下方。 |
| 2026-06-22 | 新增 /v1/gto/preflop/range(整段 13×13 翻前范围,一次返回 169 手型)。 |
| 2026-06-18 | 拆分 flop:删除单点查询 /v1/gto/flop,改为 /v1/gto/flop/tree(取树)+ /v1/gto/flop/node(取节点,免费),与 solver 的 tree/node 对齐。 |
| 2026-06-17 | 新增 /v1/gto/flop/projected-range(/v1/gto/range 的便捷封装:给齐 flop 局面 + 行动线,服务端自动拼决策树,直接返回进 turn 范围)。 |
| 2026-06-17 | 牌面 / 手牌格式统一:输入无分隔串,响应 board 统一返回数组。 |
| 2026-06-17 | 新增 OpenAPI 3.0 规范;新增范围记法 / 概念 / 全流程教程文档。 |
| 2026-06-17 | /v1/gto/solver 支持 flop 实时求解(board=3);bet_sizes.flop 可自定义 flop 下注档。 |
| 2026-06-17 | 修复:flop 查询 raise 的 amount_bb 误为 0(现返回正确绝对 BB)。 |
| 2026-06-17 | 新增 范围转换 /v1/gto/range;/flop/tree 暴露起手 oop_range / ip_range;/flop 与 /solver/node 不传 hole_cards 时返回整段范围策略。 |
| 2026-06-16 | 新增 turn / river 实时求解器 /v1/gto/solver 系列(独立 solve 配额);新增 flop 决策树 /v1/gto/flop/tree。 |
| 2026-06-15 | 移除所有响应里的 recommendation 字段——请按 frequency 自行选择动作。 |
pokerai.bet · GTO API v1