{"info":{"_postman_id":"a281f420-902a-4469-b4f8-766714e2730b","name":"Texas Hold'em Poker API","description":"<html><head></head><body><p>REST API and WebSocket documentation for the multiplayer Texas Hold'em poker application.</p>\n<p><strong>Architecture:</strong> Go backend, PostgreSQL database, JWT authentication, WebSocket for real-time gameplay.</p>\n<p><strong>Authentication:</strong> Most endpoints require a JWT Bearer token. Obtain one via register, login, or guest login. The login request includes a test script that auto-saves the token to the collection variable.</p>\n<p><strong>Base URLs:</strong></p>\n<ul>\n<li>Production: <a href=\"https://poker.ilheureux.dev\">https://poker.ilheureux.dev</a></li>\n<li>Development: <a href=\"http://localhost:8080\">http://localhost:8080</a></li>\n</ul>\n<p><strong>Quick Start:</strong></p>\n<ol>\n<li>Set <code>baseUrl</code> variable to your target environment</li>\n<li>Register or login to get a JWT token (auto-saved)</li>\n<li>Browse tables, sit down via WebSocket, and play</li>\n</ol>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[],"owner":"53534571","collectionId":"a281f420-902a-4469-b4f8-766714e2730b","publishedId":"2sBXikoXEG","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"publishDate":"2026-03-26T22:30:54.000Z"},"item":[{"name":"Authentication","item":[{"name":"Register","event":[{"listen":"test","script":{"type":"text/javascript","exec":["if (pm.response.code === 200) {","    var jsonData = pm.response.json();","    if (jsonData.token) {","        pm.collectionVariables.set(\"token\", jsonData.token);","        console.log(\"Token saved from register response\");","    }","}"],"id":"59c72033-cafb-478f-869a-ad66085d410d"}}],"id":"36d6e536-d68c-485e-a7dd-f812483cfb66","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n\t\"username\": \"phil_ivey\",\n\t\"displayName\": \"Phil Ivey\",\n\t\"password\": \"str0ngP@ssword!\"\n}"},"url":"https://poker.ilheureux.dev/auth/register","description":"<p>Create a new player account with a username, display name, and password. Returns a JWT token and player info. The player starts with a default chip balance.</p>\n","urlObject":{"path":["auth","register"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"72f6595a-7819-4c97-acfa-1b38dd247743","name":"Successful Registration","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n\t\"username\": \"phil_ivey\",\n\t\"displayName\": \"Phil Ivey\",\n\t\"password\": \"str0ngP@ssword!\"\n}"},"url":"https://poker.ilheureux.dev/auth/register"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5ZXJJZCI6ImE3YjNjOWQxLWU1ZjYtNDc4OS1hYmNkLWVmMTIzNDU2Nzg5MCIsImV4cCI6MTcxMTUwMDAwMH0.abc123\",\n\t\"player\": {\n\t\t\"playerId\": \"a7b3c9d1-e5f6-4789-abcd-ef1234567890\",\n\t\t\"displayName\": \"Phil Ivey\",\n\t\t\"balance\": 10000,\n\t\t\"isGuest\": false\n\t}\n}"}],"_postman_id":"36d6e536-d68c-485e-a7dd-f812483cfb66"},{"name":"Login","event":[{"listen":"test","script":{"type":"text/javascript","exec":["if (pm.response.code === 200) {","    var jsonData = pm.response.json();","    if (jsonData.token) {","        pm.collectionVariables.set(\"token\", jsonData.token);","        console.log(\"Token saved from login response\");","    }","}"],"id":"0dc6ed91-f3f2-45fc-b133-8058d44c9de8"}}],"id":"a0a2972d-60fa-4ebd-ab4f-5d81eddc968b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n\t\"username\": \"phil_ivey\",\n\t\"password\": \"str0ngP@ssword!\"\n}"},"url":"https://poker.ilheureux.dev/auth/login","description":"<p>Authenticate with an existing account using username and password. Returns a JWT token. The test script automatically saves the token to the <code>token</code> collection variable for use in subsequent requests.</p>\n","urlObject":{"path":["auth","login"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"29558337-63c2-40da-8f08-99465f1e96b6","name":"Successful Login","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n\t\"username\": \"phil_ivey\",\n\t\"password\": \"str0ngP@ssword!\"\n}"},"url":"https://poker.ilheureux.dev/auth/login"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5ZXJJZCI6ImE3YjNjOWQxLWU1ZjYtNDc4OS1hYmNkLWVmMTIzNDU2Nzg5MCIsImV4cCI6MTcxMTUwMDAwMH0.xyz789\"\n}"}],"_postman_id":"a0a2972d-60fa-4ebd-ab4f-5d81eddc968b"},{"name":"Guest Login","event":[{"listen":"test","script":{"type":"text/javascript","exec":["if (pm.response.code === 200) {","    var jsonData = pm.response.json();","    if (jsonData.token) {","        pm.collectionVariables.set(\"token\", jsonData.token);","        console.log(\"Token saved from guest login response\");","    }","}"],"id":"a0160d1a-0925-4340-b01e-777798597c8e"}}],"id":"41545456-7e0e-41b3-93a6-726e4e8a75bf","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n\t\"displayName\": \"Lucky Guest\"\n}"},"url":"https://poker.ilheureux.dev/auth/guest","description":"<p>Create a guest account with an optional display name. No username or password required. Returns a JWT token. Guest accounts have limited persistence but can play immediately.</p>\n","urlObject":{"path":["auth","guest"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"4efa7a1d-27a9-46bf-8473-24c60eecd543","name":"Successful Guest Login","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n\t\"displayName\": \"Lucky Guest\"\n}"},"url":"https://poker.ilheureux.dev/auth/guest"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5ZXJJZCI6Imd1ZXN0LTEyMzQ1Njc4LTkwYWItY2RlZi0xMjM0LTU2Nzg5MGFiY2RlZiIsImV4cCI6MTcxMTUwMDAwMH0.guest123\",\n\t\"player\": {\n\t\t\"playerId\": \"guest-12345678-90ab-cdef-1234-567890abcdef\",\n\t\t\"displayName\": \"Lucky Guest\",\n\t\t\"balance\": 10000,\n\t\t\"isGuest\": true\n\t}\n}"},{"id":"6ddf4ad6-3af3-4e8f-a342-be533ac13fc2","name":"Guest Login (No Display Name)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{}"},"url":"https://poker.ilheureux.dev/auth/guest"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5ZXJJZCI6Imd1ZXN0LWFiY2RlZjEyLTM0NTYtNzg5MC1hYmNkLWVmMTIzNDU2Nzg5MCIsImV4cCI6MTcxMTUwMDAwMH0.guest456\",\n\t\"player\": {\n\t\t\"playerId\": \"guest-abcdef12-3456-7890-abcd-ef1234567890\",\n\t\t\"displayName\": \"Guest_7a3f\",\n\t\t\"balance\": 10000,\n\t\t\"isGuest\": true\n\t}\n}"}],"_postman_id":"41545456-7e0e-41b3-93a6-726e4e8a75bf"}],"id":"b4044511-f627-4952-88ba-0f4d84e1ed8a","description":"<p>Register, login, or create a guest account. All three endpoints return a JWT token used for authenticated requests throughout the API.</p>\n","_postman_id":"b4044511-f627-4952-88ba-0f4d84e1ed8a"},{"name":"Tables & Lobby","item":[{"name":"List Tables","id":"59c379d5-0817-4d06-b2ca-24e3a46a9e60","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/tables","description":"<p>Retrieve all active tables in the lobby. Returns each table's ID, stakes (small/big blind), current player count, max seats, and seat availability. Used by the frontend to render the lobby view.</p>\n","urlObject":{"path":["tables"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"ac23b10e-2f24-4db2-a6c7-d49e5329465e","name":"Tables List","originalRequest":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/tables"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"tables\": [\n\t\t{\n\t\t\t\"tableId\": \"micro\",\n\t\t\t\"smallBlind\": 1,\n\t\t\t\"bigBlind\": 2,\n\t\t\t\"maxSeats\": 6,\n\t\t\t\"playerCount\": 4,\n\t\t\t\"seats\": [\n\t\t\t\t{\"seatIndex\": 0, \"occupied\": true, \"displayName\": \"Phil Ivey\"},\n\t\t\t\t{\"seatIndex\": 1, \"occupied\": true, \"displayName\": \"Bot_Aggressive\"},\n\t\t\t\t{\"seatIndex\": 2, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 3, \"occupied\": true, \"displayName\": \"Lucky Guest\"},\n\t\t\t\t{\"seatIndex\": 4, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 5, \"occupied\": true, \"displayName\": \"Bot_Passive\"}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"tableId\": \"low\",\n\t\t\t\"smallBlind\": 5,\n\t\t\t\"bigBlind\": 10,\n\t\t\t\"maxSeats\": 6,\n\t\t\t\"playerCount\": 2,\n\t\t\t\"seats\": [\n\t\t\t\t{\"seatIndex\": 0, \"occupied\": true, \"displayName\": \"Doyle Brunson\"},\n\t\t\t\t{\"seatIndex\": 1, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 2, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 3, \"occupied\": true, \"displayName\": \"Bot_Balanced\"},\n\t\t\t\t{\"seatIndex\": 4, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 5, \"occupied\": false}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"tableId\": \"mid\",\n\t\t\t\"smallBlind\": 25,\n\t\t\t\"bigBlind\": 50,\n\t\t\t\"maxSeats\": 6,\n\t\t\t\"playerCount\": 0,\n\t\t\t\"seats\": [\n\t\t\t\t{\"seatIndex\": 0, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 1, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 2, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 3, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 4, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 5, \"occupied\": false}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"tableId\": \"high\",\n\t\t\t\"smallBlind\": 100,\n\t\t\t\"bigBlind\": 200,\n\t\t\t\"maxSeats\": 6,\n\t\t\t\"playerCount\": 0,\n\t\t\t\"seats\": [\n\t\t\t\t{\"seatIndex\": 0, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 1, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 2, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 3, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 4, \"occupied\": false},\n\t\t\t\t{\"seatIndex\": 5, \"occupied\": false}\n\t\t\t]\n\t\t}\n\t]\n}"}],"_postman_id":"59c379d5-0817-4d06-b2ca-24e3a46a9e60"},{"name":"Create Table","id":"890eac87-e29b-4f91-b90f-a3c9498d9ff2","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Authorization","value":"Bearer "}],"body":{"mode":"raw","raw":"{\n\t\"tableId\": \"micro\",\n\t\"smallBlind\": 1,\n\t\"bigBlind\": 2,\n\t\"maxSeats\": 6\n}"},"url":"https://poker.ilheureux.dev/tables/create","description":"<p>Create a new table with specified stakes and seating. Requires authentication. Fixed table presets: micro (1/2), low (5/10), mid (25/50), high (100/200). The tableId determines the stakes tier.</p>\n","urlObject":{"path":["tables","create"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"c7ca86a4-94a6-4892-b779-dedfc778275c","name":"Table Created","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Authorization","value":"Bearer "}],"body":{"mode":"raw","raw":"{\n\t\"tableId\": \"micro\",\n\t\"smallBlind\": 1,\n\t\"bigBlind\": 2,\n\t\"maxSeats\": 6\n}"},"url":"https://poker.ilheureux.dev/tables/create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"tableId\": \"micro\",\n\t\"smallBlind\": 1,\n\t\"bigBlind\": 2,\n\t\"maxSeats\": 6,\n\t\"playerCount\": 0,\n\t\"message\": \"Table created successfully\"\n}"}],"_postman_id":"890eac87-e29b-4f91-b90f-a3c9498d9ff2"}],"id":"93c6335c-f757-47ab-b86b-9a3175fb7b3c","description":"<p>Browse active tables and create new ones. The lobby shows all tables with real-time player counts, stakes, and seat availability.</p>\n","_postman_id":"93c6335c-f757-47ab-b86b-9a3175fb7b3c"},{"name":"Player Profile","item":[{"name":"Get Current Player","id":"73783534-6b81-4473-aeeb-cd5789e7376b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/player/me","description":"<p>Get the current authenticated player's profile information including player ID, display name, chip balance, and guest status. Used by the frontend to display the player's info in the header and lobby.</p>\n","urlObject":{"path":["player","me"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"32800316-8db7-4915-8233-d19aa74bc18b","name":"Player Profile","originalRequest":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/player/me"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"playerId\": \"a7b3c9d1-e5f6-4789-abcd-ef1234567890\",\n\t\"displayName\": \"Phil Ivey\",\n\t\"balance\": 14750,\n\t\"isGuest\": false\n}"}],"_postman_id":"73783534-6b81-4473-aeeb-cd5789e7376b"},{"name":"Get Player Stats","id":"e925ca45-81f8-4332-b578-48efc2009c8d","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/player/stats","description":"<p>Get detailed gameplay statistics for the authenticated player, including total hands played, hands won, win rate, biggest pot won, and total profit/loss.</p>\n","urlObject":{"path":["player","stats"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"765bd189-344d-4e2e-a518-74e177673a14","name":"Player Statistics","originalRequest":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/player/stats"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"playerId\": \"a7b3c9d1-e5f6-4789-abcd-ef1234567890\",\n\t\"displayName\": \"Phil Ivey\",\n\t\"handsPlayed\": 247,\n\t\"handsWon\": 68,\n\t\"winRate\": 27.53,\n\t\"biggestPot\": 4800,\n\t\"totalProfit\": 4750\n}"}],"_postman_id":"e925ca45-81f8-4332-b578-48efc2009c8d"}],"id":"5eb77a9a-0efd-40f6-bcae-c6e8437d417d","description":"<p>Retrieve the authenticated player's profile information and gameplay statistics.</p>\n","_postman_id":"5eb77a9a-0efd-40f6-bcae-c6e8437d417d"},{"name":"Game History","item":[{"name":"Get Hand History","id":"82c719f7-bf8c-4b3e-869f-0576f2c005fe","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/player/hands","description":"<p>Retrieve the authenticated player's recent hand history. Each hand includes the table ID, hole cards dealt to the player, community cards, pot size, winners, and the hand rank that won.</p>\n","urlObject":{"path":["player","hands"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"1f48714a-611f-44ee-8f95-75dcc7cb4f26","name":"Hand History","originalRequest":{"method":"GET","header":[{"key":"Authorization","value":"Bearer "}],"url":"https://poker.ilheureux.dev/player/hands"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"hands\": [\n\t\t{\n\t\t\t\"handId\": \"h-00000142\",\n\t\t\t\"tableId\": \"micro\",\n\t\t\t\"timestamp\": \"2026-03-26T14:32:18Z\",\n\t\t\t\"holeCards\": [\"As\", \"Kd\"],\n\t\t\t\"community\": [\"Ah\", \"7c\", \"3s\", \"Kh\", \"9d\"],\n\t\t\t\"pot\": 156,\n\t\t\t\"winners\": [\n\t\t\t\t{\n\t\t\t\t\t\"playerId\": \"a7b3c9d1-e5f6-4789-abcd-ef1234567890\",\n\t\t\t\t\t\"displayName\": \"Phil Ivey\",\n\t\t\t\t\t\"handRank\": \"Two Pair\",\n\t\t\t\t\t\"amount\": 156\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"result\": \"won\"\n\t\t},\n\t\t{\n\t\t\t\"handId\": \"h-00000141\",\n\t\t\t\"tableId\": \"micro\",\n\t\t\t\"timestamp\": \"2026-03-26T14:30:45Z\",\n\t\t\t\"holeCards\": [\"Jh\", \"Td\"],\n\t\t\t\"community\": [\"Qc\", \"9s\", \"2h\", \"8d\", \"4c\"],\n\t\t\t\"pot\": 88,\n\t\t\t\"winners\": [\n\t\t\t\t{\n\t\t\t\t\t\"playerId\": \"bot-aggressive-001\",\n\t\t\t\t\t\"displayName\": \"Bot_Aggressive\",\n\t\t\t\t\t\"handRank\": \"Pair\",\n\t\t\t\t\t\"amount\": 88\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"result\": \"lost\"\n\t\t},\n\t\t{\n\t\t\t\"handId\": \"h-00000140\",\n\t\t\t\"tableId\": \"low\",\n\t\t\t\"timestamp\": \"2026-03-26T14:28:12Z\",\n\t\t\t\"holeCards\": [\"Qs\", \"Qd\"],\n\t\t\t\"community\": [\"Qh\", \"5c\", \"8s\", \"2d\", \"Jc\"],\n\t\t\t\"pot\": 640,\n\t\t\t\"winners\": [\n\t\t\t\t{\n\t\t\t\t\t\"playerId\": \"a7b3c9d1-e5f6-4789-abcd-ef1234567890\",\n\t\t\t\t\t\"displayName\": \"Phil Ivey\",\n\t\t\t\t\t\"handRank\": \"Three of a Kind\",\n\t\t\t\t\t\"amount\": 640\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"result\": \"won\"\n\t\t}\n\t]\n}"}],"_postman_id":"82c719f7-bf8c-4b3e-869f-0576f2c005fe"}],"id":"6d85978f-7624-4f76-9807-4f1c5cdb1dc1","description":"<p>Access the player's hand history stored in PostgreSQL. Review past hands with full details including hole cards, community cards, and winners.</p>\n","_postman_id":"6d85978f-7624-4f76-9807-4f1c5cdb1dc1"},{"name":"Leaderboard & Stats","item":[{"name":"Get Leaderboard","id":"a9123598-a01f-4b2f-9884-1c2af8c7db76","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://poker.ilheureux.dev/leaderboard?limit=20","description":"<p>Get the top players ranked by chip balance. This is a public endpoint that does not require authentication. Use the <code>limit</code> query parameter to control how many players are returned.</p>\n","urlObject":{"path":["leaderboard"],"host":["https://poker.ilheureux.dev"],"query":[{"description":{"content":"<p>Maximum number of players to return (default: 20)</p>\n","type":"text/plain"},"key":"limit","value":"20"}],"variable":[]}},"response":[{"id":"ce6ef8bf-d252-47f1-ae69-3f4315d43b86","name":"Leaderboard","originalRequest":{"method":"GET","header":[],"url":{"raw":"https://poker.ilheureux.dev/leaderboard?limit=20","host":["https://poker.ilheureux.dev"],"path":["leaderboard"],"query":[{"key":"limit","value":"20"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"leaderboard\": [\n\t\t{\n\t\t\t\"rank\": 1,\n\t\t\t\"playerId\": \"a7b3c9d1-e5f6-4789-abcd-ef1234567890\",\n\t\t\t\"displayName\": \"Phil Ivey\",\n\t\t\t\"balance\": 14750\n\t\t},\n\t\t{\n\t\t\t\"rank\": 2,\n\t\t\t\"playerId\": \"b8c4d0e2-f6a7-5890-bcde-fa2345678901\",\n\t\t\t\"displayName\": \"Doyle Brunson\",\n\t\t\t\"balance\": 13200\n\t\t},\n\t\t{\n\t\t\t\"rank\": 3,\n\t\t\t\"playerId\": \"c9d5e1f3-a7b8-6901-cdef-ab3456789012\",\n\t\t\t\"displayName\": \"Daniel Negreanu\",\n\t\t\t\"balance\": 11850\n\t\t},\n\t\t{\n\t\t\t\"rank\": 4,\n\t\t\t\"playerId\": \"guest-12345678-90ab-cdef-1234-567890abcdef\",\n\t\t\t\"displayName\": \"Lucky Guest\",\n\t\t\t\"balance\": 10400\n\t\t},\n\t\t{\n\t\t\t\"rank\": 5,\n\t\t\t\"playerId\": \"d0e6f2a4-b8c9-7012-defa-bc4567890123\",\n\t\t\t\"displayName\": \"Johnny Chan\",\n\t\t\t\"balance\": 9600\n\t\t}\n\t]\n}"}],"_postman_id":"a9123598-a01f-4b2f-9884-1c2af8c7db76"},{"name":"Get Card Statistics","id":"a54aaeed-a2b9-426a-90dd-8bfe98c8b23d","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://poker.ilheureux.dev/stats/cards","description":"<p>Get RNG card dealing statistics that prove fair dealing. Shows hand rank distribution (actual vs mathematically expected percentages) and per-card deal frequency with statistical deviation from expected uniform distribution. The dealing algorithm uses Go's crypto/rand with a Fisher-Yates shuffle to ensure cryptographically secure randomness.</p>\n","urlObject":{"path":["stats","cards"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"b3ce97df-efea-4365-b16d-9b17bed9f50e","name":"Card Statistics","originalRequest":{"method":"GET","header":[],"url":"https://poker.ilheureux.dev/stats/cards"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"totalHandsAnalyzed\": 15842,\n\t\"handRankDistribution\": [\n\t\t{\"rank\": \"Royal Flush\", \"actual\": 0.002, \"expected\": 0.0002, \"count\": 3},\n\t\t{\"rank\": \"Straight Flush\", \"actual\": 0.013, \"expected\": 0.0014, \"count\": 2},\n\t\t{\"rank\": \"Four of a Kind\", \"actual\": 0.18, \"expected\": 0.024, \"count\": 28},\n\t\t{\"rank\": \"Full House\", \"actual\": 2.61, \"expected\": 2.60, \"count\": 413},\n\t\t{\"rank\": \"Flush\", \"actual\": 3.07, \"expected\": 3.03, \"count\": 486},\n\t\t{\"rank\": \"Straight\", \"actual\": 4.55, \"expected\": 4.62, \"count\": 721},\n\t\t{\"rank\": \"Three of a Kind\", \"actual\": 4.82, \"expected\": 4.83, \"count\": 764},\n\t\t{\"rank\": \"Two Pair\", \"actual\": 23.48, \"expected\": 23.50, \"count\": 3720},\n\t\t{\"rank\": \"One Pair\", \"actual\": 43.81, \"expected\": 43.82, \"count\": 6940},\n\t\t{\"rank\": \"High Card\", \"actual\": 17.44, \"expected\": 17.41, \"count\": 2763}\n\t],\n\t\"cardDealFrequency\": {\n\t\t\"totalCardsDealt\": 110894,\n\t\t\"expectedPerCard\": 2132.58,\n\t\t\"sample\": [\n\t\t\t{\"card\": \"As\", \"count\": 2148, \"deviation\": \"+0.72%\"},\n\t\t\t{\"card\": \"Kh\", \"count\": 2119, \"deviation\": \"-0.64%\"},\n\t\t\t{\"card\": \"Qd\", \"count\": 2137, \"deviation\": \"+0.21%\"},\n\t\t\t{\"card\": \"2c\", \"count\": 2125, \"deviation\": \"-0.36%\"}\n\t\t],\n\t\t\"maxDeviation\": \"1.24%\"\n\t},\n\t\"shuffleAlgorithm\": \"Fisher-Yates (crypto/rand)\"\n}"}],"_postman_id":"a54aaeed-a2b9-426a-90dd-8bfe98c8b23d"}],"id":"c3f238eb-d343-4803-aed2-901d33a2073f","description":"<p>Public endpoints for viewing the leaderboard and card dealing statistics. No authentication required.</p>\n","_postman_id":"c3f238eb-d343-4803-aed2-901d33a2073f"},{"name":"Health","item":[{"name":"Health Check","id":"59f36441-2666-4282-9d34-d137fe1c04ed","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"https://poker.ilheureux.dev/health","description":"<p>Check if the server is running and healthy. Returns the server status and uptime. This is a public endpoint that does not require authentication. Useful for monitoring and deployment verification.</p>\n","urlObject":{"path":["health"],"host":["https://poker.ilheureux.dev"],"query":[],"variable":[]}},"response":[{"id":"93b1cb02-9310-400f-91ee-77f0116f4c92","name":"Healthy","originalRequest":{"method":"GET","header":[],"url":"https://poker.ilheureux.dev/health"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n\t\"status\": \"ok\",\n\t\"uptime\": \"72h14m33s\",\n\t\"version\": \"1.0.0\"\n}"}],"_postman_id":"59f36441-2666-4282-9d34-d137fe1c04ed"}],"id":"ac20e363-aae4-46f0-8fee-6195b4a615bd","description":"<p>Server health check endpoint. Public, no authentication required.</p>\n","_postman_id":"ac20e363-aae4-46f0-8fee-6195b4a615bd"},{"name":"WebSocket (Real-Time Gameplay)","item":[],"id":"0b5455b1-edb5-4659-9003-81811863738b","description":"<h2 id=\"websocket-connection\">WebSocket Connection</h2>\n<p>The core gameplay happens over a WebSocket connection. All table actions (sitting down, betting, folding) and game state updates are transmitted in real-time via WebSocket messages.</p>\n<h3 id=\"connect\">Connect</h3>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>ws://localhost:8080/ws?token=&lt;JWT_TOKEN&gt;\nwss://poker.ilheureux.dev/ws?token=&lt;JWT_TOKEN&gt;\n</code></pre><p>Pass the JWT token as a query parameter. The server authenticates the connection and associates it with the player.</p>\n<hr />\n<h3 id=\"client-to-server-messages\">Client to Server Messages</h3>\n<p><strong>Sit Down at Table</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"sit_down\",\n  \"tableId\": \"micro\",\n  \"seatIndex\": 2,\n  \"buyIn\": 200\n}\n</code></pre>\n<p><strong>Player Action (Fold / Check / Call / Raise)</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"action\",\n  \"action\": \"raise\",\n  \"amount\": 50\n}\n</code></pre>\n<p>Valid actions: <code>fold</code>, <code>check</code>, <code>call</code>, <code>raise</code> (with amount).</p>\n<p><strong>Leave Table</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"leave_table\"\n}\n</code></pre>\n<hr />\n<h3 id=\"server-to-client-messages\">Server to Client Messages</h3>\n<p><strong>table_state</strong> - Full table snapshot (sent on join and reconnect)</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"table_state\",\n  \"tableId\": \"micro\",\n  \"smallBlind\": 1,\n  \"bigBlind\": 2,\n  \"pot\": 0,\n  \"community\": [],\n  \"seats\": [\n    {\"seatIndex\": 0, \"playerId\": \"abc-123\", \"displayName\": \"Phil Ivey\", \"chips\": 200, \"bet\": 0, \"folded\": false},\n    {\"seatIndex\": 1, \"playerId\": null}\n  ],\n  \"phase\": \"WAITING\"\n}\n</code></pre>\n<p><strong>hand_start</strong> - New hand beginning, includes your hole cards</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"hand_start\",\n  \"handId\": \"h-00000143\",\n  \"dealerSeat\": 0,\n  \"smallBlindSeat\": 1,\n  \"bigBlindSeat\": 2,\n  \"holeCards\": [\"Ah\", \"Kd\"]\n}\n</code></pre>\n<p><strong>action_on</strong> - It's a player's turn to act</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"action_on\",\n  \"seatIndex\": 2,\n  \"playerId\": \"a7b3c9d1-e5f6-4789-abcd-ef1234567890\",\n  \"validActions\": [\"fold\", \"call\", \"raise\"],\n  \"callAmount\": 10,\n  \"minRaise\": 20,\n  \"maxRaise\": 200,\n  \"timeLimit\": 30\n}\n</code></pre>\n<p><strong>community</strong> - Community cards revealed</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"community\",\n  \"phase\": \"FLOP\",\n  \"cards\": [\"Ts\", \"7h\", \"2d\"]\n}\n</code></pre>\n<p><strong>showdown</strong> - Hands revealed at showdown</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"showdown\",\n  \"players\": [\n    {\"seatIndex\": 0, \"playerId\": \"abc-123\", \"holeCards\": [\"Ah\", \"Kd\"], \"handRank\": \"Two Pair\"},\n    {\"seatIndex\": 3, \"playerId\": \"def-456\", \"holeCards\": [\"Qc\", \"Qs\"], \"handRank\": \"One Pair\"}\n  ]\n}\n</code></pre>\n<p><strong>hand_over</strong> - Hand complete, includes winner info</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"hand_over\",\n  \"winners\": [\n    {\"playerId\": \"abc-123\", \"displayName\": \"Phil Ivey\", \"amount\": 320, \"handRank\": \"Two Pair\"}\n  ],\n  \"pot\": 320\n}\n</code></pre>\n<p><strong>winner</strong> - Pot awarded to winner(s)</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"winner\",\n  \"playerId\": \"abc-123\",\n  \"displayName\": \"Phil Ivey\",\n  \"amount\": 320\n}\n</code></pre>\n<p><strong>redirect</strong> - Server instructs client to redirect (e.g., back to lobby)</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"redirect\",\n  \"url\": \"/lobby\"\n}\n</code></pre>\n<p><strong>server_restart</strong> - Server is restarting, clients should reconnect</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"type\": \"server_restart\",\n  \"message\": \"Server restarting for update. Please reconnect in a moment.\"\n}\n</code></pre>\n<hr />\n<h3 id=\"game-state-machine\">Game State Machine</h3>\n<p>The hand progresses through these phases:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>DEALING -&gt; PRE_FLOP -&gt; FLOP -&gt; TURN -&gt; RIVER -&gt; SHOWDOWN -&gt; HAND_OVER\n</code></pre><ul>\n<li><strong>DEALING</strong>: Cards are dealt to all seated players</li>\n<li><strong>PRE_FLOP</strong>: Blinds posted, first betting round</li>\n<li><strong>FLOP</strong>: Three community cards revealed, second betting round</li>\n<li><strong>TURN</strong>: Fourth community card revealed, third betting round</li>\n<li><strong>RIVER</strong>: Fifth community card revealed, final betting round</li>\n<li><strong>SHOWDOWN</strong>: Remaining players reveal hands, best hand determined</li>\n<li><strong>HAND_OVER</strong>: Pot awarded, hand history recorded to PostgreSQL</li>\n</ul>\n<hr />\n<h3 id=\"bot-ai\">Bot AI</h3>\n<p>Tables are populated with bots that use three distinct strategies:</p>\n<ul>\n<li><strong>Passive</strong>: Checks and calls frequently, rarely raises. Folds weak hands. Conservative play style.</li>\n<li><strong>Aggressive</strong>: Raises and re-raises often. Bluffs frequently. Puts pressure on opponents.</li>\n<li><strong>Balanced</strong>: Mixes aggression with caution based on hand strength and position. Most realistic play style.</li>\n</ul>\n<p>Bots have <strong>human awareness</strong> -- they adjust their strategy based on whether opponents are human players or other bots, creating a more natural gameplay experience.</p>\n","_postman_id":"0b5455b1-edb5-4659-9003-81811863738b"}],"variable":[{"key":"baseUrl","value":"https://poker.ilheureux.dev"},{"key":"token","value":""}]}