사전 풀이 조회
빠름프리플랍 및 580만 개 이상의 플롭 풀이. 작업 폴링 없이 밀리초 단위로 전략을 반환합니다.
프리플랍으로 시작단일 셀프 서비스 API로 MelaSolver GPU를 사용하세요. 밀리초 단위의 사전 풀이된 조회로 시작하거나, 맞춤 플롭, 턴 또는 리버 스폿을 실시간 풀이 풀에 제출하세요.
공개 컬렉션을 다운로드하여 Postman으로 가져온 다음 요청을 보내기 전에 컬렉션 apiKey 변수를 API 키로 설정하세요. 이 컬렉션은 Authorization: Bearer {{apiKey}}와 공개 https://pokerai.bet 기본 URL을 사용하며, 포함된 예제는 GTO 프리플랍 전략과 PokerKit 보드 텍스처를 다룹니다.
Postman 컬렉션 다운로드 가능한 소스에는 실제 키, Cookie 또는 비공개 엔드포인트가 포함되어 있지 않습니다. 전체 공개 계약은 API 레퍼런스 및 OpenAPI 스냅샷을 참조하세요.
둘 다 동일한 API 키와 월간 할당량을 사용합니다.
설치하고, 인증하고, 호출하세요. 별도로 프로비저닝할 것은 없습니다.
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}]}'
{
"hole_cards": "AhKh",
"situation": "RFI",
"strategy": [
{ "action": "raise", "frequency": 1, "amount_bb": 3, "sizing_pot": 0.8 }
],
"quota": { "used": 6, "limit": 100 }
}
긴 한 페이지를 뒤질 필요 없이 첫 호출에서 프로덕션까지 진행하세요.
모든 요청에는 API 키가 있어야 합니다. 60초 안에 키 받기:
export POKERAI_API_KEY=gto_xxxxxxxx. 그러면 아래 빠른 시작을 실행할 수 있습니다.그 후에는 모든 요청의 요청 헤더에 같은 키(방금 복사한 gto_xxx — “Bearer 토큰”입니다)를 보냅니다. 아래 형식 중 하나를 선택하세요 — 키는 하나이지 둘이 아닙니다:
Authorization: Bearer gto_xxxxxxxx # 표준(권장; OpenAPI 스키마 BearerApiKey와 일치)
# 또는(완전히 동등함, 하나 선택)
X-API-Key: gto_xxxxxxxx # 동등함(OpenAPI 스키마 XApiKey); 일부 게이트웨이 / SDK / 빠른 테스트에 편리
별도로 측정되며 매월 1일에 재설정되는 월간 할당량은 두 종류입니다. 현재 사용량은 콘솔에서 확인할 수 있습니다:
/v1/gto/range, 예측 레인지 호출은 각각 1회 차감됩니다./v1/gto/solver는 새 풀이를 트리거할 때마다 1회 차감됩니다. 캐시됨 상태의 풀이를 재사용하고 트리/노드를 가져오는 것은 무료입니다(차감될 때 응답에 solve_quota 필드가 있고, 차감되지 않을 때는 없습니다).모든 오류는 통일된 JSON을 반환합니다: { "error": "<code>", "message": "<description>" }. 몇 가지 변형이 있습니다. 일부 502는 message 대신 reason을 사용하며, 모든 솔버가 바쁠 때의 429는 { "status": "busy", "message": ... } 형태입니다. 엔드포인트별 error 값은 각 엔드포인트의 "가능한 오류" 표에 있고, 공통 상태 코드는 아래와 같습니다:
| HTTP | 오류 / 의미 | 재시도? |
|---|---|---|
| 400 | 잘못된 입력 또는 누락된 필드(구체적인 error는 각 엔드포인트 표 참조). | 아니요, 입력을 수정하세요 |
| 401 | missing_api_key / invalid_api_key: 키가 없거나 유효하지 않습니다. | 아니요, 키를 확인하세요 |
| 403 | invalid_node_token / invalid_solve: 토큰/핸들이 유효하지 않거나 본인의 것이 아닙니다. | 아니요, 먼저 트리를 다시 가져오거나 다시 예약하세요 |
| 404 | no_solution: 이 스팟의 GTO 데이터가 아직 없습니다. | 아니요, 스팟을 변경하세요 |
| 429 | quota_exceeded (일반) / solve_quota_exceeded (풀이): 월간 할당량을 모두 사용했습니다. | 아니요, 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(키 누락) / 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뿐입니다 — 지수 백오프를 사용하세요(약 1초부터 시작해 두 배로 늘리고, 최대 2~3회). 나머지(400/401/403/404/할당량 소진)는 최종 상태이므로 재시도해도 소용없습니다. 입력을 수정하거나 / 키를 변경하거나 / 트리를 다시 가져오거나, 매월 1일에 할당량이 재설정될 때까지 기다리세요. 초당 요청 제한은 없으므로 Retry-After 헤더도 없습니다.
키를 받았다면(위 참조) POKERAI_API_KEY로 저장하고 이 curl을 복사하세요. 가장 간단한 성공 호출입니다. 히어로에게 UTG에서 오픈 기회가 있고(RFI), 프리플랍 사전 풀이가 밀리초 안에 반환됩니다. 대시보드에서도 같은 시작 스니펫을 복사할 수 있습니다.
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}]}'
실제 응답(AKs를 가진 UTG, 오픈 기회 → 3BB로 100% 오픈):
{
"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}를 추가하고 히어로를 MP로 변경 → 3벳 상황이 되며, situation은 Raise를 반환합니다). 각 액션의 혼합 빈도가 반환됩니다(추천 액션 없음; frequency를 기준으로 직접 선택하세요). 아래 섹션은 사전 풀이(프리플랍 / 플롭), 실시간 풀이, 레인지 변환의 세 부분으로 구성됩니다.
HTTP를 직접 작성하고 싶지 않으신가요? 공식 클라이언트는 OpenAPI 사양에서 자동 생성되고 완전한 타입이 지정되어 있어 항상 API를 따라갑니다. 인증에는 API 키만 사용합니다.
pip install pokerai-bet # 배포 이름은 pokerai-bet, pokerai로 import
동일한 빠른 시작 상황(히어로 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())
실제 출력(빠른 시작과 같은 상황):
{"hole_cards": "AhKh", "situation": "RFI",
"strategy": [{"action": "raise", "frequency": 1, "sizing_pot": 0.8, "amount_bb": 3}],
"quota": {"used": 2702, "limit": 100000}}
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입니다.
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"을 추가하면 실시간 솔버 도구가 활성화됩니다(풀이 할당량 소모).
전반적인 정신 모델입니다. 이것을 한 번 읽으면 아래 엔드포인트별 섹션을 더 원활히 이해할 수 있습니다.
모든 전략은 각 액션의 혼합 빈도(0–1)를 반환하며 액션을 대신 선택하지 않습니다 — frequency에서 직접 구현하세요(최대 확률을 선택하거나 빈도에 따라 무작위로 샘플링).
각 bet/raise에는 두 개의 크기 필드가 있습니다. amount_bb(절대 금액, 즉 레이즈 목표 총 BB 금액) 및 sizing_pot(팟 대비 값, 표준 팟 비율 표기):
예시: 3 오픈에 대응해 9로 3벳 — 팟은 4.5이고, 콜 후 4.5+3=7.5이며, 레이즈 초과분은 9−3=6이므로 sizing_pot = 6/7.5 = 0.8입니다. 올인일 때는 allin: true도 포함합니다.
플롭 결정 트리와 실시간 솔버는 모두 두 단계입니다. 먼저 전체 트리를 가져오고(각 결정 노드에 token이 있음), 히어로 노드의 토큰으로 해당 단계의 전략을 가져옵니다.
트리 가져오기 /flop/tree 또는 /solver (+ /solver/tree 폴링)
└─→ nodes[]: 각 노드에는 is_hero + token이 있음
└─→ is_hero:true인 노드 선택
노드 가져오기 /flop/node 또는 /solver/node (본문에 해당 노드의 token 포함)
└─→ 이 단계의 혼합 전략
/flop/tree(1회 과금) → /flop/node(무료). root 노드 = 히어로의 첫 결정입니다./solver 예약은 solve 핸들을 반환합니다(1회 과금) → /solver/tree 폴링 + /solver/node(둘 다 무료). 레인지는 예약 시 한 번만 제공하며 다시 전달하지 않습니다.노드 경로 표기법(트리 소스에 따른 두 가지 규칙): 플롭 결정 트리는 BET_8(밑줄, 정수 BB)를 사용하며, 솔버 트리는 BET 8.000000(공백, 소수점 이하 6자리)를 사용합니다. node_id를 전달하거나 탐색할 때는 해당 트리(또는 solver_results)의 레이블과 문자 단위까지 일치해야 합니다.
예약 후 /solver/tree의 spot_status를 폴링합니다: available(예약되지 않음) → computing(풀이 중, 계속 폴링) → queryable(노드를 가져올 수 있음) → expired(TTL로 캐시가 회수됨, 다시 예약해야 함). 쿼리가 끝나면 선택적으로 /solver/release를 호출하여 포트를 즉시 풀에 반환할 수 있습니다(그렇지 않으면 TTL에 의해 회수됨). 해제 후 이 solve 핸들에 대한 추가 쿼리는 expired를 반환합니다.
프리플랍과 플롭은 즉시 제공되는 사전 풀이된 GTO 솔루션을 사용하며, 빠른 응답이 필요한 사용 사례에 적합합니다. 유효 스택은 100BB로 고정됩니다(사전 풀이됨, 입력값 아님). 실제 솔버로 플롭을 실시간 계산하려면 다음 섹션을 참조하세요.
POST https://pokerai.bet/v1/gto/preflop 일반 할당량 1 소모
전체 파라미터 / 응답 스키마 및 직접 테스트 → 대화형 레퍼런스.
"팟이 몇 베팅인지"를 판단할 필요가 없습니다. 히어로 이전의 프리플랍 액션을 순서대로 제공하면 서버가 스팟을 자동으로 도출합니다(오픈되지 않음 / 레이즈에 직면 / 3벳 / 4벳…).
| 필드 | 유형 | 설명 |
|---|---|---|
hole_cards | 문자열 | 히어로의 홀 카드 2장. 예: "AdKd". |
positions.hero | 문자열 | 히어로의 포지션이며, SB BB UTG MP CO BTN 중 하나입니다(positions 아래에 배치). |
preflop_actions | 배열 | 스몰 블라인드부터 히어로 바로 전 플레이어까지의 완전하고 명시적인 액션 시퀀스(히어로는 시퀀스에 포함되지 않으며, 히어로의 포지션은 positions.hero로 제공되고 시퀀스는 히어로 전 플레이어에서 끝납니다). 각 항목은 { position, action, amount, allin? }, 아래 표를 참조하세요. |
preflop_version | 문자열 | 선택 사항. 사용할 6max 프리플랍 차트 세트: 6max(기본값) / 6max_RC_100bb_200NL / 6max_RC_100bb_100NL / 6max_RC_40bb. 플랫폼 기본값(6max )은 생략하세요. 알 수 없는 값 -> 400 unsupported_preflop_version. 버전마다 같은 스팟의 빈도가 다릅니다. |
| 필드 | 유형 | 설명 |
|---|---|---|
position | 문자열 | 이 액션의 포지션. SB BB UTG MP CO BTN 중 하나. |
action | 문자열 | ∈ "small blind" / "big blind" / "raise" / "call" / "fold"(블라인드는 두 단어 문자열임에 유의). |
amount | 숫자 | 이 액션으로 새롭게 투자되는 증분 금액(BB, 누적 합계 아님). 예: 스몰 블라인드 0.5; 빅 블라인드 1; 3으로 오픈 레이즈 → amount 3(0에서); 이미 1을 투자한 플레이어가 9로 리레이즈 → amount 8. fold는 이를 생략합니다(0으로 계산). 팟 = 모든 amount의 합계. |
allin | 불리언 | 선택 사항. 쇼트스택 올인(최소 레이즈보다 작은 베팅/콜 금액)을 표시합니다. true이면 최소 레이즈 검사를 건너뜁니다. |
검증(위반 → 400 invalid_actions): 시퀀스는 small blind (0.5), 그다음 big blind (1)로 시작해야 합니다. 각 raise/call에는 양수 amount가 필요합니다. raise의 누적 합계는 현재 베팅을 초과하고 최소 레이즈(= 현재 베팅 + 이전 레이즈의 크기, 따라서 오픈 ≥ 2BB, 3으로 오픈한 경우 3벳은 ≥ 5BB)를 충족해야 합니다. 단, allin:true는 예외입니다. call의 누적 합계는 현재 베팅과 정확히 같아야 합니다. 단, allin:true는 예외입니다.
정확한 금액은 빈도가 아니라 팟 / sizing_pot에만 영향을 줍니다: 정확한 amount 값을 제공하면 팟 / sizing_pot만 정확해집니다. GTO 빈도는 스팟(RFI / 3벳 / 4벳 + 포지션)에 의해 결정되며 베팅 크기에 따라 변하지 않습니다.
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}]}'
기본값(6max)에는 preflop_version을 생략하세요. 사용 가능한 버전은 아래에 나열되어 있으며, GET /v1/gto/preflop/versions로 실시간 조회할 수도 있습니다.
{"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 | 히어로 차례일 때 테이블이 맞닥뜨린 상태: RFI(팟에 아무도 없고 히어로에게 오픈 기회가 있음) / Limp(누군가 림프했고 레이즈 없음) / Raise(한 번의 오픈 레이즈에 직면) / 3-Bet / 4-Bet / 5-Bet. 참고: BB는 항상 Limp에 해당합니다(액션하기 전에 누군가 팟에 들어왔어야 함). |
strategy[] | 각 액션의 혼합 전략. raise에는 amount_bb(BB 단위로 레이즈 후의 절대 총액)와 sizing_pot(베팅 크기 참조)가 포함됩니다. 프리플랍 amount_bb는 히어로 이전의 레이즈 횟수로 설정되며 아래 표를 참조하세요. 권장 액션은 반환되지 않습니다. frequency를 기준으로 직접 선택하세요. |
quota | 이번 달 일반 할당량 사용량(used / limit). |
프리플랍 amount_bb(사전 풀이된 플롭 팟에서 도출된 값, 레이즈 후의 금액):
| 히어로 이전 레이즈 횟수 | 스팟 | amount_bb |
|---|---|---|
| 0 | 오픈 | 3 |
| 1 | 3벳 | 9 |
| 2 | 4벳 | 25 |
| ≥3 | 5벳+ | 올인 100 (allin: true) |
preflop_version동일한 6max이지만 차트 세트가 다릅니다(같은 스팟의 빈도는 다름). 기본값 6max에는 생략하세요. 권위 있는 목록은 디스커버리 엔드포인트 GET /v1/gto/preflop/versions입니다(무료, id + label + default 반환):
id (preflop_version으로 전달) | 설명 |
|---|---|
6max (기본값) | 6맥스 100bb Deepsolver |
6max_RC_100bb_200NL | 6맥스 100bb GG 200NL 3b/f 2.2x - 2.5x |
6max_RC_100bb_100NL | 6맥스 100bb GG 100NL 3b/f |
6max_RC_40bb | 6맥스 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 | 오류 | 발생 조건 / 해결 방법 |
|---|---|---|
| 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 | 이 프리플랍 스팟에 사전 계산된 풀이가 없습니다. 스팟을 변경하세요. |
다운로드: request.jsonresponse.json
POST https://pokerai.bet/v1/gto/preflop/range · 스팟(포지션 + 액션 라인)의 전체 13×13 레인지로, 한 번의 호출에서 169개 모든 핸드 유형의 폴드/콜/레이즈를 반환합니다. 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(높은 카드 우선). 각 항목의 폴드+콜+레이즈≈1입니다. 전체 스키마 / 라이브로 사용해 보기 → 대화형 레퍼런스.
플롭 전략은 의사결정 트리입니다. 먼저 트리를 가져와(모든 의사결정 노드 + 각 노드의 token 획득) 사용자 시스템이 실제 베팅에 따라 트리의 경로를 따라가고, 히어로의 노드에서 해당 단계의 전략을 가져옵니다. 솔버와 동일한 두 단계(tree → node)입니다.
POST https://pokerai.bet/v1/gto/flop/tree · 입력: board + pot_type + positions(hole_cards 불필요, 트리는 핸드와 무관).
전체 파라미터 / 응답 스키마 및 라이브로 사용해 보기 → 대화형 레퍼런스.
board | 3장의 플롭 카드(예: "2c2h2s"). |
pot_type | "SRP" 싱글 레이즈 / "3BET" / "4BET" / "LIMP" 림프. |
positions | 각 역할의 포지션(SB BB UTG MP CO BTN)이며, 아래의 pot_type별로 필요합니다. |
flop_version | 선택 사항. 어떤 플롭 데이터세트인지(프리플랍 버전당 하나의 풀이): 6max(기본값) / 6max_RC_100bb_200NL / 6max_RC_100bb_100NL / 6max_RC_40bb. 기본값(6max)에는 생략하세요. 해당 버전에 스팟 데이터가 없으면 6max로 원활하게 대체됩니다. 알 수 없는 값 -> 400 unsupported_flop_version. preflop_version과 무관합니다. 노드 토큰이 이 버전을 담으므로 /v1/gto/flop/node는 동일한 데이터세트를 유지합니다. |
| pot_type | 필수 포지션 | 히어로 값 |
|---|---|---|
SRP | hero, raiser, caller | raiser 또는 caller |
3BET / 4BET | hero, raiser, three_bettor | raiser 또는 three_bettor |
LIMP | hero, limper | 히어로 또는 limper 중 하나는 BB여야 합니다 |
// 요청(hole_cards 없음)
{"board": "2c2h2s", "pot_type": "SRP", "positions": {"hero": "UTG", "raiser": "UTG", "caller": "BTN"}}
// 응답(총 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(히어로의 의사결정 지점인지 여부), token(해당 노드의 전략을 가져오기 위한 자격 증명으로 2단계에 전달됨; 계정 + 스팟에 연결되어 위조할 수 없음). |
pot / effective_stack / node_count | 팟, 유효 스택(BB), 전체 의사결정 노드 수. |
quota | 이번 달 일반 할당량 사용량(used / limit). |
POST https://pokerai.bet/v1/gto/flop/node · node(1단계의 특정 노드 토큰)를 전달합니다. hole_cards 포함 → 해당 핸드의 혼합 전략, hole_cards 미포함 → 전체 레인지 전략.
전체 파라미터 / 응답 스키마 및 직접 사용해 보기 → 대화형 레퍼런스.
모든 히어로 의사결정은 여기서 처리됩니다: 히어로의 첫 액션 = root 노드(OOP가 먼저 액션, 체크/베팅), 히어로가 IP이거나 베팅에 맞서거나 두 번째로 액션할 때는 해당 is_hero:true 노드를 선택합니다(예: root/CHECK/BET_8 = 체크한 뒤 베팅에 맞섬 → 폴드/콜/레이즈). 플롭 트리는 단일 스트리트입니다. 스트리트 간(턴/리버)은 /v1/gto/solver/*를 사용하세요.
// 요청(히어로 노드, hole_cards 포함) -> 히어로 전략
{"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 | 이 노드가 히어로의 의사결정인지 여부. |
strategy[] | 히어로 노드(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 | 오류 | 발생 조건 / 해결 방법 |
|---|---|---|
| 400 | 1) invalid_board / invalid_positions; 2) missing_node / invalid_hole_cards | 1) board가 3장이 아니거나 hero/포지션이 유효하지 않음, 2) node가 없거나 hole_cards가 2장이 아님. |
| 403 | invalid_node_token | (2단계) node 토큰이 유효하지 않거나 본인의 것이 아닙니다. 먼저 /v1/gto/flop/tree를 호출해 트리를 가져오세요. |
| 404 | no_solution | 이 스팟/board에 대한 사전 풀이가 없습니다. |
다운로드: tree_request.jsontree_response.jsonnode_request.jsonnode_response.json
POST https://pokerai.bet/v1/gto/solver 계열. 실시간으로 계산되는 순수 포스트플랍 솔버이며 별도 풀이 할당량을 사용합니다. 핵심은 입력에서 풀이까지입니다. board + oop/ip 레인지 + 팟 + 남은 스택 + 히어로가 누구인지로, 히스토리가 필요 없으므로 어느 스팟에서나 입력할 수 있습니다. 세 단계: 예약 → 트리 폴링 → 노드의 전략 가져오기.
전체 파라미터 / 응답 스키마 및 직접 사용해 보기 → 대화형 레퍼런스(/solver/tree, /solver/node 포함).
board 길이가 스트리트를 정합니다: 3=플롭 / 4=턴 / 5=리버. ⚠ 플롭부터 시작하는 실시간 풀이는 시간이 걸립니다(측정된 SRP 플롭 약 70초). 빠른 응답이 필요한 사용 사례에는 적합하지 않습니다. 빠른 플롭이 필요하면 위의 "사전 풀이"를 사용하세요(밀리초 단위로 즉시 제공). 턴 / 리버는 더 빠릅니다(수초~수십 초).
# 1) 예약(board 3/4/5 = 플롭/턴/리버, 플롭 약 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","bet_sizes":{"flop":[33,75],"turn":[67],"river":[75]},"raise_sizes":{"flop":[50],"turn":[80],"river":[125]},"donk_sizes":{"turn":[55],"river":[90]},"raise_limit":3}'
# 2) spot_status=queryable가 될 때까지 트리를 폴링합니다. 3) 노드를 가져옵니다
curl -s https://pokerai.bet/v1/gto/solver/tree -H "Authorization: Bearer $POKERAI_API_KEY" \
-H "Content-Type: application/json" -d '{"solve":"eyJ...<이전 단계의 solve>"}'
board | 3=플롭 / 4=턴 / 5=리버, 예: "2c2h2s9d" (턴). |
oop_range / ip_range | 필수. 이 스트리트에 진입하는 두 플레이어의 레인지이며, 가중치가 적용된 콤보 문자열입니다. 예: "AsKs:1,QQ:0.75,...". |
pot / effective_stack | 필수. 이 스트리트에 진입할 때의 팟과 남은 유효 스택(BB)이며, 베팅 크기를 결정하므로 실제 값이어야 합니다. |
hero | 필수: "OOP" 또는 "IP". |
bet_sizes | 선택 사항: 스트리트별 오프닝 베팅 크기를 재정의합니다. 예: {"flop":[33,75],"turn":[67],"river":[75]} (팟의 %); flop이 생략되면 기본값은 50%입니다. |
raise_sizes | 선택 사항: 스트리트별 레이즈 크기를 재정의합니다. 예: {"flop":[50],"turn":[80],"river":[125]} (팟의 %); 생략된 스트리트는 bet_sizes 또는 기본값을 재사용합니다. |
donk_sizes | 선택 사항: OOP 돈크 리드 크기를 재정의합니다. 예: {"turn":[55],"river":[90]} (팟의 %); 기본값은 턴 67%, 리버 100%입니다. |
raise_limit | 선택 사항: 트리 전체 레이즈 상한, 1–4; 기본값은 플롭/턴 풀이의 경우 3, 리버 전용 풀이의 경우 4입니다. |
// 요청 (플롭, 사용자 지정 베팅 / 레이즈 / 돈크 크기 포함)
{"board": "2c2h2s", "oop_range": "AA,KK,QQ,AKs", "ip_range": "JJ,TT,AQs,KQs", "pot": 7.5, "effective_stack": 97, "hero": "OOP", "bet_sizes": {"flop": [33,75], "turn": [67], "river": [75]}, "raise_sizes": {"flop": [50], "turn": [80], "river": [125]}, "donk_sizes": {"turn": [55], "river": [90]}, "raise_limit": 3}
// 응답 (첫 트리거, 풀이 1회 차감)
{"status": "computing", "solve": "eyJ0Ijoic2x2XzJmMjk2MWU3Y2Y0ODU3OGUiLCJ1IjoiYjk4Y2Y5NzAtZTVjMS00Njk5LTg4ODQtOGQzYzcwMGIyNGJlIiwidHMiOjE3ODIxMjkxMTUyMDJ9.rtmeNcZoBNWJRhkAGkTSSR58ZafpAh35mi510bgPU6c", "solve_quota": {"used": 1, "limit": 100}}
| 필드 / 경우 | 설명 |
|---|---|
solve | 풀이 핸들입니다. 이후 /tree 및 /node에서 사용하며, 레인지는 이 단계에서 한 번만 제공합니다. |
status = computing | 새 풀이가 트리거되었으며, 풀이 할당량 1회가 차감됩니다 (solve_quota 참조). |
status = queryable | 이 스팟에 대해 캐시됨 풀이가 이미 존재하며, 차감되지 않습니다 (solve_quota 필드 없음). /tree를 직접 폴링하세요. |
429 status = busy | 모든 솔버가 사용 중이며 차감되지 않습니다. 나중에 재시도하세요. |
캐시 적중 (다시 차감되지 않음): 동일한 스팟(동일한 board/레인지/pot/스택/hero/bet_sizes/raise_sizes/donk_sizes/raise_limit)을 다시 예약해도 풀이 할당량이 더 이상 차감되지 않습니다 — 응답에 solve_quota 필드가 없으면 차감되지 않았다는 뜻입니다. 반환된 solve 핸들을 사용해 /tree를 폴링하면 됩니다. 예시: 요청 / 응답.
POST https://pokerai.bet/v1/gto/solver/tree · solve 핸들을 전달하며, spot_status = queryable가 될 때까지 폴링합니다. 이후 스트리트에 도달하려면, 딜된 카드인 turn_card(플롭 풀이 → 특정 턴) 및/또는 river_card를 전달하세요. 플롭 풀이의 리버 스팟에는 turn_card + river_card가 모두 필요합니다(리버만으로는 고유하지 않음). 턴 풀이에는 river_card만 필요하며, 풀이 자체 스트리트에서는 둘 다 생략하세요.
// (2) 이 스트리트(플롭) 트리 가져오기
{"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_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…"}, …]}
// 리버 트리 (플롭 풀이 + 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 (캐시가 회수됨, 1단계에서 다시 예약) / no_nodes (풀이가 수렴했지만 조회한 런아웃/스트리트에 트리 내 의사결정 노드가 없음 — 종료 상태이므로 폴링을 중지). |
nodes[] | 각 의사결정 노드: node (액션 경로), is_hero, status, token (해당 노드의 전략을 가져오는 자격 증명이며 3단계로 전달). 리버 런아웃은 리버 카드로 탐색하는 찬스 노드입니다. |
street / pot / effective_stack / node_count | 스트리트, 팟, 유효 스택 및 의사결정 노드의 총수입니다. |
solve_seconds | 예약부터 수렴까지 이 실시간 풀이에 소요된 실제 시간(초)입니다. queryable일 때만 반환되며, 동일한 풀이의 모든 런아웃은 이 값을 공유합니다. |
전체 매개변수 / 응답 스키마 및 대화형 레퍼런스에서 직접 시도하기 → 대화형 레퍼런스.
POST https://pokerai.bet/v1/gto/solver/node · node 토큰을 전달합니다. 히어로 노드는 히어로 전략을 반환하며, 상대 노드(또는 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 | 이 노드가 히어로의 결정인지 여부입니다. |
strategy[] | 히어로 노드: 이 핸드에 대한 히어로의 혼합 전략(action / amount_bb / sizing_pot(베팅 크기 참조) / frequency)이며, 올인일 때 allin: true가 추가됩니다. |
actions[] + range_strategy | 상대 노드(또는 hole_cards가 없는 경우): range_strategy에서 각 핸드의 빈도는 actions 순서에 맞춰지며, range_hand_count도 포함됩니다. |
전체 매개변수 / 응답 스키마 및 대화형 레퍼런스에서 직접 시도하기 → 대화형 레퍼런스.
완료한 후에는 선택적으로 /v1/gto/solver/release를 호출하여 포트를 즉시 해제할 수 있습니다(그렇지 않으면 시스템이 TTL에 따라 자동으로 회수합니다). 캐시가 회수되었거나 더 새로운 풀이로 대체된 경우 이 단계는 { "node_status": "expired" }를 반환합니다. 1단계에서 다시 예약하면 됩니다. 노드별 풀이 오류는 { "node_status": "error", "message": … }를 반환합니다(종료 상태 — 폴링을 중지하세요). 전체 /solver/release 매개변수 / 응답 스키마 → 대화형 레퍼런스.
| HTTP | 오류 | 발생 조건 / 해결 방법 |
|---|---|---|
| 400 | invalid_board / missing_range / invalid_pot / invalid_effective_stack / invalid_hero | (예약) 보드, oop/ip 레인지, 팟, 남은 스택, 히어로 또는 기타 풀이 입력이 유효하지 않습니다. |
| 400 | missing_solve / missing_node | (트리/노드 가져오기) solve 핸들 또는 node 토큰이 없습니다. |
| 403 | invalid_solve / invalid_node_token | 핸들/토큰이 유효하지 않거나 본인의 것이 아닙니다 — 다시 예약하거나 트리를 다시 가져오세요. |
| 429 | status: busy | 모든 솔버가 사용 중이며, 과금되지 않습니다. 대기한 후 재시도하세요. |
| 502 | solve_failed | 풀이 실행에 실패했습니다. 나중에 다시 시도하세요. |
| 503 | upstream_unavailable | (트리/노드) 서비스 자체 재시도(전송 오류 / 5xx) 후에도 솔버에 연결할 수 없습니다 — 재시도할 수 있습니다. |
다운로드 (턴, board=4): schedule_reqschedule_restree_reqtree_resnode_reqnode_res
다운로드 (플롭, board=3): schedule_reqschedule_restree_reqtree_resnode_reqnode_res
다운로드 (리버, board=5): schedule_reqschedule_restree_reqtree_resnode_reqnode_res
import requests, time
H = {"Authorization": "Bearer $POKERAI_API_KEY"}
BASE = "https://pokerai.bet/v1/gto"
# 1) 예약(풀이 할당량 1개 과금, 캐시 적중 시 무료)
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",
"bet_sizes": {"turn": [67], "river": [75]},
"raise_sizes": {"turn": [80], "river": [125]},
"donk_sizes": {"turn": [55], "river": [90]},
"raise_limit": 3}).json()["solve"]
# 2) 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) # 계산 중 -> 대기 후 재시도
# 3) 히어로의 루트 노드 전략 가져오기
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"])
POST https://pokerai.bet/v1/gto/range 일반 할당량 1개 과금
전체 매개변수 / 응답 스키마 및 대화형 레퍼런스에서 직접 시도하기 → 대화형 레퍼런스.
액션 라인을 따라 OOP/IP 레인지를 업데이트합니다. 주로 다음 스트리트로 진입하는 레인지(플롭→턴 / 턴→리버)를 가져온 후 /v1/gto/solver에 전달하는 데 사용합니다. 정규화와 블러프 할인을 포함한 모든 레인지 업데이트 계산은 솔버가 수행하며, 솔버의 결과와 일치합니다.
이것은 패스스루 프록시입니다. solver_results(의사 결정 트리)를 포함해 모든 입력을 직접 조립합니다. 의사 결정 트리는 자체 풀이 중 하나이거나 이 플랫폼의 플롭 의사 결정 트리에서 조립할 수 있습니다. 시작 레인지는 /v1/gto/flop/tree를 호출하고, 이후 각 노드에서 /v1/gto/flop/node를 hole_cards 없이 호출하여 {node_type,player,strategy,childrens}로 중첩된 전체 range_strategy를 가져옵니다. 끝부분의 스크립트를 참조하세요.
{
"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_hand": "AsKs" // 선택 사항, 히어로의 카드를 포함하는 콤보 제거(블로커); 그대로 반환됨
}
카드 차단(선택 사항): hero_position("oop"/"ip") + hero_hand를 설정하면 레인지에서 히어로의 카드 중 하나를 포함하는 모든 콤보를 제거합니다. 레인지 대 핸드 분석에 유용합니다. 둘 다 응답에 그대로 반환됩니다. (이 쌍은 프로젝티드 레인지 래퍼에서도 적용되며, /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
{"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로 솔버에 직접 전달됩니다. |
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 | 핸드 강도 순위(combo:rank, 값이 작을수록 강함)입니다. |
hand_bottom_ranks_oop / hand_bottom_ranks_ip | 레인지 하위권 순위입니다. |
node_id / board / path_length | 그대로 반환된 액션 라인, 보드 및 액션 라인 단계 수입니다. |
bluff_discount_ratio / bluff_combos_ratio | 이번에 실제로 사용된 블러프 할인 파라미터입니다. |
quota | 이번 달 일반 할당량 사용량(used / limit)입니다. |
| HTTP | 오류 | 발생 조건 / 해결 방법 |
|---|---|---|
| 400 | missing_field | range_oop / range_ip / solver_results / node_id 중 하나가 없습니다. |
| 400 | bad_request | 솔버 측에서 거부했습니다(예: 사용자가 제공한 의사 결정 트리에서 node_id가 어디에도 연결되지 않음). |
다운로드: request.json(~1MB, 의사 결정 트리 포함)response.jsonassemble_solver_results.py(엔드투엔드 스크립트)
POST https://pokerai.bet/v1/gto/flop/projected-range 일반 1회 차감
전체 파라미터 / 응답 스키마 및 대화형 API 참조에서 직접 사용해 보기 → 대화형 API 참조.
플롭 액션 라인을 따라 아웃오브포지션/인포지션 레인지를 좁혀 턴에 진입하는 시작 레인지를 직접 가져옵니다. 전체 스팟(board/pot_type/positions)과 하나의 액션 라인(node_id)을 제공하면 플랫폼이 서버에서 의사 결정 트리를 자동으로 조립하고 레인지 업데이트를 완료하여 레인지 변환과 같은 필드 및 그대로 반환된 pot_type를 반환합니다.
이것은 /v1/gto/range를 위한 편의 래퍼입니다. solver_results를 조립하기 위해 /v1/gto/flop/tree + 노드별 /v1/gto/flop/node를 호출하는 수동 단계를 생략할 수 있습니다. 플롭 액션 라인에만 적용됩니다(의사 결정 트리는 이 플랫폼에서 사전 풀이된 플롭 결과로 조립됨). 자체 의사 결정 트리를 가져와야 하는 턴→리버 등의 경우에는 계속 /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 }(플롭과 동일)이며, 3벳/림프 스팟에는 three_bettor / limper가 포함될 수 있습니다. |
node_id | 선택 사항, 기본값 "root". /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는 블러프로 처리되는 레인지의 비율입니다. 생략하면 서버의 턴/리버 기본값을 사용합니다. 둘 다 에코되어 반환됩니다. |
hero_position / hero_hand | 선택적 카드 차단입니다. hero_position ("oop"/"ip") + hero_hand (예: "AsKs")을 설정하면 히어로의 카드 중 하나를 포함하는 모든 콤보가 빌런의 업데이트된 레인지(range_*_new_raw)에서 제거되고, 히어로 자신의 핸드가 히어로 자신의 레인지에 존재하도록 보장합니다. 둘 다 에코되어 반환됩니다. range_*_new_raw만 영향을 받으며, hand_ranks / hand_bottom_ranks는 보드로만 필터링됩니다. |
partner_hands | 선택적 4자 콤보 배열(예: ["Ac9c"])이며, hero_position이 필요합니다. 해당 카드 중 하나를 포함하는 모든 콤보를 빌런의 range_*_new_raw에서 제거합니다. 알려진 데드 카드를 모델링합니다(폴드된 핸드, 노출된 카드). 입력 전용이며(에코되어 반환되지 않음), /v1/gto/turn/projected-range에서도 지원됩니다. |
flop_version | 선택 사항입니다. 사용할 플롭 데이터세트(프리플랍 버전별로 하나의 풀이): 6max (기본값) / 6max_RC_100bb_200NL / 6max_RC_100bb_100NL / 6max_RC_40bb. 기본값(6max)을 사용하려면 생략하세요. 해당 버전에 그 스팟의 데이터가 없으면 원활하게 대체되어 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
{"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로 직접 사용됩니다. |
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 | 핸드 강도 순위(combo: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 | 오류 | 발생 조건 / 해결 방법 |
|---|---|---|
| 400 | invalid_board / invalid_positions | 보드가 카드 3장이 아니거나 positions.hero가 유효하지 않습니다. |
| 404 | no_solution (및 서버 errorType, 예: no_ranges / no_root_node) | 이 스팟에 대해 사전 풀이된 플롭 트리가 없거나 node_id 액션 라인이 어디에도 연결되지 않습니다. |
다운로드: request.jsonresponse.json
POST https://pokerai.bet/v1/gto/turn/projected-range 무료
전체 매개변수 / 응답 스키마와 라이브로 사용해 보기 → 대화형 API 참조.
플롭 프로젝티드 레인지의 턴→리버 버전으로, 실시간 턴 풀이를 위한 것입니다. 턴 액션 라인(스트리트를 마감하는 콜/체크 포함)을 따라 레인지를 좁혀 리버에 진입하는 시작 레인지를 직접 구합니다. 진입 턴 아웃오브포지션/인포지션 레인지는 풀이 자체의 구성에서 읽어 오므로(/v1/gto/solver를 통해 대기열 등록된 레인지), 풀이 핸들 solve + 하나의 node_id만 전달하면 됩니다. 무료(풀이는 이미 /v1/gto/solver를 통해 과금됨)이며, /v1/gto/solver/tree와 마찬가지로 무료입니다. 레인지 변환과 동일한 필드를 반환합니다.
먼저 /v1/gto/solver/tree를 spot_status = queryable가 될 때까지 폴링하세요. 턴→리버에서는 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가 반환한 풀이 핸들(턴 풀이)입니다. |
node_id | 필수입니다. 스트리트를 마감하는 콜/체크로 끝날 수 있는 턴 액션 라인입니다. 공백이 포함된 솔버 노드 표기법입니다. 예: "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")은 히어로의 카드 중 하나를 포함하는 모든 콤보를 빌런의 업데이트된 레인지에서 제거합니다. |
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
{"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 | 정규화된 리버 진입 레인지(클래스 표기법)이며, 리버 풀이의 oop_range / ip_range로 직접 사용됩니다. |
range_*_raw / range_*_raw_before_normalization | 정규화되지 않은 / 할인 전 중간값(콤보 표기법)입니다. |
hand_ranks_* / hand_bottom_ranks_* | 핸드 강도 순위 / 레인지 하위 순위(combo:rank, 더 작을수록 강함)입니다. |
node_id / board / path_length | 에코된 액션 라인, 보드(카드 4장), 액션 라인 단계 수입니다. |
bluff_discount_ratio / bluff_combos_ratio | 이번에 실제로 사용된 블러프 할인 매개변수입니다. |
참고: 무료이므로 응답에 quota 필드가 없으며, pot_type도 없습니다(이는 플롭 전용입니다).
| HTTP | 오류 / 상태 | 발생 조건 / 해결 방법 |
|---|---|---|
| 200 | { "spot_status": "computing" } | 풀이가 아직 수렴하지 않았습니다. 조회할 수 있을 때까지 /v1/gto/solver/tree를 계속 폴링하세요. |
| 400 | missing_solve / missing_node_id | solve 핸들 또는 node_id가 없습니다. |
| 410 | expired | 풀이가 만료되었습니다(TTL). /v1/gto/solver를 통해 다시 예약하세요. |
| 502 | no_solution 등 | 업스트림 풀이 오류입니다. |
다운로드: request.jsonresponse.json
POST https://pokerai.bet/v1/gto/evs 무료
전체 매개변수 / 응답 스키마, 라이브로 사용해 보기 → 대화형 API 참조.
완료된 풀이의 한 노드에서 핸드별, 액션별 기대값을 제공합니다. 풀이 핸들 solve(/v1/gto/solver에서 가져옴) + node_id(/v1/gto/solver/tree에서 가져옴)를 제공하세요. 선택적인 hand로 한 핸드만 필터링할 수 있습니다. 무료입니다(풀이는 이미 과금되었습니다). 먼저 spot_status = queryable이 될 때까지 /v1/gto/solver/tree를 폴링하세요.
{
"solve": "eyJ0Ijoic2x2X3h4eXoi...(/v1/gto/solver의 핸들)",
"node_id": "root",
"hand": "2c2d"
}
| 필드 | 설명 |
|---|---|
solve | 필수입니다. /v1/gto/solver의 풀이 핸들입니다. |
node_id | 필수입니다. /v1/gto/solver/tree의 노드(솔버 표기법, 예: "root", "root/CHECK/BET 6.000000")입니다. |
hand | 선택 사항입니다. 한 핸드의 EV만 필터링합니다(예: "2c2d"). 모든 핸드의 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 콜), 히어로 = UTG. 아래 curl에서는 인증 헤더를 생략했습니다(빠른 시작과 동일).
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 } ] }
SB + BB 포스트만 있고(레이즈 없음) = 히어로가 첫 액션 플레이어(오프닝 스팟)입니다. 오프닝 빈도와 사이징을 반환합니다.
플롭 2c2h2s. 플롭은 의사결정 트리이며, 두 단계입니다. 먼저 트리를 가져온 다음 히어로의 노드 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을 사용해 히어로 전략 가져오기
POST /v1/gto/flop/node
{ "node": "<root의 token>", "hole_cards": "AdKd" }
히어로의 첫 결정 = root; 베팅에 직면하거나 두 번째로 액션할 때 → 해당하는 is_hero:true 노드를 선택하세요. 플롭 의사결정 트리를 참조하세요.
턴(예: 9d)에는 실시간 풀이가 필요하며, 턴에 진입하는 두 플레이어의 레인지가 필요합니다. 플롭 의사결정 트리 + 레인지 변환으로 가져오세요:
oop_range / ip_range와 의사결정 노드를 위해 /v1/gto/flop/tree를 호출합니다.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는 턴에 진입하는 레인지입니다.queryable 상태가 될 때까지 폴링한 다음 노드를 가져옵니다:
POST /v1/gto/solver
{ "board": "2c2h2s9d", "oop_range": "<OOP 턴 진입 레인지>", "ip_range": "<IP 턴 진입 레인지>",
"pot": <턴 팟>, "effective_stack": <턴 유효 스택>, "hero": "OOP" }
이미 자체 레인지/스팟이 있나요? 3단계에서 oop_range / ip_range를 직접 제공하고 도출 과정을 건너뛰세요.
리버(카드 5장의 board)는 턴과 동일합니다. 독립적으로 풀이할 수 있고(리버에 진입하는 레인지를 직접 제공), 또는 레인지 변환을 사용해 턴 액션 라인을 한 번 더 업데이트하여 리버에 진입하는 레인지를 구한 후 솔버에 전달할 수 있습니다.
pokerkit-plus(pokerkit 0.7.3의 상위 집합)를 래핑합니다: 보드/핸드 의미론, 레인지 및 에퀴티, 평가/에퀴티/ICM/표기법, 게임 시뮬레이션. 동일한 API 키 및 할당량을 재사용합니다 — 저렴한 엔드포인트는 general 버킷에, 몬테카를로 엔드포인트는 solve 버킷에 과금됩니다. 기본 경로는 /v1/pokerkit/*이며, 카드 입력은 구분자 없는 문자열(AsKsQs)이고 열거형은 {name,value}를 반환합니다. 엔드포인트별 전체 매개변수/스키마 및 라이브 테스트 → 대화형 참조; 기계 판독 가능 사양 → /openapi.en.json (결합된 GTO + pokerkit 스냅샷).
보드(히어로와 무관): /texture (보드 웻니스/연결성/사용 가능한 드로우), /nuts (넛츠 + 무승부 콤보), /category-combos, /board-report (텍스처+넛츠). 히어로: /hand-tier (완성 핸드 티어), /draws, /outs, /blockers, /hand-report (한 번의 호출로 텍스처+티어+드로우+아웃).
| 필드 | 설명 |
|---|---|
board | 필수. 구분자 없는 커뮤니티 카드 3/4/5장. 예: "AsKsQs". |
hole | 히어로 엔드포인트(hand-tier / draws / outs / blockers / hand-report)에 필수. 홀 카드 2장. 예: "JhTh"; 보드 엔드포인트(texture / nuts / category-combos / board-report)에서는 생략합니다. |
hand_type | 선택 사항, 기본값은 StandardHighHand입니다(v1 전용, 다른 유형은 400 반환). |
dead | 선택 사항. 죽은 카드 / 제거된 카드(이 그룹의 모든 엔드포인트에서 허용). |
POST https://pokerai.bet/v1/pokerkit/texture — 보드 구조: 보드 웻니스/연결성/랭크 밴드/드로우 가능성/수트 형태. 전체 매개변수 / 라이브 테스트 →
{"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}}
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"}}}
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"]}], …}}}
POST https://pokerai.bet/v1/pokerkit/board-report — 한 번의 호출로 텍스처 + 넛츠(보드 개요). 전체 매개변수 / 라이브 테스트 →
{"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"}}}}
POST https://pokerai.bet/v1/pokerkit/hand-tier — 히어로의 완성 핸드 티어(페어 / 투 페어 / 트립스 / 키커 티어, is_nut). 전체 매개변수 / 라이브 테스트 →
{"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"}}}
POST https://pokerai.bet/v1/pokerkit/draws — 히어로의 드로우(스트레이트 / 플러시 드로우, 넛 랭크). 전체 매개변수 / 라이브 테스트 →
{"hole": "Ah5h", "board": "Kh7h2c"}
{"result": {"straight_draw": null, "flush_draw": {"name": "LIVE", "value": "Live"}, "nut_rank": {"name": "NUT", "value": "Nut"}}}
POST https://pokerai.bet/v1/pokerkit/outs — 완성 카테고리를 향상시키는 히어로의 아웃, 그룹화 및 개수. 전체 매개변수 / 라이브 테스트 →
{"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}}
POST https://pokerai.bet/v1/pokerkit/blockers — 히어로가 막는 넛 콤보 수(블로커 카드 / 비율). 전체 매개변수 / 라이브 테스트 →
{"hole": "AhAd", "board": "AsKsQs"}
{"result": {"nut_combos_total": 1, "nut_combos_blocked": 0, "blocker_cards": [], "block_fraction": 0.0, "blocks_nuts": false}}
POST https://pokerai.bet/v1/pokerkit/hand-report — 한 번의 호출로 텍스처 + 티어 + 드로우 + 아웃(히어로 개요, 대표 기능). 전체 매개변수 / 라이브 테스트 →
{"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}}}
/range/expand (표기법 → 구체적 콤보), /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로 명시적으로 설정할 수도 있습니다. |
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"]]}
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"], …]}
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"}}}
일반 1회 차감 /eval/hand, /eval/compare (순위 + 동점), /icm (결정적), /notation/parse (.phh → 구조화됨). 풀이 1회 차감 몬테카를로: /equity, /hand-strength, /range/equity-advantage — sample_count(상한 적용) 및 seed(재현 가능, 10k당 약 2초)를 사용합니다.
몬테카를로 엔드포인트(equity / hand-strength / range/equity-advantage)는 풀이 버킷을 차감하며, 나머지는 일반 버킷을 차감합니다.
| 필드 | 설명 |
|---|---|
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 | 몬테카를로: 샘플 수(상한 적용, 상한 초과 시 상한값으로 제한) / RNG 시드(재현 가능). |
payouts / chips | (icm) 상금 구조 / 플레이어별 칩. |
text | (notation/parse) .phh 핸드 히스토리 문자열. |
POST https://pokerai.bet/v1/pokerkit/eval/hand — hole + board를 메이드 핸드(카드 5장 + 카테고리 라벨)로 평가합니다. 전체 파라미터 / 라이브로 사용해 보기 →
{"hole": "JhTh", "board": "AsKsQs"}
{"result": {"hand": "JhThAsKsQs", "label": {"name": "STRAIGHT", "value": "Straight"}}}
POST https://pokerai.bet/v1/pokerkit/eval/compare — 보드에서 2개 이상의 holdings 순위를 매깁니다(동점 포함). 전체 파라미터 / 라이브로 사용해 보기 →
{"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"}}]}
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}}
POST https://pokerai.bet/v1/pokerkit/hand-strength — 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}}
POST https://pokerai.bet/v1/pokerkit/icm — 칩 / 상금에 따른 ICM 에퀴티 분할(결정적). 전체 파라미터 / 라이브로 사용해 보기 →
{"payouts": [50, 30, 20], "chips": [5000, 3000, 2000]}
{"result": {"icm": [38.392857142857146, 32.75, 28.857142857142854]}}
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}}
POST https://pokerai.bet/v1/pokerkit/notation/parse — .phh 핸드 히스토리를 구조화된 설정(variant / blinds / stacks / actions…)으로 파싱합니다. 전체 파라미터 / 라이브로 사용해 보기 →
{"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}}
전체 정보, 상태 비저장 재생: 클라이언트가 액션 목록을 보유하고, 서버는 pokerkit으로 상태를 재구성합니다(서버 상태 없음). /games/state (현재 스팟 스냅샷), /games/step (next_action 적용; expected_action_count는 낙관적 동시성 토큰이며 불일치 → 409), /notation/replay (설정 또는 .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 | (단계) 적용할 액션 / 동시성 토큰(= 확장하는 목록의 길이, 불일치 시 → 409). |
text / index | (재생) 대신 .phh 텍스트를 사용합니다. index는 해당 단계만 반환합니다. cards/normalize는 cards(카드 문자열)만 받습니다. |
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"]}}
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"]}}
POST https://pokerai.bet/v1/pokerkit/notation/replay — 구성 또는 .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}}
POST https://pokerai.bet/v1/pokerkit/cards/normalize — 카드 문자열을 표준 2자 카드로 검증 / 정규화합니다. 전체 파라미터 / 라이브로 사용해 보기 →
{"cards": "Ah Ks Qs"}
{"result": ["Ah", "Ks", "Qs"]}
또한 GET /v1/pokerkit/meta(버전 / 변형 코드 / 핸드 유형 / 열거형 어휘)가 있습니다. 모든 엔드포인트의 전체 파라미터 스키마 및 라이브 사용 → 대화형 레퍼런스(상단에서 두 API를 모두 탐색).
각 엔드포인트의 완전한 요청/응답 요약(실제 데이터, 생략된 필드 없음)은 위 각 섹션의 "다운로드"에 있거나 다음에서 확인할 수 있습니다. 프리플랍 · 플롭 트리 · 플롭 노드 · 솔버 · 레인지 · 예측 레인지 · 예측 레인지 응답 · 조립 스크립트.
/v1은 메이저 버전입니다. 호환성이 깨지는 변경(필드 제거/변경, 의미 변경)은 새 메이저 버전 /v2로 이동하며, /v1은 계속 사용할 수 있습니다./v1에 직접 추가됩니다. "알 수 없는 필드 무시" 방식으로 파싱하고 응답 필드를 엄격하게 허용 목록으로 검증하지 마세요.| 날짜 | 변경 사항 |
|---|---|
| 2026-07-22 | /v1/gto/solver는 이제 bet_sizes 외에도 독립적인 raise_sizes, donk_sizes, raise_limit 필드를 허용합니다. |
| 2026-07-12 | POST /v1/gto/solver/release 추가 — 풀이의 풀 포트를 미리 해제하여 캐시 TTL이 만료될 때까지 기다리지 않고 즉시 풀로 반환합니다(선택 사항, 무료. 해당 풀이에 대한 마지막 /solver/tree / /solver/node 호출 후 호출). |
| 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를 반영하고, 히어로 자신의 핸드를 히어로의 레인지에 주입하며, partner_hands를 추가합니다(상대 레인지에서 파트너의 데드 카드를 차단). |
| 2026-06-22 | 포커 엔진 / 의미론 API /v1/pokerkit/* 추가(보드/핸드 의미론, 레인지/에퀴티, 핸드 평가/에퀴티/ICM/표기법, 게임 시뮬레이션, 동일한 키 및 할당량). 아래를 참조하세요. |
| 2026-06-22 | /v1/gto/preflop/range 추가(전체 13×13 프리플랍 레인지, 한 번의 호출로 169개 핸드). |
| 2026-06-18 | 플롭 분리: 단일 쿼리 /v1/gto/flop을 제거하고 /v1/gto/flop/tree(트리 가져오기) + /v1/gto/flop/node(노드 가져오기, 무료)로 대체했으며, 솔버의 트리/노드 구조와 일관되게 맞췄습니다. |
| 2026-06-17 | /v1/gto/flop/projected-range 추가(/v1/gto/range를 편리하게 감싼 래퍼: 전체 플롭 스팟 + 액션 라인을 제공하면 서버가 의사 결정 트리를 자동으로 조립하고 턴 레인지를 직접 반환). |
| 2026-06-17 | 보드 / 핸드 형식 통합: 입력은 구분자 없는 문자열이고, 응답의 board는 항상 배열로 반환됩니다. |
| 2026-06-17 | OpenAPI 3.0 사양 추가, 레인지 표기법 / 개념 / 전체 흐름 튜토리얼 문서 추가. |
| 2026-06-17 | /v1/gto/solver는 이제 실시간 플롭 풀이(board=3)를 지원하며, bet_sizes.flop로 플롭 베팅 크기를 맞춤 설정할 수 있습니다. |
| 2026-06-17 | 수정: 플롭 쿼리 레이즈의 amount_bb가 잘못 0이었습니다(이제 올바른 절대 BB를 반환). |
| 2026-06-17 | 레인지 변환 /v1/gto/range 추가. /flop/tree는 시작 oop_range / ip_range를 노출하며, /flop 및 /solver/node는 hole_cards를 전달하지 않으면 전체 레인지 전략을 반환합니다. |
| 2026-06-16 | 턴 / 리버 실시간 풀이 /v1/gto/solver 제품군을 추가했습니다(별도 풀이 할당량). 플롭 결정 트리 /v1/gto/flop/tree를 추가했습니다. |
| 2026-06-15 | 모든 응답에서 recommendation 필드를 제거했습니다 — frequency를 기준으로 직접 액션을 선택하세요. |
pokerai.bet · GTO API v1