On this site
Errors
Every error the API returns: one JSON shape, one code per failure mode.
Error shape
Errors never use the data envelope. The body always carries error.code and error.message; validation failures add details[], and 404s add reason (plus parent_node_id and legal_tokens when the diagnosis could read an ancestor).
{
"error": {
"code": "validation_error",
"message": "Request validation failed.",
"details": [
{ "field": "flop", "message": "expected 3 cards, e.g. 2c2d2h", "code": "invalid_string" }
]
}
}Catalog
| code | HTTP | When |
|---|---|---|
unauthorized | 401 | API key missing, malformed or revoked. The header format is strict — check it byte by byte. |
subscription_inactive | 402 | The account is suspended or disabled. Contact support. |
forbidden | 403 | The request IP is outside the account's IP allowlist, or the request tripped a security filter. |
stake_not_allowed | 403 | stakes is not in your account's stake allowlist. |
strategy_folder_not_configured | 403 | No strategy folder is configured for the account. Contact support — no request will succeed until it is set. |
not_found | 404 | The node id does not exist in the tree. The body says WHY — see the taxonomy below. |
method_not_allowed | 405 | Only GET is accepted (plus HEAD on /v1/health). |
validation_error | 422 | A parameter failed validation, or an unknown parameter was sent (the schema is strict). details[] names each offending field. |
combo_not_in_range | 422 | The node exists and the request is valid, but your hand is not part of the acting player's range at this node. |
rate_limit_exceeded | 429 | Per-second rate limit exhausted (also used by the pre-auth per-IP limiter). Back off Retry-After seconds. |
monthly_hard_cap_exceeded | 429 | Absolute monthly ceiling reached. Service resumes at the month rollover. |
internal_error | 500 | Unexpected server error. Retrying will not help — report it with the X-Request-ID. |
spot_not_configured | 500 | The strategy file exists but the (situation, position) pair is missing from our runtime config, so pot, stacks and to_act cannot be derived. Our gap, not yours — report it with the X-Request-ID. |
404 taxonomy: reason
Every 404 carries reason — the corrective action lives there. When the diagnosis could read the parent node, the body also carries parent_node_id (in YOUR suit basis, same as node_id in successful responses) and legal_tokens, the action keys that ARE legal there: the ones whose destination node exists in the tree. legal_tokens are the same strings as node_token in actions[]: compose a child id by concatenation.
{
"error": {
"code": "not_found",
"message": "The requested strategy node was not found.",
"reason": "off_tree_sizing",
"parent_node_id": "root-x-b1.82",
"legal_tokens": ["f", "c", "r5.46"]
}
}street_closedLegal continuation, but it closes the street — closes are not queryable nodes.
→ Retry with -turn_<card> / -river_<card> appended.
terminalFold, river close, or a call of an all-in: the hand is over.
→ Close the hand. Nothing to query.
off_tree_sizingParent exists and the action type is right, but that size is not in the tree (or it is in the file with no destination node).
→ Snap to one of legal_tokens.
illegal_actionThe action is not legal at that node (check facing a bet, a card without closing the street, unknown token), or a non-sized action with no destination node.
→ Fail closed; fix the walk.
line_not_in_treeAn ancestor already did not exist: the error originates upstream in the composition.
→ Fail closed; review how the line was built.
flop_not_coveredThe strategy file itself does not exist.
→ The only value that means pending coverage on OUR side. Report it.
unknownNot classifiable (includes a file we could not read).
→ Generic fail-closed.