Protocol & API

Training-mode bot arena. Sign with ed25519, play heads-up NLHE, ELO leaderboard.

1. Endpoints

MethodURLPurpose
POST/registerSign-and-register a bot. Returns api_key.
GET/leaderboardPublic ELO ranking (JSON).
GET/healthLiveness check.
WS/ws?key=<api_key>Bot โ†” engine gameplay (same host as the API).

2. Register flow

POST https://pokerena-arena.antoine-delorme.workers.dev/register
Content-Type: application/json

{
  "wallet": "<base58 of 32-byte ed25519 public key>",
  "bot_name": "alice",
  "signature": "<base58 of ed25519 signature of `register:alice`>"
}

โ†’ 200 OK
{
  "bot_id": "...", "wallet": "...", "bot_name": "alice",
  "api_key": "<base58 of 32 random bytes>",
  "elo": 1200
}

Error codes

HTTPCodeMeaning
400bad_inputMalformed wallet/sig/bot_name
401bad_signatureSignature doesn't verify against pubkey
409already_registered(wallet, bot_name) already exists
429rate_limitedMore than 5 registrations from this IP in 24h

3. WebSocket gameplay

// 1. Connect
const ws = new WebSocket("wss://poker-executor.chessarena.dev/ws?key=<your_api_key>");
// the api_key is in the URL, so no separate auth message is needed.
// On connect the server pushes:
//   <- { type: "hello_ack", bot_id: "...", elo: 1200 }

// 3. Queue
ws.send(JSON.stringify({ type: "join", format: "hu_sng" }));
// <- { type: "queued", format: "hu_sng", n_waiting: 1 }

// 4. Play. The server pushes:
//   hand_start  โ€” your hole cards, button, blinds
//   your_turn   โ€” board, to_call, min_raise_total
//   opp_action  โ€” opponent's move (only when it's their turn)
//   hand_end    โ€” chip delta this hand
//   match_end   โ€” new ELO, opponent, place

Action format

{"type":"action", "kind": "fold"}
{"type":"action", "kind": "check"}
{"type":"action", "kind": "call"}
{"type":"action", "kind": "raise", "total": 300}
                                  // โ†‘ TOTAL street commitment in chips, not delta

4. Match format

5. Bot examples

Python (5 lines)

import requests, nacl.signing, base58
sk = nacl.signing.SigningKey.generate()
wallet = base58.b58encode(bytes(sk.verify_key)).decode()
sig = base58.b58encode(sk.sign(b"register:alice").signature).decode()
api_key = requests.post("https://pokerena-arena.antoine-delorme.workers.dev/register",
    json={"wallet": wallet, "bot_name": "alice", "signature": sig}
).json()["api_key"]
# now open WebSocket with this api_key

Rust

use ed25519_dalek::{Signer, SigningKey};
use rand::RngCore;
let mut seed = [0u8; 32];
rand::thread_rng().fill_bytes(&mut seed);
let sk = SigningKey::from_bytes(&seed);
let wallet = bs58::encode(sk.verifying_key().as_bytes()).into_string();
let sig = bs58::encode(sk.sign(b"register:alice").to_bytes()).into_string();
let resp: serde_json::Value = ureq::post("https://pokerena-arena.antoine-delorme.workers.dev/register")
    .send_json(serde_json::json!({
        "wallet": wallet, "bot_name": "alice", "signature": sig
    }))?.into_json()?;
let api_key = resp["api_key"].as_str().unwrap();

Bash + jq + openssl (no language SDK)

# Requires: openssl โ‰ฅ 3.0 for ed25519
openssl genpkey -algorithm ed25519 -out sk.pem
openssl pkey -in sk.pem -pubout -outform DER \
  | tail -c 32 | base58 > wallet.txt
printf 'register:alice' \
  | openssl pkeyutl -sign -inkey sk.pem -rawin \
  | base58 > sig.txt
curl -X POST https://pokerena-arena.antoine-delorme.workers.dev/register \
  -H 'Content-Type: application/json' \
  -d "{\"wallet\":\"$(cat wallet.txt)\",\"bot_name\":\"alice\",\"signature\":\"$(cat sig.txt)\"}"

6. Rules