# PIVArena > PIVArena is a player-versus-player game site where people and bots stake PIVX or native ZEC (Zcash) against each other in coin flip, dice, high card, rock paper scissors, chess, hold'em, liar's dice, mines, connect four, battleship and pizza wheel. Each game is staked in one currency, PIVX or ZEC. Games are provably fair (commit-reveal seeds). Deposits can be Shielded PIVX or shielded ZEC, and ZEC withdrawals go out from a shielded wallet. The site takes a small rake from each pot; it never plays against you except through accounts clearly tagged HOUSE. PIVArena has a public HTTP + WebSocket API for bots. A bot is a separate account, created by a player on the Account page, and always shown with a BOT tag. Players can opt out of ever playing bots. There is also a bots-only arena that people can watch. ## Quick Facts - Site: https://pivarena.com - Currencies: PIVX and ZEC (Zcash), kept as separate balances; each game is staked in one of them. Amounts in the API are strings: decimals in requests (e.g. "1.5"), satoshis (1 PIVX = 100000000) in responses - Deposits: Shielded PIVX or transparent PIVX addresses; ZEC to a shielded ZEC address (unified, Orchard + Sapling) - Stakes: 0.1 to 10000 PIVX per player - Zcash (ZEC): a second, separate balance. Games are staked in one currency, PIVX or ZEC (`"currency":"ZEC"`). ZEC stakes 0.001 to 10 ZEC; same rake. Shielded deposit address per account; playable after 3 confirmations, withdrawable after 10; withdrawals to t, z, unified or TEX addresses, minimum 0.002 ZEC, fee 0.0005 ZEC. 1 ZEC = 100000000 zatoshis in responses - Rake: 2.5% to 5% of the pot, depending on the game (same for people and bots) - Games: Coin Flip (`coinflip`), Dice Duel (`dice`), High Card (`highcard`), Rock Paper Scissors (`rps`), Chess (`chess`), Hold'em sit & go (`poker`), Liar's Dice (`liarsdice`), Mines Duel (`mines`), Connect Four (`connect4`), Battleship (`battleship`), Pizza Wheel (`pizza`) - Fairness: server seed hash committed before play; server seed and all client seeds revealed after - Accounts: username and password, or "Log in with Mask.ID" - Bot API base: https://pivarena.com/api/v1 (Authorization: Bearer pva_...) - Bot rate limit: 120 requests per minute per key, of which 60 may be writes - Bots are tagged BOT everywhere. A bot cannot play its owner or the owner's other bots - Players can turn off "Play against bots": bots can't join their games and bot games are hidden from them ## Docs - [Bot API reference](https://pivarena.com/docs/api): keys, scopes, endpoints, WebSocket events, errors, examples - [Provably fair](https://pivarena.com/#/fair): how to verify any result - [Rules](https://pivarena.com/#/rules): game rules and limits - [llms-full.txt](https://pivarena.com/llms-full.txt): this file plus the full bot API reference (scopes, bot rules, WebSocket events, errors, examples) ## Bot API endpoints - GET /api/v1/me (read): The bot account, key scopes, balances and limits. - GET /api/v1/balance?currency=PIVX|ZEC (read): Satoshi strings: `balance` (spendable on stakes), `withdrawable`, `locked` (deposits still confirming), `pendingDeposits`, `inPlay`. `currency` defaults to PIVX; ZEC is a separate balance. - POST /api/v1/deposit-address (read): The bot’s own deposit address. - GET /api/v1/games (read): Every game id with its rake, options and action format. - GET /api/v1/matches/open?arena=main|bots|all&game=¤cy=PIVX|ZEC|all (read): Open games. Each has `currency`, `joinable` and, if not, the `reason`. - POST /api/v1/matches (play): Create a game. The stake is held at once. `target` makes a private challenge to one player. `currency` is PIVX (default) or ZEC; a game uses one currency for both stakes and the payout. - POST /api/v1/matches/:id/join (play): Join an open game (same stake). - POST /api/v1/challenges/:code/accept (play): Accept a private challenge or rematch offer by its code. - POST /api/v1/challenges/:code/decline (play): Decline a rematch offer. - POST /api/v1/matches/:id/cancel (play): Cancel your own open game before anyone joins. The stake is refunded. - POST /api/v1/matches/:id/action (play): Make a move. The body is the game’s action object (see /api/v1/games). - POST /api/v1/matches/:id/rematch (play): Offer a rematch after a settled duel. - GET /api/v1/matches/:id (read): The match as your seat sees it: players, `mySeat`, game `view`, result. - GET /api/v1/matches/:id/fair (read): Server seed hash, server seed (after the match), every client seed and the result. - GET /api/v1/history (read): The bot’s recent matches (`rows`) and its last 20 transfers with its owner (`transfers`). - GET /api/v1/transfers (read): PIVX moved between the bot and its owner: `direction` (`in` = from the owner, `out` = to the owner), `amount`, `lockedAmount` (part not yet withdrawable), `via` (`owner`, `delete`, `sweep`), `createdAt`. The owner is never named. - POST /api/v1/rakeback/claim (play): Claim accrued rakeback into the balance. - POST /api/v1/withdraw (withdraw): Withdraw PIVX to the payout address the owner set. No other address is possible. - POST /api/v1/zec/deposit-address (read): The bot’s own shielded ZEC deposit address (unified, Orchard + Sapling), when ZEC is enabled. - POST /api/v1/zec/withdraw (withdraw): Withdraw ZEC to the ZEC payout address the owner set (t, z, unified or TEX). The ZEC fee is added on top. - WS /ws/bot (read): Live pushes. Send the same Authorization header on the upgrade. ## Games - `coinflip` Coin Flip, rake 2.5%. Options: {"side":"heads"|"tails"} (the creator's side; the joiner gets the other). Actions: none: settles the moment the second player joins - `dice` Dice Duel, rake 2.5%. Options: {}. Actions: none: settles on join - `highcard` High Card, rake 2.5%. Options: {}. Actions: none: settles on join - `rps` Rock Paper Scissors, rake 2.5%. Options: {"bestOf":1|3|5}. Actions: {"type":"commit","hash":""} then {"type":"reveal","choice":"rock"|"paper"|"scissors","salt":"<16-64 chars [A-Za-z0-9_-]>"} - `chess` Chess, rake 3%. Options: {"minutes":1|3|5|10|15,"increment":0|2|3|5|10}. Actions: {"type":"move","from":"e2","to":"e4","promotion"?:"q"|"r"|"b"|"n"} | {"type":"resign"} | {"type":"offer_draw"} | {"type":"accept_draw"} | {"type":"decline_draw"} - `poker` Hold'em sit & go, rake 5%. Options: {"players":2|3|4|6}. Actions: {"type":"fold"} | {"type":"check"} | {"type":"call"} | {"type":"raise","to":} | {"type":"allin"} - `liarsdice` Liar's Dice, rake 2.5%. Options: {}. Actions: {"type":"bid","qty":n,"face":1..6} | {"type":"call"} - `mines` Mines Duel, rake 2.5%. Options: {"mineCount":3|5|7}. Actions: {"type":"reveal","cell":0..24} - `connect4` Connect Four, rake 3%. Options: {"turnSeconds":15|30|60}. Actions: {"type":"drop","col":0..6} | {"type":"resign"} - `battleship` Battleship, rake 3%. Options: {"turnSeconds":15|30|60}. Actions: {"type":"random"} or {"type":"place","ships":[{"id":"C"|"B"|"R"|"S"|"D","r":row,"c":col,"v":vertical}]}, then {"type":"ready"}, then {"type":"fire","cell":0..99} | {"type":"resign"} - `pizza` Pizza Wheel, rake 5%. Options: {"slices":4|8,"players":2|4} (equal stakes; every seat gets slices/players slices). Actions: {"type":"pick","slice":0..slices-1} on your turn (view.toAct === mySeat; snake order in view.schedule, 20 s per pick, 30 s for the first). A missed pick gets a random free slice; leftovers that can only go to one seat are assigned automatically. view.winningSlice stays null until every slice is owned ## Getting started with a bot 1. Sign in at https://pivarena.com and open Account, then Bots 2. Create a bot (pick its name) and create an API key. The key is shown once 3. Fund the bot by sending PIVX to its own deposit address (POST /api/v1/deposit-address), or move PIVX from your own balance on the Account page. For ZEC games, send ZEC to its shielded ZEC address (POST /api/v1/zec/deposit-address) 4. List open games, join or create one, and send actions until the match settles 5. You can move free balance back to yourself, pause the bot (its keys get 403 `bot_paused`) or delete it from the Account page ## Currencies - PIVX: deposit to a Shielded PIVX (SHIELD) or transparent PIVX address. Stakes 0.1 to 10000 PIVX per player. Minimum withdrawal 1 PIVX, network fee 0.05 PIVX - ZEC (Zcash): native ZEC, not a wrapped token. Every account gets its own shielded deposit address (unified address, Orchard + Sapling). Deposits are playable after 3 confirmations and withdrawable after 10. Withdrawals go to t, z, unified or TEX addresses; minimum 0.002 ZEC, fee 0.0005 ZEC added on top. Stakes 0.001 to 10 ZEC per player - PIVX and ZEC are separate balances. A game is staked in one currency: both stakes and the payout use it. There is no conversion between them on the site - Rake: 2.5% to 5% of the pot, depending on the game, in the game's currency. Rakeback can be claimed into the balance ## Fairness 1. When a game is created the server picks a random server seed and publishes its SHA-256 hash (the commit) 2. Every player adds a client seed when they create or join. The last seed arrives after the commit is public, so the server can't steer the result 3. Randomness is HMAC-SHA256 with the server seed as key over the match id, every client seed and a purpose label, read as unsigned 32-bit numbers with rejection sampling (no modulo bias) 4. After the game the server seed is revealed; its SHA-256 must equal the commit. GET /api/v1/matches/:id/fair returns everything needed, and the same verifier code runs in the browser at https://pivarena.com/shared/fair.js 5. Rock paper scissors uses commit-reveal between the players: send sha256(choice + ":" + salt) as hex, then reveal the choice and salt Verify any result at https://pivarena.com/#/fair. ## Bot API reference ### Keys and scopes - Send the key on every request: Authorization: Bearer pva_... Cookies are ignored on /api/v1. A key is shown once; only a hash is stored - read: balance, deposit address, games, open games, match state, fairness, history, WebSocket - play: create, join, cancel, act, rematch, claim rakeback - withdraw: off by default. Needs the owner's 2FA to create. Pays out only to the bot's payout address, which the owner sets on the Account page with 2FA - Limits: 120 requests per minute per key, 60 of them writes. Responses carry X-RateLimit-Limit and X-RateLimit-Remaining; a 429 carries Retry-After (seconds). Up to 5 bots per player and 5 active keys per bot. A revoked key stops working at once ### Bot rules - Bots are tagged BOT in the lobby, in matches, on profiles and in results - A bot can't play its owner, and bots with the same owner can't play each other - Players can turn off "Play against bots". Bots can't join their games, and bot games are hidden from them. /matches/open reports this as joinable: false with a reason - The bot arena ("arena":"bots") is bots only. People can watch but not join - Bots can't chat and can't log in on the website - The owner's account status covers their bots: if the account is frozen, self-excluded or cooling off, its bots can't start new games - The owner can move free balance both ways between themselves and the bot, pause it or delete it. Bot owners are private: no endpoint shows who owns a bot - A paused bot's keys get 403 with "code":"bot_paused". Its open lobby games are cancelled and refunded and its WebSocket is closed (code 4403). It can still finish games in progress - A deleted bot's keys stop working (401). Its balance goes back to the owner, and its name is free again after 30 days - The daily withdrawal cap is shared between an owner and their bots. At most 5 open games at a time ### Endpoints Base URL: https://pivarena.com/api/v1. Bodies are JSON. - GET /api/v1/me (scope: read) The bot account, key scopes, balances and limits. - GET /api/v1/balance?currency=PIVX|ZEC (scope: read) Satoshi strings: `balance` (spendable on stakes), `withdrawable`, `locked` (deposits still confirming), `pendingDeposits`, `inPlay`. `currency` defaults to PIVX; ZEC is a separate balance. - POST /api/v1/deposit-address (scope: read) The bot’s own deposit address. Body: {"kind":"shield"|"transparent"} - GET /api/v1/games (scope: read) Every game id with its rake, options and action format. - GET /api/v1/matches/open?arena=main|bots|all&game=¤cy=PIVX|ZEC|all (scope: read) Open games. Each has `currency`, `joinable` and, if not, the `reason`. - POST /api/v1/matches (scope: play) Create a game. The stake is held at once. `target` makes a private challenge to one player. `currency` is PIVX (default) or ZEC; a game uses one currency for both stakes and the payout. Body: {"game":"coinflip","stake":"1.5","currency":"PIVX"|"ZEC","options":{},"arena":"main"|"bots","clientSeed":"optional"} - POST /api/v1/matches/:id/join (scope: play) Join an open game (same stake). Body: {"clientSeed":"optional"} - POST /api/v1/challenges/:code/accept (scope: play) Accept a private challenge or rematch offer by its code. Body: {"clientSeed":"optional"} - POST /api/v1/challenges/:code/decline (scope: play) Decline a rematch offer. - POST /api/v1/matches/:id/cancel (scope: play) Cancel your own open game before anyone joins. The stake is refunded. - POST /api/v1/matches/:id/action (scope: play) Make a move. The body is the game’s action object (see /api/v1/games). Body: {"type":"drop","col":3} - POST /api/v1/matches/:id/rematch (scope: play) Offer a rematch after a settled duel. - GET /api/v1/matches/:id (scope: read) The match as your seat sees it: players, `mySeat`, game `view`, result. - GET /api/v1/matches/:id/fair (scope: read) Server seed hash, server seed (after the match), every client seed and the result. - GET /api/v1/history (scope: read) The bot’s recent matches (`rows`) and its last 20 transfers with its owner (`transfers`). - GET /api/v1/transfers (scope: read) PIVX moved between the bot and its owner: `direction` (`in` = from the owner, `out` = to the owner), `amount`, `lockedAmount` (part not yet withdrawable), `via` (`owner`, `delete`, `sweep`), `createdAt`. The owner is never named. - POST /api/v1/rakeback/claim (scope: play) Claim accrued rakeback into the balance. Body: {"nonce":"unique-per-claim"} - POST /api/v1/withdraw (scope: withdraw) Withdraw PIVX to the payout address the owner set. No other address is possible. Body: {"amount":"10"} - POST /api/v1/zec/deposit-address (scope: read) The bot’s own shielded ZEC deposit address (unified, Orchard + Sapling), when ZEC is enabled. - POST /api/v1/zec/withdraw (scope: withdraw) Withdraw ZEC to the ZEC payout address the owner set (t, z, unified or TEX). The ZEC fee is added on top. Body: {"amount":"0.5"} - WS /ws/bot (scope: read) Live pushes. Send the same Authorization header on the upgrade. Match fields used most: status (open, active, settled, cancelled), currency, mySeat (-1 if watching), players[] (each with bot and house flags), view (game-specific, only what your seat may see; turn games include toAct and a deadline), result. ### WebSocket Connect to wss://pivarena.com/ws/bot with the same Authorization header. Up to 5 sockets per key. Send JSON: {"t":"sub","ch":"lobby"} open games, live games, recent results {"t":"sub","ch":"match","id":123} pushes for one match (up to 20) {"t":"unsub","ch":"match","id":123} {"t":"ping"} You receive: - hello: on connect, your username plus the house and bots name lists - lobby: open, live and recent games changed (open[] items carry arena and creator_bot) - match: a subscribed match changed; view is the same object as GET /matches/:id - balance: your balance changed - joined: someone joined a game you sit at (matchId, by, full, seats, max, host) - rematch_offer: a rematch offer for you; accept with /challenges/:code/accept using code - rematch_declined: your rematch offer was declined - err: bad or rate-limited message ### Errors Errors are JSON: {"error":"human readable message"}, some with a machine-readable code, e.g. {"error":"bot paused: the owner paused this bot","code":"bot_paused"}. - 400: invalid input, not enough balance, or a move the game doesn't allow - 401: missing, malformed or revoked key - 403: missing scope, or a rule blocks it (bot arena, opted-out player, own bot, account status); code bot_paused when paused - 404: no such match or challenge - 409: wrong state: already joined, already started, too many open games - 429: rate limited; wait Retry-After seconds - 503: deposit address pool refilling; retry in a minute ### Examples curl: export KEY=pva_your_key_here curl -s https://pivarena.com/api/v1/me -H "Authorization: Bearer $KEY" curl -s "https://pivarena.com/api/v1/matches/open?arena=bots&game=coinflip" -H "Authorization: Bearer $KEY" curl -s -X POST https://pivarena.com/api/v1/matches -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{"game":"coinflip","stake":"1","options":{"side":"heads"},"arena":"bots"}' curl -s -X POST https://pivarena.com/api/v1/matches -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{"game":"dice","stake":"0.01","currency":"ZEC","arena":"bots"}' Python: import os, requests S = requests.Session() S.headers["Authorization"] = "Bearer " + os.environ["PIVARENA_KEY"] BASE = "https://pivarena.com/api/v1" me = S.get(BASE + "/me").json() r = S.post(BASE + "/matches", json={"game": "dice", "stake": "0.5", "arena": "bots"}) r.raise_for_status() fair = S.get(BASE + "/matches/%d/fair" % r.json()["id"]).json() print(fair["serverSeedHash"]) Full HTML reference with a JavaScript game loop and a WebSocket example: https://pivarena.com/docs/api ## Responsible play - Limits, cool-off and self-exclusion: https://pivarena.com/#/rg - Tor: https://pivarena.com/#/tor ## Contact - Site: https://pivarena.com